Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: data validation using schema #30797

Merged
3 changes: 2 additions & 1 deletion lib/data/monorepo.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"$schema": "../../tools/schemas/monorepo-schema.json",
"repoGroups": {
"accounts": "https://github.com/accounts-js/accounts",
"acot": "https://github.com/acot-a11y/acot",
Expand Down Expand Up @@ -350,7 +351,7 @@
"https://github.com/mui/material-ui",
"https://github.com/mui/mui-x"
],
"mdc-react": "material-components/material-components-web-react",
"mdc-react": "https://github.com/material-components/material-components-web-react",
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved
"mdx": "https://github.com/mdx-js/mdx",
"middy-js": "https://github.com/middyjs/middy",
"mikro-orm": "https://github.com/mikro-orm/mikro-orm",
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"generate:imports": "node tools/generate-imports.mjs",
"git-check": "node tools/check-git-version.mjs",
"jest": "GIT_ALLOW_PROTOCOL=file LOG_LEVEL=fatal node --experimental-vm-modules node_modules/jest/bin/jest.js --logHeapUsage",
"lint": "run-s ls-lint type-check eslint prettier markdown-lint git-check doc-fence-check",
"lint": "run-s ls-lint type-check eslint prettier markdown-lint git-check doc-fence-check validate-schemas",
"lint-fix": "run-s eslint-fix prettier-fix markdown-lint-fix",
"ls-lint": "ls-lint",
"markdown-lint": "markdownlint-cli2",
Expand Down Expand Up @@ -57,7 +57,8 @@
"type-check": "run-s 'generate:*' 'tsc --noEmit {@}' --",
"update-static-data": "run-s 'update-static-data:*'",
"update-static-data:distro-info": "node tools/static-data/generate-distro-info.mjs",
"update-static-data:node-schedule": "node tools/static-data/generate-node-schedule.mjs"
"update-static-data:node-schedule": "node tools/static-data/generate-node-schedule.mjs",
"validate-schemas": "ts-node tools/validate-schemas.ts"
},
"repository": {
"type": "git",
Expand Down
60 changes: 60 additions & 0 deletions tools/schemas/monorepo-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"$schema": {
"type": "string",
"oneOf": [
{ "format": "uri" },
{ "pattern": "^(\\.\\.?/)*[\\w.-]+(/[\\w.-]+)*\\.json$" }
]
},
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved
"repoGroups": {
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9. -]+$": {
"oneOf": [
{ "type": "string", "format": "uri" },
{
"type": "array",
"items": { "type": "string", "format": "uri" }
}
]
}
},
"additionalProperties": false
},
"orgGroups": {
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9. -]+$": {
"oneOf": [
{ "type": "string", "format": "uri" },
{
"type": "array",
"items": { "type": "string", "format": "uri" }
}
]
}
},
"additionalProperties": false
},
"patternGroups": {
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9. -]+$": {
"oneOf": [
{ "type": "string", "pattern": "^/.+/$" },
{
"type": "array",
"items": { "type": "string", "pattern": "^/.+/$" }
}
]
}
},
"additionalProperties": false
}
},
"required": ["repoGroups", "orgGroups", "patternGroups"],
"additionalProperties": false
}
12 changes: 12 additions & 0 deletions tools/schemas/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { z } from 'zod';

const MonorepoSchema = z.object({
repoGroups: z.record(z.string(), z.union([z.string(), z.array(z.string())])),
orgGroups: z.record(z.string(), z.union([z.string(), z.array(z.string())])),
patternGroups: z.record(
z.string(),
z.union([z.string(), z.array(z.string())]),
),
});

export { MonorepoSchema };
71 changes: 71 additions & 0 deletions tools/validate-schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import fs from 'fs-extra';
import upath from 'upath';
import { logger } from '../lib/logger';
import { capitalize } from './docs/utils';
import * as Schemas from './schemas/schema';

void (async () => {
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved
logger.debug('Validating lib/data JSOn files against their schemas.');
const dataFileDir = 'lib/data';
const schemaDir = 'tools/schemas';

try {
const schemaFiles = (await fs.readdir(schemaDir)).filter(
(file) => upath.extname(file) === '.json',
);

const validationErrors = [];

for (const schemaFile of schemaFiles) {
try {
const dataFileName = schemaFile.replace('-schema', '');
const schemaName = `${schemaFile
.replace('.json', '')
.split('-')
.map(capitalize)
.join('')}` as keyof typeof Schemas;

const data = JSON.parse(
await fs.readFile(upath.join(dataFileDir, dataFileName), 'utf8'),
);

// validate the data
// eslint-disable-next-line import/namespace
const result = Schemas[schemaName].safeParse(data);

if (result.error) {
validationErrors.push({
file: dataFileName,
errors: result.error.errors,
});
}
} catch (err) {
validationErrors.push({
file: schemaFile,
errors: [
{
message: `\nError reading or parsing JSON Schema: ${err.message}`,
},
],
});
}
}

// print errors after processing all files
validationErrors.forEach(({ file, errors }) => {
logger.error({ errors, file }, `JSON does not satisfy its schema`);
});

if (validationErrors.length > 0) {
process.exit(1);
} else {
logger.info('All JSON files satisfy their schemas.');
}
} catch (error) {
logger.error(
{ message: error.message },
'Error during schema validation of json files.',
);
process.exit(1);
}
})();