mirror of
				https://github.com/Mibew/simple-icons.git
				synced 2025-10-31 02:25:59 +03:00 
			
		
		
		
	Add XO linter (#10643)
This commit is contained in:
		
							parent
							
								
									d66bdb1380
								
							
						
					
					
						commit
						bf69b6dee0
					
				
							
								
								
									
										2
									
								
								.github/renovate.json5
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/renovate.json5
									
									
									
									
										vendored
									
									
								
							| @ -16,5 +16,5 @@ | ||||
|   separateMajorMinor: false, | ||||
| 
 | ||||
|   // We manually update digest dependencies (eg. hashes in Github actions) | ||||
|   digest: { enabled: false }, | ||||
|   digest: {enabled: false}, | ||||
| } | ||||
|  | ||||
							
								
								
									
										8
									
								
								.github/workflows/create-release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/create-release.yml
									
									
									
									
										vendored
									
									
								
							| @ -54,13 +54,13 @@ jobs: | ||||
|       - name: Install dependencies | ||||
|         run: npm i --ignore-scripts --no-audit --no-fund | ||||
|       - name: Update major version in CDN URLs | ||||
|         run: node ./scripts/release/update-cdn-urls.js | ||||
|         run: ./scripts/release/update-cdn-urls.js | ||||
|       - name: Update SVGs count milestone | ||||
|         run: node ./scripts/release/update-svgs-count.js | ||||
|         run: ./scripts/release/update-svgs-count.js | ||||
|       - name: Update slugs table | ||||
|         run: node ./scripts/release/update-slugs-table.js | ||||
|         run: ./scripts/release/update-slugs-table.js | ||||
|       - name: Update SDK Typescript definitions | ||||
|         run: node ./scripts/release/update-sdk-ts-defs.js | ||||
|         run: ./scripts/release/update-sdk-ts-defs.js | ||||
|       - name: Commit version bump | ||||
|         uses: stefanzweifel/git-auto-commit-action@v5 | ||||
|         with: | ||||
|  | ||||
							
								
								
									
										6
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
								
							| @ -43,9 +43,9 @@ jobs: | ||||
|       - name: Install dependencies | ||||
|         run: npm i --ignore-scripts --no-audit --no-fund | ||||
|       - name: Reformat to regular markdown | ||||
|         run: node ./scripts/release/reformat-markdown.js "${{ steps.get-version.outputs.version }}" | ||||
|         run: ./scripts/release/reformat-markdown.js "${{ steps.get-version.outputs.version }}" | ||||
|       - name: Update SDK Typescript definitions | ||||
|         run: node ./scripts/release/update-sdk-ts-defs.js | ||||
|         run: ./scripts/release/update-sdk-ts-defs.js | ||||
|       - name: Build NodeJS package | ||||
|         run: npm run build | ||||
|       - name: Deploy to NPM | ||||
| @ -65,7 +65,7 @@ jobs: | ||||
|       - id: get-version | ||||
|         uses: ./.github/actions/get-version | ||||
|       - name: Reformat to regular markdown | ||||
|         run: node ./scripts/release/reformat-markdown.js "${{ steps.get-version.outputs.version }}" | ||||
|         run: ./scripts/release/reformat-markdown.js "${{ steps.get-version.outputs.version }}" | ||||
|       - name: Configure GIT credentials | ||||
|         run: | | ||||
|           git config user.name "${GITHUB_ACTOR}" | ||||
|  | ||||
| @ -32,12 +32,12 @@ | ||||
|             "aka": { | ||||
|               "description": "The brand is also known as (e.g. full length name or abbreviation)", | ||||
|               "type": "array", | ||||
|               "items": { "type": "string" } | ||||
|               "items": {"type": "string"} | ||||
|             }, | ||||
|             "dup": { | ||||
|               "description": "Different brands that use the exact same icon", | ||||
|               "type": "array", | ||||
|               "items": { "$ref": "#/definitions/duplicate" } | ||||
|               "items": {"$ref": "#/definitions/duplicate"} | ||||
|             }, | ||||
|             "loc": { | ||||
|               "description": "Localized names of the brand", | ||||
| @ -46,7 +46,7 @@ | ||||
|             "old": { | ||||
|               "description": "Old names, for backwards compatibility", | ||||
|               "type": "array", | ||||
|               "items": { "type": "string" } | ||||
|               "items": {"type": "string"} | ||||
|             } | ||||
|           }, | ||||
|           "minProperties": 1, | ||||
| @ -702,7 +702,7 @@ | ||||
|     "icons": { | ||||
|       "description": "A list of brands", | ||||
|       "type": "array", | ||||
|       "items": { "$ref": "#/definitions/brand" } | ||||
|       "items": {"$ref": "#/definitions/brand"} | ||||
|     } | ||||
|   }, | ||||
|   "additionalProperties": false, | ||||
|  | ||||
| @ -6,12 +6,3 @@ | ||||
| 
 | ||||
| # We use our own formatting for the data files. | ||||
| _data/simple-icons.json | ||||
| 
 | ||||
| # JavaScript templates are invalid JavaScript so cannot be formatted. | ||||
| scripts/build/templates/*.js | ||||
| 
 | ||||
| # Generated JavaScript files don't need to be formatted | ||||
| index.js | ||||
| index.mjs | ||||
| index.d.ts | ||||
| sdk.js | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| { | ||||
|   "singleQuote": true | ||||
|   "singleQuote": true, | ||||
|   "bracketSpacing": false | ||||
| } | ||||
|  | ||||
							
								
								
									
										49
									
								
								.xo-config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								.xo-config.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| { | ||||
|   "prettier": true, | ||||
|   "space": 2, | ||||
|   "plugins": ["import"], | ||||
|   "rules": { | ||||
|     "n/no-unsupported-features": "off", | ||||
|     "n/no-unsupported-features/node-builtins": "off", | ||||
|     "n/file-extension-in-import": "off", | ||||
|     "sort-imports": [ | ||||
|       "error", | ||||
|       { | ||||
|         "ignoreCase": false, | ||||
|         "ignoreDeclarationSort": true, | ||||
|         "ignoreMemberSort": false, | ||||
|         "memberSyntaxSortOrder": ["none", "all", "multiple", "single"], | ||||
|         "allowSeparatedGroups": false | ||||
|       } | ||||
|     ], | ||||
|     "import/no-named-as-default": "off", | ||||
|     "import/extensions": "off", | ||||
|     "import/order": [ | ||||
|       "error", | ||||
|       { | ||||
|         "groups": ["builtin", "external", "parent", "sibling", "index"], | ||||
|         "alphabetize": { | ||||
|           "order": "asc", | ||||
|           "caseInsensitive": true | ||||
|         }, | ||||
|         "warnOnUnassignedImports": true, | ||||
|         "newlines-between": "never" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|   "overrides": [ | ||||
|     { | ||||
|       "files": ["sdk.mjs", "sdk.d.ts"], | ||||
|       "nodeVersion": ">=14" | ||||
|     }, | ||||
|     { | ||||
|       "files": [ | ||||
|         "scripts/**/*", | ||||
|         "tests/**/*", | ||||
|         "svglint.config.mjs", | ||||
|         "svgo.config.mjs" | ||||
|       ], | ||||
|       "nodeVersion": ">=18" | ||||
|     } | ||||
|   ] | ||||
| } | ||||
							
								
								
									
										26
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								package.json
									
									
									
									
									
								
							| @ -88,6 +88,7 @@ | ||||
