Convert simple-icons manual backup from submodule to tracked files
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env node
|
||||
// @ts-check
|
||||
/**
|
||||
* @file
|
||||
* Send release message to Discord #releases channel.
|
||||
*/
|
||||
|
||||
import process from 'node:process';
|
||||
|
||||
const releaseVersion = process.argv[2];
|
||||
const discordReleasesRoleId = process.env.DISCORD_RELEASES_ROLE_ID;
|
||||
const discordReleasesWebhookUrl = process.env.DISCORD_RELEASES_WEBHOOK_URL;
|
||||
const githubReleaseUrl = `https://github.com/simple-icons/simple-icons/releases/tag/${releaseVersion}`;
|
||||
|
||||
if (discordReleasesRoleId === undefined) {
|
||||
console.error('DISCORD_RELEASES_ROLE_ID environment variable is not set.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (discordReleasesWebhookUrl === undefined) {
|
||||
console.error(
|
||||
'DISCORD_RELEASES_WEBHOOK_URL environment variable is not set.',
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
await globalThis.fetch(discordReleasesWebhookUrl, {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
content: `<@&${discordReleasesRoleId}> ${githubReleaseUrl}`,
|
||||
}),
|
||||
});
|
||||
} catch {
|
||||
console.error('Failed to send release message to Discord.');
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
// @ts-check
|
||||
/**
|
||||
* @file
|
||||
* Minify data/simple-icons.json file.
|
||||
*/
|
||||
import {getIconSlug, getIconsData} from '../../sdk.mjs';
|
||||
import {formatIconData, writeIconsData} from '../utils.js';
|
||||
|
||||
const plainIcons = await getIconsData();
|
||||
const iconsWithSlugs = plainIcons.map((icon) =>
|
||||
icon.slug ? icon : {...icon, slug: getIconSlug(icon)},
|
||||
);
|
||||
await writeIconsData(formatIconData(iconsWithSlugs), true);
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env node
|
||||
// @ts-check
|
||||
/**
|
||||
* @file
|
||||
* Rewrite some Markdown files.
|
||||
*/
|
||||
|
||||
import {readFile, writeFile} from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
|
||||
const LINKS_BRANCH = process.argv[2] || 'develop';
|
||||
|
||||
const rootDirectory = path.resolve(import.meta.dirname, '..', '..');
|
||||
const readmeFile = path.resolve(rootDirectory, 'README.md');
|
||||
const disclaimerFile = path.resolve(rootDirectory, 'DISCLAIMER.md');
|
||||
|
||||
/**
|
||||
* Reformat a file.
|
||||
* @param {string} filePath Path to the file.
|
||||
*/
|
||||
const reformat = async (filePath) => {
|
||||
const fileContent = await readFile(filePath, 'utf8');
|
||||
await writeFile(
|
||||
filePath,
|
||||
fileContent
|
||||
// Replace all CDN links with raw links
|
||||
.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
|
||||
.replaceAll(
|
||||
/\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)](?!\()/g,
|
||||
(string_, $0) => {
|
||||
const capital = $0.slice(0, 1);
|
||||
const body = $0.slice(1).toLowerCase();
|
||||
return `**${capital + body}**`;
|
||||
},
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
await Promise.all([reformat(readmeFile), reformat(disclaimerFile)]);
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"lib": ["es2022"],
|
||||
"module": "es2022",
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"removeComments": true,
|
||||
"esModuleInterop": true,
|
||||
"checkJs": false,
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": ["../../sdk.mjs"]
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env node
|
||||
// @ts-check
|
||||
/**
|
||||
* @file
|
||||
* 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 fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
|
||||
const rootDirectory = path.resolve(import.meta.dirname, '..', '..');
|
||||
const packageJsonFile = path.resolve(rootDirectory, 'package.json');
|
||||
const readmeFile = path.resolve(rootDirectory, 'README.md');
|
||||
|
||||
/**
|
||||
* Get the major version number from a semantic version string.
|
||||
* @param {string} semVersion A semantic version string.
|
||||
* @returns {number} The major version number.
|
||||
*/
|
||||
const getMajorVersion = (semVersion) => {
|
||||
const majorVersionAsString = semVersion.split('.')[0];
|
||||
return Number.parseInt(majorVersionAsString, 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the package.json manifest.
|
||||
* @returns {Promise<{version: string}>} The package.json manifest.
|
||||
*/
|
||||
const getManifest = async () => {
|
||||
const manifestRaw = await fs.readFile(packageJsonFile, 'utf8');
|
||||
return JSON.parse(manifestRaw);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the version number in the README.md.
|
||||
* @param {number} majorVersion The major version number.
|
||||
*/
|
||||
const updateVersionInReadmeIfNecessary = async (majorVersion) => {
|
||||
let content = await fs.readFile(readmeFile, 'utf8');
|
||||
|
||||
content = content.replaceAll(
|
||||
/simple-icons@v\d+/g,
|
||||
`simple-icons@v${majorVersion}`,
|
||||
);
|
||||
|
||||
await fs.writeFile(readmeFile, content);
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
const manifest = await getManifest();
|
||||
const majorVersion = getMajorVersion(manifest.version);
|
||||
await updateVersionInReadmeIfNecessary(majorVersion);
|
||||
} catch (error) {
|
||||
console.error('Failed to update CDN version number:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
await main();
|
||||
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env node
|
||||
// @ts-check
|
||||
/**
|
||||
* @file
|
||||
* Updates the SDK Typescript definitions located in the file sdk.d.ts
|
||||
* to match the current definitions of functions of sdk.mjs.
|
||||
*/
|
||||
|
||||
import {spawnSync} from 'node:child_process';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
import {fileExists} from '../utils.js';
|
||||
|
||||
const rootDirectory = path.resolve(import.meta.dirname, '..', '..');
|
||||
|
||||
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
|
||||
// in sdk.mjs to avoid circular imports
|
||||
const originalSdkMjsContent = await fs.readFile(sdkMjs, 'utf8');
|
||||
const temporarySdkMjsContent = originalSdkMjsContent
|
||||
.split('\n')
|
||||
.filter((line) => !line.startsWith(' * @typedef {import("./sdk")'))
|
||||
.join('\n');
|
||||
await fs.writeFile(sdkMjs, temporarySdkMjsContent);
|
||||
|
||||
let cmd;
|
||||
let error = false;
|
||||
try {
|
||||
cmd = spawnSync(
|
||||
'npx',
|
||||
[
|
||||
'tsc',
|
||||
'-p',
|
||||
path.join('scripts', 'release', 'sdk-ts-defs-jsconfig.json'),
|
||||
'--declaration',
|
||||
'--emitDeclarationOnly',
|
||||
],
|
||||
{stdio: 'inherit'},
|
||||
);
|
||||
} catch {
|
||||
await fs.writeFile(sdkMjs, originalSdkMjsContent);
|
||||
error = true;
|
||||
}
|
||||
|
||||
let errorMessage = "Command 'npx tsc sdk.mjs' failed for an unknown reason";
|
||||
if (cmd && cmd.stderr) {
|
||||
errorMessage = cmd.stderr.toString();
|
||||
}
|
||||
|
||||
if (error || cmd === undefined) {
|
||||
process.stdout.write(
|
||||
`Error generating Typescript definitions: '${errorMessage}'\n`,
|
||||
);
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await fs.writeFile(sdkMjs, originalSdkMjsContent);
|
||||
};
|
||||
|
||||
/**
|
||||
* We must remove the duplicated export types that tsc generates from
|
||||
* JSDoc `typedef` comments.
|
||||
* See {@link https://github.com/microsoft/TypeScript/issues/46011}.
|
||||
* @param {string} content Content of the file.
|
||||
* @returns {string} The content without duplicated export types.
|
||||
*/
|
||||
const removeDuplicatedExportTypes = (content) => {
|
||||
const newContent = [];
|
||||
const lines = content.split('\n');
|
||||
/** @type {string[]} */
|
||||
const exportTypesFound = [];
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('export type ')) {
|
||||
const type = line.split(' ')[2];
|
||||
if (!exportTypesFound.includes(type)) {
|
||||
newContent.push(line);
|
||||
exportTypesFound.push(type);
|
||||
}
|
||||
} else {
|
||||
newContent.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
return newContent.join('\n');
|
||||
};
|
||||
|
||||
const generateSdkTs = async () => {
|
||||
const sdkMtsExists = await fileExists(sdkMts);
|
||||
if (sdkMtsExists) await fs.unlink(sdkMts);
|
||||
await generateSdkMts();
|
||||
|
||||
const autogeneratedMessage =
|
||||
'/* The next code is autogenerated from sdk.mjs */\n/* eslint-disable */';
|
||||
const newSdkTsContent =
|
||||
// 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, removeDuplicatedExportTypes(newSdkTsContent));
|
||||
await fs.unlink(sdkMts);
|
||||
|
||||
let cmd;
|
||||
let error = false;
|
||||
try {
|
||||
cmd = spawnSync('npx', ['prettier', '-w', 'sdk.d.ts'], {stdio: 'inherit'});
|
||||
} catch {
|
||||
error = true;
|
||||
}
|
||||
|
||||
let errorMessage =
|
||||
"Command 'npx prettier -w sdk.d.ts' failed for an unknown reason";
|
||||
if (cmd && cmd.stderr) {
|
||||
errorMessage = cmd.stderr.toString();
|
||||
}
|
||||
|
||||
if (error || cmd === undefined) {
|
||||
process.stdout.write(
|
||||
'Error executing Prettier to prettify' +
|
||||
` SDK TS definitions: '${errorMessage}'\n`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
await generateSdkTs();
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env node
|
||||
// @ts-check
|
||||
/**
|
||||
* @file
|
||||
* Generates a MarkDown file that lists every brand name and their slug.
|
||||
*/
|
||||
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import {getIconSlug, getIconsData} from '../../sdk.mjs';
|
||||
|
||||
const rootDirectory = path.resolve(import.meta.dirname, '..', '..');
|
||||
const slugsFile = path.resolve(rootDirectory, 'slugs.md');
|
||||
|
||||
let content = `<!--
|
||||
|
||||
update the script at '${path.relative(rootDirectory, import.meta.filename)}'.
|
||||
-->
|
||||
|
||||
# Simple Icons slugs
|
||||
|
||||
| Brand name | Brand slug |
|
||||
| :--- | :--- |
|
||||
`;
|
||||
|
||||
const icons = await getIconsData();
|
||||
for (const icon of icons) {
|
||||
const brandName = icon.title;
|
||||
const brandSlug = getIconSlug(icon);
|
||||
content += `| \`${brandName}\` | \`${brandSlug}\` |\n`;
|
||||
}
|
||||
|
||||
await fs.writeFile(slugsFile, content);
|
||||
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env node
|
||||
// @ts-check
|
||||
/**
|
||||
* @file
|
||||
* Replaces the SVG count milestone "Over <NUMBER> SVG icons..." located
|
||||
* at README every time the number of current icons is more than `updateRange`
|
||||
* more than the previous milestone.
|
||||
*/
|
||||
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
import {getIconsData} from '../../sdk.mjs';
|
||||
|
||||
const regexMatcher = /Over\s(\d+)\s/;
|
||||
const updateRange = 100;
|
||||
|
||||
const rootDirectory = path.resolve(import.meta.dirname, '..', '..');
|
||||
const readmeFile = path.resolve(rootDirectory, 'README.md');
|
||||
|
||||
const readmeContent = await fs.readFile(readmeFile, 'utf8');
|
||||
|
||||
try {
|
||||
const match = regexMatcher.exec(readmeContent);
|
||||
if (match === null) {
|
||||
console.error(
|
||||
'Failed to obtain number of SVG icons of current milestone in README:',
|
||||
'No match found',
|
||||
);
|
||||
process.exit(1);
|
||||
} else {
|
||||
const overNIconsInReadme = Number.parseInt(match[1], 10);
|
||||
const iconsData = await getIconsData();
|
||||
const nIcons = iconsData.length;
|
||||
const nIconsRounded = Math.floor(nIcons / updateRange) * updateRange;
|
||||
|
||||
if (overNIconsInReadme !== nIconsRounded) {
|
||||
const newContent = readmeContent.replace(
|
||||
regexMatcher,
|
||||
`Over ${nIconsRounded} `,
|
||||
);
|
||||
await fs.writeFile(readmeFile, newContent);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
'Failed to update number of SVG icons of current milestone in README:',
|
||||
error,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user