Skip to content

Commit bc1ffc3

Browse files
committed
FEATURE: Add binary to package to be used as validator in other projects
1 parent be57d46 commit bc1ffc3

File tree

10 files changed

+1351
-126
lines changed

10 files changed

+1351
-126
lines changed

.github/workflows/tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ jobs:
1111
runs-on: ubuntu-latest
1212

1313
steps:
14-
- uses: actions/setup-node@v1
14+
- uses: actions/setup-node@v4
1515
with:
16-
node-version: '16.x'
17-
- uses: actions/checkout@v2
16+
node-version: '22.x'
17+
- uses: actions/checkout@v4
1818

1919
- name: Install dependencies
2020
run: yarn

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
11
/node_modules
2+
.pnp.*
3+
.yarn/*
4+
!.yarn/patches
5+
!.yarn/plugins
6+
!.yarn/releases
7+
!.yarn/sdks
8+
!.yarn/versions

.npmignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules/
2+
*.log
3+
.DS_Store
4+
.yarn
5+
.github

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
16
1+
22

.yarn/releases/yarn-4.6.0.cjs

Lines changed: 934 additions & 0 deletions
Large diffs are not rendered by default.

.yarnrc.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
nodeLinker: node-modules
2+
3+
yarnPath: .yarn/releases/yarn-4.6.0.cjs

bin/validate.js

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#!/usr/bin/env node
2+
const Ajv = require('ajv');
3+
const fs = require('fs');
4+
const path = require('path');
5+
const yaml = require('js-yaml');
6+
const yargs = require('yargs/yargs')
7+
const {hideBin} = require('yargs/helpers')
8+
const ajv = new Ajv({
9+
strictTypes: false,
10+
});
11+
12+
// Add support for intellij html description
13+
ajv.addKeyword('x-intellij-html-description');
14+
15+
// Build schema map
16+
const schemas = [
17+
{
18+
pattern: /NodeTypes(\/?).*\.yaml$/,
19+
schemaFile: './NodeTypes.Schema.json',
20+
},
21+
{
22+
pattern: /Caches.*\.yaml$/,
23+
schemaFile: './Caches.Schema.json',
24+
},
25+
{
26+
pattern: /Version.*\.yaml$/,
27+
schemaFile: './NodeMigration.Schema.json',
28+
},
29+
{
30+
pattern: /Routes.*\.yaml$/,
31+
schemaFile: './Routes.Schema.json',
32+
},
33+
{
34+
pattern: /Settings.Presets.yaml$/,
35+
schemaFile: './NodeTypes.Presets.Schema.json',
36+
},
37+
].map(sd => {
38+
const schema = JSON.parse(fs.readFileSync(sd.schemaFile, {encoding: 'utf8', flag: 'r'}));
39+
const validate = ajv.compile(schema);
40+
return {
41+
...sd,
42+
schema,
43+
validate,
44+
};
45+
});
46+
47+
/**
48+
* Recursively list yaml files in a directory
49+
*
50+
* @param {string} dir
51+
* @return {string[]}
52+
*/
53+
function listYamlFiles(dir) {
54+
let results = [];
55+
let files = [];
56+
57+
// Read the contents of the directory
58+
try {
59+
files = fs.readdirSync(dir);
60+
} catch (e) {
61+
console.error('Could not read directory %s', dir);
62+
process.exit(1);
63+
}
64+
65+
files.forEach(file => {
66+
const filePath = path.join(dir, file);
67+
const stat = fs.statSync(filePath);
68+
69+
// If it's a directory, recurse into it
70+
if (stat && stat.isDirectory()) {
71+
results = results.concat(listYamlFiles(filePath));
72+
} else if (file.endsWith('.yaml') || file.endsWith('.yml')) {
73+
// If it's a YAML file, add to results
74+
results.push(filePath);
75+
}
76+
});
77+
78+
return results;
79+
}
80+
81+
/**
82+
* @param {string} filePath
83+
* @param {object} schema
84+
*/
85+
function validateFile(filePath, schema) {
86+
const fileContent = fs.readFileSync(filePath, {encoding: 'utf8', flag: 'r'});
87+
const data = yaml.load(fileContent);
88+
return schema.validate(data);
89+
}
90+
91+
/**
92+
* @param {string} folder
93+
* @param {boolean} verbose
94+
* @return {void}
95+
*/
96+
function validateFolder(folder, verbose) {
97+
const files = listYamlFiles(folder);
98+
let hasError = false;
99+
let validFiles = 0;
100+
let skippedFiles = 0;
101+
let invalidFiles = 0;
102+
103+
if (verbose) {
104+
console.info('Found %d files to validate', files.length);
105+
}
106+
107+
for (const file of files) {
108+
// Only validate yaml files
109+
if (path.extname(file).match(/\.ya?ml/) === null) {
110+
continue;
111+
}
112+
113+
const schema = schemas.find(sd => sd.pattern.test(file));
114+
if (!schema) {
115+
if (verbose) {
116+
console.warn('Skipped %s, no matching schema found', file);
117+
}
118+
skippedFiles++;
119+
continue;
120+
}
121+
122+
const valid = validateFile(file, schema);
123+
if (valid) {
124+
if (verbose) {
125+
console.info('✅ %s is valid', file);
126+
}
127+
validFiles++;
128+
} else {
129+
console.error('❌ %s is invalid', file, schema.validate.errors);
130+
hasError = true;
131+
invalidFiles++;
132+
}
133+
}
134+
135+
if (verbose) {
136+
console.info('Valid files %d, skipped %d, invalid %d', validFiles, skippedFiles, invalidFiles);
137+
}
138+
139+
process.exit(hasError ? 1 : 0);
140+
}
141+
142+
yargs(hideBin(process.argv))
143+
.command('validate <folder>', 'validate yaml files', (yargs) => {
144+
return yargs
145+
.positional('folder', {
146+
describe: 'folder with files to be validated',
147+
type: 'string',
148+
});
149+
}, (argv) => {
150+
const {folder, verbose} = argv;
151+
validateFolder(folder, verbose);
152+
})
153+
.example('$0 validate -v DistributionPackages/My.Site', 'Recursively validates all nodetype and other supported yaml files in your Neos site package and shows the results for each file')
154+
.option('verbose', {
155+
alias: 'v',
156+
type: 'boolean',
157+
description: 'Run with verbose logging'
158+
})
159+
.demandCommand()
160+
.help()
161+
.parse();

package.json

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
{
22
"name": "shel-neos-schema",
33
"version": "1.0.0",
4-
"main": "test.js",
4+
"main": "bin/validate.js",
55
"author": "Sebastian Helzle <sebastian@helzle.it>",
66
"license": "MIT",
7-
"devDependencies": {
8-
"ajv": "^8.0.5",
9-
"js-yaml": "^4.0.0"
7+
"engines": {
8+
"node": ">=20"
109
},
1110
"scripts": {
12-
"test": "node test.js"
13-
}
11+
"test": "validate -v examples"
12+
},
13+
"bin": {
14+
"validate": "bin/validate.js"
15+
},
16+
"dependencies": {
17+
"ajv": "^8.0.5",
18+
"js-yaml": "^4.0.0",
19+
"yargs": "^17.7.2"
20+
},
21+
"packageManager": "yarn@4.6.0"
1422
}

test.js

Lines changed: 0 additions & 64 deletions
This file was deleted.

0 commit comments

Comments
 (0)