|     "chalk": "5.3.0", | ||||
|     "editorconfig-checker": "5.1.5", | ||||
|     "esbuild": "0.19.4", | ||||
|     "eslint-plugin-import": "2.29.1", | ||||
|     "fake-diff": "1.0.0", | ||||
|     "fast-fuzzy": "1.12.0", | ||||
|     "get-relative-luminance": "1.0.0", | ||||
| @ -97,23 +98,24 @@ | ||||
|     "markdown-link-check": "3.11.2", | ||||
|     "mocha": "10.2.0", | ||||
|     "named-html-entities-json": "1.0.0", | ||||
|     "prettier": "3.0.3", | ||||
|     "svg-path-bbox": "1.2.5", | ||||
|     "svg-path-segments": "1.0.0", | ||||
|     "svglint": "2.4.0", | ||||
|     "svgo": "3.0.2", | ||||
|     "svgpath": "2.6.0", | ||||
|     "typescript": "5.2.2" | ||||
|     "typescript": "5.2.2", | ||||
|     "xo": "0.58.0" | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "build": "node scripts/build/package.js", | ||||
|     "clean": "node scripts/build/clean.js", | ||||
|     "format": "prettier --cache --write .", | ||||
|     "lint": "npm run ourlint && npm run jslint && npm run jsonlint && npm run svglint && npm run wslint", | ||||
|     "ourlint": "node scripts/lint/ourlint.js", | ||||
|     "jslint": "prettier --cache --check .", | ||||
|     "jsonlint": "node scripts/lint/jsonlint.js", | ||||
|     "svglint": "svglint --ci $npm_config_icons", | ||||
|     "build": "./scripts/build/package.js", | ||||
|     "clean": "./scripts/build/clean.js", | ||||
|     "format": "prettier --cache --write --ignore-unknown '**/*.!(js|jsx|mjs|cjs|ts|tsx|mts|cts|svg)' && xo --fix", | ||||
|     "lint": "npm run ourlint && npm run prettierlint && npm run jslint && npm run jsonlint && npm run svglint && npm run wslint", | ||||
|     "ourlint": "./scripts/lint/ourlint.js", | ||||
|     "prettierlint": "prettier --cache --check --ignore-unknown '**/*.!(js|jsx|mjs|cjs|ts|tsx|mts|cts|svg)'", | ||||
|     "jslint": "xo", | ||||
|     "jsonlint": "./scripts/lint/jsonlint.js", | ||||
|     "svglint": "svglint --ci $npm_config_icons --config svglint.config.mjs", | ||||
|     "wslint": "editorconfig-checker", | ||||
|     "prepare": "husky", | ||||
|     "prepublishOnly": "npm run build", | ||||
| @ -121,8 +123,8 @@ | ||||
|     "test": "mocha tests --reporter tests/min-reporter.cjs --inline-diffs", | ||||
|     "pretest": "npm run prepublishOnly", | ||||
|     "posttest": "npm run postpublish", | ||||
|     "get-filename": "node scripts/get-filename.js", | ||||
|     "add-icon-data": "node scripts/add-icon-data.js" | ||||
|     "get-filename": "./scripts/get-filename.js", | ||||
|     "add-icon-data": "./scripts/add-icon-data.js" | ||||
|   }, | ||||
|   "engines": { | ||||
|     "node": ">=0.12.18" | ||||
|  | ||||
							
								
								
									
										29
									
								
								scripts/add-icon-data.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										29
									
								
								scripts/add-icon-data.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,22 +1,23 @@ | ||||
| #!/usr/bin/env node
 | ||||
| import process from 'node:process'; | ||||
| import {ExitPromptError, checkbox, confirm, input} from '@inquirer/prompts'; | ||||
| import chalk from 'chalk'; | ||||
| import { input, confirm, checkbox, ExitPromptError } from '@inquirer/prompts'; | ||||
| import autocomplete from 'inquirer-autocomplete-standalone'; | ||||
| import {search} from 'fast-fuzzy'; | ||||
| import getRelativeLuminance from 'get-relative-luminance'; | ||||
| import { search } from 'fast-fuzzy'; | ||||
| import autocomplete from 'inquirer-autocomplete-standalone'; | ||||
| import { | ||||
|   URL_REGEX, | ||||
|   collator, | ||||
|   getIconsDataString, | ||||
|   titleToSlug, | ||||
|   normalizeColor, | ||||
|   titleToSlug, | ||||
| } from '../sdk.mjs'; | ||||
| import { getJsonSchemaData, writeIconsData } from './utils.js'; | ||||
| import {getJsonSchemaData, writeIconsData} from './utils.js'; | ||||
| 
 | ||||
| const iconsData = JSON.parse(await getIconsDataString()); | ||||
| const jsonSchema = await getJsonSchemaData(); | ||||
| 
 | ||||
| const HEX_REGEX = /^#?[a-f0-9]{3,8}$/i; | ||||
| const HEX_REGEX = /^#?[a-f\d]{3,8}$/i; | ||||
| 
 | ||||
| const aliasTypes = ['aka', 'old'].map((key) => ({ | ||||
|   name: `${key} (${jsonSchema.definitions.brand.properties.aliases.properties[key].description})`, | ||||
| @ -25,7 +26,7 @@ const aliasTypes = ['aka', 'old'].map((key) => ({ | ||||
| 
 | ||||
| const licenseTypes = | ||||
|   jsonSchema.definitions.brand.properties.license.oneOf[0].properties.type.enum.map( | ||||
|     (license) => ({ name: license, value: license }), | ||||
|     (license) => ({name: license, value: license}), | ||||
|   ); | ||||
| 
 | ||||
| const isValidURL = (input) => | ||||
| @ -35,7 +36,7 @@ const isValidHexColor = (input) => | ||||
|   HEX_REGEX.test(input) || 'Must be a valid hex code.'; | ||||
| 
 | ||||
| const isNewIcon = (input) => | ||||
|   !iconsData.icons.find( | ||||
|   !iconsData.icons.some( | ||||
|     (icon) => | ||||
|       icon.title === input || titleToSlug(icon.title) === titleToSlug(input), | ||||
|   ) || 'This icon title or slug already exists.'; | ||||
| @ -83,10 +84,10 @@ try { | ||||
|       ? { | ||||
|           type: await autocomplete({ | ||||
|             message: "What is the icon's license?", | ||||
|             source: async (input) => { | ||||
|             async source(input) { | ||||
|               input = (input || '').trim(); | ||||
|               return input | ||||
|                 ? search(input, licenseTypes, { keySelector: (x) => x.value }) | ||||
|                 ? search(input, licenseTypes, {keySelector: (x) => x.value}) | ||||
|                 : licenseTypes; | ||||
|             }, | ||||
|           }), | ||||
| @ -107,12 +108,14 @@ try { | ||||
|         }).then(async (aliases) => { | ||||
|           const result = {}; | ||||
|           for (const alias of aliases) { | ||||
|             // eslint-disable-next-line no-await-in-loop
 | ||||
|             result[alias] = await input({ | ||||
|               message: `What ${alias} aliases would you like to add? (separate with commas)`, | ||||
|             }).then((aliases) => | ||||
|               aliases.split(',').map((alias) => alias.trim()), | ||||
|             ); | ||||
|           } | ||||
| 
 | ||||
|           return result; | ||||
|         }) | ||||
|       : undefined, | ||||
| @ -136,11 +139,11 @@ try { | ||||
|     console.log(chalk.red('\nAborted.')); | ||||
|     process.exit(1); | ||||
|   } | ||||
| } catch (err) { | ||||
|   if (err instanceof ExitPromptError) { | ||||
| } catch (error) { | ||||
|   if (error instanceof ExitPromptError) { | ||||
|     console.log(chalk.red('\nAborted.')); | ||||
|     process.exit(1); | ||||
|   } | ||||
| 
 | ||||
|   throw err; | ||||
|   throw error; | ||||
| } | ||||
|  | ||||
							
								
								
									
										38
									
								
								scripts/build/clean.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										38
									
								
								scripts/build/clean.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,29 +1,37 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * @fileoverview | ||||
|  * Clean files built by the build process. | ||||
|  */ | ||||
| 
 | ||||
| import fs from 'node:fs'; | ||||
| import fs from 'node:fs/promises'; | ||||
| import path from 'node:path'; | ||||
| import { getDirnameFromImportMeta } from '../../sdk.mjs'; | ||||
| import process from 'node:process'; | ||||
| import {getDirnameFromImportMeta} from '../../sdk.mjs'; | ||||
| 
 | ||||
| const __dirname = getDirnameFromImportMeta(import.meta.url); | ||||
| const rootDirectory = path.resolve(__dirname, '..', '..'); | ||||
| const files = ['index.js', 'index.mjs', 'index.d.ts', 'sdk.js']; | ||||
| 
 | ||||
| const fileExists = (fpath) => | ||||
|   new Promise((r) => fs.access(fpath, fs.constants.F_OK, (e) => r(!e))); | ||||
|   fs | ||||
|     .access(fpath, fs.constants.F_OK) | ||||
|     .then(() => true) | ||||
|     .catch(() => false); | ||||
| 
 | ||||
| Promise.all( | ||||
|   files.map(async (file) => { | ||||
|     const filepath = path.join(rootDirectory, file); | ||||
|     if (!(await fileExists(filepath))) { | ||||
|       console.error(`File ${file} does not exist, skipping...`); | ||||
|       return; | ||||
|     } | ||||
|     return fs.promises.unlink(filepath); | ||||
|   }), | ||||
| ).catch((error) => { | ||||
|   console.error(`Error cleaning files: ${error.message}`); | ||||
| try { | ||||
|   Promise.all( | ||||
|     files.map(async (file) => { | ||||
|       const filepath = path.join(rootDirectory, file); | ||||
|       if (!(await fileExists(filepath))) { | ||||
|         console.error(`File ${file} does not exist, skipping...`); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       return fs.unlink(filepath); | ||||
|     }), | ||||
|   ); | ||||
| } catch (error) { | ||||
|   console.error('Error cleaning files:', error); | ||||
|   process.exit(1); | ||||
| }); | ||||
| } | ||||
|  | ||||
							
								
								
									
										65
									
								
								scripts/build/package.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										65
									
								
								scripts/build/package.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,36 +1,40 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * @fileoverview | ||||
|  * Simple Icons package build script. | ||||
|  */ | ||||
| 
 | ||||
| import { promises as fs } from 'node:fs'; | ||||
| import {promises as fs} from 'node:fs'; | ||||
| import path from 'node:path'; | ||||
| import util from 'node:util'; | ||||
| import { transform as esbuildTransform } from 'esbuild'; | ||||
| import {transform as esbuildTransform} from 'esbuild'; | ||||
| import { | ||||
|   collator, | ||||
|   getDirnameFromImportMeta, | ||||
|   getIconSlug, | ||||
|   getIconsData, | ||||
|   slugToVariableName, | ||||
|   svgToPath, | ||||
|   titleToHtmlFriendly, | ||||
|   slugToVariableName, | ||||
|   getIconsData, | ||||
|   getDirnameFromImportMeta, | ||||
|   collator, | ||||
| } from '../../sdk.mjs'; | ||||
| 
 | ||||
| const __dirname = getDirnameFromImportMeta(import.meta.url); | ||||
| 
 | ||||
| const UTF8 = 'utf8'; | ||||
| 
 | ||||
| const rootDir = path.resolve(__dirname, '..', '..'); | ||||
| const iconsDir = path.resolve(rootDir, 'icons'); | ||||
| const indexJsFile = path.resolve(rootDir, 'index.js'); | ||||
| const indexMjsFile = path.resolve(rootDir, 'index.mjs'); | ||||
| const sdkJsFile = path.resolve(rootDir, 'sdk.js'); | ||||
| const sdkMjsFile = path.resolve(rootDir, 'sdk.mjs'); | ||||
| const indexDtsFile = path.resolve(rootDir, 'index.d.ts'); | ||||
| const rootDirectory = path.resolve(__dirname, '..', '..'); | ||||
| const iconsDirectory = path.resolve(rootDirectory, 'icons'); | ||||
| const indexJsFile = path.resolve(rootDirectory, 'index.js'); | ||||
| const indexMjsFile = path.resolve(rootDirectory, 'index.mjs'); | ||||
| const sdkJsFile = path.resolve(rootDirectory, 'sdk.js'); | ||||
| const sdkMjsFile = path.resolve(rootDirectory, 'sdk.mjs'); | ||||
| const indexDtsFile = path.resolve(rootDirectory, 'index.d.ts'); | ||||
| 
 | ||||
| const templatesDir = path.resolve(__dirname, 'templates'); | ||||
| const iconObjectTemplateFile = path.resolve(templatesDir, 'icon-object.js'); | ||||
| const templatesDirectory = path.resolve(__dirname, 'templates'); | ||||
| const iconObjectTemplateFile = path.resolve( | ||||
|   templatesDirectory, | ||||
|   'icon-object.js.template', | ||||
| ); | ||||
| 
 | ||||
| const build = async () => { | ||||
|   const icons = await getIconsData(); | ||||
| @ -38,8 +42,9 @@ const build = async () => { | ||||
| 
 | ||||
|   // Local helper functions
 | ||||
|   const escape = (value) => { | ||||
|     return value.replace(/(?<!\\)'/g, "\\'"); | ||||
|     return value.replaceAll(/(?<!\\)'/g, "\\'"); | ||||
|   }; | ||||
| 
 | ||||
|   const licenseToObject = (license) => { | ||||
|     if (license === undefined) { | ||||
|       return; | ||||
| @ -48,8 +53,10 @@ const build = async () => { | ||||
|     if (license.url === undefined) { | ||||
|       license.url = `https://spdx.org/licenses/${license.type}`; | ||||
|     } | ||||
| 
 | ||||
|     return license; | ||||
|   }; | ||||
| 
 | ||||
|   const iconToObject = (icon) => { | ||||
|     return util.format( | ||||
|       iconObjectTemplate, | ||||
| @ -65,11 +72,13 @@ const build = async () => { | ||||
|         : '', | ||||
|     ); | ||||
|   }; | ||||
|   const writeJs = async (filepath, rawJavaScript, opts = null) => { | ||||
|     opts = opts === null ? { minify: true } : opts; | ||||
|     const { code } = await esbuildTransform(rawJavaScript, opts); | ||||
| 
 | ||||
|   const writeJs = async (filepath, rawJavaScript, options = null) => { | ||||
|     options = options === null ? {minify: true} : options; | ||||
|     const {code} = await esbuildTransform(rawJavaScript, options); | ||||
|     await fs.writeFile(filepath, code); | ||||
|   }; | ||||
| 
 | ||||
|   const writeTs = async (filepath, rawTypeScript) => { | ||||
|     await fs.writeFile(filepath, rawTypeScript); | ||||
|   }; | ||||
| @ -78,13 +87,13 @@ const build = async () => { | ||||
|   const buildIcons = await Promise.all( | ||||
|     icons.map(async (icon) => { | ||||
|       const filename = getIconSlug(icon); | ||||
|       const svgFilepath = path.resolve(iconsDir, `${filename}.svg`); | ||||
|       const svgFilepath = path.resolve(iconsDirectory, `${filename}.svg`); | ||||
|       icon.svg = await fs.readFile(svgFilepath, UTF8); | ||||
|       icon.path = svgToPath(icon.svg); | ||||
|       icon.slug = filename; | ||||
|       const iconObject = iconToObject(icon); | ||||
|       const iconExportName = slugToVariableName(icon.slug); | ||||
|       return { icon, iconObject, iconExportName }; | ||||
|       return {icon, iconObject, iconExportName}; | ||||
|     }), | ||||
|   ); | ||||
| 
 | ||||
| @ -93,33 +102,33 @@ const build = async () => { | ||||
|   const iconsBarrelMjs = []; | ||||
| 
 | ||||
|   buildIcons.sort((a, b) => collator.compare(a.icon.title, b.icon.title)); | ||||
|   for (const { iconObject, iconExportName } of buildIcons) { | ||||
|   for (const {iconObject, iconExportName} of buildIcons) { | ||||
|     iconsBarrelDts.push(`export const ${iconExportName}:I;`); | ||||
|     iconsBarrelJs.push(`${iconExportName}:${iconObject},`); | ||||
|     iconsBarrelMjs.push(`export const ${iconExportName}=${iconObject}`); | ||||
|   } | ||||
| 
 | ||||
|   // constants used in templates to reduce package size
 | ||||
|   // Constants used in templates to reduce package size
 | ||||
|   const constantsString = `const a='<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>',b='</title><path d="',c='"/></svg>';`; | ||||
| 
 | ||||
|   // write our file containing the exports of all icons in CommonJS ...
 | ||||
|   // Write our file containing the exports of all icons in CommonJS ...
 | ||||
|   const rawIndexJs = `${constantsString}module.exports={${iconsBarrelJs.join( | ||||
|     '', | ||||
|   )}};`;
 | ||||
|   await writeJs(indexJsFile, rawIndexJs); | ||||
|   // and ESM
 | ||||
|   // ... and ESM
 | ||||
|   const rawIndexMjs = constantsString + iconsBarrelMjs.join(''); | ||||
|   await writeJs(indexMjsFile, rawIndexMjs); | ||||
|   // and create a type declaration file
 | ||||
|   // ... and create a type declaration file
 | ||||
|   const rawIndexDts = `import {SimpleIcon} from "./types";export {SimpleIcon};type I=SimpleIcon;${iconsBarrelDts.join( | ||||
|     '', | ||||
|   )}`;
 | ||||
|   await writeTs(indexDtsFile, rawIndexDts); | ||||
| 
 | ||||
|   // create a CommonJS SDK file
 | ||||
|   // Create a CommonJS SDK file
 | ||||
|   await writeJs(sdkJsFile, await fs.readFile(sdkMjsFile, UTF8), { | ||||
|     format: 'cjs', | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| build(); | ||||
| await build(); | ||||
|  | ||||
							
								
								
									
										8
									
								
								scripts/get-filename.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										8
									
								
								scripts/get-filename.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,3 +1,4 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * @fileoverview | ||||
|  * Script that takes a brand name as argument and outputs the corresponding | ||||
| @ -5,16 +6,13 @@ | ||||
|  */ | ||||
| 
 | ||||
| import process from 'node:process'; | ||||
| import { titleToSlug } from '../sdk.mjs'; | ||||
| import {titleToSlug} from '../sdk.mjs'; | ||||
| 
 | ||||
| if (process.argv.length < 3) { | ||||
|   console.error('Provide a brand name as argument'); | ||||
|   process.exit(1); | ||||
| } else { | ||||
|   const brandName = process.argv | ||||
|     .slice(3) | ||||
|     .reduce((acc, arg) => `${acc} ${arg}`, process.argv[2]); | ||||
| 
 | ||||
|   const brandName = process.argv[2]; | ||||
|   const filename = titleToSlug(brandName); | ||||
|   console.log(`For '${brandName}' use the file 'icons/${filename}.svg'`); | ||||
| } | ||||
|  | ||||
							
								
								
									
										11
									
								
								scripts/lint/jsonlint.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										11
									
								
								scripts/lint/jsonlint.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,20 +1,21 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * @fileoverview | ||||
|  * CLI tool to run jsonschema on the simple-icons.json data file. | ||||
|  */ | ||||
| 
 | ||||
| import process from 'node:process'; | ||||
| import { Validator } from 'jsonschema'; | ||||
| import { getIconsData } from '../../sdk.mjs'; | ||||
| import { getJsonSchemaData } from '../utils.js'; | ||||
| import {Validator} from 'jsonschema'; | ||||
| import {getIconsData} from '../../sdk.mjs'; | ||||
| import {getJsonSchemaData} from '../utils.js'; | ||||
| 
 | ||||
| const icons = await getIconsData(); | ||||
| const schema = await getJsonSchemaData(); | ||||
| 
 | ||||
| const validator = new Validator(); | ||||
| const result = validator.validate({ icons }, schema); | ||||
| const result = validator.validate({icons}, schema); | ||||
| if (result.errors.length > 0) { | ||||
|   result.errors.forEach((error) => console.error(error)); | ||||
|   for (const error of result.errors) console.error(error); | ||||
|   console.error(`Found ${result.errors.length} error(s) in simple-icons.json`); | ||||
|   process.exit(1); | ||||
| } | ||||
|  | ||||
							
								
								
									
										40
									
								
								scripts/lint/ourlint.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										40
									
								
								scripts/lint/ourlint.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,3 +1,4 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * @fileoverview | ||||
|  * Linters for the package that can't easily be implemented in the existing | ||||
| @ -5,9 +6,8 @@ | ||||
|  */ | ||||
| 
 | ||||
| import process from 'node:process'; | ||||
| import { URL } from 'node:url'; | ||||
| import fakeDiff from 'fake-diff'; | ||||
| import { getIconsDataString, normalizeNewlines, collator } from '../../sdk.mjs'; | ||||
| import {collator, getIconsDataString, normalizeNewlines} from '../../sdk.mjs'; | ||||
| 
 | ||||
| /** | ||||
|  * Contains our tests so they can be isolated from each other. | ||||
| @ -15,39 +15,43 @@ import { getIconsDataString, normalizeNewlines, collator } from '../../sdk.mjs'; | ||||
|  */ | ||||
| const TESTS = { | ||||
|   /* Tests whether our icons are in alphabetical order */ | ||||
|   alphabetical: (data) => { | ||||
|   alphabetical(data) { | ||||
|     const collector = (invalidEntries, icon, index, array) => { | ||||
|       if (index > 0) { | ||||
|         const prev = array[index - 1]; | ||||
|         const comparison = collator.compare(icon.title, prev.title); | ||||
|         const previous = array[index - 1]; | ||||
|         const comparison = collator.compare(icon.title, previous.title); | ||||
|         if (comparison < 0) { | ||||
|           invalidEntries.push(icon); | ||||
|         } else if (comparison === 0) { | ||||
|           if (prev.slug) { | ||||
|             if (!icon.slug || collator.compare(icon.slug, prev.slug) < 0) { | ||||
|               invalidEntries.push(icon); | ||||
|             } | ||||
|           } | ||||
|         } else if ( | ||||
|           comparison === 0 && | ||||
|           previous.slug && | ||||
|           (!icon.slug || collator.compare(icon.slug, previous.slug) < 0) | ||||
|         ) { | ||||
|           invalidEntries.push(icon); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       return invalidEntries; | ||||
|     }; | ||||
| 
 | ||||
|     const format = (icon) => { | ||||
|       if (icon.slug) { | ||||
|         return `${icon.title} (${icon.slug})`; | ||||
|       } | ||||
| 
 | ||||
|       return icon.title; | ||||
|     }; | ||||
| 
 | ||||
|     // eslint-disable-next-line unicorn/no-array-reduce, unicorn/no-array-callback-reference
 | ||||
|     const invalids = data.icons.reduce(collector, []); | ||||
|     if (invalids.length) { | ||||
|     if (invalids.length > 0) { | ||||
|       return `Some icons aren't in alphabetical order:
 | ||||
|         ${invalids.map((icon) => format(icon)).join(', ')}`;
 | ||||
|     } | ||||
|   }, | ||||
| 
 | ||||
|   /* Check the formatting of the data file */ | ||||
|   prettified: (data, dataString) => { | ||||
|   prettified(data, dataString) { | ||||
|     const normalizedDataString = normalizeNewlines(dataString); | ||||
|     const dataPretty = `${JSON.stringify(data, null, 4)}\n`; | ||||
| 
 | ||||
| @ -58,9 +62,9 @@ const TESTS = { | ||||
|   }, | ||||
| 
 | ||||
|   /* Check redundant trailing slash in URL */ | ||||
|   checkUrl: (data) => { | ||||
|   checkUrl(data) { | ||||
|     const hasRedundantTrailingSlash = (url) => { | ||||
|       const origin = new URL(url).origin; | ||||
|       const {origin} = new global.URL(url); | ||||
|       return /^\/+$/.test(url.replace(origin, '')); | ||||
|     }; | ||||
| 
 | ||||
| @ -89,9 +93,11 @@ const data = JSON.parse(dataString); | ||||
| 
 | ||||
| const errors = ( | ||||
|   await Promise.all(Object.values(TESTS).map((test) => test(data, dataString))) | ||||
| ).filter(Boolean); | ||||
| ) | ||||
|   // eslint-disable-next-line unicorn/no-await-expression-member
 | ||||
|   .filter(Boolean); | ||||
| 
 | ||||
| if (errors.length > 0) { | ||||
|   errors.forEach((error) => console.error(`\u001b[31m${error}\u001b[0m`)); | ||||
|   for (const error of errors) console.error(`\u001B[31m${error}\u001B[0m`); | ||||
|   process.exit(1); | ||||
| } | ||||
|  | ||||
							
								
								
									
										24
									
								
								scripts/release/reformat-markdown.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										24
									
								
								scripts/release/reformat-markdown.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,19 +1,21 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * @fileoverview | ||||
|  * Rewrite some Markdown files. | ||||
|  */ | ||||
| 
 | ||||
| import {readFile, writeFile} from 'node:fs/promises'; | ||||
| import path from 'node:path'; | ||||
| import { writeFile, readFile } from 'node:fs/promises'; | ||||
| import { getDirnameFromImportMeta } from '../../sdk.mjs'; | ||||
| import process from 'node:process'; | ||||
| import {getDirnameFromImportMeta} from '../../sdk.mjs'; | ||||
| 
 | ||||
| const LINKS_BRANCH = process.argv[2] || 'develop'; | ||||
| 
 | ||||
| const __dirname = getDirnameFromImportMeta(import.meta.url); | ||||
| 
 | ||||
| const rootDir = path.resolve(__dirname, '..', '..'); | ||||
| const readmeFile = path.resolve(rootDir, 'README.md'); | ||||
| const disclaimerFile = path.resolve(rootDir, 'DISCLAIMER.md'); | ||||
| const rootDirectory = path.resolve(__dirname, '..', '..'); | ||||
| const readmeFile = path.resolve(rootDirectory, 'README.md'); | ||||
| const disclaimerFile = path.resolve(rootDirectory, 'DISCLAIMER.md'); | ||||
| 
 | ||||
| const reformat = async (filePath) => { | ||||
|   const fileContent = await readFile(filePath, 'utf8'); | ||||
| @ -21,17 +23,17 @@ const reformat = async (filePath) => { | ||||
|     filePath, | ||||
|     fileContent | ||||
|       // Replace all CDN links with raw links
 | ||||
|       .replace( | ||||
|       .replaceAll( | ||||
|         /https:\/\/cdn.simpleicons.org\/(.+)\/000\/fff/g, | ||||
|         `https://raw.githubusercontent.com/simple-icons/simple-icons/${LINKS_BRANCH}/icons/$1.svg`, | ||||
|       ) | ||||
|       // Replace all GitHub blockquotes with regular markdown
 | ||||
|       // Reference: https://github.com/orgs/community/discussions/16925
 | ||||
|       .replace( | ||||
|         /\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\](?!\()/g, | ||||
|         function (str, $0) { | ||||
|           const capital = $0.substr(0, 1); | ||||
|           const body = $0.substr(1).toLowerCase(); | ||||
|       .replaceAll( | ||||
|         /\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)](?!\()/g, | ||||
|         function (string_, $0) { | ||||
|           const capital = $0.slice(0, 1); | ||||
|           const body = $0.slice(1).toLowerCase(); | ||||
|           return `**${capital + body}**`; | ||||
|         }, | ||||
|       ), | ||||
|  | ||||
							
								
								
									
										23
									
								
								scripts/release/update-cdn-urls.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										23
									
								
								scripts/release/update-cdn-urls.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,35 +1,36 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * @fileoverview | ||||
|  * Updates the CDN URLs in the README.md to match the major version in the | ||||
|  * NPM package manifest. Does nothing if the README.md is already up-to-date. | ||||
|  */ | ||||
| 
 | ||||
| import process from 'node:process'; | ||||
| import fs from 'node:fs/promises'; | ||||
| import path from 'node:path'; | ||||
| import { getDirnameFromImportMeta } from '../../sdk.mjs'; | ||||
| import process from 'node:process'; | ||||
| import {getDirnameFromImportMeta} from '../../sdk.mjs'; | ||||
| 
 | ||||
| const __dirname = getDirnameFromImportMeta(import.meta.url); | ||||
| 
 | ||||
| const rootDir = path.resolve(__dirname, '..', '..'); | ||||
| const packageJsonFile = path.resolve(rootDir, 'package.json'); | ||||
| const readmeFile = path.resolve(rootDir, 'README.md'); | ||||
| const rootDirectory = path.resolve(__dirname, '..', '..'); | ||||
| const packageJsonFile = path.resolve(rootDirectory, 'package.json'); | ||||
| const readmeFile = path.resolve(rootDirectory, 'README.md'); | ||||
| 
 | ||||
| const getMajorVersion = (semVerVersion) => { | ||||
|   const majorVersionAsString = semVerVersion.split('.')[0]; | ||||
|   return parseInt(majorVersionAsString); | ||||
| const getMajorVersion = (semVersion) => { | ||||
|   const majorVersionAsString = semVersion.split('.')[0]; | ||||
|   return Number.parseInt(majorVersionAsString, 10); | ||||
| }; | ||||
| 
 | ||||
| const getManifest = async () => { | ||||
|   const manifestRaw = await fs.readFile(packageJsonFile, 'utf-8'); | ||||
|   const manifestRaw = await fs.readFile(packageJsonFile, 'utf8'); | ||||
|   return JSON.parse(manifestRaw); | ||||
| }; | ||||
| 
 | ||||
| const updateVersionInReadmeIfNecessary = async (majorVersion) => { | ||||
|   let content = await fs.readFile(readmeFile, 'utf8'); | ||||
| 
 | ||||
|   content = content.replace( | ||||
|     /simple-icons@v[0-9]+/g, | ||||
|   content = content.replaceAll( | ||||
|     /simple-icons@v\d+/g, | ||||
|     `simple-icons@v${majorVersion}`, | ||||
|   ); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										34
									
								
								scripts/release/update-sdk-ts-defs.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										34
									
								
								scripts/release/update-sdk-ts-defs.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,33 +1,34 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * @fileoverview | ||||
|  * Updates the SDK Typescript definitions located in the file sdk.d.ts | ||||
|  * to match the current definitions of functions of sdk.mjs. | ||||
|  */ | ||||
| 
 | ||||
| import process from 'node:process'; | ||||
| import {execSync} from 'node:child_process'; | ||||
| import fs from 'node:fs/promises'; | ||||
| import path from 'node:path'; | ||||
| import { execSync } from 'node:child_process'; | ||||
| import { getDirnameFromImportMeta } from '../../sdk.mjs'; | ||||
| import process from 'node:process'; | ||||
| import {getDirnameFromImportMeta} from '../../sdk.mjs'; | ||||
| 
 | ||||
| const __dirname = getDirnameFromImportMeta(import.meta.url); | ||||
| const rootDir = path.resolve(__dirname, '..', '..'); | ||||
| const rootDirectory = path.resolve(__dirname, '..', '..'); | ||||
| 
 | ||||
| const sdkTs = path.resolve(rootDir, 'sdk.d.ts'); | ||||
| const sdkMts = path.resolve(rootDir, 'sdk.d.mts'); | ||||
| const sdkMjs = path.resolve(rootDir, 'sdk.mjs'); | ||||
| const sdkTs = path.resolve(rootDirectory, 'sdk.d.ts'); | ||||
| const sdkMts = path.resolve(rootDirectory, 'sdk.d.mts'); | ||||
| const sdkMjs = path.resolve(rootDirectory, 'sdk.mjs'); | ||||
| 
 | ||||
| const generateSdkMts = async () => { | ||||
|   // remove temporally type definitions imported with comments
 | ||||
|   // Remove temporally type definitions imported with comments
 | ||||
|   // in sdk.mjs to avoid circular imports
 | ||||
|   const originalSdkMjsContent = await fs.readFile(sdkMjs, 'utf-8'); | ||||
|   const tempSdkMjsContent = originalSdkMjsContent | ||||
|   const originalSdkMjsContent = await fs.readFile(sdkMjs, 'utf8'); | ||||
|   const temporarySdkMjsContent = originalSdkMjsContent | ||||
|     .split('\n') | ||||
|     .filter((line) => { | ||||
|       return !line.startsWith(' * @typedef {import("./sdk")'); | ||||
|     }) | ||||
|     .join('\n'); | ||||
|   await fs.writeFile(sdkMjs, tempSdkMjsContent); | ||||
|   await fs.writeFile(sdkMjs, temporarySdkMjsContent); | ||||
|   try { | ||||
|     execSync( | ||||
|       'npx tsc sdk.mjs' + | ||||
| @ -41,6 +42,7 @@ const generateSdkMts = async () => { | ||||
|     ); | ||||
|     process.exit(1); | ||||
|   } | ||||
| 
 | ||||
|   await fs.writeFile(sdkMjs, originalSdkMjsContent); | ||||
| }; | ||||
| 
 | ||||
| @ -49,13 +51,15 @@ const generateSdkTs = async () => { | ||||
|     .access(sdkMts) | ||||
|     .then(() => true) | ||||
|     .catch(() => false); | ||||
|   fileExists && (await fs.unlink(sdkMts)); | ||||
|   if (fileExists) await fs.unlink(sdkMts); | ||||
|   await generateSdkMts(); | ||||
| 
 | ||||
|   const autogeneratedMsg = '/* The next code is autogenerated from sdk.mjs */'; | ||||
|   const autogeneratedMessage = | ||||
|     '/* The next code is autogenerated from sdk.mjs */'; | ||||
|   const newSdkTsContent = | ||||
|     (await fs.readFile(sdkTs, 'utf-8')).split(autogeneratedMsg)[0] + | ||||
|     `${autogeneratedMsg}\n\n${await fs.readFile(sdkMts, 'utf-8')}`; | ||||
|     // eslint-disable-next-line unicorn/no-await-expression-member
 | ||||
|     (await fs.readFile(sdkTs, 'utf8')).split(autogeneratedMessage)[0] + | ||||
|     `${autogeneratedMessage}\n\n${await fs.readFile(sdkMts, 'utf8')}`; | ||||
| 
 | ||||
|   await fs.writeFile(sdkTs, newSdkTsContent); | ||||
|   await fs.unlink(sdkMts); | ||||
|  | ||||
							
								
								
									
										14
									
								
								scripts/release/update-slugs-table.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										14
									
								
								scripts/release/update-slugs-table.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,22 +1,23 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * @fileoverview | ||||
|  * Generates a MarkDown file that lists every brand name and their slug. | ||||
|  */ | ||||
| 
 | ||||
| import { promises as fs } from 'node:fs'; | ||||
| import fs from 'node:fs/promises'; | ||||
| import path from 'node:path'; | ||||
| import { fileURLToPath } from 'node:url'; | ||||
| import { getIconsData, getIconSlug } from '../../sdk.mjs'; | ||||
| import {fileURLToPath} from 'node:url'; | ||||
| import {getIconSlug, getIconsData} from '../../sdk.mjs'; | ||||
| 
 | ||||
| const __filename = fileURLToPath(import.meta.url); | ||||
| const __dirname = path.dirname(__filename); | ||||
| 
 | ||||
| const rootDir = path.resolve(__dirname, '..', '..'); | ||||
| const slugsFile = path.resolve(rootDir, 'slugs.md'); | ||||
| const rootDirectory = path.resolve(__dirname, '..', '..'); | ||||
| const slugsFile = path.resolve(rootDirectory, 'slugs.md'); | ||||
| 
 | ||||
| let content = `<!--
 | ||||
| This file is automatically generated. If you want to change something, please | ||||
| update the script at '${path.relative(rootDir, __filename)}'. | ||||
| update the script at '${path.relative(rootDirectory, __filename)}'. | ||||
| --> | ||||
| 
 | ||||
| # Simple Icons slugs | ||||
| @ -31,4 +32,5 @@ for (const icon of icons) { | ||||
|   const brandSlug = getIconSlug(icon); | ||||
|   content += `| \`${brandName}\` | \`${brandSlug}\` |\n`; | ||||
| } | ||||
| 
 | ||||
| await fs.writeFile(slugsFile, content); | ||||
|  | ||||
							
								
								
									
										20
									
								
								scripts/release/update-svgs-count.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										20
									
								
								scripts/release/update-svgs-count.js
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -1,3 +1,4 @@ | ||||
| #!/usr/bin/env node
 | ||||
| /** | ||||
|  * @fileoverview | ||||
|  * Replaces the SVG count milestone "Over <NUMBER> Free SVG icons..." located | ||||
| @ -5,32 +6,33 @@ | ||||
|  * more than the previous milestone. | ||||
|  */ | ||||
| 
 | ||||
| import process from 'node:process'; | ||||
| import fs from 'node:fs/promises'; | ||||
| import path from 'node:path'; | ||||
| import { getDirnameFromImportMeta, getIconsData } from '../../sdk.mjs'; | ||||
| import process from 'node:process'; | ||||
| import {getDirnameFromImportMeta, getIconsData} from '../../sdk.mjs'; | ||||
| 
 | ||||
| const regexMatcher = /Over\s(\d+)\s/; | ||||
| const updateRange = 100; | ||||
| 
 | ||||
| const __dirname = getDirnameFromImportMeta(import.meta.url); | ||||
| const rootDir = path.resolve(__dirname, '..', '..'); | ||||
| const readmeFile = path.resolve(rootDir, 'README.md'); | ||||
| const rootDirectory = path.resolve(__dirname, '..', '..'); | ||||
| const readmeFile = path.resolve(rootDirectory, 'README.md'); | ||||
| 
 | ||||
| const readmeContent = await fs.readFile(readmeFile, 'utf-8'); | ||||
| const readmeContent = await fs.readFile(readmeFile, 'utf8'); | ||||
| 
 | ||||
| let overNIconsInReadme; | ||||
| try { | ||||
|   overNIconsInReadme = parseInt(regexMatcher.exec(readmeContent)[1]); | ||||
| } catch (err) { | ||||
|   overNIconsInReadme = Number.parseInt(regexMatcher.exec(readmeContent)[1], 10); | ||||
| } catch (error) { | ||||
|   console.error( | ||||
|     'Failed to obtain number of SVG icons of current milestone in README:', | ||||
|     err, | ||||
|     error, | ||||
|   ); | ||||
|   process.exit(1); | ||||
| } | ||||
| 
 | ||||
| const nIcons = (await getIconsData()).length; | ||||
| const iconsData = await getIconsData(); | ||||
| const nIcons = iconsData.length; | ||||
| const newNIcons = overNIconsInReadme + updateRange; | ||||
| 
 | ||||
| if (nIcons > newNIcons) { | ||||
|  | ||||
| @ -1,17 +1,17 @@ | ||||
| import path from 'node:path'; | ||||
| import fs from 'node:fs/promises'; | ||||
| import { getDirnameFromImportMeta, getIconDataPath } from '../sdk.mjs'; | ||||
| import path from 'node:path'; | ||||
| import {getDirnameFromImportMeta, getIconDataPath} from '../sdk.mjs'; | ||||
| 
 | ||||
| const __dirname = getDirnameFromImportMeta(import.meta.url); | ||||
| 
 | ||||
| /** | ||||
|  * Get JSON schema data. | ||||
|  * @param {String} rootDir Path to the root directory of the project. | ||||
|  * @param {String} rootDirectory Path to the root directory of the project. | ||||
|  */ | ||||
| export const getJsonSchemaData = async ( | ||||
|   rootDir = path.resolve(__dirname, '..'), | ||||
|   rootDirectory = path.resolve(__dirname, '..'), | ||||
| ) => { | ||||
|   const jsonSchemaPath = path.resolve(rootDir, '.jsonschema.json'); | ||||
|   const jsonSchemaPath = path.resolve(rootDirectory, '.jsonschema.json'); | ||||
|   const jsonSchemaString = await fs.readFile(jsonSchemaPath, 'utf8'); | ||||
|   return JSON.parse(jsonSchemaString); | ||||
| }; | ||||
| @ -19,14 +19,14 @@ export const getJsonSchemaData = async ( | ||||
| /** | ||||
|  * Write icons data to _data/simple-icons.json. | ||||
|  * @param {Object} iconsData Icons data object. | ||||
|  * @param {String} rootDir Path to the root directory of the project. | ||||
|  * @param {String} rootDirectory Path to the root directory of the project. | ||||
|  */ | ||||
| export const writeIconsData = async ( | ||||
|   iconsData, | ||||
|   rootDir = path.resolve(__dirname, '..'), | ||||
|   rootDirectory = path.resolve(__dirname, '..'), | ||||
| ) => { | ||||
|   await fs.writeFile( | ||||
|     getIconDataPath(rootDir), | ||||
|     getIconDataPath(rootDirectory), | ||||
|     `${JSON.stringify(iconsData, null, 4)}\n`, | ||||
|     'utf8', | ||||
|   ); | ||||
|  | ||||
							
								
								
									
										16
									
								
								sdk.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								sdk.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -3,7 +3,7 @@ | ||||
|  * Types for Simple Icons SDK. | ||||
|  */ | ||||
| 
 | ||||
| import type { CustomLicense, SPDXLicense } from './types'; | ||||
| import type {CustomLicense, SPDXLicense} from './types'; | ||||
| 
 | ||||
| /** | ||||
|  * The data for a third-party extension. | ||||
| @ -33,14 +33,14 @@ type ThirdPartyExtensionSubject = { | ||||
| export type Aliases = { | ||||
|   aka?: string[]; | ||||
|   dup?: DuplicateAlias[]; | ||||
|   loc?: { [key: string]: string }; | ||||
|   loc?: Record<string, string>; | ||||
| }; | ||||
| 
 | ||||
| type DuplicateAlias = { | ||||
|   title: string; | ||||
|   hex?: string; | ||||
|   guidelines?: string; | ||||
|   loc?: { [key: string]: string }; | ||||
|   loc?: Record<string, string>; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
| @ -62,8 +62,8 @@ export type IconData = { | ||||
| 
 | ||||
| /* The next code is autogenerated from sdk.mjs */ | ||||
| 
 | ||||
| export const URL_REGEX: RegExp; | ||||
| export const SVG_PATH_REGEX: RegExp; | ||||
| export const URL_REGEX: RegExp; // eslint-disable-line @typescript-eslint/naming-convention
 | ||||
| export const SVG_PATH_REGEX: RegExp; // eslint-disable-line @typescript-eslint/naming-convention
 | ||||
| export function getDirnameFromImportMeta(importMetaUrl: string): string; | ||||
| export function getIconSlug(icon: IconData): string; | ||||
| export function svgToPath(svg: string): string; | ||||
| @ -71,9 +71,9 @@ export function titleToSlug(title: string): string; | ||||
| export function slugToVariableName(slug: string): string; | ||||
| export function titleToHtmlFriendly(brandTitle: string): string; | ||||
| export function htmlFriendlyToTitle(htmlFriendlyTitle: string): string; | ||||
| export function getIconDataPath(rootDir?: string): string; | ||||
| export function getIconsDataString(rootDir?: string): string; | ||||
| export function getIconsData(rootDir?: string): IconData[]; | ||||
| export function getIconDataPath(rootDirectory?: string): string; | ||||
| export function getIconsDataString(rootDirectory?: string): string; | ||||
| export function getIconsData(rootDirectory?: string): IconData[]; | ||||
| export function normalizeNewlines(text: string): string; | ||||
| export function normalizeColor(text: string): string; | ||||
| export function getThirdPartyExtensions( | ||||
|  | ||||
							
								
								
									
										64
									
								
								sdk.mjs
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								sdk.mjs
									
									
									
									
									
								
							| @ -3,9 +3,9 @@ | ||||
|  * Simple Icons SDK. | ||||
|  */ | ||||
| 
 | ||||
| import path from 'node:path'; | ||||
| import fs from 'node:fs/promises'; | ||||
| import { fileURLToPath } from 'node:url'; | ||||
| import path from 'node:path'; | ||||
| import {fileURLToPath} from 'node:url'; | ||||
| 
 | ||||
| /** | ||||
|  * @typedef {import("./sdk").ThirdPartyExtension} ThirdPartyExtension | ||||
| @ -26,12 +26,12 @@ const TITLE_TO_SLUG_REPLACEMENTS = { | ||||
|   ŧ: 't', | ||||
| }; | ||||
| 
 | ||||
| const TITLE_TO_SLUG_CHARS_REGEX = RegExp( | ||||
| const TITLE_TO_SLUG_CHARS_REGEX = new RegExp( | ||||
|   `[${Object.keys(TITLE_TO_SLUG_REPLACEMENTS).join('')}]`, | ||||
|   'g', | ||||
| ); | ||||
| 
 | ||||
| const TITLE_TO_SLUG_RANGE_REGEX = /[^a-z0-9]/g; | ||||
| const TITLE_TO_SLUG_RANGE_REGEX = /[^a-z\d]/g; | ||||
| 
 | ||||
| /** | ||||
|  * Regex to validate HTTPs URLs. | ||||
| @ -41,7 +41,7 @@ export const URL_REGEX = /^https:\/\/[^\s"']+$/; | ||||
| /** | ||||
|  * Regex to validate SVG paths. | ||||
|  */ | ||||
| export const SVG_PATH_REGEX = /^m[-mzlhvcsqtae0-9,. ]+$/i; | ||||
| export const SVG_PATH_REGEX = /^m[-mzlhvcsqtae\d,. ]+$/i; | ||||
| 
 | ||||
| /** | ||||
|  * Get the directory name where this file is located from `import.meta.url`, | ||||
| @ -74,12 +74,12 @@ export const svgToPath = (svg) => svg.split('"', 8)[7]; | ||||
| export const titleToSlug = (title) => | ||||
|   title | ||||
|     .toLowerCase() | ||||
|     .replace( | ||||
|     .replaceAll( | ||||
|       TITLE_TO_SLUG_CHARS_REGEX, | ||||
|       (char) => TITLE_TO_SLUG_REPLACEMENTS[char], | ||||
|     ) | ||||
|     .normalize('NFD') | ||||
|     .replace(TITLE_TO_SLUG_RANGE_REGEX, ''); | ||||
|     .replaceAll(TITLE_TO_SLUG_RANGE_REGEX, ''); | ||||
| 
 | ||||
| /** | ||||
|  * Converts a slug into a variable name that can be exported. | ||||
| @ -99,12 +99,12 @@ export const slugToVariableName = (slug) => { | ||||
|  */ | ||||
| export const titleToHtmlFriendly = (brandTitle) => | ||||
|   brandTitle | ||||
|     .replace(/&/g, '&') | ||||
|     .replace(/"/g, '"') | ||||
|     .replace(/</g, '<') | ||||
|     .replace(/>/g, '>') | ||||
|     .replace(/./g, (char) => { | ||||
|       const charCode = char.charCodeAt(0); | ||||
|     .replaceAll('&', '&') | ||||
|     .replaceAll('"', '"') | ||||
|     .replaceAll('<', '<') | ||||
|     .replaceAll('>', '>') | ||||
|     .replaceAll(/./g, (char) => { | ||||
|       const charCode = char.codePointAt(0); | ||||
|       return charCode > 127 ? `&#${charCode};` : char; | ||||
|     }); | ||||
| 
 | ||||
| @ -116,43 +116,45 @@ export const titleToHtmlFriendly = (brandTitle) => | ||||
|  */ | ||||
| export const htmlFriendlyToTitle = (htmlFriendlyTitle) => | ||||
|   htmlFriendlyTitle | ||||
|     .replace(/&#([0-9]+);/g, (_, num) => String.fromCodePoint(parseInt(num))) | ||||
|     .replace( | ||||
|     .replaceAll(/&#(\d+);/g, (_, number_) => | ||||
|       String.fromCodePoint(Number.parseInt(number_, 10)), | ||||
|     ) | ||||
|     .replaceAll( | ||||
|       /&(quot|amp|lt|gt);/g, | ||||
|       (_, ref) => ({ quot: '"', amp: '&', lt: '<', gt: '>' })[ref], | ||||
|       (_, reference) => ({quot: '"', amp: '&', lt: '<', gt: '>'})[reference], | ||||
|     ); | ||||
| 
 | ||||
| /** | ||||
|  * Get path of *_data/simpe-icons.json*. | ||||
|  * @param {String} rootDir Path to the root directory of the project | ||||
|  * @param {String} rootDirectory Path to the root directory of the project | ||||
|  * @returns {String} Path of *_data/simple-icons.json* | ||||
|  */ | ||||
| export const getIconDataPath = ( | ||||
|   rootDir = getDirnameFromImportMeta(import.meta.url), | ||||
|   rootDirectory = getDirnameFromImportMeta(import.meta.url), | ||||
| ) => { | ||||
|   return path.resolve(rootDir, '_data', 'simple-icons.json'); | ||||
|   return path.resolve(rootDirectory, '_data', 'simple-icons.json'); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Get contents of *_data/simple-icons.json*. | ||||
|  * @param {String} rootDir Path to the root directory of the project | ||||
|  * @param {String} rootDirectory Path to the root directory of the project | ||||
|  * @returns {String} Content of *_data/simple-icons.json* | ||||
|  */ | ||||
| export const getIconsDataString = ( | ||||
|   rootDir = getDirnameFromImportMeta(import.meta.url), | ||||
|   rootDirectory = getDirnameFromImportMeta(import.meta.url), | ||||
| ) => { | ||||
|   return fs.readFile(getIconDataPath(rootDir), 'utf8'); | ||||
|   return fs.readFile(getIconDataPath(rootDirectory), 'utf8'); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Get icons data as object from *_data/simple-icons.json*. | ||||
|  * @param {String} rootDir Path to the root directory of the project | ||||
|  * @param {String} rootDirectory Path to the root directory of the project | ||||
|  * @returns {IconData[]} Icons data as array from *_data/simple-icons.json* | ||||
|  */ | ||||
| export const getIconsData = async ( | ||||
|   rootDir = getDirnameFromImportMeta(import.meta.url), | ||||
|   rootDirectory = getDirnameFromImportMeta(import.meta.url), | ||||
| ) => { | ||||
|   const fileContents = await getIconsDataString(rootDir); | ||||
|   const fileContents = await getIconsDataString(rootDirectory); | ||||
|   return JSON.parse(fileContents).icons; | ||||
| }; | ||||
| 
 | ||||
| @ -162,7 +164,7 @@ export const getIconsData = async ( | ||||
|  * @returns {String} The text with Windows newline characters replaced by Unix ones | ||||
|  */ | ||||
| export const normalizeNewlines = (text) => { | ||||
|   return text.replace(/\r\n/g, '\n'); | ||||
|   return text.replaceAll('\r\n', '\n'); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
| @ -173,10 +175,14 @@ export const normalizeNewlines = (text) => { | ||||
| export const normalizeColor = (text) => { | ||||
|   let color = text.replace('#', '').toUpperCase(); | ||||
|   if (color.length < 6) { | ||||
|     color = [...color.slice(0, 3)].map((x) => x.repeat(2)).join(''); | ||||
|     color = color | ||||
|       .slice(0, 3) | ||||
|       .map((x) => x.repeat(2)) | ||||
|       .join(''); | ||||
|   } else if (color.length > 6) { | ||||
|     color = color.slice(0, 6); | ||||
|   } | ||||
| 
 | ||||
|   return color; | ||||
| }; | ||||
| 
 | ||||
| @ -201,11 +207,11 @@ export const getThirdPartyExtensions = async ( | ||||
|       module = module.split('<img src="')[0]; | ||||
|       return { | ||||
|         module: { | ||||
|           name: /\[(.+)\]/.exec(module)[1], | ||||
|           name: /\[(.+)]/.exec(module)[1], | ||||
|           url: /\((.+)\)/.exec(module)[1], | ||||
|         }, | ||||
|         author: { | ||||
|           name: /\[(.+)\]/.exec(author)[1], | ||||
|           name: /\[(.+)]/.exec(author)[1], | ||||
|           url: /\((.+)\)/.exec(author)[1], | ||||
|         }, | ||||
|       }; | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,4 +1,4 @@ | ||||
| export default { | ||||
| const config = { | ||||
|   multipass: true, | ||||
|   eol: 'lf', | ||||
|   plugins: [ | ||||
| @ -62,7 +62,7 @@ export default { | ||||
|       // Convert basic shapes (such as <circle>) to <path>
 | ||||
|       name: 'convertShapeToPath', | ||||
|       params: { | ||||
|         // including <arc>
 | ||||
|         // Including <arc>
 | ||||
|         convertArcs: true, | ||||
|       }, | ||||
|     }, | ||||
| @ -93,7 +93,7 @@ export default { | ||||
|       // to the <svg> tag if it's not there already
 | ||||
|       name: 'addAttributesToSVGElement', | ||||
|       params: { | ||||
|         attributes: [{ role: 'img', xmlns: 'http://www.w3.org/2000/svg' }], | ||||
|         attributes: [{role: 'img', xmlns: 'http://www.w3.org/2000/svg'}], | ||||
|       }, | ||||
|     }, | ||||
|     'removeOffCanvasPaths', | ||||
| @ -102,3 +102,5 @@ export default { | ||||
|     'reusePaths', | ||||
|   ], | ||||
| }; | ||||
| 
 | ||||
| export default config; | ||||
|  | ||||
| @ -1,16 +1,16 @@ | ||||
| import { test } from 'mocha'; | ||||
| import { strict as assert } from 'node:assert'; | ||||
| import { getThirdPartyExtensions } from '../sdk.mjs'; | ||||
| import {strict as assert} from 'node:assert'; | ||||
| import {test} from 'mocha'; | ||||
| import {getThirdPartyExtensions} from '../sdk.mjs'; | ||||
| 
 | ||||
| test('README third party extensions must be alphabetically sorted', async () => { | ||||
|   const thirdPartyExtensions = await getThirdPartyExtensions(); | ||||
|   assert.ok(thirdPartyExtensions.length > 0); | ||||
| 
 | ||||
|   const thirdPartyExtensionsNames = thirdPartyExtensions.map( | ||||
|     (ext) => ext.module.name, | ||||
|     (extension) => extension.module.name, | ||||
|   ); | ||||
| 
 | ||||
|   const expectedOrder = thirdPartyExtensionsNames.slice().sort(); | ||||
|   const expectedOrder = [...thirdPartyExtensionsNames].sort(); | ||||
|   assert.deepEqual( | ||||
|     thirdPartyExtensionsNames, | ||||
|     expectedOrder, | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| import { getIconsData, getIconSlug, slugToVariableName } from '../sdk.mjs'; | ||||
| import * as simpleIcons from '../index.mjs'; | ||||
| import { testIcon } from './test-icon.js'; | ||||
| import {getIconSlug, getIconsData, slugToVariableName} from '../sdk.mjs'; | ||||
| import {testIcon} from './test-icon.js'; | ||||
| 
 | ||||
| for (const icon of await getIconsData()) { | ||||
|   const slug = getIconSlug(icon); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| const { reporters, Runner } = require('mocha'); | ||||
| const {reporters, Runner} = require('mocha'); | ||||
| 
 | ||||
| const { EVENT_RUN_END } = Runner.constants; | ||||
| const {EVENT_RUN_END} = Runner.constants; | ||||
| 
 | ||||
| class EvenMoreMin extends reporters.Base { | ||||
|   constructor(runner) { | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| import {strict as assert} from 'node:assert'; | ||||
| import fs from 'node:fs/promises'; | ||||
| import path from 'node:path'; | ||||
| import { strict as assert } from 'node:assert'; | ||||
| import { describe, it } from 'mocha'; | ||||
| import {describe, it} from 'mocha'; | ||||
| import { | ||||
|   SVG_PATH_REGEX, | ||||
|   URL_REGEX, | ||||
| @ -9,7 +9,7 @@ import { | ||||
|   titleToSlug, | ||||
| } from '../sdk.mjs'; | ||||
| 
 | ||||
| const iconsDir = path.resolve( | ||||
| const iconsDirectory = path.resolve( | ||||
|   getDirnameFromImportMeta(import.meta.url), | ||||
|   '..', | ||||
|   'icons', | ||||
| @ -26,7 +26,7 @@ const iconsDir = path.resolve( | ||||
|  * @param {String} slug Icon data slug | ||||
|  */ | ||||
| export const testIcon = (icon, subject, slug) => { | ||||
|   const svgPath = path.resolve(iconsDir, `${slug}.svg`); | ||||
|   const svgPath = path.resolve(iconsDirectory, `${slug}.svg`); | ||||
| 
 | ||||
|   describe(icon.title, () => { | ||||
|     it('has the correct "title"', () => { | ||||
| @ -81,7 +81,7 @@ export const testIcon = (icon, subject, slug) => { | ||||
|     }); | ||||
| 
 | ||||
|     if (icon.slug) { | ||||
|       // if an icon data has a slug, it must be different to the
 | ||||
|       // If an icon data has a slug, it must be different to the
 | ||||
|       // slug inferred from the title, which prevents adding
 | ||||
|       // unnecessary slugs to icons data
 | ||||
|       it(`'${icon.title}' slug must be necessary`, () => { | ||||
|  | ||||
							
								
								
									
										5
									
								
								types.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								types.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -5,6 +5,7 @@ | ||||
|  */ | ||||
| export type License = SPDXLicense | CustomLicense; | ||||
| 
 | ||||
| // eslint-disable-next-line @typescript-eslint/naming-convention
 | ||||
| export type SPDXLicense = { | ||||
|   type: string; | ||||
|   url: string; | ||||
| @ -18,7 +19,7 @@ export type CustomLicense = { | ||||
| /** | ||||
|  * The data for a Simple Icon as is exported by the npm package. | ||||
|  */ | ||||
| export interface SimpleIcon { | ||||
| export type SimpleIcon = { | ||||
|   title: string; | ||||
|   slug: string; | ||||
|   svg: string; | ||||
| @ -27,4 +28,4 @@ export interface SimpleIcon { | ||||
|   hex: string; | ||||
|   guidelines?: string; | ||||
|   license?: License; | ||||
| } | ||||
| }; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user