@gallop.software/canon 2.22.0 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { audit } from './commands/audit.js';
|
|
3
3
|
import { generate } from './commands/generate.js';
|
|
4
|
-
import { validate } from './commands/validate.js';
|
|
5
4
|
import { version } from '../index.js';
|
|
6
5
|
const args = process.argv.slice(2);
|
|
7
6
|
const command = args[0];
|
|
@@ -28,7 +27,6 @@ ${colors.bold}Usage:${colors.reset}
|
|
|
28
27
|
${colors.bold}Commands:${colors.reset}
|
|
29
28
|
audit [path] Check Canon compliance (default: src/blocks/)
|
|
30
29
|
generate [output] Generate AI rules from Canon (default: .cursorrules)
|
|
31
|
-
validate [path] Validate project folder structure (default: .)
|
|
32
30
|
version Show version information
|
|
33
31
|
help Show this help message
|
|
34
32
|
|
|
@@ -39,18 +37,12 @@ ${colors.bold}Audit Options:${colors.reset}
|
|
|
39
37
|
${colors.bold}Generate Options:${colors.reset}
|
|
40
38
|
--output, -o Output file path (default: .cursorrules)
|
|
41
39
|
|
|
42
|
-
${colors.bold}Validate Options:${colors.reset}
|
|
43
|
-
--strict Exit with error code on violations
|
|
44
|
-
--json Output as JSON
|
|
45
|
-
|
|
46
40
|
${colors.bold}Examples:${colors.reset}
|
|
47
41
|
gallop audit
|
|
48
42
|
gallop audit src/blocks/ --strict
|
|
49
43
|
gallop generate
|
|
50
44
|
gallop generate .cursorrules
|
|
51
45
|
gallop generate --output .github/copilot-instructions.md
|
|
52
|
-
gallop validate
|
|
53
|
-
gallop validate . --strict
|
|
54
46
|
`);
|
|
55
47
|
}
|
|
56
48
|
function showVersion() {
|
|
@@ -88,14 +80,6 @@ async function main() {
|
|
|
88
80
|
};
|
|
89
81
|
await generate(generateOptions);
|
|
90
82
|
break;
|
|
91
|
-
case 'validate':
|
|
92
|
-
const validatePath = args[1] && !args[1].startsWith('--') ? args[1] : '.';
|
|
93
|
-
const validateOptions = {
|
|
94
|
-
strict: args.includes('--strict'),
|
|
95
|
-
json: args.includes('--json'),
|
|
96
|
-
};
|
|
97
|
-
await validate(validatePath, validateOptions);
|
|
98
|
-
break;
|
|
99
83
|
case 'version':
|
|
100
84
|
case '-v':
|
|
101
85
|
case '--version':
|
|
@@ -117,4 +101,4 @@ main().catch((error) => {
|
|
|
117
101
|
console.error('Error:', error.message);
|
|
118
102
|
process.exit(1);
|
|
119
103
|
});
|
|
120
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
104
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2xpL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFFQSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFDM0MsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHdCQUF3QixDQUFBO0FBQ2pELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFFckMsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDbEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFBO0FBRXZCLDZCQUE2QjtBQUM3QixNQUFNLE1BQU0sR0FBRztJQUNiLEtBQUssRUFBRSxTQUFTO0lBQ2hCLElBQUksRUFBRSxTQUFTO0lBQ2YsR0FBRyxFQUFFLFNBQVM7SUFDZCxHQUFHLEVBQUUsVUFBVTtJQUNmLEtBQUssRUFBRSxVQUFVO0lBQ2pCLE1BQU0sRUFBRSxVQUFVO0lBQ2xCLElBQUksRUFBRSxVQUFVO0lBQ2hCLE9BQU8sRUFBRSxVQUFVO0lBQ25CLElBQUksRUFBRSxVQUFVO0NBQ2pCLENBQUE7QUFFRCxTQUFTLFFBQVE7SUFDZixPQUFPLENBQUMsR0FBRyxDQUFDO0VBQ1osTUFBTSxDQUFDLElBQUksYUFBYSxNQUFNLENBQUMsS0FBSztFQUNwQyxNQUFNLENBQUMsR0FBRyxrQkFBa0IsT0FBTyxHQUFHLE1BQU0sQ0FBQyxLQUFLOztFQUVsRCxNQUFNLENBQUMsSUFBSSxTQUFTLE1BQU0sQ0FBQyxLQUFLOzs7RUFHaEMsTUFBTSxDQUFDLElBQUksWUFBWSxNQUFNLENBQUMsS0FBSzs7Ozs7O0VBTW5DLE1BQU0sQ0FBQyxJQUFJLGlCQUFpQixNQUFNLENBQUMsS0FBSzs7OztFQUl4QyxNQUFNLENBQUMsSUFBSSxvQkFBb0IsTUFBTSxDQUFDLEtBQUs7OztFQUczQyxNQUFNLENBQUMsSUFBSSxZQUFZLE1BQU0sQ0FBQyxLQUFLOzs7Ozs7Q0FNcEMsQ0FBQyxDQUFBO0FBQ0YsQ0FBQztBQUVELFNBQVMsV0FBVztJQUNsQixPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUE7SUFDaEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLE9BQU8sRUFBRSxDQUFDLENBQUE7QUFDbEMsQ0FBQztBQUVELEtBQUssVUFBVSxJQUFJO0lBQ2pCLFFBQVEsT0FBTyxFQUFFLENBQUM7UUFDaEIsS0FBSyxPQUFPO1lBQ1YsTUFBTSxTQUFTLEdBQ2IsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUE7WUFDaEUsTUFBTSxZQUFZLEdBQUc7Z0JBQ25CLE1BQU0sRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQztnQkFDakMsSUFBSSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDO2dCQUM3QixHQUFHLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7YUFDNUIsQ0FBQTtZQUNELE1BQU0sS0FBSyxDQUFDLFNBQVMsRUFBRSxZQUFZLENBQUMsQ0FBQTtZQUNwQyxNQUFLO1FBRVAsS0FBSyxVQUFVO1lBQ2IsNkJBQTZCO1lBQzdCLElBQUksVUFBVSxHQUFHLGNBQWMsQ0FBQTtZQUMvQixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFBO1lBQzVDLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQTtZQUMzQyxJQUFJLFdBQVcsS0FBSyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ2hELFVBQVUsR0FBRyxJQUFJLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQyxDQUFBO1lBQ3BDLENBQUM7aUJBQU0sSUFBSSxnQkFBZ0IsS0FBSyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDakUsVUFBVSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxDQUFDLENBQUMsQ0FBQTtZQUN6QyxDQUFDO2lCQUFNLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUNoRCxVQUFVLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFBO1lBQ3RCLENBQUM7WUFDRCxNQUFNLGVBQWUsR0FBRztnQkFDdEIsTUFBTSxFQUFFLFVBQVU7Z0JBQ2xCLE1BQU0sRUFBRSxhQUFzQjthQUMvQixDQUFBO1lBQ0QsTUFBTSxRQUFRLENBQUMsZUFBZSxDQUFDLENBQUE7WUFDL0IsTUFBSztRQUVQLEtBQUssU0FBUyxDQUFDO1FBQ2YsS0FBSyxJQUFJLENBQUM7UUFDVixLQUFLLFdBQVc7WUFDZCxXQUFXLEVBQUUsQ0FBQTtZQUNiLE1BQUs7UUFFUCxLQUFLLE1BQU0sQ0FBQztRQUNaLEtBQUssSUFBSSxDQUFDO1FBQ1YsS0FBSyxRQUFRLENBQUM7UUFDZCxLQUFLLFNBQVM7WUFDWixRQUFRLEVBQUUsQ0FBQTtZQUNWLE1BQUs7UUFFUDtZQUNFLE9BQU8sQ0FBQyxLQUFLLENBQUMsb0JBQW9CLE9BQU8sRUFBRSxDQUFDLENBQUE7WUFDNUMsT0FBTyxDQUFDLEtBQUssQ0FBQywwQ0FBMEMsQ0FBQyxDQUFBO1lBQ3pELE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFDbkIsQ0FBQztBQUNILENBQUM7QUFFRCxJQUFJLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtJQUNyQixPQUFPLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUE7SUFDdEMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQTtBQUNqQixDQUFDLENBQUMsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbIiMhL3Vzci9iaW4vZW52IG5vZGVcblxuaW1wb3J0IHsgYXVkaXQgfSBmcm9tICcuL2NvbW1hbmRzL2F1ZGl0LmpzJ1xuaW1wb3J0IHsgZ2VuZXJhdGUgfSBmcm9tICcuL2NvbW1hbmRzL2dlbmVyYXRlLmpzJ1xuaW1wb3J0IHsgdmVyc2lvbiB9IGZyb20gJy4uL2luZGV4LmpzJ1xuXG5jb25zdCBhcmdzID0gcHJvY2Vzcy5hcmd2LnNsaWNlKDIpXG5jb25zdCBjb21tYW5kID0gYXJnc1swXVxuXG4vLyBDb2xvcnMgZm9yIHRlcm1pbmFsIG91dHB1dFxuY29uc3QgY29sb3JzID0ge1xuICByZXNldDogJ1xceDFiWzBtJyxcbiAgYm9sZDogJ1xceDFiWzFtJyxcbiAgZGltOiAnXFx4MWJbMm0nLFxuICByZWQ6ICdcXHgxYlszMW0nLFxuICBncmVlbjogJ1xceDFiWzMybScsXG4gIHllbGxvdzogJ1xceDFiWzMzbScsXG4gIGJsdWU6ICdcXHgxYlszNG0nLFxuICBtYWdlbnRhOiAnXFx4MWJbMzVtJyxcbiAgY3lhbjogJ1xceDFiWzM2bScsXG59XG5cbmZ1bmN0aW9uIHNob3dIZWxwKCkge1xuICBjb25zb2xlLmxvZyhgXG4ke2NvbG9ycy5ib2xkfUdhbGxvcCBDTEkke2NvbG9ycy5yZXNldH0gLSBDYW5vbiBDb21wbGlhbmNlIFRvb2xpbmdcbiR7Y29sb3JzLmRpbX1DYW5vbiBWZXJzaW9uOiAke3ZlcnNpb259JHtjb2xvcnMucmVzZXR9XG5cbiR7Y29sb3JzLmJvbGR9VXNhZ2U6JHtjb2xvcnMucmVzZXR9XG4gIGdhbGxvcCA8Y29tbWFuZD4gW29wdGlvbnNdXG5cbiR7Y29sb3JzLmJvbGR9Q29tbWFuZHM6JHtjb2xvcnMucmVzZXR9XG4gIGF1ZGl0IFtwYXRoXSAgICAgICBDaGVjayBDYW5vbiBjb21wbGlhbmNlIChkZWZhdWx0OiBzcmMvYmxvY2tzLylcbiAgZ2VuZXJhdGUgW291dHB1dF0gIEdlbmVyYXRlIEFJIHJ1bGVzIGZyb20gQ2Fub24gKGRlZmF1bHQ6IC5jdXJzb3JydWxlcylcbiAgdmVyc2lvbiAgICAgICAgICAgIFNob3cgdmVyc2lvbiBpbmZvcm1hdGlvblxuICBoZWxwICAgICAgICAgICAgICAgU2hvdyB0aGlzIGhlbHAgbWVzc2FnZVxuXG4ke2NvbG9ycy5ib2xkfUF1ZGl0IE9wdGlvbnM6JHtjb2xvcnMucmVzZXR9XG4gIC0tc3RyaWN0ICAgICAgICAgICBFeGl0IHdpdGggZXJyb3IgY29kZSBvbiB2aW9sYXRpb25zXG4gIC0tanNvbiAgICAgICAgICAgICBPdXRwdXQgYXMgSlNPTlxuXG4ke2NvbG9ycy5ib2xkfUdlbmVyYXRlIE9wdGlvbnM6JHtjb2xvcnMucmVzZXR9XG4gIC0tb3V0cHV0LCAtbyAgICAgICBPdXRwdXQgZmlsZSBwYXRoIChkZWZhdWx0OiAuY3Vyc29ycnVsZXMpXG5cbiR7Y29sb3JzLmJvbGR9RXhhbXBsZXM6JHtjb2xvcnMucmVzZXR9XG4gIGdhbGxvcCBhdWRpdFxuICBnYWxsb3AgYXVkaXQgc3JjL2Jsb2Nrcy8gLS1zdHJpY3RcbiAgZ2FsbG9wIGdlbmVyYXRlXG4gIGdhbGxvcCBnZW5lcmF0ZSAuY3Vyc29ycnVsZXNcbiAgZ2FsbG9wIGdlbmVyYXRlIC0tb3V0cHV0IC5naXRodWIvY29waWxvdC1pbnN0cnVjdGlvbnMubWRcbmApXG59XG5cbmZ1bmN0aW9uIHNob3dWZXJzaW9uKCkge1xuICBjb25zb2xlLmxvZyhgR2FsbG9wIENMSSB2MS4wLjBgKVxuICBjb25zb2xlLmxvZyhgQ2Fub24gdiR7dmVyc2lvbn1gKVxufVxuXG5hc3luYyBmdW5jdGlvbiBtYWluKCkge1xuICBzd2l0Y2ggKGNvbW1hbmQpIHtcbiAgICBjYXNlICdhdWRpdCc6XG4gICAgICBjb25zdCBhdWRpdFBhdGggPVxuICAgICAgICBhcmdzWzFdICYmICFhcmdzWzFdLnN0YXJ0c1dpdGgoJy0tJykgPyBhcmdzWzFdIDogJ3NyYy9ibG9ja3MvJ1xuICAgICAgY29uc3QgYXVkaXRPcHRpb25zID0ge1xuICAgICAgICBzdHJpY3Q6IGFyZ3MuaW5jbHVkZXMoJy0tc3RyaWN0JyksXG4gICAgICAgIGpzb246IGFyZ3MuaW5jbHVkZXMoJy0tanNvbicpLFxuICAgICAgICBmaXg6IGFyZ3MuaW5jbHVkZXMoJy0tZml4JyksXG4gICAgICB9XG4gICAgICBhd2FpdCBhdWRpdChhdWRpdFBhdGgsIGF1ZGl0T3B0aW9ucylcbiAgICAgIGJyZWFrXG5cbiAgICBjYXNlICdnZW5lcmF0ZSc6XG4gICAgICAvLyBGaW5kIG91dHB1dCBwYXRoIGZyb20gYXJnc1xuICAgICAgbGV0IG91dHB1dFBhdGggPSAnLmN1cnNvcnJ1bGVzJ1xuICAgICAgY29uc3Qgb3V0cHV0SW5kZXggPSBhcmdzLmluZGV4T2YoJy0tb3V0cHV0JylcbiAgICAgIGNvbnN0IG91dHB1dEluZGV4U2hvcnQgPSBhcmdzLmluZGV4T2YoJy1vJylcbiAgICAgIGlmIChvdXRwdXRJbmRleCAhPT0gLTEgJiYgYXJnc1tvdXRwdXRJbmRleCArIDFdKSB7XG4gICAgICAgIG91dHB1dFBhdGggPSBhcmdzW291dHB1dEluZGV4ICsgMV1cbiAgICAgIH0gZWxzZSBpZiAob3V0cHV0SW5kZXhTaG9ydCAhPT0gLTEgJiYgYXJnc1tvdXRwdXRJbmRleFNob3J0ICsgMV0pIHtcbiAgICAgICAgb3V0cHV0UGF0aCA9IGFyZ3Nbb3V0cHV0SW5kZXhTaG9ydCArIDFdXG4gICAgICB9IGVsc2UgaWYgKGFyZ3NbMV0gJiYgIWFyZ3NbMV0uc3RhcnRzV2l0aCgnLS0nKSkge1xuICAgICAgICBvdXRwdXRQYXRoID0gYXJnc1sxXVxuICAgICAgfVxuICAgICAgY29uc3QgZ2VuZXJhdGVPcHRpb25zID0ge1xuICAgICAgICBvdXRwdXQ6IG91dHB1dFBhdGgsXG4gICAgICAgIGZvcm1hdDogJ2N1cnNvcnJ1bGVzJyBhcyBjb25zdCxcbiAgICAgIH1cbiAgICAgIGF3YWl0IGdlbmVyYXRlKGdlbmVyYXRlT3B0aW9ucylcbiAgICAgIGJyZWFrXG5cbiAgICBjYXNlICd2ZXJzaW9uJzpcbiAgICBjYXNlICctdic6XG4gICAgY2FzZSAnLS12ZXJzaW9uJzpcbiAgICAgIHNob3dWZXJzaW9uKClcbiAgICAgIGJyZWFrXG5cbiAgICBjYXNlICdoZWxwJzpcbiAgICBjYXNlICctaCc6XG4gICAgY2FzZSAnLS1oZWxwJzpcbiAgICBjYXNlIHVuZGVmaW5lZDpcbiAgICAgIHNob3dIZWxwKClcbiAgICAgIGJyZWFrXG5cbiAgICBkZWZhdWx0OlxuICAgICAgY29uc29sZS5lcnJvcihgVW5rbm93biBjb21tYW5kOiAke2NvbW1hbmR9YClcbiAgICAgIGNvbnNvbGUuZXJyb3IoYFJ1biAnZ2FsbG9wIGhlbHAnIGZvciB1c2FnZSBpbmZvcm1hdGlvbi5gKVxuICAgICAgcHJvY2Vzcy5leGl0KDEpXG4gIH1cbn1cblxubWFpbigpLmNhdGNoKChlcnJvcikgPT4ge1xuICBjb25zb2xlLmVycm9yKCdFcnJvcjonLCBlcnJvci5tZXNzYWdlKVxuICBwcm9jZXNzLmV4aXQoMSlcbn0pXG4iXX0=
|
package/package.json
CHANGED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
// Required dev dependencies
|
|
4
|
-
const REQUIRED_DEV_DEPENDENCIES = ['knip', '@gallop.software/canon'];
|
|
5
|
-
// Required npm scripts
|
|
6
|
-
const REQUIRED_SCRIPTS = {
|
|
7
|
-
unused: 'knip',
|
|
8
|
-
check: 'npm run lint && npm run ts && npm run unused',
|
|
9
|
-
lint: 'eslint',
|
|
10
|
-
ts: 'tsc',
|
|
11
|
-
audit: 'gallop audit',
|
|
12
|
-
'generate:ai-rules': 'gallop generate',
|
|
13
|
-
};
|
|
14
|
-
// Allowed top-level directories (non-dotfiles)
|
|
15
|
-
const ALLOWED_TOP_LEVEL = [
|
|
16
|
-
'src',
|
|
17
|
-
'public',
|
|
18
|
-
'_scripts',
|
|
19
|
-
'_data',
|
|
20
|
-
'_docs',
|
|
21
|
-
'node_modules',
|
|
22
|
-
];
|
|
23
|
-
// Allowed folders directly under /src
|
|
24
|
-
const ALLOWED_SRC_FOLDERS = [
|
|
25
|
-
'app',
|
|
26
|
-
'blocks',
|
|
27
|
-
'blog',
|
|
28
|
-
'components',
|
|
29
|
-
'hooks',
|
|
30
|
-
'styles',
|
|
31
|
-
'template',
|
|
32
|
-
'tools',
|
|
33
|
-
'types',
|
|
34
|
-
'utils',
|
|
35
|
-
];
|
|
36
|
-
// Files allowed at top level
|
|
37
|
-
const ALLOWED_TOP_LEVEL_FILES = [
|
|
38
|
-
'package.json',
|
|
39
|
-
'package-lock.json',
|
|
40
|
-
'tsconfig.json',
|
|
41
|
-
'tsconfig.tsbuildinfo',
|
|
42
|
-
'next.config.mjs',
|
|
43
|
-
'next.config.js',
|
|
44
|
-
'next-env.d.ts',
|
|
45
|
-
'eslint.config.mjs',
|
|
46
|
-
'eslint.config.js',
|
|
47
|
-
'.eslintrc.js',
|
|
48
|
-
'.eslintrc.json',
|
|
49
|
-
'postcss.config.js',
|
|
50
|
-
'tailwind.config.js',
|
|
51
|
-
'tailwind.config.ts',
|
|
52
|
-
'README.md',
|
|
53
|
-
'LICENSE',
|
|
54
|
-
'CHANGELOG.md',
|
|
55
|
-
'.gitignore',
|
|
56
|
-
'.cursorrules',
|
|
57
|
-
];
|
|
58
|
-
/**
|
|
59
|
-
* Check if a path is a dotfile or dotfolder
|
|
60
|
-
*/
|
|
61
|
-
function isDotfile(name) {
|
|
62
|
-
return name.startsWith('.');
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Check if a path is an archive content folder (allowed new folders in /src)
|
|
66
|
-
*/
|
|
67
|
-
function isArchiveContentFolder(name) {
|
|
68
|
-
// Archive folders typically have plural names for content collections
|
|
69
|
-
// We allow any folder that could reasonably be archive content
|
|
70
|
-
// This is a heuristic - we check if it looks like a content collection
|
|
71
|
-
return !ALLOWED_SRC_FOLDERS.includes(name);
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Validate project structure
|
|
75
|
-
*/
|
|
76
|
-
export async function validate(projectPath, options) {
|
|
77
|
-
const violations = [];
|
|
78
|
-
const absolutePath = path.resolve(process.cwd(), projectPath);
|
|
79
|
-
if (!fs.existsSync(absolutePath)) {
|
|
80
|
-
console.error(`Path does not exist: ${projectPath}`);
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
83
|
-
// Check top-level directories
|
|
84
|
-
const topLevelItems = fs.readdirSync(absolutePath);
|
|
85
|
-
for (const item of topLevelItems) {
|
|
86
|
-
const itemPath = path.join(absolutePath, item);
|
|
87
|
-
const stat = fs.statSync(itemPath);
|
|
88
|
-
if (stat.isDirectory()) {
|
|
89
|
-
// Dotfolders are exempt
|
|
90
|
-
if (isDotfile(item)) {
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
// Check if it's an allowed top-level directory
|
|
94
|
-
if (!ALLOWED_TOP_LEVEL.includes(item)) {
|
|
95
|
-
violations.push({
|
|
96
|
-
type: 'invalid-top-level',
|
|
97
|
-
path: item,
|
|
98
|
-
message: `Invalid top-level directory: ${item}. Allowed: ${ALLOWED_TOP_LEVEL.join(', ')} (dotfolders exempt)`,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
// It's a file - check if it's allowed at top level
|
|
104
|
-
if (!isDotfile(item) && !ALLOWED_TOP_LEVEL_FILES.includes(item)) {
|
|
105
|
-
// Allow common config file patterns
|
|
106
|
-
const isConfigFile = item.endsWith('.config.js') ||
|
|
107
|
-
item.endsWith('.config.mjs') ||
|
|
108
|
-
item.endsWith('.config.ts') ||
|
|
109
|
-
item.endsWith('.json') ||
|
|
110
|
-
item.endsWith('.md') ||
|
|
111
|
-
item.endsWith('.sh');
|
|
112
|
-
if (!isConfigFile) {
|
|
113
|
-
violations.push({
|
|
114
|
-
type: 'orphan-file',
|
|
115
|
-
path: item,
|
|
116
|
-
message: `Orphan file at project root: ${item}. Files should be in defined zones.`,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
// Check /src folder structure
|
|
123
|
-
const srcPath = path.join(absolutePath, 'src');
|
|
124
|
-
if (fs.existsSync(srcPath)) {
|
|
125
|
-
const srcItems = fs.readdirSync(srcPath);
|
|
126
|
-
for (const item of srcItems) {
|
|
127
|
-
const itemPath = path.join(srcPath, item);
|
|
128
|
-
const stat = fs.statSync(itemPath);
|
|
129
|
-
if (stat.isDirectory()) {
|
|
130
|
-
// Check if it's an allowed /src folder
|
|
131
|
-
if (!ALLOWED_SRC_FOLDERS.includes(item) &&
|
|
132
|
-
!isArchiveContentFolder(item)) {
|
|
133
|
-
violations.push({
|
|
134
|
-
type: 'invalid-src-folder',
|
|
135
|
-
path: `src/${item}`,
|
|
136
|
-
message: `Invalid folder in /src: ${item}. Allowed: ${ALLOWED_SRC_FOLDERS.join(', ')} or archive content folders`,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
// Check that src/app has route groups
|
|
142
|
-
const appPath = path.join(srcPath, 'app');
|
|
143
|
-
if (fs.existsSync(appPath)) {
|
|
144
|
-
const appItems = fs.readdirSync(appPath);
|
|
145
|
-
const hasDefaultGroup = appItems.some((item) => item === '(default)' || item.startsWith('('));
|
|
146
|
-
if (!hasDefaultGroup) {
|
|
147
|
-
violations.push({
|
|
148
|
-
type: 'invalid-src-folder',
|
|
149
|
-
path: 'src/app',
|
|
150
|
-
message: 'src/app should have at least one route group folder (e.g., (default)/)',
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
// Check package.json for required dependencies and scripts
|
|
156
|
-
const packageJsonPath = path.join(absolutePath, 'package.json');
|
|
157
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
158
|
-
try {
|
|
159
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
160
|
-
// Check dev dependencies
|
|
161
|
-
const devDeps = packageJson.devDependencies || {};
|
|
162
|
-
const deps = packageJson.dependencies || {};
|
|
163
|
-
const allDeps = { ...deps, ...devDeps };
|
|
164
|
-
for (const dep of REQUIRED_DEV_DEPENDENCIES) {
|
|
165
|
-
if (!allDeps[dep]) {
|
|
166
|
-
violations.push({
|
|
167
|
-
type: 'missing-dependency',
|
|
168
|
-
path: 'package.json',
|
|
169
|
-
message: `Missing required dependency: ${dep}. Run: npm install -D ${dep}`,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
// Check scripts
|
|
174
|
-
const scripts = packageJson.scripts || {};
|
|
175
|
-
for (const [scriptName, expectedPattern] of Object.entries(REQUIRED_SCRIPTS)) {
|
|
176
|
-
if (!scripts[scriptName]) {
|
|
177
|
-
violations.push({
|
|
178
|
-
type: 'missing-script',
|
|
179
|
-
path: 'package.json',
|
|
180
|
-
message: `Missing required script: "${scriptName}". Expected pattern: "${expectedPattern}"`,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
else if (!scripts[scriptName].includes(expectedPattern.split(' ')[0])) {
|
|
184
|
-
// Check if the script contains the main command (first word of expected pattern)
|
|
185
|
-
violations.push({
|
|
186
|
-
type: 'missing-script',
|
|
187
|
-
path: 'package.json',
|
|
188
|
-
message: `Script "${scriptName}" should contain "${expectedPattern.split(' ')[0]}". Found: "${scripts[scriptName]}"`,
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
catch (e) {
|
|
194
|
-
console.error('Failed to parse package.json');
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
else {
|
|
198
|
-
violations.push({
|
|
199
|
-
type: 'orphan-file',
|
|
200
|
-
path: 'package.json',
|
|
201
|
-
message: 'Missing package.json file',
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
// Output results
|
|
205
|
-
if (options.json) {
|
|
206
|
-
console.log(JSON.stringify({
|
|
207
|
-
valid: violations.length === 0,
|
|
208
|
-
violations,
|
|
209
|
-
}, null, 2));
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
if (violations.length === 0) {
|
|
213
|
-
console.log('✓ Project structure is valid');
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
console.log(`Found ${violations.length} violation(s):\n`);
|
|
217
|
-
for (const v of violations) {
|
|
218
|
-
console.log(` ✗ ${v.message}`);
|
|
219
|
-
}
|
|
220
|
-
console.log('');
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
// Exit with error code if strict mode and violations found
|
|
224
|
-
if (options.strict && violations.length > 0) {
|
|
225
|
-
process.exit(1);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2xpL2NvbW1hbmRzL3ZhbGlkYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLE1BQU0sSUFBSSxDQUFBO0FBQ3hCLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBYTVCLDRCQUE0QjtBQUM1QixNQUFNLHlCQUF5QixHQUFHLENBQUMsTUFBTSxFQUFFLHdCQUF3QixDQUFDLENBQUE7QUFFcEUsdUJBQXVCO0FBQ3ZCLE1BQU0sZ0JBQWdCLEdBQTJCO0lBQy9DLE1BQU0sRUFBRSxNQUFNO0lBQ2QsS0FBSyxFQUFFLDhDQUE4QztJQUNyRCxJQUFJLEVBQUUsUUFBUTtJQUNkLEVBQUUsRUFBRSxLQUFLO0lBQ1QsS0FBSyxFQUFFLGNBQWM7SUFDckIsbUJBQW1CLEVBQUUsaUJBQWlCO0NBQ3ZDLENBQUE7QUFFRCwrQ0FBK0M7QUFDL0MsTUFBTSxpQkFBaUIsR0FBRztJQUN4QixLQUFLO0lBQ0wsUUFBUTtJQUNSLFVBQVU7SUFDVixPQUFPO0lBQ1AsT0FBTztJQUNQLGNBQWM7Q0FDZixDQUFBO0FBRUQsc0NBQXNDO0FBQ3RDLE1BQU0sbUJBQW1CLEdBQUc7SUFDMUIsS0FBSztJQUNMLFFBQVE7SUFDUixNQUFNO0lBQ04sWUFBWTtJQUNaLE9BQU87SUFDUCxRQUFRO0lBQ1IsVUFBVTtJQUNWLE9BQU87SUFDUCxPQUFPO0lBQ1AsT0FBTztDQUNSLENBQUE7QUFFRCw2QkFBNkI7QUFDN0IsTUFBTSx1QkFBdUIsR0FBRztJQUM5QixjQUFjO0lBQ2QsbUJBQW1CO0lBQ25CLGVBQWU7SUFDZixzQkFBc0I7SUFDdEIsaUJBQWlCO0lBQ2pCLGdCQUFnQjtJQUNoQixlQUFlO0lBQ2YsbUJBQW1CO0lBQ25CLGtCQUFrQjtJQUNsQixjQUFjO0lBQ2QsZ0JBQWdCO0lBQ2hCLG1CQUFtQjtJQUNuQixvQkFBb0I7SUFDcEIsb0JBQW9CO0lB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QixPQUFPLEVBQUUsMkJBQTJCO1NBQ3JDLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRCxpQkFBaUI7SUFDakIsSUFBSSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDakIsT0FBTyxDQUFDLEdBQUcsQ0FDVCxJQUFJLENBQUMsU0FBUyxDQUNaO1lBQ0UsS0FBSyxFQUFFLFVBQVUsQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUM5QixVQUFVO1NBQ1gsRUFDRCxJQUFJLEVBQ0osQ0FBQyxDQUNGLENBQ0YsQ0FBQTtJQUNILENBQUM7U0FBTSxDQUFDO1FBQ04sSUFBSSxVQUFVLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzVCLE9BQU8sQ0FBQyxHQUFHLENBQUMsOEJBQThCLENBQUMsQ0FBQTtRQUM3QyxDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxVQUFVLENBQUMsTUFBTSxrQkFBa0IsQ0FBQyxDQUFBO1lBQ3pELEtBQUssTUFBTSxDQUFDLElBQUksVUFBVSxFQUFFLENBQUM7Z0JBQzNCLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQTtZQUNqQyxDQUFDO1lBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUNqQixDQUFDO0lBQ0gsQ0FBQztJQUVELDJEQUEyRDtJQUMzRCxJQUFJLE9BQU8sQ0FBQyxNQUFNLElBQUksVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM1QyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFBO0lBQ2pCLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnXG5cbmludGVyZmFjZSBWYWxpZGF0ZU9wdGlvbnMge1xuICBzdHJpY3Q6IGJvb2xlYW5cbiAganNvbjogYm9vbGVhblxufVxuXG5pbnRlcmZhY2UgVmlvbGF0aW9uIHtcbiAgdHlwZTogJ29ycGhhbi1maWxlJyB8ICdpbnZhbGlkLXRvcC1sZXZlbCcgfCAnaW52YWxpZC1zcmMtZm9sZGVyJyB8ICdtaXNzaW5nLWRlcGVuZGVuY3knIHwgJ21pc3Npbmctc2NyaXB0J1xuICBwYXRoOiBzdHJpbmdcbiAgbWVzc2FnZTogc3RyaW5nXG59XG5cbi8vIFJlcXVpcmVkIGRldiBkZXBlbmRlbmNpZXNcbmNvbnN0IFJFUVVJUkVEX0RFVl9ERVBFTkRFTkNJRVMgPSBbJ2tuaXAnLCAnQGdhbGxvcC5zb2Z0d2FyZS9jYW5vbiddXG5cbi8vIFJlcXVpcmVkIG5wbSBzY3JpcHRzXG5jb25zdCBSRVFVSVJFRF9TQ1JJUFRTOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICB1bnVzZWQ6ICdrbmlwJyxcbiAgY2hlY2s6ICducG0gcnVuIGxpbnQgJiYgbnBtIHJ1biB0cyAmJiBucG0gcnVuIHVudXNlZCcsXG4gIGxpbnQ6ICdlc2xpbnQnLFxuICB0czogJ3RzYycsXG4gIGF1ZGl0OiAnZ2FsbG9wIGF1ZGl0JyxcbiAgJ2dlbmVyYXRlOmFpLXJ1bGVzJzogJ2dhbGxvcCBnZW5lcmF0ZScsXG59XG5cbi8vIEFsbG93ZWQgdG9wLWxldmVsIGRpcmVjdG9yaWVzIChub24tZG90ZmlsZXMpXG5jb25zdCBBTExPV0VEX1RPUF9MRVZFTCA9IFtcbiAgJ3NyYycsXG4gICdwdWJsaWMnLFxuICAnX3NjcmlwdHMnLFxuICAnX2RhdGEnLFxuICAnX2RvY3MnLFxuICAnbm9kZV9tb2R1bGVzJyxcbl1cblxuLy8gQWxsb3dlZCBmb2xkZXJzIGRpcmVjdGx5IHVuZGVyIC9zcmNcbmNvbnN0IEFMTE9XRURfU1JDX0ZPTERFUlMgPSBbXG4gICdhcHAnLFxuICAnYmxvY2tzJyxcbiAgJ2Jsb2cnLFxuICAnY29tcG9uZW50cycsXG4gICdob29rcycsXG4gICdzdHlsZXMnLFxuICAndGVtcGxhdGUnLFxuICAndG9vbHMnLFxuICAndHlwZXMnLFxuICAndXRpbHMnLFxuXVxuXG4vLyBGaWxlcyBhbGxvd2VkIGF0IHRvcCBsZXZlbFxuY29uc3QgQUxMT1dFRF9UT1BfTEVWRUxfRklMRVMgPSBbXG4gICdwYWNrYWdlLmpzb24nLFxuICAncGFja2FnZS1sb2NrLmpzb24nLFxuICAndHNjb25maWcuanNvbicsXG4gICd0c2NvbmZpZy50c2J1aWxkaW5mbycsXG4gICduZXh0LmNvbmZpZy5tanMnLFxuICAnbmV4dC5jb25maWcuanMnLFxuICAnbmV4dC1lbnYuZC50cycsXG4gICdlc2xpbnQuY29uZmlnLm1qcycsXG4gICdlc2xpbnQuY29uZmlnLmpzJyxcbiAgJy5lc2xpbnRyYy5qcycsXG4gICcuZXNsaW50cmMuanNvbicsXG4gICdwb3N0Y3NzLmNvbmZpZy5qcycsXG4gICd0YWlsd2luZC5jb25maWcuanMnLFxuICAndGFpbHdpbmQuY29uZmlnLnRzJyxcbiAgJ1JFQURNRS5tZCcsXG4gICdMSUNFTlNFJyxcbiAgJ0NIQU5HRUxPRy5tZCcsXG4gICcuZ2l0aWdub3JlJyxcbiAgJy5jdXJzb3JydWxlcycsXG5dXG5cbi8qKlxuICogQ2hlY2sgaWYgYSBwYXRoIGlzIGEgZG90ZmlsZSBvciBkb3Rmb2xkZXJcbiAqL1xuZnVuY3Rpb24gaXNEb3RmaWxlKG5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICByZXR1cm4gbmFtZS5zdGFydHNXaXRoKCcuJylcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBhIHBhdGggaXMgYW4gYXJjaGl2ZSBjb250ZW50IGZvbGRlciAoYWxsb3dlZCBuZXcgZm9sZGVycyBpbiAvc3JjKVxuICovXG5mdW5jdGlvbiBpc0FyY2hpdmVDb250ZW50Rm9sZGVyKG5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAvLyBBcmNoaXZlIGZvbGRlcnMgdHlwaWNhbGx5IGhhdmUgcGx1cmFsIG5hbWVzIGZvciBjb250ZW50IGNvbGxlY3Rpb25zXG4gIC8vIFdlIGFsbG93IGFueSBmb2xkZXIgdGhhdCBjb3VsZCByZWFzb25hYmx5IGJlIGFyY2hpdmUgY29udGVudFxuICAvLyBUaGlzIGlzIGEgaGV1cmlzdGljIC0gd2UgY2hlY2sgaWYgaXQgbG9va3MgbGlrZSBhIGNvbnRlbnQgY29sbGVjdGlvblxuICByZXR1cm4gIUFMTE9XRURfU1JDX0ZPTERFUlMuaW5jbHVkZXMobmFtZSlcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZSBwcm9qZWN0IHN0cnVjdHVyZVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdmFsaWRhdGUoXG4gIHByb2plY3RQYXRoOiBzdHJpbmcsXG4gIG9wdGlvbnM6IFZhbGlkYXRlT3B0aW9uc1xuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IHZpb2xhdGlvbnM6IFZpb2xhdGlvbltdID0gW11cbiAgY29uc3QgYWJzb2x1dGVQYXRoID0gcGF0aC5yZXNvbHZlKHByb2Nlc3MuY3dkKCksIHByb2plY3RQYXRoKVxuXG4gIGlmICghZnMuZXhpc3RzU3luYyhhYnNvbHV0ZVBhdGgpKSB7XG4gICAgY29uc29sZS5lcnJvcihgUGF0aCBkb2VzIG5vdCBleGlzdDogJHtwcm9qZWN0UGF0aH1gKVxuICAgIHByb2Nlc3MuZXhpdCgxKVxuICB9XG5cbiAgLy8gQ2hlY2sgdG9wLWxldmVsIGRpcmVjdG9yaWVzXG4gIGNvbnN0IHRvcExldmVsSXRlbXMgPSBmcy5yZWFkZGlyU3luYyhhYnNvbHV0ZVBhdGgpXG4gIGZvciAoY29uc3QgaXRlbSBvZiB0b3BMZXZlbEl0ZW1zKSB7XG4gICAgY29uc3QgaXRlbVBhdGggPSBwYXRoLmpvaW4oYWJzb2x1dGVQYXRoLCBpdGVtKVxuICAgIGNvbnN0IHN0YXQgPSBmcy5zdGF0U3luYyhpdGVtUGF0aClcblxuICAgIGlmIChzdGF0LmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgIC8vIERvdGZvbGRlcnMgYXJlIGV4ZW1wdFxuICAgICAgaWYgKGlzRG90ZmlsZShpdGVtKSkge1xuICAgICAgICBjb250aW51ZVxuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGFsbG93ZWQgdG9wLWxldmVsIGRpcmVjdG9yeVxuICAgICAgaWYgKCFBTExPV0VEX1RPUF9MRVZFTC5pbmNsdWRlcyhpdGVtKSkge1xuICAgICAgICB2aW9sYXRpb25zLnB1c2goe1xuICAgICAgICAgIHR5cGU6ICdpbnZhbGlkLXRvcC1sZXZlbCcsXG4gICAgICAgICAgcGF0aDogaXRlbSxcbiAgICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB0b3AtbGV2ZWwgZGlyZWN0b3J5OiAke2l0ZW19LiBBbGxvd2VkOiAke0FMTE9XRURfVE9QX0xFVkVMLmpvaW4oJywgJyl9IChkb3Rmb2xkZXJzIGV4ZW1wdClgLFxuICAgICAgICB9KVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBJdCdzIGEgZmlsZSAtIGNoZWNrIGlmIGl0J3MgYWxsb3dlZCBhdCB0b3AgbGV2ZWxcbiAgICAgIGlmICghaXNEb3RmaWxlKGl0ZW0pICYmICFBTExPV0VEX1RPUF9MRVZFTF9GSUxFUy5pbmNsdWRlcyhpdGVtKSkge1xuICAgICAgICAvLyBBbGxvdyBjb21tb24gY29uZmlnIGZpbGUgcGF0dGVybnNcbiAgICAgICAgY29uc3QgaXNDb25maWdGaWxlID1cbiAgICAgICAgICBpdGVtLmVuZHNXaXRoKCcuY29uZmlnLmpzJykgfHxcbiAgICAgICAgICBpdGVtLmVuZHNXaXRoKCcuY29uZmlnLm1qcycpIHx8XG4gICAgICAgICAgaXRlbS5lbmRzV2l0aCgnLmNvbmZpZy50cycpIHx8XG4gICAgICAgICAgaXRlbS5lbmRzV2l0aCgnLmpzb24nKSB8fFxuICAgICAgICAgIGl0ZW0uZW5kc1dpdGgoJy5tZCcpIHx8XG4gICAgICAgICAgaXRlbS5lbmRzV2l0aCgnLnNoJylcblxuICAgICAgICBpZiAoIWlzQ29uZmlnRmlsZSkge1xuICAgICAgICAgIHZpb2xhdGlvbnMucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiAnb3JwaGFuLWZpbGUnLFxuICAgICAgICAgICAgcGF0aDogaXRlbSxcbiAgICAgICAgICAgIG1lc3NhZ2U6IGBPcnBoYW4gZmlsZSBhdCBwcm9qZWN0IHJvb3Q6ICR7aXRlbX0uIEZpbGVzIHNob3VsZCBiZSBpbiBkZWZpbmVkIHpvbmVzLmAsXG4gICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIENoZWNrIC9zcmMgZm9sZGVyIHN0cnVjdHVyZVxuICBjb25zdCBzcmNQYXRoID0gcGF0aC5qb2luKGFic29sdXRlUGF0aCwgJ3NyYycpXG4gIGlmIChmcy5leGlzdHNTeW5jKHNyY1BhdGgpKSB7XG4gICAgY29uc3Qgc3JjSXRlbXMgPSBmcy5yZWFkZGlyU3luYyhzcmNQYXRoKVxuICAgIGZvciAoY29uc3QgaXRlbSBvZiBzcmNJdGVtcykge1xuICAgICAgY29uc3QgaXRlbVBhdGggPSBwYXRoLmpvaW4oc3JjUGF0aCwgaXRlbSlcbiAgICAgIGNvbnN0IHN0YXQgPSBmcy5zdGF0U3luYyhpdGVtUGF0aClcblxuICAgICAgaWYgKHN0YXQuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGFsbG93ZWQgL3NyYyBmb2xkZXJcbiAgICAgICAgaWYgKFxuICAgICAgICAgICFBTExPV0VEX1NSQ19GT0xERVJTLmluY2x1ZGVzKGl0ZW0pICYmXG4gICAgICAgICAgIWlzQXJjaGl2ZUNvbnRlbnRGb2xkZXIoaXRlbSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgdmlvbGF0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgIHR5cGU6ICdpbnZhbGlkLXNyYy1mb2xkZXInLFxuICAgICAgICAgICAgcGF0aDogYHNyYy8ke2l0ZW19YCxcbiAgICAgICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIGZvbGRlciBpbiAvc3JjOiAke2l0ZW19LiBBbGxvd2VkOiAke0FMTE9XRURfU1JDX0ZPTERFUlMuam9pbignLCAnKX0gb3IgYXJjaGl2ZSBjb250ZW50IGZvbGRlcnNgLFxuICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDaGVjayB0aGF0IHNyYy9hcHAgaGFzIHJvdXRlIGdyb3Vwc1xuICAgIGNvbnN0IGFwcFBhdGggPSBwYXRoLmpvaW4oc3JjUGF0aCwgJ2FwcCcpXG4gICAgaWYgKGZzLmV4aXN0c1N5bmMoYXBwUGF0aCkpIHtcbiAgICAgIGNvbnN0IGFwcEl0ZW1zID0gZnMucmVhZGRpclN5bmMoYXBwUGF0aClcbiAgICAgIGNvbnN0IGhhc0RlZmF1bHRHcm91cCA9IGFwcEl0ZW1zLnNvbWUoXG4gICAgICAgIChpdGVtKSA9PiBpdGVtID09PSAnKGRlZmF1bHQpJyB8fCBpdGVtLnN0YXJ0c1dpdGgoJygnKVxuICAgICAgKVxuXG4gICAgICBpZiAoIWhhc0RlZmF1bHRHcm91cCkge1xuICAgICAgICB2aW9sYXRpb25zLnB1c2goe1xuICAgICAgICAgIHR5cGU6ICdpbnZhbGlkLXNyYy1mb2xkZXInLFxuICAgICAgICAgIHBhdGg6ICdzcmMvYXBwJyxcbiAgICAgICAgICBtZXNzYWdlOlxuICAgICAgICAgICAgJ3NyYy9hcHAgc2hvdWxkIGhhdmUgYXQgbGVhc3Qgb25lIHJvdXRlIGdyb3VwIGZvbGRlciAoZS5nLiwgKGRlZmF1bHQpLyknLFxuICAgICAgICB9KVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIENoZWNrIHBhY2thZ2UuanNvbiBmb3IgcmVxdWlyZWQgZGVwZW5kZW5jaWVzIGFuZCBzY3JpcHRzXG4gIGNvbnN0IHBhY2thZ2VKc29uUGF0aCA9IHBhdGguam9pbihhYnNvbHV0ZVBhdGgsICdwYWNrYWdlLmpzb24nKVxuICBpZiAoZnMuZXhpc3RzU3luYyhwYWNrYWdlSnNvblBhdGgpKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHBhY2thZ2VKc29uID0gSlNPTi5wYXJzZShmcy5yZWFkRmlsZVN5bmMocGFja2FnZUpzb25QYXRoLCAndXRmOCcpKVxuICAgICAgXG4gICAgICAvLyBDaGVjayBkZXYgZGVwZW5kZW5jaWVzXG4gICAgICBjb25zdCBkZXZEZXBzID0gcGFja2FnZUpzb24uZGV2RGVwZW5kZW5jaWVzIHx8IHt9XG4gICAgICBjb25zdCBkZXBzID0gcGFja2FnZUpzb24uZGVwZW5kZW5jaWVzIHx8IHt9XG4gICAgICBjb25zdCBhbGxEZXBzID0geyAuLi5kZXBzLCAuLi5kZXZEZXBzIH1cbiAgICAgIFxuICAgICAgZm9yIChjb25zdCBkZXAgb2YgUkVRVUlSRURfREVWX0RFUEVOREVOQ0lFUykge1xuICAgICAgICBpZiAoIWFsbERlcHNbZGVwXSkge1xuICAgICAgICAgIHZpb2xhdGlvbnMucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiAnbWlzc2luZy1kZXBlbmRlbmN5JyxcbiAgICAgICAgICAgIHBhdGg6ICdwYWNrYWdlLmpzb24nLFxuICAgICAgICAgICAgbWVzc2FnZTogYE1pc3NpbmcgcmVxdWlyZWQgZGVwZW5kZW5jeTogJHtkZXB9LiBSdW46IG5wbSBpbnN0YWxsIC1EICR7ZGVwfWAsXG4gICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBDaGVjayBzY3JpcHRzXG4gICAgICBjb25zdCBzY3JpcHRzID0gcGFja2FnZUpzb24uc2NyaXB0cyB8fCB7fVxuICAgICAgXG4gICAgICBmb3IgKGNvbnN0IFtzY3JpcHROYW1lLCBleHBlY3RlZFBhdHRlcm5dIG9mIE9iamVjdC5lbnRyaWVzKFJFUVVJUkVEX1NDUklQVFMpKSB7XG4gICAgICAgIGlmICghc2NyaXB0c1tzY3JpcHROYW1lXSkge1xuICAgICAgICAgIHZpb2xhdGlvbnMucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiAnbWlzc2luZy1zY3JpcHQnLFxuICAgICAgICAgICAgcGF0aDogJ3BhY2thZ2UuanNvbicsXG4gICAgICAgICAgICBtZXNzYWdlOiBgTWlzc2luZyByZXF1aXJlZCBzY3JpcHQ6IFwiJHtzY3JpcHROYW1lfVwiLiBFeHBlY3RlZCBwYXR0ZXJuOiBcIiR7ZXhwZWN0ZWRQYXR0ZXJufVwiYCxcbiAgICAgICAgICB9KVxuICAgICAgICB9IGVsc2UgaWYgKCFzY3JpcHRzW3NjcmlwdE5hbWVdLmluY2x1ZGVzKGV4cGVjdGVkUGF0dGVybi5zcGxpdCgnICcpWzBdKSkge1xuICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBzY3JpcHQgY29udGFpbnMgdGhlIG1haW4gY29tbWFuZCAoZmlyc3Qgd29yZCBvZiBleHBlY3RlZCBwYXR0ZXJuKVxuICAgICAgICAgIHZpb2xhdGlvbnMucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiAnbWlzc2luZy1zY3JpcHQnLFxuICAgICAgICAgICAgcGF0aDogJ3BhY2thZ2UuanNvbicsXG4gICAgICAgICAgICBtZXNzYWdlOiBgU2NyaXB0IFwiJHtzY3JpcHROYW1lfVwiIHNob3VsZCBjb250YWluIFwiJHtleHBlY3RlZFBhdHRlcm4uc3BsaXQoJyAnKVswXX1cIi4gRm91bmQ6IFwiJHtzY3JpcHRzW3NjcmlwdE5hbWVdfVwiYCxcbiAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS5lcnJvcignRmFpbGVkIHRvIHBhcnNlIHBhY2thZ2UuanNvbicpXG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHZpb2xhdGlvbnMucHVzaCh7XG4gICAgICB0eXBlOiAnb3JwaGFuLWZpbGUnLFxuICAgICAgcGF0aDogJ3BhY2thZ2UuanNvbicsXG4gICAgICBtZXNzYWdlOiAnTWlzc2luZyBwYWNrYWdlLmpzb24gZmlsZScsXG4gICAgfSlcbiAgfVxuXG4gIC8vIE91dHB1dCByZXN1bHRzXG4gIGlmIChvcHRpb25zLmpzb24pIHtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgIEpTT04uc3RyaW5naWZ5KFxuICAgICAgICB7XG4gICAgICAgICAgdmFsaWQ6IHZpb2xhdGlvbnMubGVuZ3RoID09PSAwLFxuICAgICAgICAgIHZpb2xhdGlvbnMsXG4gICAgICAgIH0sXG4gICAgICAgIG51bGwsXG4gICAgICAgIDJcbiAgICAgIClcbiAgICApXG4gIH0gZWxzZSB7XG4gICAgaWYgKHZpb2xhdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zb2xlLmxvZygn4pyTIFByb2plY3Qgc3RydWN0dXJlIGlzIHZhbGlkJylcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5sb2coYEZvdW5kICR7dmlvbGF0aW9ucy5sZW5ndGh9IHZpb2xhdGlvbihzKTpcXG5gKVxuICAgICAgZm9yIChjb25zdCB2IG9mIHZpb2xhdGlvbnMpIHtcbiAgICAgICAgY29uc29sZS5sb2coYCAg4pyXICR7di5tZXNzYWdlfWApXG4gICAgICB9XG4gICAgICBjb25zb2xlLmxvZygnJylcbiAgICB9XG4gIH1cblxuICAvLyBFeGl0IHdpdGggZXJyb3IgY29kZSBpZiBzdHJpY3QgbW9kZSBhbmQgdmlvbGF0aW9ucyBmb3VuZFxuICBpZiAob3B0aW9ucy5zdHJpY3QgJiYgdmlvbGF0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgcHJvY2Vzcy5leGl0KDEpXG4gIH1cbn1cbiJdfQ==
|