mirror of
https://github.com/simple-icons/simple-icons.git
synced 2024-11-26 01:00:27 +02:00
Refactor add-icon-data script (#10639)
This commit is contained in:
parent
842d60ca2d
commit
4cd4603432
@ -13,171 +13,122 @@ import {
|
||||
} from '../sdk.mjs';
|
||||
import { getJsonSchemaData, writeIconsData } from './utils.js';
|
||||
|
||||
const hexPattern = /^#?[a-f0-9]{3,8}$/i;
|
||||
|
||||
const iconsData = JSON.parse(await getIconsDataString());
|
||||
const jsonSchema = await getJsonSchemaData();
|
||||
|
||||
const titleValidator = (text) => {
|
||||
if (!text) return 'This field is required';
|
||||
if (
|
||||
iconsData.icons.find(
|
||||
(x) => x.title === text || titleToSlug(x.title) === titleToSlug(text),
|
||||
)
|
||||
)
|
||||
return 'This icon title or slug already exists';
|
||||
return true;
|
||||
};
|
||||
const HEX_REGEX = /^#?[a-f0-9]{3,8}$/i;
|
||||
|
||||
const hexValidator = (text) =>
|
||||
hexPattern.test(text) || 'This should be a valid hex code';
|
||||
const aliasTypes = ['aka', 'old'].map((key) => ({
|
||||
name: `${key} (${jsonSchema.definitions.brand.properties.aliases.properties[key].description})`,
|
||||
value: key,
|
||||
}));
|
||||
|
||||
const sourceValidator = (text) =>
|
||||
URL_REGEX.test(text) || 'This should be a secure URL';
|
||||
const licenseTypes =
|
||||
jsonSchema.definitions.brand.properties.license.oneOf[0].properties.type.enum.map(
|
||||
(license) => ({ name: license, value: license }),
|
||||
);
|
||||
|
||||
const hexTransformer = (text) => {
|
||||
const color = normalizeColor(text);
|
||||
const luminance = hexPattern.test(text)
|
||||
const isValidURL = (input) =>
|
||||
URL_REGEX.test(input) || 'Must be a valid and secure (https://) URL.';
|
||||
|
||||
const isValidHexColor = (input) =>
|
||||
HEX_REGEX.test(input) || 'Must be a valid hex code.';
|
||||
|
||||
const isNewIcon = (input) =>
|
||||
!iconsData.icons.find(
|
||||
(icon) =>
|
||||
icon.title === input || titleToSlug(icon.title) === titleToSlug(input),
|
||||
) || 'This icon title or slug already exists.';
|
||||
|
||||
const previewHexColor = (input) => {
|
||||
const color = normalizeColor(input);
|
||||
const luminance = HEX_REGEX.test(input)
|
||||
? getRelativeLuminance.default(`#${color}`)
|
||||
: -1;
|
||||
if (luminance === -1) return text.toUpperCase();
|
||||
if (luminance === -1) return input.toUpperCase();
|
||||
return chalk.bgHex(`#${color}`).hex(luminance < 0.4 ? '#fff' : '#000')(
|
||||
text.toUpperCase(),
|
||||
input.toUpperCase(),
|
||||
);
|
||||
};
|
||||
|
||||
const aliasesTransformer = (text) =>
|
||||
text
|
||||
.split(',')
|
||||
.map((x) => chalk.cyan(x))
|
||||
.join(',');
|
||||
try {
|
||||
const answers = {
|
||||
title: await input({
|
||||
message: 'What is the title of this icon?',
|
||||
validate: (input) =>
|
||||
input.trim().length > 0 ? isNewIcon(input) : 'This field is required.',
|
||||
}),
|
||||
hex: normalizeColor(
|
||||
await input({
|
||||
message: 'What is the brand color of this icon?',
|
||||
validate: isValidHexColor,
|
||||
transformer: previewHexColor,
|
||||
}),
|
||||
),
|
||||
source: await input({
|
||||
message: 'What is the source URL of the icon?',
|
||||
validate: isValidURL,
|
||||
}),
|
||||
guidelines: (await confirm({
|
||||
message: 'Does this icon have brand guidelines?',
|
||||
}))
|
||||
? await input({
|
||||
message: 'What is the URL for the brand guidelines?',
|
||||
validate: isValidURL,
|
||||
})
|
||||
: undefined,
|
||||
license: (await confirm({
|
||||
message: 'Does this icon have a license?',
|
||||
}))
|
||||
? {
|
||||
type: await autocomplete({
|
||||
message: "What is the icon's license?",
|
||||
source: async (input) => {
|
||||
input = (input || '').trim();
|
||||
return input
|
||||
? search(input, licenseTypes, { keySelector: (x) => x.value })
|
||||
: licenseTypes;
|
||||
},
|
||||
}),
|
||||
url:
|
||||
(await input({
|
||||
message: `What is the URL for the license? (optional)`,
|
||||
validate: (input) => input.length === 0 || isValidURL(input),
|
||||
})) || undefined,
|
||||
}
|
||||
: undefined,
|
||||
aliases: (await confirm({
|
||||
message: 'Does this icon have brand aliases?',
|
||||
default: false,
|
||||
}))
|
||||
? await checkbox({
|
||||
message: 'What types of aliases do you want to add?',
|
||||
choices: aliasTypes,
|
||||
}).then(async (aliases) => {
|
||||
const result = {};
|
||||
for (const alias of aliases) {
|
||||
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,
|
||||
};
|
||||
|
||||
const aliasesChoices = Object.entries(
|
||||
jsonSchema.definitions.brand.properties.aliases.properties,
|
||||
)
|
||||
.filter(([k]) => ['aka', 'old'].includes(k))
|
||||
.map(([k, v]) => ({ name: `${k}: ${v.description}`, value: k }));
|
||||
console.log(
|
||||
'About to write the following to simple-icons.json:\n' +
|
||||
JSON.stringify(answers, null, 4),
|
||||
);
|
||||
|
||||
const getIconDataFromAnswers = (answers) => ({
|
||||
title: answers.title,
|
||||
hex: normalizeColor(answers.hex),
|
||||
source: answers.source,
|
||||
...(answers.hasGuidelines ? { guidelines: answers.guidelines } : {}),
|
||||
...(answers.hasLicense
|
||||
? {
|
||||
license: {
|
||||
type: answers.licenseType,
|
||||
...(answers.licenseUrl ? { url: answers.licenseUrl } : {}),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(answers.hasAliases
|
||||
? {
|
||||
aliases: aliasesChoices.reduce((previous, current) => {
|
||||
const promptKey = `${current.value}AliasesList`;
|
||||
if (answers[promptKey])
|
||||
return {
|
||||
...previous,
|
||||
[current.value]: answers[promptKey]
|
||||
.split(',')
|
||||
.map((x) => x.trim()),
|
||||
};
|
||||
return previous;
|
||||
}, {}),
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
const answers = {};
|
||||
|
||||
answers.title = await input({
|
||||
message: 'Title:',
|
||||
validate: titleValidator,
|
||||
});
|
||||
|
||||
answers.hex = await input({
|
||||
message: 'Hex:',
|
||||
validate: hexValidator,
|
||||
transformer: hexTransformer,
|
||||
});
|
||||
|
||||
answers.source = await input({
|
||||
message: 'Source URL:',
|
||||
validate: sourceValidator,
|
||||
});
|
||||
|
||||
answers.hasGuidelines = await confirm({
|
||||
message: 'The icon has brand guidelines?',
|
||||
});
|
||||
|
||||
if (answers.hasGuidelines) {
|
||||
answers.guidelines = await input({
|
||||
message: 'Guidelines URL:',
|
||||
validate: sourceValidator,
|
||||
});
|
||||
}
|
||||
|
||||
answers.hasLicense = await confirm({
|
||||
message: 'The icon has brand license?',
|
||||
});
|
||||
|
||||
if (answers.hasLicense) {
|
||||
const licenseTypes =
|
||||
jsonSchema.definitions.brand.properties.license.oneOf[0].properties.type.enum.map(
|
||||
(license) => {
|
||||
return { value: license };
|
||||
},
|
||||
);
|
||||
answers.licenseType = await autocomplete({
|
||||
message: 'License type:',
|
||||
source: async (input) => {
|
||||
input = (input || '').trim();
|
||||
return input
|
||||
? search(input, licenseTypes, { keySelector: (x) => x.value })
|
||||
: licenseTypes;
|
||||
},
|
||||
});
|
||||
|
||||
answers.licenseUrl = await input({
|
||||
message: `License URL ${chalk.reset('(optional)')}:`,
|
||||
validate: (text) => text.length === 0 || sourceValidator(text),
|
||||
});
|
||||
}
|
||||
|
||||
answers.hasAliases = await confirm({
|
||||
message: 'This icon has brand aliases?',
|
||||
default: false,
|
||||
});
|
||||
|
||||
if (answers.hasAliases) {
|
||||
answers.aliasesTypes = await checkbox({
|
||||
message: 'What types of aliases do you want to add?',
|
||||
choices: aliasesChoices,
|
||||
});
|
||||
|
||||
for (const x of aliasesChoices) {
|
||||
if (!answers?.aliasesTypes?.includes(x.value)) continue;
|
||||
answers[`${x.value}AliasesList`] = await input({
|
||||
message: x.value + chalk.reset(' (separate with commas)'),
|
||||
validate: (text) => text.trim().length > 0,
|
||||
transformer: aliasesTransformer,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
answers.confirmToAdd = await confirm({
|
||||
message: [
|
||||
'About to write the following to simple-icons.json:',
|
||||
chalk.reset(JSON.stringify(getIconDataFromAnswers(answers), null, 4)),
|
||||
chalk.reset('Is this OK?'),
|
||||
].join('\n\n'),
|
||||
});
|
||||
|
||||
const icon = getIconDataFromAnswers(answers);
|
||||
|
||||
if (answers.confirmToAdd) {
|
||||
iconsData.icons.push(icon);
|
||||
if (
|
||||
await confirm({
|
||||
message: 'Is this OK?',
|
||||
})
|
||||
) {
|
||||
iconsData.icons.push(answers);
|
||||
iconsData.icons.sort((a, b) => collator.compare(a.title, b.title));
|
||||
await writeIconsData(iconsData);
|
||||
console.log(chalk.green('\nData written successfully.'));
|
||||
@ -185,19 +136,11 @@ const run = async () => {
|
||||
console.log(chalk.red('\nAborted.'));
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
await run();
|
||||
} catch (err) {
|
||||
if (err instanceof ExitPromptError) {
|
||||
console.log(chalk.red('\nAborted.'));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
throw err;
|
||||
} catch (err) {
|
||||
if (err instanceof ExitPromptError) {
|
||||
console.log(chalk.red('\nAborted.'));
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
await main();
|
||||
throw err;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user