Skip to content

Commit 236f5fc

Browse files
authored
Add types to source code (simple-icons#10637)
1 parent 1224e34 commit 236f5fc

25 files changed

+619
-205
lines changed

.npmignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616
!sdk.js
1717
!sdk.d.ts
1818
!.jsonschema.json
19+
!jsconfig.json

.xo-config.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"prettier": true,
33
"space": 2,
44
"plugins": ["import"],
5+
"extends": ["plugin:jsdoc/recommended"],
56
"rules": {
67
"sort-imports": [
78
"error",
@@ -27,7 +28,8 @@
2728
"newlines-between": "never"
2829
}
2930
],
30-
"no-console": ["error", {"allow": ["warn", "error"]}]
31+
"no-console": ["error", {"allow": ["warn", "error"]}],
32+
"jsdoc/require-file-overview": "error"
3133
},
3234
"overrides": [
3335
{
@@ -46,6 +48,12 @@
4648
"svgo.config.mjs"
4749
],
4850
"nodeVersion": ">=18"
51+
},
52+
{
53+
"files": ["svglint.config.mjs"],
54+
"rules": {
55+
"max-depth": "off"
56+
}
4957
}
5058
]
5159
}

jsconfig.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2022",
4+
"module": "node16",
5+
"moduleResolution": "node16",
6+
"checkJs": true,
7+
"skipLibCheck": false,
8+
"strict": true,
9+
"noImplicitAny": true,
10+
"noImplicitThis": true,
11+
"forceConsistentCasingInFileNames": true
12+
}
13+
}

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,12 @@
8686
"devDependencies": {
8787
"@inquirer/core": "8.1.0",
8888
"@inquirer/prompts": "5.0.2",
89+
"@types/node": "20.14.2",
8990
"chalk": "5.3.0",
9091
"editorconfig-checker": "5.1.5",
9192
"esbuild": "0.20.2",
9293
"eslint-plugin-import": "2.29.1",
94+
"eslint-plugin-jsdoc": "48.2.8",
9395
"fake-diff": "1.0.0",
9496
"fast-fuzzy": "1.12.0",
9597
"get-relative-luminance": "1.0.0",
@@ -99,8 +101,8 @@
99101
"markdown-link-check": "3.12.1",
100102
"mocha": "10.4.0",
101103
"named-html-entities-json": "1.0.0",
102-
"svg-path-bbox": "1.2.6",
103-
"svg-path-segments": "2.0.0",
104+
"svg-path-bbox": "2.0.0",
105+
"svg-path-segments": "2.0.1",
104106
"svglint": "2.7.1",
105107
"svgo": "3.2.0",
106108
"svgpath": "2.6.0",

scripts/add-icon-data.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
#!/usr/bin/env node
2+
/**
3+
* @file
4+
* Script to add data for a new icon to the simple-icons dataset.
5+
*/
6+
7+
/**
8+
* @typedef {import("../sdk.js").IconData} IconData
9+
*/
210
import process from 'node:process';
311
import {ExitPromptError} from '@inquirer/core';
412
import {checkbox, confirm, input} from '@inquirer/prompts';
@@ -15,6 +23,7 @@ import {
1523
} from '../sdk.mjs';
1624
import {getJsonSchemaData, writeIconsData} from './utils.js';
1725

26+
/** @type {{icons: import('../sdk.js').IconData[]}} */
1827
const iconsData = JSON.parse(await getIconsDataString());
1928
const jsonSchema = await getJsonSchemaData();
2029

@@ -25,25 +34,42 @@ const aliasTypes = ['aka', 'old'].map((key) => ({
2534
value: key,
2635
}));
2736

37+
/** @type {{name: string, value: string}[]} */
2838
const licenseTypes =
2939
jsonSchema.definitions.brand.properties.license.oneOf[0].properties.type.enum.map(
30-
(license) => ({name: license, value: license}),
40+
(/** @type {string} */ license) => ({name: license, value: license}),
3141
);
3242

43+
/**
44+
* @param {string} input URL input
45+
* @returns {Promise<boolean|string>} Whether the input is a valid URL
46+
*/
3347
const isValidURL = async (input) => {
3448
const regex = await urlRegex();
3549
return regex.test(input) || 'Must be a valid and secure (https://) URL.';
3650
};
3751

52+
/**
53+
* @param {string} input Hex color
54+
* @returns {boolean|string} Whether the input is a valid hex color
55+
*/
3856
const isValidHexColor = (input) =>
3957
HEX_REGEX.test(input) || 'Must be a valid hex code.';
4058

59+
/**
60+
* @param {string} input New icon input
61+
* @returns {boolean} Whether the icon is new
62+
*/
4163
const isNewIcon = (input) =>
4264
!iconsData.icons.some(
4365
(icon) =>
4466
icon.title === input || titleToSlug(icon.title) === titleToSlug(input),
45-
) || 'This icon title or slug already exists.';
67+
);
4668

