2020-01-16 13:40:46 +03:00
|
|
|
/**
|
2021-02-08 19:14:31 +03:00
|
|
|
* @fileoverview
|
|
|
|
* Linters for the package that can't easily be implemented in the existing
|
|
|
|
* linters (e.g. jsonlint/svglint).
|
2020-01-16 13:40:46 +03:00
|
|
|
*/
|
2021-01-15 23:47:00 +03:00
|
|
|
|
2023-08-08 07:38:52 +03:00
|
|
|
import process from 'node:process';
|
2023-05-29 04:34:33 +03:00
|
|
|
import { URL } from 'node:url';
|
2021-12-25 17:22:56 +03:00
|
|
|
import fakeDiff from 'fake-diff';
|
2023-04-19 16:23:13 +03:00
|
|
|
import { getIconsDataString, normalizeNewlines, collator } from '../../sdk.mjs';
|
2020-01-16 13:40:46 +03:00
|
|
|
|
|
|
|
/**
|
2021-02-08 19:14:31 +03:00
|
|
|
* Contains our tests so they can be isolated from each other.
|
2020-01-16 13:40:46 +03:00
|
|
|
* @type {{[k:string]: () => (string|undefined)}}
|
|
|
|
*/
|
|
|
|
const TESTS = {
|
2020-12-13 23:17:41 +03:00
|
|
|
/* Tests whether our icons are in alphabetical order */
|
2021-12-25 17:22:56 +03:00
|
|
|
alphabetical: (data) => {
|
2020-01-16 13:40:46 +03:00
|
|
|
const collector = (invalidEntries, icon, index, array) => {
|
|
|
|
if (index > 0) {
|
|
|
|
const prev = array[index - 1];
|
2022-09-24 18:29:43 +03:00
|
|
|
const comparison = collator.compare(icon.title, prev.title);
|
|
|
|
if (comparison < 0) {
|
2020-01-16 13:40:46 +03:00
|
|
|
invalidEntries.push(icon);
|
2022-09-24 18:29:43 +03:00
|
|
|
} else if (comparison === 0) {
|
2021-04-16 19:05:44 +03:00
|
|
|
if (prev.slug) {
|
2022-09-24 18:29:43 +03:00
|
|
|
if (!icon.slug || collator.compare(icon.slug, prev.slug) < 0) {
|
2021-04-16 19:05:44 +03:00
|
|
|
invalidEntries.push(icon);
|
|
|
|
}
|
|
|
|
}
|
2020-01-16 13:40:46 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return invalidEntries;
|
|
|
|
};
|
2021-10-25 22:13:10 +03:00
|
|
|
const format = (icon) => {
|
2021-04-16 19:05:44 +03:00
|
|
|
if (icon.slug) {
|
|
|
|
return `${icon.title} (${icon.slug})`;
|
|
|
|
}
|
|
|
|
return icon.title;
|
|
|
|
};
|
2020-01-16 13:40:46 +03:00
|
|
|
|
2021-02-08 19:14:31 +03:00
|
|
|
const invalids = data.icons.reduce(collector, []);
|
2020-01-16 13:40:46 +03:00
|
|
|
if (invalids.length) {
|
|
|
|
return `Some icons aren't in alphabetical order:
|
2021-10-25 22:13:10 +03:00
|
|
|
${invalids.map((icon) => format(icon)).join(', ')}`;
|
2020-01-16 13:40:46 +03:00
|
|
|
}
|
2020-12-13 23:17:41 +03:00
|
|
|
},
|
|
|
|
|
2021-02-08 19:14:31 +03:00
|
|
|
/* Check the formatting of the data file */
|
2023-08-08 07:38:52 +03:00
|
|
|
prettified: (data, dataString) => {
|
2022-03-31 15:30:30 +03:00
|
|
|
const normalizedDataString = normalizeNewlines(dataString);
|
2022-09-25 04:04:58 +03:00
|
|
|
const dataPretty = `${JSON.stringify(data, null, 4)}\n`;
|
2021-12-25 17:22:56 +03:00
|
|
|
|
|
|
|
if (normalizedDataString !== dataPretty) {
|
|
|
|
const dataDiff = fakeDiff(normalizedDataString, dataPretty);
|
2021-02-08 19:14:31 +03:00
|
|
|
return `Data file is formatted incorrectly:\n\n${dataDiff}`;
|
2020-12-13 23:17:41 +03:00
|
|
|
}
|
2021-10-25 22:13:10 +03:00
|
|
|
},
|
2023-05-29 04:34:33 +03:00
|
|
|
|
|
|
|
/* Check redundant trailing slash in URL */
|
|
|
|
checkUrl: (data) => {
|
|
|
|
const hasRedundantTrailingSlash = (url) => {
|
|
|
|
const origin = new URL(url).origin;
|
|
|
|
return /^\/+$/.test(url.replace(origin, ''));
|
|
|
|
};
|
|
|
|
|
|
|
|
const allUrlFields = [
|
|
|
|
...new Set(
|
|
|
|
data.icons
|
2023-08-08 07:38:52 +03:00
|
|
|
.flatMap((icon) => [icon.source, icon.guidelines, icon.license?.url])
|
2023-05-29 04:34:33 +03:00
|
|
|
.filter(Boolean),
|
|
|
|
),
|
|
|
|
];
|
|
|
|
|
|
|
|
const invalidUrls = allUrlFields.filter((url) =>
|
|
|
|
hasRedundantTrailingSlash(url),
|
|
|
|
);
|
|
|
|
|
|
|
|
if (invalidUrls.length > 0) {
|
|
|
|
return `Some URLs have a redundant trailing slash:\n\n${invalidUrls.join(
|
|
|
|
'\n',
|
|
|
|
)}`;
|
|
|
|
}
|
|
|
|
},
|
2020-01-16 13:40:46 +03:00
|
|
|
};
|
|
|
|
|
2023-08-08 07:38:52 +03:00
|
|
|
const dataString = await getIconsDataString();
|
|
|
|
const data = JSON.parse(dataString);
|
2021-12-25 17:22:56 +03:00
|
|
|
|
2023-08-08 07:38:52 +03:00
|
|
|
const errors = (
|
|
|
|
await Promise.all(Object.values(TESTS).map((test) => test(data, dataString)))
|
|
|
|
).filter(Boolean);
|
2020-01-16 13:40:46 +03:00
|
|
|
|
2023-08-08 07:38:52 +03:00
|
|
|
if (errors.length > 0) {
|
|
|
|
errors.forEach((error) => console.error(`\u001b[31m${error}\u001b[0m`));
|
|
|
|
process.exit(1);
|
|
|
|
}
|