@rcrsr/rill-cli 0.6.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/LICENSE +21 -0
- package/dist/check/config.d.ts +20 -0
- package/dist/check/config.d.ts.map +1 -0
- package/dist/check/config.js +151 -0
- package/dist/check/config.js.map +1 -0
- package/dist/check/fixer.d.ts +39 -0
- package/dist/check/fixer.d.ts.map +1 -0
- package/dist/check/fixer.js +119 -0
- package/dist/check/fixer.js.map +1 -0
- package/dist/check/index.d.ts +10 -0
- package/dist/check/index.d.ts.map +1 -0
- package/dist/check/index.js +21 -0
- package/dist/check/index.js.map +1 -0
- package/dist/check/rules/anti-patterns.d.ts +65 -0
- package/dist/check/rules/anti-patterns.d.ts.map +1 -0
- package/dist/check/rules/anti-patterns.js +481 -0
- package/dist/check/rules/anti-patterns.js.map +1 -0
- package/dist/check/rules/closures.d.ts +66 -0
- package/dist/check/rules/closures.d.ts.map +1 -0
- package/dist/check/rules/closures.js +370 -0
- package/dist/check/rules/closures.js.map +1 -0
- package/dist/check/rules/collections.d.ts +90 -0
- package/dist/check/rules/collections.d.ts.map +1 -0
- package/dist/check/rules/collections.js +373 -0
- package/dist/check/rules/collections.js.map +1 -0
- package/dist/check/rules/conditionals.d.ts +41 -0
- package/dist/check/rules/conditionals.d.ts.map +1 -0
- package/dist/check/rules/conditionals.js +134 -0
- package/dist/check/rules/conditionals.js.map +1 -0
- package/dist/check/rules/flow.d.ts +46 -0
- package/dist/check/rules/flow.d.ts.map +1 -0
- package/dist/check/rules/flow.js +206 -0
- package/dist/check/rules/flow.js.map +1 -0
- package/dist/check/rules/formatting.d.ts +143 -0
- package/dist/check/rules/formatting.d.ts.map +1 -0
- package/dist/check/rules/formatting.js +656 -0
- package/dist/check/rules/formatting.js.map +1 -0
- package/dist/check/rules/helpers.d.ts +26 -0
- package/dist/check/rules/helpers.d.ts.map +1 -0
- package/dist/check/rules/helpers.js +66 -0
- package/dist/check/rules/helpers.js.map +1 -0
- package/dist/check/rules/index.d.ts +21 -0
- package/dist/check/rules/index.d.ts.map +1 -0
- package/dist/check/rules/index.js +78 -0
- package/dist/check/rules/index.js.map +1 -0
- package/dist/check/rules/loops.d.ts +77 -0
- package/dist/check/rules/loops.d.ts.map +1 -0
- package/dist/check/rules/loops.js +310 -0
- package/dist/check/rules/loops.js.map +1 -0
- package/dist/check/rules/naming.d.ts +21 -0
- package/dist/check/rules/naming.d.ts.map +1 -0
- package/dist/check/rules/naming.js +174 -0
- package/dist/check/rules/naming.js.map +1 -0
- package/dist/check/rules/strings.d.ts +28 -0
- package/dist/check/rules/strings.d.ts.map +1 -0
- package/dist/check/rules/strings.js +79 -0
- package/dist/check/rules/strings.js.map +1 -0
- package/dist/check/rules/types.d.ts +41 -0
- package/dist/check/rules/types.d.ts.map +1 -0
- package/dist/check/rules/types.js +167 -0
- package/dist/check/rules/types.js.map +1 -0
- package/dist/check/types.d.ts +112 -0
- package/dist/check/types.d.ts.map +1 -0
- package/dist/check/types.js +6 -0
- package/dist/check/types.js.map +1 -0
- package/dist/check/validator.d.ts +18 -0
- package/dist/check/validator.d.ts.map +1 -0
- package/dist/check/validator.js +110 -0
- package/dist/check/validator.js.map +1 -0
- package/dist/check/visitor.d.ts +33 -0
- package/dist/check/visitor.d.ts.map +1 -0
- package/dist/check/visitor.js +259 -0
- package/dist/check/visitor.js.map +1 -0
- package/dist/cli-check.d.ts +43 -0
- package/dist/cli-check.d.ts.map +1 -0
- package/dist/cli-check.js +366 -0
- package/dist/cli-check.js.map +1 -0
- package/dist/cli-error-enrichment.d.ts +73 -0
- package/dist/cli-error-enrichment.d.ts.map +1 -0
- package/dist/cli-error-enrichment.js +205 -0
- package/dist/cli-error-enrichment.js.map +1 -0
- package/dist/cli-error-formatter.d.ts +45 -0
- package/dist/cli-error-formatter.d.ts.map +1 -0
- package/dist/cli-error-formatter.js +218 -0
- package/dist/cli-error-formatter.js.map +1 -0
- package/dist/cli-eval.d.ts +15 -0
- package/dist/cli-eval.d.ts.map +1 -0
- package/dist/cli-eval.js +116 -0
- package/dist/cli-eval.js.map +1 -0
- package/dist/cli-exec.d.ts +58 -0
- package/dist/cli-exec.d.ts.map +1 -0
- package/dist/cli-exec.js +326 -0
- package/dist/cli-exec.js.map +1 -0
- package/dist/cli-explain.d.ts +24 -0
- package/dist/cli-explain.d.ts.map +1 -0
- package/dist/cli-explain.js +68 -0
- package/dist/cli-explain.js.map +1 -0
- package/dist/cli-lsp-diagnostic.d.ts +35 -0
- package/dist/cli-lsp-diagnostic.d.ts.map +1 -0
- package/dist/cli-lsp-diagnostic.js +98 -0
- package/dist/cli-lsp-diagnostic.js.map +1 -0
- package/dist/cli-module-loader.d.ts +19 -0
- package/dist/cli-module-loader.d.ts.map +1 -0
- package/dist/cli-module-loader.js +83 -0
- package/dist/cli-module-loader.js.map +1 -0
- package/dist/cli-shared.d.ts +62 -0
- package/dist/cli-shared.d.ts.map +1 -0
- package/dist/cli-shared.js +158 -0
- package/dist/cli-shared.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +62 -0
- package/dist/cli.js.map +1 -0
- package/dist/test-internal-import.d.ts +2 -0
- package/dist/test-internal-import.d.ts.map +1 -0
- package/dist/test-internal-import.js +7 -0
- package/dist/test-internal-import.js.map +1 -0
- package/package.json +24 -0
- package/src/check/config.ts +202 -0
- package/src/check/fixer.ts +174 -0
- package/src/check/index.ts +39 -0
- package/src/check/rules/anti-patterns.ts +585 -0
- package/src/check/rules/closures.ts +445 -0
- package/src/check/rules/collections.ts +437 -0
- package/src/check/rules/conditionals.ts +155 -0
- package/src/check/rules/flow.ts +262 -0
- package/src/check/rules/formatting.ts +811 -0
- package/src/check/rules/helpers.ts +89 -0
- package/src/check/rules/index.ts +140 -0
- package/src/check/rules/loops.ts +372 -0
- package/src/check/rules/naming.ts +242 -0
- package/src/check/rules/strings.ts +104 -0
- package/src/check/rules/types.ts +214 -0
- package/src/check/types.ts +163 -0
- package/src/check/validator.ts +136 -0
- package/src/check/visitor.ts +338 -0
- package/src/cli-check.ts +456 -0
- package/src/cli-error-enrichment.ts +274 -0
- package/src/cli-error-formatter.ts +313 -0
- package/src/cli-eval.ts +145 -0
- package/src/cli-exec.ts +408 -0
- package/src/cli-explain.ts +76 -0
- package/src/cli-lsp-diagnostic.ts +132 -0
- package/src/cli-module-loader.ts +101 -0
- package/src/cli-shared.ts +187 -0
- package/tests/check/cli-check.test.ts +189 -0
- package/tests/check/config.test.ts +350 -0
- package/tests/check/fixer.test.ts +373 -0
- package/tests/check/format-diagnostics.test.ts +327 -0
- package/tests/check/rules/anti-patterns.test.ts +467 -0
- package/tests/check/rules/closures.test.ts +192 -0
- package/tests/check/rules/collections.test.ts +380 -0
- package/tests/check/rules/conditionals.test.ts +185 -0
- package/tests/check/rules/flow.test.ts +250 -0
- package/tests/check/rules/formatting.test.ts +755 -0
- package/tests/check/rules/loops.test.ts +334 -0
- package/tests/check/rules/naming.test.ts +336 -0
- package/tests/check/rules/strings.test.ts +129 -0
- package/tests/check/rules/types.test.ts +257 -0
- package/tests/check/validator.test.ts +444 -0
- package/tests/check/visitor.test.ts +171 -0
- package/tests/cli/check.test.ts +801 -0
- package/tests/cli/error-enrichment.test.ts +510 -0
- package/tests/cli/error-formatter.test.ts +631 -0
- package/tests/cli/eval.test.ts +85 -0
- package/tests/cli/exec.test.ts +537 -0
- package/tests/cli-explain.test.ts +249 -0
- package/tests/cli-lsp-diagnostic.test.ts +202 -0
- package/tests/cli-shared.test.ts +439 -0
- package/tsconfig.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Module Loader
|
|
3
|
+
*
|
|
4
|
+
* Implements module loading for the Rill CLI with circular dependency detection.
|
|
5
|
+
* See docs/integration-modules.md for module convention specification.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'fs/promises';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import * as yaml from 'yaml';
|
|
10
|
+
import { parse } from '@rcrsr/rill';
|
|
11
|
+
import { execute, createRuntimeContext } from '@rcrsr/rill';
|
|
12
|
+
/**
|
|
13
|
+
* Load a module and its dependencies recursively.
|
|
14
|
+
*
|
|
15
|
+
* @param specifier - Module path (relative or absolute)
|
|
16
|
+
* @param fromPath - Path of the importing file
|
|
17
|
+
* @param cache - Module cache keyed by canonical path
|
|
18
|
+
* @param chain - Set of paths in current import chain for circular detection
|
|
19
|
+
* @returns Dict of exported values
|
|
20
|
+
* @throws Error if module not found or circular dependency detected
|
|
21
|
+
*/
|
|
22
|
+
export async function loadModule(specifier, fromPath, cache, chain = new Set()) {
|
|
23
|
+
// Resolve to absolute canonical path
|
|
24
|
+
const absolutePath = path.resolve(path.dirname(fromPath), specifier);
|
|
25
|
+
// Check for circular dependency
|
|
26
|
+
if (chain.has(absolutePath)) {
|
|
27
|
+
const cycle = [...chain, absolutePath].join(' -> ');
|
|
28
|
+
throw new Error(`Circular dependency detected: ${cycle}`);
|
|
29
|
+
}
|
|
30
|
+
// Return cached module if already loaded
|
|
31
|
+
if (cache.has(absolutePath)) {
|
|
32
|
+
return cache.get(absolutePath);
|
|
33
|
+
}
|
|
34
|
+
// Check if module file exists
|
|
35
|
+
try {
|
|
36
|
+
await fs.access(absolutePath);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new Error(`Module not found: ${specifier}`);
|
|
40
|
+
}
|
|
41
|
+
// Add to chain to detect cycles in dependencies
|
|
42
|
+
chain.add(absolutePath);
|
|
43
|
+
try {
|
|
44
|
+
// Load and parse module source
|
|
45
|
+
const source = await fs.readFile(absolutePath, 'utf-8');
|
|
46
|
+
const ast = parse(source);
|
|
47
|
+
// Extract frontmatter (yaml.parse returns null for empty content)
|
|
48
|
+
const frontmatter = ast.frontmatter
|
|
49
|
+
? (yaml.parse(ast.frontmatter.content) ?? {})
|
|
50
|
+
: {};
|
|
51
|
+
// Resolve dependencies first
|
|
52
|
+
const imports = {};
|
|
53
|
+
if (frontmatter['use'] && Array.isArray(frontmatter['use'])) {
|
|
54
|
+
for (const entry of frontmatter['use']) {
|
|
55
|
+
if (typeof entry === 'object' && entry !== null) {
|
|
56
|
+
const [name, depPath] = Object.entries(entry)[0];
|
|
57
|
+
imports[name] = await loadModule(depPath, absolutePath, cache, chain);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Execute module with dependencies
|
|
62
|
+
const ctx = createRuntimeContext({ variables: imports });
|
|
63
|
+
const result = await execute(ast, ctx);
|
|
64
|
+
// Extract exports
|
|
65
|
+
const exports = {};
|
|
66
|
+
const exportList = frontmatter['export'];
|
|
67
|
+
if (Array.isArray(exportList)) {
|
|
68
|
+
for (const name of exportList) {
|
|
69
|
+
if (typeof name === 'string' && result.variables[name] !== undefined) {
|
|
70
|
+
exports[name] = result.variables[name];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Cache and return
|
|
75
|
+
cache.set(absolutePath, exports);
|
|
76
|
+
return exports;
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
// Remove from chain after processing
|
|
80
|
+
chain.delete(absolutePath);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=cli-module-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-module-loader.js","sourceRoot":"","sources":["../src/cli-module-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Shared Utilities
|
|
3
|
+
* Common formatting functions for CLI tools
|
|
4
|
+
*/
|
|
5
|
+
import { VERSION } from '@rcrsr/rill';
|
|
6
|
+
import type { RillValue } from '@rcrsr/rill';
|
|
7
|
+
import { type ScopeInfo } from './cli-error-enrichment.js';
|
|
8
|
+
import { type FormatOptions } from './cli-error-formatter.js';
|
|
9
|
+
/**
|
|
10
|
+
* Convert execution result to human-readable string
|
|
11
|
+
*
|
|
12
|
+
* @param value - The value to format
|
|
13
|
+
* @returns Formatted string representation
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatOutput(value: RillValue): string;
|
|
16
|
+
/**
|
|
17
|
+
* Format error for stderr output
|
|
18
|
+
*
|
|
19
|
+
* When source is available, uses enrichment pipeline to add source snippets and suggestions.
|
|
20
|
+
* Otherwise, falls back to simple formatting for backward compatibility.
|
|
21
|
+
*
|
|
22
|
+
* @param err - The error to format
|
|
23
|
+
* @param source - Optional source code for enrichment
|
|
24
|
+
* @param options - Optional format options (defaults to human format)
|
|
25
|
+
* @param scope - Optional scope information for suggestions
|
|
26
|
+
* @returns Formatted error message
|
|
27
|
+
*/
|
|
28
|
+
export declare function formatError(err: Error, source?: string, options?: Partial<FormatOptions>, scope?: ScopeInfo): string;
|
|
29
|
+
/**
|
|
30
|
+
* Determine exit code from script result
|
|
31
|
+
*
|
|
32
|
+
* Implements exit code semantics per language spec:
|
|
33
|
+
* - true / non-empty string: exit 0
|
|
34
|
+
* - false / empty string: exit 1
|
|
35
|
+
* - [0, "message"]: exit 0 with message
|
|
36
|
+
* - [1, "message"]: exit 1 with message
|
|
37
|
+
*
|
|
38
|
+
* @param value - The script return value
|
|
39
|
+
* @returns Exit code and optional message
|
|
40
|
+
*/
|
|
41
|
+
export declare function determineExitCode(value: RillValue): {
|
|
42
|
+
code: number;
|
|
43
|
+
message?: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Detect help or version flags in CLI argument array.
|
|
47
|
+
* Checks for --help, -h, --version, -v in any position.
|
|
48
|
+
*
|
|
49
|
+
* @param argv - Command-line arguments (process.argv.slice(2))
|
|
50
|
+
* @returns Object with mode if flag found, null otherwise
|
|
51
|
+
*/
|
|
52
|
+
export declare function detectHelpVersionFlag(argv: string[]): {
|
|
53
|
+
mode: 'help' | 'version';
|
|
54
|
+
} | null;
|
|
55
|
+
/**
|
|
56
|
+
* Package version string (re-exported from version-data.ts)
|
|
57
|
+
*
|
|
58
|
+
* This replaces the previous async readVersion() function with a synchronous constant.
|
|
59
|
+
* The version is now generated at build time by packages/core/scripts/generate-version.ts.
|
|
60
|
+
*/
|
|
61
|
+
export { VERSION };
|
|
62
|
+
//# sourceMappingURL=cli-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-shared.d.ts","sourceRoot":"","sources":["../src/cli-shared.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAc,OAAO,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,0BAA0B,CAAC;AAElC;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAQrD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,KAAK,EACV,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,EAChC,KAAK,CAAC,EAAE,SAAS,GAChB,MAAM,CA6DR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAgCA;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EAAE,GACb;IAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,IAAI,CASrC;AAED;;;;;GAKG;AACH,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Shared Utilities
|
|
3
|
+
* Common formatting functions for CLI tools
|
|
4
|
+
*/
|
|
5
|
+
import { isCallable, VERSION } from '@rcrsr/rill';
|
|
6
|
+
import { ParseError, RuntimeError } from '@rcrsr/rill';
|
|
7
|
+
import { LexerError } from '@rcrsr/rill';
|
|
8
|
+
import { enrichError } from './cli-error-enrichment.js';
|
|
9
|
+
import { formatError as formatEnrichedError, } from './cli-error-formatter.js';
|
|
10
|
+
/**
|
|
11
|
+
* Convert execution result to human-readable string
|
|
12
|
+
*
|
|
13
|
+
* @param value - The value to format
|
|
14
|
+
* @returns Formatted string representation
|
|
15
|
+
*/
|
|
16
|
+
export function formatOutput(value) {
|
|
17
|
+
if (value === null)
|
|
18
|
+
return 'null';
|
|
19
|
+
if (typeof value === 'string')
|
|
20
|
+
return value;
|
|
21
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
22
|
+
return String(value);
|
|
23
|
+
}
|
|
24
|
+
if (isCallable(value))
|
|
25
|
+
return '[closure]';
|
|
26
|
+
return JSON.stringify(value, null, 2);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Format error for stderr output
|
|
30
|
+
*
|
|
31
|
+
* When source is available, uses enrichment pipeline to add source snippets and suggestions.
|
|
32
|
+
* Otherwise, falls back to simple formatting for backward compatibility.
|
|
33
|
+
*
|
|
34
|
+
* @param err - The error to format
|
|
35
|
+
* @param source - Optional source code for enrichment
|
|
36
|
+
* @param options - Optional format options (defaults to human format)
|
|
37
|
+
* @param scope - Optional scope information for suggestions
|
|
38
|
+
* @returns Formatted error message
|
|
39
|
+
*/
|
|
40
|
+
export function formatError(err, source, options, scope) {
|
|
41
|
+
// IC-12: Use enrichment pipeline when source is available and error is RillError
|
|
42
|
+
if (source !== undefined &&
|
|
43
|
+
(err instanceof LexerError ||
|
|
44
|
+
err instanceof ParseError ||
|
|
45
|
+
err instanceof RuntimeError)) {
|
|
46
|
+
try {
|
|
47
|
+
const enriched = enrichError(err, source, scope);
|
|
48
|
+
const formatOpts = {
|
|
49
|
+
format: options?.format ?? 'human',
|
|
50
|
+
verbose: options?.verbose ?? false,
|
|
51
|
+
includeCallStack: options?.includeCallStack ?? false,
|
|
52
|
+
maxCallStackDepth: options?.maxCallStackDepth ?? 10,
|
|
53
|
+
};
|
|
54
|
+
return formatEnrichedError(enriched, formatOpts);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// If enrichment fails, fall back to simple formatting
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// IC-12: Fallback to existing behavior for backward compatibility
|
|
61
|
+
if (err instanceof LexerError) {
|
|
62
|
+
const location = err.location;
|
|
63
|
+
return `Lexer error at line ${location.line}: ${err.message.replace(/ at \d+:\d+$/, '')}`;
|
|
64
|
+
}
|
|
65
|
+
if (err instanceof ParseError) {
|
|
66
|
+
const location = err.location;
|
|
67
|
+
if (location) {
|
|
68
|
+
return `Parse error at line ${location.line}: ${err.message.replace(/ at \d+:\d+$/, '')}`;
|
|
69
|
+
}
|
|
70
|
+
return `Parse error: ${err.message}`;
|
|
71
|
+
}
|
|
72
|
+
if (err instanceof RuntimeError) {
|
|
73
|
+
const location = err.location;
|
|
74
|
+
const baseMessage = err.message.replace(/ at \d+:\d+$/, '');
|
|
75
|
+
if (location) {
|
|
76
|
+
return `Runtime error at line ${location.line}: ${baseMessage}`;
|
|
77
|
+
}
|
|
78
|
+
return `Runtime error: ${baseMessage}`;
|
|
79
|
+
}
|
|
80
|
+
// Handle file not found errors (ENOENT)
|
|
81
|
+
if (err instanceof Error &&
|
|
82
|
+
'code' in err &&
|
|
83
|
+
err.code === 'ENOENT' &&
|
|
84
|
+
'path' in err) {
|
|
85
|
+
return `File not found: ${err.path}`;
|
|
86
|
+
}
|
|
87
|
+
// Handle module errors
|
|
88
|
+
if (err.message.includes('Cannot find module')) {
|
|
89
|
+
return `Module error: ${err.message}`;
|
|
90
|
+
}
|
|
91
|
+
return err.message;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Determine exit code from script result
|
|
95
|
+
*
|
|
96
|
+
* Implements exit code semantics per language spec:
|
|
97
|
+
* - true / non-empty string: exit 0
|
|
98
|
+
* - false / empty string: exit 1
|
|
99
|
+
* - [0, "message"]: exit 0 with message
|
|
100
|
+
* - [1, "message"]: exit 1 with message
|
|
101
|
+
*
|
|
102
|
+
* @param value - The script return value
|
|
103
|
+
* @returns Exit code and optional message
|
|
104
|
+
*/
|
|
105
|
+
export function determineExitCode(value) {
|
|
106
|
+
// Handle tuple format: [code, message]
|
|
107
|
+
if (Array.isArray(value)) {
|
|
108
|
+
if (value.length >= 2) {
|
|
109
|
+
const code = value[0];
|
|
110
|
+
const message = value[1];
|
|
111
|
+
// Validate code is 0 or 1
|
|
112
|
+
if (typeof code === 'number' && (code === 0 || code === 1)) {
|
|
113
|
+
// Return with message if provided as string
|
|
114
|
+
if (typeof message === 'string' && message !== '') {
|
|
115
|
+
return { code, message };
|
|
116
|
+
}
|
|
117
|
+
return { code };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Non-conforming array: treat as truthy (exit 0)
|
|
121
|
+
return { code: 0 };
|
|
122
|
+
}
|
|
123
|
+
// Boolean values
|
|
124
|
+
if (typeof value === 'boolean') {
|
|
125
|
+
return { code: value ? 0 : 1 };
|
|
126
|
+
}
|
|
127
|
+
// String values
|
|
128
|
+
if (typeof value === 'string') {
|
|
129
|
+
return { code: value === '' ? 1 : 0 };
|
|
130
|
+
}
|
|
131
|
+
// All other values (number, dict, closure, etc.) are truthy: exit 0
|
|
132
|
+
return { code: 0 };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Detect help or version flags in CLI argument array.
|
|
136
|
+
* Checks for --help, -h, --version, -v in any position.
|
|
137
|
+
*
|
|
138
|
+
* @param argv - Command-line arguments (process.argv.slice(2))
|
|
139
|
+
* @returns Object with mode if flag found, null otherwise
|
|
140
|
+
*/
|
|
141
|
+
export function detectHelpVersionFlag(argv) {
|
|
142
|
+
// Help takes precedence over version
|
|
143
|
+
if (argv.includes('--help') || argv.includes('-h')) {
|
|
144
|
+
return { mode: 'help' };
|
|
145
|
+
}
|
|
146
|
+
if (argv.includes('--version') || argv.includes('-v')) {
|
|
147
|
+
return { mode: 'version' };
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Package version string (re-exported from version-data.ts)
|
|
153
|
+
*
|
|
154
|
+
* This replaces the previous async readVersion() function with a synchronous constant.
|
|
155
|
+
* The version is now generated at build time by packages/core/scripts/generate-version.ts.
|
|
156
|
+
*/
|
|
157
|
+
export { VERSION };
|
|
158
|
+
//# sourceMappingURL=cli-shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-shared.js","sourceRoot":"","sources":["../src/cli-shared.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Rill CLI - Run rill scripts from the command line
|
|
4
|
+
*
|
|
5
|
+
* @deprecated Use rill-exec or rill-eval commands instead. This file will be removed in v1.0.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* npx tsx src/cli.ts <script.rill>
|
|
9
|
+
* npx tsx src/cli.ts -e "code"
|
|
10
|
+
* echo "code" | npx tsx src/cli.ts -
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Rill CLI - Run rill scripts from the command line
|
|
4
|
+
*
|
|
5
|
+
* @deprecated Use rill-exec or rill-eval commands instead. This file will be removed in v1.0.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* npx tsx src/cli.ts <script.rill>
|
|
9
|
+
* npx tsx src/cli.ts -e "code"
|
|
10
|
+
* echo "code" | npx tsx src/cli.ts -
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import { createRuntimeContext, execute, parse } from '@rcrsr/rill';
|
|
14
|
+
import { formatOutput } from './cli-shared.js';
|
|
15
|
+
async function run(source) {
|
|
16
|
+
const ctx = createRuntimeContext({
|
|
17
|
+
callbacks: {
|
|
18
|
+
onLog: (value) => console.log(formatOutput(value)),
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
try {
|
|
22
|
+
const ast = parse(source);
|
|
23
|
+
const result = await execute(ast, ctx);
|
|
24
|
+
console.log(formatOutput(result.value));
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function main() {
|
|
32
|
+
const args = process.argv.slice(2);
|
|
33
|
+
if (args.length === 0) {
|
|
34
|
+
console.error('Usage: rill <script.rill> | rill -e "code" | rill -');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
let source;
|
|
38
|
+
const arg0 = args[0];
|
|
39
|
+
if (arg0 === '-e') {
|
|
40
|
+
// Inline code: rill -e "code"
|
|
41
|
+
if (!args[1]) {
|
|
42
|
+
console.error('Missing code after -e');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
source = args[1];
|
|
46
|
+
}
|
|
47
|
+
else if (arg0 === '-') {
|
|
48
|
+
// Stdin: echo "code" | rill -
|
|
49
|
+
source = fs.readFileSync(0, 'utf-8');
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// File: rill script.rill
|
|
53
|
+
if (!fs.existsSync(arg0)) {
|
|
54
|
+
console.error(`File not found: ${arg0}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
source = fs.readFileSync(arg0, 'utf-8');
|
|
58
|
+
}
|
|
59
|
+
await run(source);
|
|
60
|
+
}
|
|
61
|
+
main();
|
|
62
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,oBAAoB,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,KAAK,UAAU,GAAG,CAAC,MAAc;IAC/B,MAAM,GAAG,GAAG,oBAAoB,CAAC;QAC/B,SAAS,EAAE;YACT,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;SACnD;KACF,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAc,CAAC;IACnB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;IAEtB,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,8BAA8B;QAC9B,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC;SAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QACxB,8BAA8B;QAC9B,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;SAAM,CAAC;QACN,yBAAyB;QACzB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC;AACpB,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-internal-import.d.ts","sourceRoot":"","sources":["../src/test-internal-import.ts"],"names":[],"mappings":"AAKA,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// VERIFICATION TEST: This file should cause pnpm install to fail
|
|
2
|
+
// Testing EC-1: CLI imports internal core path → pnpm install fails
|
|
3
|
+
import { Parser } from '@rill-lang/core/src/parser/parser.js';
|
|
4
|
+
export function testInternalImport() {
|
|
5
|
+
console.log('This should not compile or build successfully');
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=test-internal-import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-internal-import.js","sourceRoot":"","sources":["../src/test-internal-import.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,oEAAoE;AAEpE,OAAO,EAAE,MAAM,EAAE,MAAM,sCAAsC,CAAC;AAE9D,MAAM,UAAU,kBAAkB;IAChC,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;AAC/D,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rcrsr/rill-cli",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"rill-exec": "./dist/cli-exec.js",
|
|
7
|
+
"rill-eval": "./dist/cli-eval.js",
|
|
8
|
+
"rill-check": "./dist/cli-check.js"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"yaml": "^2.8.2",
|
|
12
|
+
"@rcrsr/rill": "^0.6.0"
|
|
13
|
+
},
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc --build",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"lint": "eslint --config ../../eslint.config.js src/",
|
|
22
|
+
"check": "pnpm run build && pnpm run test && pnpm run lint"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Loader for rill-check
|
|
3
|
+
* Loads and validates .rill-check.json configuration files.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import type { CheckConfig, RuleState, Severity } from './types.js';
|
|
9
|
+
import { VALIDATION_RULES } from './rules/index.js';
|
|
10
|
+
|
|
11
|
+
// ============================================================
|
|
12
|
+
// CONSTANTS
|
|
13
|
+
// ============================================================
|
|
14
|
+
|
|
15
|
+
/** Configuration file name */
|
|
16
|
+
const CONFIG_FILE_NAME = '.rill-check.json';
|
|
17
|
+
|
|
18
|
+
// ============================================================
|
|
19
|
+
// DEFAULT CONFIGURATION
|
|
20
|
+
// ============================================================
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Create default configuration with all rules enabled.
|
|
24
|
+
* Returns configuration where all known rules are set to 'on'.
|
|
25
|
+
*/
|
|
26
|
+
export function createDefaultConfig(): CheckConfig {
|
|
27
|
+
const rules: Record<string, RuleState> = {};
|
|
28
|
+
const severity: Record<string, Severity> = {};
|
|
29
|
+
|
|
30
|
+
for (const rule of VALIDATION_RULES) {
|
|
31
|
+
rules[rule.code] = 'on';
|
|
32
|
+
severity[rule.code] = rule.severity;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return { rules, severity };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ============================================================
|
|
39
|
+
// VALIDATION
|
|
40
|
+
// ============================================================
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Validate that a value is a valid RuleState.
|
|
44
|
+
*/
|
|
45
|
+
function isRuleState(value: unknown): value is RuleState {
|
|
46
|
+
return value === 'on' || value === 'off' || value === 'warn';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validate that a value is a valid Severity.
|
|
51
|
+
*/
|
|
52
|
+
function isSeverity(value: unknown): value is Severity {
|
|
53
|
+
return value === 'error' || value === 'warning' || value === 'info';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Validate configuration structure and values.
|
|
58
|
+
* Throws Error if configuration is invalid.
|
|
59
|
+
*/
|
|
60
|
+
function validateConfig(data: unknown): asserts data is {
|
|
61
|
+
rules?: Record<string, unknown>;
|
|
62
|
+
severity?: Record<string, unknown>;
|
|
63
|
+
} {
|
|
64
|
+
if (typeof data !== 'object' || data === null || Array.isArray(data)) {
|
|
65
|
+
throw new Error('[RILL-C003] Invalid configuration: must be an object');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const config = data as Record<string, unknown>;
|
|
69
|
+
|
|
70
|
+
// Validate rules field if present
|
|
71
|
+
if ('rules' in config) {
|
|
72
|
+
if (
|
|
73
|
+
typeof config['rules'] !== 'object' ||
|
|
74
|
+
config['rules'] === null ||
|
|
75
|
+
Array.isArray(config['rules'])
|
|
76
|
+
) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
'[RILL-C003] Invalid configuration: rules must be an object'
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const rules = config['rules'] as Record<string, unknown>;
|
|
83
|
+
for (const [code, state] of Object.entries(rules)) {
|
|
84
|
+
if (!isRuleState(state)) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`[RILL-C003] Invalid configuration: rule ${code} has invalid state "${state}" (must be 'on', 'off', or 'warn')`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Validate severity field if present
|
|
93
|
+
if ('severity' in config) {
|
|
94
|
+
if (
|
|
95
|
+
typeof config['severity'] !== 'object' ||
|
|
96
|
+
config['severity'] === null ||
|
|
97
|
+
Array.isArray(config['severity'])
|
|
98
|
+
) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
'[RILL-C003] Invalid configuration: severity must be an object'
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const severity = config['severity'] as Record<string, unknown>;
|
|
105
|
+
for (const [code, sev] of Object.entries(severity)) {
|
|
106
|
+
if (!isSeverity(sev)) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`[RILL-C003] Invalid configuration: rule ${code} has invalid severity "${sev}" (must be 'error', 'warning', or 'info')`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Validate that all rule codes in config are known rules.
|
|
117
|
+
* Throws Error if unknown rule code found.
|
|
118
|
+
*/
|
|
119
|
+
function validateRuleCodes(config: CheckConfig): void {
|
|
120
|
+
const knownRules = new Set(VALIDATION_RULES.map((r) => r.code));
|
|
121
|
+
|
|
122
|
+
// Check rules field
|
|
123
|
+
for (const code of Object.keys(config.rules)) {
|
|
124
|
+
if (!knownRules.has(code)) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`[RILL-C003] Invalid configuration: unknown rule ${code}`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Check severity field
|
|
132
|
+
for (const code of Object.keys(config.severity)) {
|
|
133
|
+
if (!knownRules.has(code)) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`[RILL-C003] Invalid configuration: unknown rule ${code}`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ============================================================
|
|
142
|
+
// CONFIGURATION LOADING
|
|
143
|
+
// ============================================================
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Load configuration from .rill-check.json in the specified directory.
|
|
147
|
+
*
|
|
148
|
+
* @param cwd - Directory to search for configuration file
|
|
149
|
+
* @returns CheckConfig object, or null if file not found
|
|
150
|
+
* @throws Error with "Invalid configuration: {reason}" if JSON is invalid [EC-3]
|
|
151
|
+
* @throws Error with "Invalid configuration: unknown rule {code}" if unknown rule [EC-4]
|
|
152
|
+
*/
|
|
153
|
+
export function loadConfig(cwd: string): CheckConfig | null {
|
|
154
|
+
const configPath = join(cwd, CONFIG_FILE_NAME);
|
|
155
|
+
|
|
156
|
+
// Return null if file not found (not an error)
|
|
157
|
+
if (!existsSync(configPath)) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let fileContent: string;
|
|
162
|
+
try {
|
|
163
|
+
fileContent = readFileSync(configPath, 'utf-8');
|
|
164
|
+
} catch (err) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`[RILL-C003] Invalid configuration: failed to read file (${err instanceof Error ? err.message : String(err)})`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Parse JSON
|
|
171
|
+
let parsedData: unknown;
|
|
172
|
+
try {
|
|
173
|
+
parsedData = JSON.parse(fileContent);
|
|
174
|
+
} catch (err) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`[RILL-C003] Invalid configuration: invalid JSON (${err instanceof Error ? err.message : String(err)})`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Validate structure
|
|
181
|
+
validateConfig(parsedData);
|
|
182
|
+
|
|
183
|
+
// Get defaults
|
|
184
|
+
const defaults = createDefaultConfig();
|
|
185
|
+
|
|
186
|
+
// Merge with defaults (parsedData is validated, so we can safely cast)
|
|
187
|
+
const rules = {
|
|
188
|
+
...defaults.rules,
|
|
189
|
+
...(parsedData.rules as Record<string, RuleState> | undefined),
|
|
190
|
+
};
|
|
191
|
+
const severity = {
|
|
192
|
+
...defaults.severity,
|
|
193
|
+
...(parsedData.severity as Record<string, Severity> | undefined),
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const config: CheckConfig = { rules, severity };
|
|
197
|
+
|
|
198
|
+
// Validate rule codes
|
|
199
|
+
validateRuleCodes(config);
|
|
200
|
+
|
|
201
|
+
return config;
|
|
202
|
+
}
|