mirror of
https://github.com/Mibew/simple-icons.git
synced 2025-01-18 08:01:08 +03:00
Refactor tests and scripts (#9237)
Co-authored-by: LitoMore <LitoMore@users.noreply.github.com>
This commit is contained in:
parent
8abcd9c8b9
commit
17ea889273
@ -1,6 +1,8 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
import process from 'node:process';
|
||||||
import {
|
import {
|
||||||
|
SVG_PATH_REGEX,
|
||||||
getDirnameFromImportMeta,
|
getDirnameFromImportMeta,
|
||||||
htmlFriendlyToTitle,
|
htmlFriendlyToTitle,
|
||||||
collator,
|
collator,
|
||||||
@ -19,16 +21,17 @@ const htmlNamedEntitiesFile = path.join(
|
|||||||
);
|
);
|
||||||
const svglintIgnoredFile = path.join(__dirname, '.svglint-ignored.json');
|
const svglintIgnoredFile = path.join(__dirname, '.svglint-ignored.json');
|
||||||
|
|
||||||
const data = JSON.parse(fs.readFileSync(dataFile, 'utf8'));
|
const data = JSON.parse(await fs.readFile(dataFile, 'utf8'));
|
||||||
const htmlNamedEntities = JSON.parse(
|
const htmlNamedEntities = JSON.parse(
|
||||||
fs.readFileSync(htmlNamedEntitiesFile, 'utf8'),
|
await fs.readFile(htmlNamedEntitiesFile, 'utf8'),
|
||||||
|
);
|
||||||
|
const svglintIgnores = JSON.parse(
|
||||||
|
await fs.readFile(svglintIgnoredFile, 'utf8'),
|
||||||
);
|
);
|
||||||
const svglintIgnores = JSON.parse(fs.readFileSync(svglintIgnoredFile, 'utf8'));
|
|
||||||
|
|
||||||
const svgRegexp =
|
const svgRegexp =
|
||||||
/^<svg( [^\s]*=".*"){3}><title>.*<\/title><path d=".*"\/><\/svg>$/;
|
/^<svg( [^\s]*=".*"){3}><title>.*<\/title><path d=".*"\/><\/svg>$/;
|
||||||
const negativeZerosRegexp = /-0(?=[^\.]|[\s\d\w]|$)/g;
|
const negativeZerosRegexp = /-0(?=[^\.]|[\s\d\w]|$)/g;
|
||||||
const svgPathRegexp = /^[Mm][MmZzLlHhVvCcSsQqTtAaEe0-9\-,. ]+$/;
|
|
||||||
|
|
||||||
const iconSize = 24;
|
const iconSize = 24;
|
||||||
const iconTargetCenter = iconSize / 2;
|
const iconTargetCenter = iconSize / 2;
|
||||||
@ -140,14 +143,14 @@ const getIconPathSegments = memoize((iconPath) => parsePath(iconPath));
|
|||||||
const getIconPathBbox = memoize((iconPath) => svgPathBbox(iconPath));
|
const getIconPathBbox = memoize((iconPath) => svgPathBbox(iconPath));
|
||||||
|
|
||||||
if (updateIgnoreFile) {
|
if (updateIgnoreFile) {
|
||||||
process.on('exit', () => {
|
process.on('exit', async () => {
|
||||||
// ensure object output order is consistent due to async svglint processing
|
// ensure object output order is consistent due to async svglint processing
|
||||||
const sorted = sortObjectByKey(iconIgnored);
|
const sorted = sortObjectByKey(iconIgnored);
|
||||||
for (const linterName in sorted) {
|
for (const linterName in sorted) {
|
||||||
sorted[linterName] = sortObjectByValue(sorted[linterName]);
|
sorted[linterName] = sortObjectByValue(sorted[linterName]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync(ignoreFile, JSON.stringify(sorted, null, 2) + '\n', {
|
await fs.writeFile(ignoreFile, JSON.stringify(sorted, null, 2) + '\n', {
|
||||||
flag: 'w',
|
flag: 'w',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -197,7 +200,7 @@ export default {
|
|||||||
{
|
{
|
||||||
// ensure that the path element only has the 'd' attribute
|
// ensure that the path element only has the 'd' attribute
|
||||||
// (no style, opacity, etc.)
|
// (no style, opacity, etc.)
|
||||||
d: svgPathRegexp,
|
d: SVG_PATH_REGEX,
|
||||||
'rule::selector': 'svg > path',
|
'rule::selector': 'svg > path',
|
||||||
'rule::whitelist': true,
|
'rule::whitelist': true,
|
||||||
},
|
},
|
||||||
@ -908,7 +911,7 @@ export default {
|
|||||||
|
|
||||||
const iconPath = getIconPath($, filepath);
|
const iconPath = getIconPath($, filepath);
|
||||||
|
|
||||||
if (!svgPathRegexp.test(iconPath)) {
|
if (!SVG_PATH_REGEX.test(iconPath)) {
|
||||||
let errorMsg = 'Invalid path format',
|
let errorMsg = 'Invalid path format',
|
||||||
reason;
|
reason;
|
||||||
|
|
||||||
@ -920,7 +923,7 @@ export default {
|
|||||||
reporter.error(`${errorMsg}: ${reason}`);
|
reporter.error(`${errorMsg}: ${reason}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const validPathCharacters = svgPathRegexp.source.replace(
|
const validPathCharacters = SVG_PATH_REGEX.source.replace(
|
||||||
/[\[\]+^$]/g,
|
/[\[\]+^$]/g,
|
||||||
'',
|
'',
|
||||||
),
|
),
|
||||||
|
@ -11461,7 +11461,7 @@
|
|||||||
{
|
{
|
||||||
"title": "SmugMug",
|
"title": "SmugMug",
|
||||||
"hex": "6DB944",
|
"hex": "6DB944",
|
||||||
"source": "https://help.smugmug.com/using-smugmug's-logo-HJulJePkEBf"
|
"source": "https://www.smugmughelp.com/articles/409-smugmug-s-logo-and-usage"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Snapchat",
|
"title": "Snapchat",
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import process from 'node:process';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { input, confirm, checkbox } from '@inquirer/prompts';
|
import { input, confirm, checkbox } from '@inquirer/prompts';
|
||||||
import getRelativeLuminance from 'get-relative-luminance';
|
import getRelativeLuminance from 'get-relative-luminance';
|
||||||
@ -27,10 +28,10 @@ const titleValidator = (text) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const hexValidator = (text) =>
|
const hexValidator = (text) =>
|
||||||
hexPattern.test(text) ? true : 'This should be a valid hex code';
|
hexPattern.test(text) || 'This should be a valid hex code';
|
||||||
|
|
||||||
const sourceValidator = (text) =>
|
const sourceValidator = (text) =>
|
||||||
URL_REGEX.test(text) ? true : 'This should be a secure URL';
|
URL_REGEX.test(text) || 'This should be a secure URL';
|
||||||
|
|
||||||
const hexTransformer = (text) => {
|
const hexTransformer = (text) => {
|
||||||
const color = normalizeColor(text);
|
const color = normalizeColor(text);
|
||||||
|
@ -40,9 +40,6 @@ const build = async () => {
|
|||||||
const escape = (value) => {
|
const escape = (value) => {
|
||||||
return value.replace(/(?<!\\)'/g, "\\'");
|
return value.replace(/(?<!\\)'/g, "\\'");
|
||||||
};
|
};
|
||||||
const iconToKeyValue = (icon) => {
|
|
||||||
return `'${icon.slug}':${iconToObject(icon)}`;
|
|
||||||
};
|
|
||||||
const licenseToObject = (license) => {
|
const licenseToObject = (license) => {
|
||||||
if (license === undefined) {
|
if (license === undefined) {
|
||||||
return;
|
return;
|
||||||
@ -82,7 +79,7 @@ const build = async () => {
|
|||||||
icons.map(async (icon) => {
|
icons.map(async (icon) => {
|
||||||
const filename = getIconSlug(icon);
|
const filename = getIconSlug(icon);
|
||||||
const svgFilepath = path.resolve(iconsDir, `${filename}.svg`);
|
const svgFilepath = path.resolve(iconsDir, `${filename}.svg`);
|
||||||
icon.svg = (await fs.readFile(svgFilepath, UTF8)).replace(/\r?\n/, '');
|
icon.svg = await fs.readFile(svgFilepath, UTF8);
|
||||||
icon.path = svgToPath(icon.svg);
|
icon.path = svgToPath(icon.svg);
|
||||||
icon.slug = filename;
|
icon.slug = filename;
|
||||||
const iconObject = iconToObject(icon);
|
const iconObject = iconToObject(icon);
|
||||||
@ -96,11 +93,11 @@ const build = async () => {
|
|||||||
const iconsBarrelMjs = [];
|
const iconsBarrelMjs = [];
|
||||||
|
|
||||||
buildIcons.sort((a, b) => collator.compare(a.icon.title, b.icon.title));
|
buildIcons.sort((a, b) => collator.compare(a.icon.title, b.icon.title));
|
||||||
buildIcons.forEach(({ iconObject, iconExportName }) => {
|
for (const { iconObject, iconExportName } of buildIcons) {
|
||||||
iconsBarrelDts.push(`export const ${iconExportName}:I;`);
|
iconsBarrelDts.push(`export const ${iconExportName}:I;`);
|
||||||
iconsBarrelJs.push(`${iconExportName}:${iconObject},`);
|
iconsBarrelJs.push(`${iconExportName}:${iconObject},`);
|
||||||
iconsBarrelMjs.push(`export const ${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>';`;
|
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>';`;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
* icon SVG filename to standard output.
|
* icon SVG filename to standard output.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import process from 'node:process';
|
||||||
import { titleToSlug } from '../sdk.mjs';
|
import { titleToSlug } from '../sdk.mjs';
|
||||||
|
|
||||||
if (process.argv.length < 3) {
|
if (process.argv.length < 3) {
|
||||||
|
@ -3,22 +3,18 @@
|
|||||||
* CLI tool to run jsonschema on the simple-icons.json data file.
|
* CLI tool to run jsonschema on the simple-icons.json data file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import path from 'node:path';
|
import process from 'node:process';
|
||||||
import { Validator } from 'jsonschema';
|
import { Validator } from 'jsonschema';
|
||||||
import { getDirnameFromImportMeta, getIconsData } from '../../sdk.mjs';
|
import { getIconsData } from '../../sdk.mjs';
|
||||||
import { getJsonSchemaData } from '../utils.js';
|
import { getJsonSchemaData } from '../utils.js';
|
||||||
|
|
||||||
const icons = await getIconsData();
|
const icons = await getIconsData();
|
||||||
const __dirname = getDirnameFromImportMeta(import.meta.url);
|
const schema = await getJsonSchemaData();
|
||||||
const schema = await getJsonSchemaData(path.resolve(__dirname, '..', '..'));
|
|
||||||
|
|
||||||
const validator = new Validator();
|
const validator = new Validator();
|
||||||
const result = validator.validate({ icons }, schema);
|
const result = validator.validate({ icons }, schema);
|
||||||
if (result.errors.length > 0) {
|
if (result.errors.length > 0) {
|
||||||
result.errors.forEach((error) => {
|
result.errors.forEach((error) => console.error(error));
|
||||||
console.error(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.error(`Found ${result.errors.length} error(s) in simple-icons.json`);
|
console.error(`Found ${result.errors.length} error(s) in simple-icons.json`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
* linters (e.g. jsonlint/svglint).
|
* linters (e.g. jsonlint/svglint).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import process from 'node:process';
|
||||||
import { URL } from 'node:url';
|
import { URL } from 'node:url';
|
||||||
import fakeDiff from 'fake-diff';
|
import fakeDiff from 'fake-diff';
|
||||||
import { getIconsDataString, normalizeNewlines, collator } from '../../sdk.mjs';
|
import { getIconsDataString, normalizeNewlines, collator } from '../../sdk.mjs';
|
||||||
@ -46,7 +47,7 @@ const TESTS = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/* Check the formatting of the data file */
|
/* Check the formatting of the data file */
|
||||||
prettified: async (data, dataString) => {
|
prettified: (data, dataString) => {
|
||||||
const normalizedDataString = normalizeNewlines(dataString);
|
const normalizedDataString = normalizeNewlines(dataString);
|
||||||
const dataPretty = `${JSON.stringify(data, null, 4)}\n`;
|
const dataPretty = `${JSON.stringify(data, null, 4)}\n`;
|
||||||
|
|
||||||
@ -66,8 +67,7 @@ const TESTS = {
|
|||||||
const allUrlFields = [
|
const allUrlFields = [
|
||||||
...new Set(
|
...new Set(
|
||||||
data.icons
|
data.icons
|
||||||
.map((icon) => [icon.source, icon.guidelines, icon.license?.url])
|
.flatMap((icon) => [icon.source, icon.guidelines, icon.license?.url])
|
||||||
.flat()
|
|
||||||
.filter(Boolean),
|
.filter(Boolean),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@ -84,19 +84,14 @@ const TESTS = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// execute all tests and log all errors
|
const dataString = await getIconsDataString();
|
||||||
(async () => {
|
const data = JSON.parse(dataString);
|
||||||
const dataString = await getIconsDataString();
|
|
||||||
const data = JSON.parse(dataString);
|
|
||||||
|
|
||||||
const errors = (
|
const errors = (
|
||||||
await Promise.all(
|
await Promise.all(Object.values(TESTS).map((test) => test(data, dataString)))
|
||||||
Object.keys(TESTS).map((test) => TESTS[test](data, dataString)),
|
).filter(Boolean);
|
||||||
)
|
|
||||||
).filter(Boolean);
|
|
||||||
|
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
errors.forEach((error) => console.error(`\u001b[31m${error}\u001b[0m`));
|
errors.forEach((error) => console.error(`\u001b[31m${error}\u001b[0m`));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
})();
|
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
* NPM package manifest. Does nothing if the README.md is already up-to-date.
|
* NPM package manifest. Does nothing if the README.md is already up-to-date.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from 'node:fs';
|
import process from 'node:process';
|
||||||
|
import fs from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { getDirnameFromImportMeta } from '../../sdk.mjs';
|
import { getDirnameFromImportMeta } from '../../sdk.mjs';
|
||||||
|
|
||||||
@ -19,31 +20,31 @@ const getMajorVersion = (semVerVersion) => {
|
|||||||
return parseInt(majorVersionAsString);
|
return parseInt(majorVersionAsString);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getManifest = () => {
|
const getManifest = async () => {
|
||||||
const manifestRaw = fs.readFileSync(packageJsonFile, 'utf-8');
|
const manifestRaw = await fs.readFile(packageJsonFile, 'utf-8');
|
||||||
return JSON.parse(manifestRaw);
|
return JSON.parse(manifestRaw);
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateVersionInReadmeIfNecessary = (majorVersion) => {
|
const updateVersionInReadmeIfNecessary = async (majorVersion) => {
|
||||||
let content = fs.readFileSync(readmeFile).toString();
|
let content = await fs.readFile(readmeFile, 'utf8');
|
||||||
|
|
||||||
content = content.replace(
|
content = content.replace(
|
||||||
/simple-icons@v[0-9]+/g,
|
/simple-icons@v[0-9]+/g,
|
||||||
`simple-icons@v${majorVersion}`,
|
`simple-icons@v${majorVersion}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
fs.writeFileSync(readmeFile, content);
|
await fs.writeFile(readmeFile, content);
|
||||||
};
|
};
|
||||||
|
|
||||||
const main = () => {
|
const main = async () => {
|
||||||
try {
|
try {
|
||||||
const manifest = getManifest();
|
const manifest = await getManifest();
|
||||||
const majorVersion = getMajorVersion(manifest.version);
|
const majorVersion = getMajorVersion(manifest.version);
|
||||||
updateVersionInReadmeIfNecessary(majorVersion);
|
await updateVersionInReadmeIfNecessary(majorVersion);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to update CDN version number:', error);
|
console.error('Failed to update CDN version number:', error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
main();
|
await main();
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* to match the current definitions of functions of sdk.mjs.
|
* to match the current definitions of functions of sdk.mjs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import fsSync from 'node:fs';
|
import process from 'node:process';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { execSync } from 'node:child_process';
|
import { execSync } from 'node:child_process';
|
||||||
@ -45,7 +45,11 @@ const generateSdkMts = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const generateSdkTs = async () => {
|
const generateSdkTs = async () => {
|
||||||
fsSync.existsSync(sdkMts) && (await fs.unlink(sdkMts));
|
const fileExists = await fs
|
||||||
|
.access(sdkMts)
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false);
|
||||||
|
fileExists && (await fs.unlink(sdkMts));
|
||||||
await generateSdkMts();
|
await generateSdkMts();
|
||||||
|
|
||||||
const autogeneratedMsg = '/* The next code is autogenerated from sdk.mjs */';
|
const autogeneratedMsg = '/* The next code is autogenerated from sdk.mjs */';
|
||||||
|
@ -25,14 +25,10 @@ update the script at '${path.relative(rootDir, __filename)}'.
|
|||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
`;
|
`;
|
||||||
|
|
||||||
(async () => {
|
const icons = await getIconsData();
|
||||||
const icons = await getIconsData();
|
for (const icon of icons) {
|
||||||
|
const brandName = icon.title;
|
||||||
icons.forEach((icon) => {
|
const brandSlug = getIconSlug(icon);
|
||||||
const brandName = icon.title;
|
content += `| \`${brandName}\` | \`${brandSlug}\` |\n`;
|
||||||
const brandSlug = getIconSlug(icon);
|
}
|
||||||
content += `| \`${brandName}\` | \`${brandSlug}\` |\n`;
|
await fs.writeFile(slugsFile, content);
|
||||||
});
|
|
||||||
|
|
||||||
await fs.writeFile(slugsFile, content);
|
|
||||||
})();
|
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
* at README every time the number of current icons is more than `updateRange`
|
* at README every time the number of current icons is more than `updateRange`
|
||||||
* more than the previous milestone.
|
* more than the previous milestone.
|
||||||
*/
|
*/
|
||||||
import { promises as fs } from 'node:fs';
|
|
||||||
|
import process from 'node:process';
|
||||||
|
import fs from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { getDirnameFromImportMeta, getIconsData } from '../../sdk.mjs';
|
import { getDirnameFromImportMeta, getIconsData } from '../../sdk.mjs';
|
||||||
|
|
||||||
@ -12,31 +14,26 @@ const regexMatcher = /Over\s(\d+)\s/;
|
|||||||
const updateRange = 100;
|
const updateRange = 100;
|
||||||
|
|
||||||
const __dirname = getDirnameFromImportMeta(import.meta.url);
|
const __dirname = getDirnameFromImportMeta(import.meta.url);
|
||||||
|
|
||||||
const rootDir = path.resolve(__dirname, '..', '..');
|
const rootDir = path.resolve(__dirname, '..', '..');
|
||||||
const readmeFile = path.resolve(rootDir, 'README.md');
|
const readmeFile = path.resolve(rootDir, 'README.md');
|
||||||
|
|
||||||
(async () => {
|
const readmeContent = await fs.readFile(readmeFile, 'utf-8');
|
||||||
const readmeContent = await fs.readFile(readmeFile, 'utf-8');
|
|
||||||
|
|
||||||
let overNIconsInReadme;
|
let overNIconsInReadme;
|
||||||
try {
|
try {
|
||||||
overNIconsInReadme = parseInt(regexMatcher.exec(readmeContent)[1]);
|
overNIconsInReadme = parseInt(regexMatcher.exec(readmeContent)[1]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(
|
console.error(
|
||||||
'Failed to obtain number of SVG icons of current milestone in README:',
|
'Failed to obtain number of SVG icons of current milestone in README:',
|
||||||
err,
|
err,
|
||||||
);
|
);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const nIcons = (await getIconsData()).length;
|
const nIcons = (await getIconsData()).length;
|
||||||
const newNIcons = overNIconsInReadme + updateRange;
|
const newNIcons = overNIconsInReadme + updateRange;
|
||||||
|
|
||||||
if (nIcons <= newNIcons) {
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (nIcons > newNIcons) {
|
||||||
const newContent = readmeContent.replace(regexMatcher, `Over ${newNIcons} `);
|
const newContent = readmeContent.replace(regexMatcher, `Over ${newNIcons} `);
|
||||||
await fs.writeFile(readmeFile, newContent);
|
await fs.writeFile(readmeFile, newContent);
|
||||||
})();
|
}
|
||||||
|
@ -6,7 +6,7 @@ const __dirname = getDirnameFromImportMeta(import.meta.url);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get JSON schema data.
|
* Get JSON schema data.
|
||||||
* @param {String|undefined} rootDir Path to the root directory of the project.
|
* @param {String} rootDir Path to the root directory of the project.
|
||||||
*/
|
*/
|
||||||
export const getJsonSchemaData = async (
|
export const getJsonSchemaData = async (
|
||||||
rootDir = path.resolve(__dirname, '..'),
|
rootDir = path.resolve(__dirname, '..'),
|
||||||
@ -19,13 +19,13 @@ export const getJsonSchemaData = async (
|
|||||||
/**
|
/**
|
||||||
* Write icons data to _data/simple-icons.json.
|
* Write icons data to _data/simple-icons.json.
|
||||||
* @param {Object} iconsData Icons data object.
|
* @param {Object} iconsData Icons data object.
|
||||||
* @param {String|undefined} rootDir Path to the root directory of the project.
|
* @param {String} rootDir Path to the root directory of the project.
|
||||||
*/
|
*/
|
||||||
export const writeIconsData = async (
|
export const writeIconsData = async (
|
||||||
iconsData,
|
iconsData,
|
||||||
rootDir = path.resolve(__dirname, '..'),
|
rootDir = path.resolve(__dirname, '..'),
|
||||||
) => {
|
) => {
|
||||||
return fs.writeFile(
|
await fs.writeFile(
|
||||||
getIconDataPath(rootDir),
|
getIconDataPath(rootDir),
|
||||||
`${JSON.stringify(iconsData, null, 4)}\n`,
|
`${JSON.stringify(iconsData, null, 4)}\n`,
|
||||||
'utf8',
|
'utf8',
|
||||||
|
1
sdk.d.ts
vendored
1
sdk.d.ts
vendored
@ -62,6 +62,7 @@ export type IconData = {
|
|||||||
/* The next code is autogenerated from sdk.mjs */
|
/* The next code is autogenerated from sdk.mjs */
|
||||||
|
|
||||||
export const URL_REGEX: RegExp;
|
export const URL_REGEX: RegExp;
|
||||||
|
export const SVG_PATH_REGEX: RegExp;
|
||||||
export function getDirnameFromImportMeta(importMetaUrl: string): string;
|
export function getDirnameFromImportMeta(importMetaUrl: string): string;
|
||||||
export function getIconSlug(icon: IconData): string;
|
export function getIconSlug(icon: IconData): string;
|
||||||
export function svgToPath(svg: string): string;
|
export function svgToPath(svg: string): string;
|
||||||
|
16
sdk.mjs
16
sdk.mjs
@ -36,7 +36,12 @@ const TITLE_TO_SLUG_RANGE_REGEX = /[^a-z0-9]/g;
|
|||||||
/**
|
/**
|
||||||
* Regex to validate HTTPs URLs.
|
* Regex to validate HTTPs URLs.
|
||||||
*/
|
*/
|
||||||
export const URL_REGEX = /^https:\/\/[^\s]+$/;
|
export const URL_REGEX = /^https:\/\/[^\s"']+$/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regex to validate SVG paths.
|
||||||
|
*/
|
||||||
|
export const SVG_PATH_REGEX = /^m[-mzlhvcsqtae0-9,. ]+$/i;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the directory name where this file is located from `import.meta.url`,
|
* Get the directory name where this file is located from `import.meta.url`,
|
||||||
@ -59,7 +64,7 @@ export const getIconSlug = (icon) => icon.slug || titleToSlug(icon.title);
|
|||||||
* @param {String} svg The icon SVG content
|
* @param {String} svg The icon SVG content
|
||||||
* @returns {String} The path from the icon SVG content
|
* @returns {String} The path from the icon SVG content
|
||||||
**/
|
**/
|
||||||
export const svgToPath = (svg) => svg.match(/<path\s+d="([^"]*)/)[1];
|
export const svgToPath = (svg) => svg.split('"', 8)[7];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a brand title into a slug/filename.
|
* Converts a brand title into a slug/filename.
|
||||||
@ -83,8 +88,7 @@ export const titleToSlug = (title) =>
|
|||||||
*/
|
*/
|
||||||
export const slugToVariableName = (slug) => {
|
export const slugToVariableName = (slug) => {
|
||||||
const slugFirstLetter = slug[0].toUpperCase();
|
const slugFirstLetter = slug[0].toUpperCase();
|
||||||
const slugRest = slug.slice(1);
|
return `si${slugFirstLetter}${slug.slice(1)}`;
|
||||||
return `si${slugFirstLetter}${slugRest}`;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,13 +193,11 @@ export const getThirdPartyExtensions = async (
|
|||||||
) =>
|
) =>
|
||||||
normalizeNewlines(await fs.readFile(readmePath, 'utf8'))
|
normalizeNewlines(await fs.readFile(readmePath, 'utf8'))
|
||||||
.split('## Third-Party Extensions\n\n')[1]
|
.split('## Third-Party Extensions\n\n')[1]
|
||||||
.split('\n\n')[0]
|
.split('\n\n', 1)[0]
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.slice(2)
|
.slice(2)
|
||||||
.map((line) => {
|
.map((line) => {
|
||||||
let [module, author] = line.split(' | ');
|
let [module, author] = line.split(' | ');
|
||||||
|
|
||||||
// README shipped with package has not Github theme image links
|
|
||||||
module = module.split('<img src="')[0];
|
module = module.split('<img src="')[0];
|
||||||
return {
|
return {
|
||||||
module: {
|
module: {
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { describe, test } from 'mocha';
|
import { test } from 'mocha';
|
||||||
import { strict as assert } from 'node:assert';
|
import { strict as assert } from 'node:assert';
|
||||||
import { getThirdPartyExtensions, getDirnameFromImportMeta } from '../sdk.mjs';
|
import {
|
||||||
|
getThirdPartyExtensions,
|
||||||
|
getDirnameFromImportMeta,
|
||||||
|
URL_REGEX,
|
||||||
|
} from '../sdk.mjs';
|
||||||
|
|
||||||
const __dirname = getDirnameFromImportMeta(import.meta.url);
|
const __dirname = getDirnameFromImportMeta(import.meta.url);
|
||||||
const root = path.dirname(__dirname);
|
const root = path.dirname(__dirname);
|
||||||
|
const getLinksRegex = new RegExp(
|
||||||
|
URL_REGEX.source.replace('^https', 'https?'),
|
||||||
|
'gm',
|
||||||
|
);
|
||||||
|
|
||||||
test('README third party extensions must be alphabetically sorted', async () => {
|
test('README third party extensions must be alphabetically sorted', async () => {
|
||||||
const readmePath = path.join(root, 'README.md');
|
const thirdPartyExtensions = await getThirdPartyExtensions();
|
||||||
const thirdPartyExtensions = await getThirdPartyExtensions(readmePath);
|
|
||||||
assert.ok(thirdPartyExtensions.length > 0);
|
assert.ok(thirdPartyExtensions.length > 0);
|
||||||
|
|
||||||
const thirdPartyExtensionsNames = thirdPartyExtensions.map(
|
const thirdPartyExtensionsNames = thirdPartyExtensions.map(
|
||||||
@ -27,22 +34,21 @@ test('README third party extensions must be alphabetically sorted', async () =>
|
|||||||
test('Only allow HTTPS links in documentation pages', async () => {
|
test('Only allow HTTPS links in documentation pages', async () => {
|
||||||
const ignoreHttpLinks = ['http://www.w3.org/2000/svg'];
|
const ignoreHttpLinks = ['http://www.w3.org/2000/svg'];
|
||||||
|
|
||||||
const docsFiles = fs
|
const docsFiles = (await fs.readdir(root)).filter((fname) =>
|
||||||
.readdirSync(root)
|
fname.endsWith('.md'),
|
||||||
.filter((fname) => fname.endsWith('.md'));
|
);
|
||||||
|
|
||||||
const linksGetter = new RegExp('http://[^\\s"\']+', 'g');
|
for (const docsFile of docsFiles) {
|
||||||
for (let docsFile of docsFiles) {
|
|
||||||
const docsFilePath = path.join(root, docsFile);
|
const docsFilePath = path.join(root, docsFile);
|
||||||
const docsFileContent = fs.readFileSync(docsFilePath, 'utf8');
|
const docsFileContent = await fs.readFile(docsFilePath, 'utf8');
|
||||||
|
|
||||||
Array.from(docsFileContent.matchAll(linksGetter)).forEach((match) => {
|
for (const match of docsFileContent.matchAll(getLinksRegex)) {
|
||||||
const link = match[0];
|
const link = match[0];
|
||||||
assert.ok(
|
assert.ok(
|
||||||
ignoreHttpLinks.includes(link) || link.startsWith('https://'),
|
ignoreHttpLinks.includes(link) || link.startsWith('https://'),
|
||||||
`Link '${link}' in '${docsFile}' (at index ${match.index})` +
|
`Link '${link}' in '${docsFile}' (at index ${match.index})` +
|
||||||
` must use the HTTPS protocol.`,
|
` must use the HTTPS protocol.`,
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,14 +2,10 @@ import { getIconsData, getIconSlug, slugToVariableName } from '../sdk.mjs';
|
|||||||
import * as simpleIcons from '../index.mjs';
|
import * as simpleIcons from '../index.mjs';
|
||||||
import { testIcon } from './test-icon.js';
|
import { testIcon } from './test-icon.js';
|
||||||
|
|
||||||
(async () => {
|
for (const icon of await getIconsData()) {
|
||||||
const icons = await getIconsData();
|
const slug = getIconSlug(icon);
|
||||||
|
const variableName = slugToVariableName(slug);
|
||||||
|
const subject = simpleIcons[variableName];
|
||||||
|
|
||||||
icons.map((icon) => {
|
testIcon(icon, subject, slug);
|
||||||
const slug = getIconSlug(icon);
|
}
|
||||||
const variableName = slugToVariableName(slug);
|
|
||||||
const subject = simpleIcons[variableName];
|
|
||||||
|
|
||||||
testIcon(icon, subject, slug);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
@ -1,15 +1,28 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { strict as assert } from 'node:assert';
|
import { strict as assert } from 'node:assert';
|
||||||
import { describe, it } from 'mocha';
|
import { describe, it } from 'mocha';
|
||||||
import { URL_REGEX, titleToSlug } from '../sdk.mjs';
|
import {
|
||||||
|
SVG_PATH_REGEX,
|
||||||
|
URL_REGEX,
|
||||||
|
getDirnameFromImportMeta,
|
||||||
|
titleToSlug,
|
||||||
|
} from '../sdk.mjs';
|
||||||
|
|
||||||
const iconsDir = path.resolve(process.cwd(), 'icons');
|
const iconsDir = path.resolve(
|
||||||
|
getDirnameFromImportMeta(import.meta.url),
|
||||||
|
'..',
|
||||||
|
'icons',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('..').SimpleIcon} SimpleIcon
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if icon data matches a subject icon.
|
* Checks if icon data matches a subject icon.
|
||||||
* @param {import('..').SimpleIcon} icon Icon data
|
* @param {SimpleIcon} icon Icon data
|
||||||
* @param {import('..').SimpleIcon} subject Icon to check against icon data
|
* @param {SimpleIcon} subject Icon to check against icon data
|
||||||
* @param {String} slug Icon data slug
|
* @param {String} slug Icon data slug
|
||||||
*/
|
*/
|
||||||
export const testIcon = (icon, subject, slug) => {
|
export const testIcon = (icon, subject, slug) => {
|
||||||
@ -38,7 +51,7 @@ export const testIcon = (icon, subject, slug) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('has a valid "path" value', () => {
|
it('has a valid "path" value', () => {
|
||||||
assert.match(subject.path, /^[MmZzLlHhVvCcSsQqTtAaEe0-9-,.\s]+$/g);
|
assert.match(subject.path, SVG_PATH_REGEX);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`has ${icon.guidelines ? 'the correct' : 'no'} "guidelines"`, () => {
|
it(`has ${icon.guidelines ? 'the correct' : 'no'} "guidelines"`, () => {
|
||||||
@ -62,8 +75,8 @@ export const testIcon = (icon, subject, slug) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has a valid svg value', () => {
|
it('has a valid svg value', async () => {
|
||||||
const svgFileContents = fs.readFileSync(svgPath, 'utf8');
|
const svgFileContents = await fs.readFile(svgPath, 'utf8');
|
||||||
assert.equal(subject.svg, svgFileContents);
|
assert.equal(subject.svg, svgFileContents);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user