69+
/**
70+
* @param {string} input Color input
71+
* @returns {string} Preview of the color
72+
*/
4773
const previewHexColor = (input) => {
4874
const color = normalizeColor(input);
4975
const luminance = HEX_REGEX.test(input)
@@ -60,7 +86,9 @@ try {
6086
title: await input({
6187
message: 'What is the title of this icon?',
6288
validate: (input) =>
63-
input.trim().length > 0 ? isNewIcon(input) : 'This field is required.',
89+
input.trim().length > 0
90+
? isNewIcon(input) || 'This icon title or slug already exists.'
91+
: 'This field is required.',
6492
}),
6593
hex: normalizeColor(
6694
await input({
@@ -111,6 +139,7 @@ try {
111139
}).then(async (aliases) => {
112140
const result = {};
113141
for (const alias of aliases) {
142+
// @ts-ignore
114143
// eslint-disable-next-line no-await-in-loop
115144
result[alias] = await input({
116145
message: `What ${alias} aliases would you like to add? (separate with commas)`,

scripts/build/clean.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22
/**
3-
* @fileoverview
3+
* @file
44
* Clean files built by the build process.
55
*/
66

scripts/build/package.js

Lines changed: 70 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
#!/usr/bin/env node
22
/**
3-
* @fileoverview
3+
* @file
44
* Simple Icons package build script.
55
*/
66

7+
/**
8+
* @typedef {import('../../types.js').License} License
9+
* @typedef {import('esbuild').TransformOptions} EsBuildTransformOptions
10+
*/
11+
712
import {promises as fs} from 'node:fs';
813
import path from 'node:path';
914
import util from 'node:util';
@@ -36,62 +41,78 @@ const iconObjectTemplateFile = path.resolve(
3641
'icon-object.js.template',
3742
);
3843

44+
const icons = await getIconsData();
45+
const iconObjectTemplate = await fs.readFile(iconObjectTemplateFile, UTF8);
46+
47+
/**
48+
* @param {string} value The value to escape
49+
* @returns {string} The escaped value
50+
*/
51+
const escape = (value) => {
52+
return value.replaceAll(/(?<!\\)'/g, "\\'");
53+
};
54+
55+
/**
56+
* @param {License} license The license object or URL
57+
* @returns {License} The license object with a URL
58+
*/
59+
const licenseToObject = (license) => {
60+
if (license.url === undefined) {
61+
license.url = `https://spdx.org/licenses/${license.type}`;
62+
}
63+
64+
return license;
65+
};
66+
67+
// TODO: Find a way to type this object without decreasing performance
68+
// @ts-ignore
69+
const iconToJsObject = (icon) => {
70+
return util.format(
71+
iconObjectTemplate,
72+
escape(icon.title),
73+
escape(icon.slug),
74+
escape(titleToHtmlFriendly(icon.title)),
75+
escape(icon.path),
76+
escape(icon.source),
77+
escape(icon.hex),
78+
icon.guidelines ? `\n guidelines: '${escape(icon.guidelines)}',` : '',
79+
icon.license === undefined
80+
? ''
81+
: `\n license: ${JSON.stringify(licenseToObject(icon.license))},`,
82+
);
83+
};
84+
85+
/**
86+
* @param {string} filepath The path to the file to write
87+
* @param {string} rawJavaScript The raw JavaScript content to write to the file
88+
* @param {EsBuildTransformOptions | null} options The options to pass to esbuild
89+
*/
90+
const writeJs = async (filepath, rawJavaScript, options = null) => {
91+
options = options === null ? {minify: true} : options;
92+
const {code} = await esbuildTransform(rawJavaScript, options);
93+
await fs.writeFile(filepath, code);
94+
};
95+
96+
/**
97+
* @param {string} filepath The path to the file to write
98+
* @param {string} rawTypeScript The raw TypeScript content to write to the file
99+
*/
100+
const writeTs = async (filepath, rawTypeScript) => {
101+
await fs.writeFile(filepath, rawTypeScript);
102+
};
103+
39104
const build = async () => {
40-
const icons = await getIconsData();
41-
const iconObjectTemplate = await fs.readFile(iconObjectTemplateFile, UTF8);
42-
43-
// Local helper functions
44-
const escape = (value) => {
45-
return value.replaceAll(/(?<!\\)'/g, "\\'");
46-
};
47-
48-
const licenseToObject = (license) => {
49-
if (license === undefined) {
50-
return;
51-
}
52-
53-
if (license.url === undefined) {
54-
license.url = `https://spdx.org/licenses/${license.type}`;
55-
}
56-
57-
return license;
58-
};
59-
60-
const iconToObject = (icon) => {
61-
return util.format(
62-
iconObjectTemplate,
63-
escape(icon.title),
64-
escape(icon.slug),
65-
escape(titleToHtmlFriendly(icon.title)),
66-
escape(icon.path),
67-
escape(icon.source),
68-
escape(icon.hex),
69-
icon.guidelines ? `\n guidelines: '${escape(icon.guidelines)}',` : '',
70-
licenseToObject(icon.license)
71-
? `\n license: ${JSON.stringify(licenseToObject(icon.license))},`
72-
: '',
73-
);
74-
};
75-
76-
const writeJs = async (filepath, rawJavaScript, options = null) => {
77-
options = options === null ? {minify: true} : options;
78-
const {code} = await esbuildTransform(rawJavaScript, options);
79-
await fs.writeFile(filepath, code);
80-
};
81-
82-
const writeTs = async (filepath, rawTypeScript) => {
83-
await fs.writeFile(filepath, rawTypeScript);
84-
};
85-
86-
// 'main'
87105
const buildIcons = await Promise.all(
88106
icons.map(async (icon) => {
89107
const filename = getIconSlug(icon);
90108
const svgFilepath = path.resolve(iconsDirectory, `${filename}.svg`);
109+
// TODO: Find a way to type these objects without decreasing performance
110+
// @ts-ignore
91111
icon.svg = await fs.readFile(svgFilepath, UTF8);
112+
// @ts-ignore
92113
icon.path = svgToPath(icon.svg);
93114
icon.slug = filename;
94-
const iconObject = iconToObject(icon);
115+
const iconObject = iconToJsObject(icon);
95116
const iconExportName = slugToVariableName(icon.slug);
96117
return {icon, iconObject, iconExportName};
97118
}),

scripts/get-filename.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22
/**
3-
* @fileoverview
3+
* @file
44
* Script that takes a brand name as argument and outputs the corresponding
55
* icon SVG filename to standard output.
66
*/

scripts/lint/jsonlint.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22
/**
3-
* @fileoverview
3+
* @file
44
* CLI tool to run jsonschema on the simple-icons.json data file.
55
*/
66

0 commit comments

Comments
 (0)