@organon-methodology/testing 0.3.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/README.md +80 -0
- package/dist/adapters/vitest.d.ts +49 -0
- package/dist/adapters/vitest.d.ts.map +1 -0
- package/dist/adapters/vitest.js +60 -0
- package/dist/adapters/vitest.js.map +1 -0
- package/dist/core/assert-custom.d.ts +43 -0
- package/dist/core/assert-custom.d.ts.map +1 -0
- package/dist/core/assert-custom.js +48 -0
- package/dist/core/assert-custom.js.map +1 -0
- package/dist/core/assert-exports-present.d.ts +52 -0
- package/dist/core/assert-exports-present.d.ts.map +1 -0
- package/dist/core/assert-exports-present.js +125 -0
- package/dist/core/assert-exports-present.js.map +1 -0
- package/dist/core/assert-file-exists.d.ts +41 -0
- package/dist/core/assert-file-exists.d.ts.map +1 -0
- package/dist/core/assert-file-exists.js +52 -0
- package/dist/core/assert-file-exists.js.map +1 -0
- package/dist/core/assert-max-value.d.ts +79 -0
- package/dist/core/assert-max-value.d.ts.map +1 -0
- package/dist/core/assert-max-value.js +90 -0
- package/dist/core/assert-max-value.js.map +1 -0
- package/dist/core/assert-naming-convention.d.ts +61 -0
- package/dist/core/assert-naming-convention.d.ts.map +1 -0
- package/dist/core/assert-naming-convention.js +92 -0
- package/dist/core/assert-naming-convention.js.map +1 -0
- package/dist/core/assert-no-side-effects.d.ts +55 -0
- package/dist/core/assert-no-side-effects.d.ts.map +1 -0
- package/dist/core/assert-no-side-effects.js +72 -0
- package/dist/core/assert-no-side-effects.js.map +1 -0
- package/dist/core/assertions/exports-present.d.ts +38 -0
- package/dist/core/assertions/exports-present.d.ts.map +1 -0
- package/dist/core/assertions/exports-present.js +47 -0
- package/dist/core/assertions/exports-present.js.map +1 -0
- package/dist/core/assertions/file-exists.d.ts +45 -0
- package/dist/core/assertions/file-exists.d.ts.map +1 -0
- package/dist/core/assertions/file-exists.js +46 -0
- package/dist/core/assertions/file-exists.js.map +1 -0
- package/dist/core/assertions/max-value.d.ts +77 -0
- package/dist/core/assertions/max-value.d.ts.map +1 -0
- package/dist/core/assertions/max-value.js +60 -0
- package/dist/core/assertions/max-value.js.map +1 -0
- package/dist/core/assertions/naming-convention.d.ts +51 -0
- package/dist/core/assertions/naming-convention.d.ts.map +1 -0
- package/dist/core/assertions/naming-convention.js +73 -0
- package/dist/core/assertions/naming-convention.js.map +1 -0
- package/dist/core/assertions/no-side-effects.d.ts +47 -0
- package/dist/core/assertions/no-side-effects.d.ts.map +1 -0
- package/dist/core/assertions/no-side-effects.js +70 -0
- package/dist/core/assertions/no-side-effects.js.map +1 -0
- package/dist/core/invariant-test.d.ts +128 -0
- package/dist/core/invariant-test.d.ts.map +1 -0
- package/dist/core/invariant-test.js +174 -0
- package/dist/core/invariant-test.js.map +1 -0
- package/dist/core/resolvers/file-resolver.d.ts +92 -0
- package/dist/core/resolvers/file-resolver.d.ts.map +1 -0
- package/dist/core/resolvers/file-resolver.js +103 -0
- package/dist/core/resolvers/file-resolver.js.map +1 -0
- package/dist/core/resolvers/import-resolver.d.ts +55 -0
- package/dist/core/resolvers/import-resolver.d.ts.map +1 -0
- package/dist/core/resolvers/import-resolver.js +99 -0
- package/dist/core/resolvers/import-resolver.js.map +1 -0
- package/dist/core/resolvers/node-fs.d.ts +13 -0
- package/dist/core/resolvers/node-fs.d.ts.map +1 -0
- package/dist/core/resolvers/node-fs.js +32 -0
- package/dist/core/resolvers/node-fs.js.map +1 -0
- package/dist/core/resolvers/parallel-reader.d.ts +35 -0
- package/dist/core/resolvers/parallel-reader.d.ts.map +1 -0
- package/dist/core/resolvers/parallel-reader.js +56 -0
- package/dist/core/resolvers/parallel-reader.js.map +1 -0
- package/dist/core/resolvers/string-resolver.d.ts +66 -0
- package/dist/core/resolvers/string-resolver.d.ts.map +1 -0
- package/dist/core/resolvers/string-resolver.js +127 -0
- package/dist/core/resolvers/string-resolver.js.map +1 -0
- package/dist/core/resolvers/types.d.ts +16 -0
- package/dist/core/resolvers/types.d.ts.map +1 -0
- package/dist/core/resolvers/types.js +10 -0
- package/dist/core/resolvers/types.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* assertMaxValue — High-level assertion that combines file resolution with pure validation.
|
|
3
|
+
*
|
|
4
|
+
* This is the public API function users call in their tests:
|
|
5
|
+
* ```typescript
|
|
6
|
+
* await assertMaxValue({
|
|
7
|
+
* files: ['src/config/*.ts'],
|
|
8
|
+
* pattern: /ttl:\s*(\d+)/,
|
|
9
|
+
* maxValue: 86400,
|
|
10
|
+
* unit: 'seconds',
|
|
11
|
+
* });
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Architecture:
|
|
15
|
+
* - Uses resolvers/file-resolver.ts to read files and extract values (I/O layer)
|
|
16
|
+
* - Delegates to assertions/max-value.ts for pure validation (no I/O)
|
|
17
|
+
* - This module is the composition layer that wires I/O to pure logic
|
|
18
|
+
*
|
|
19
|
+
* Invariants:
|
|
20
|
+
* - INV-TEST-2 (fail-fast): Throws on violation or resolver errors
|
|
21
|
+
* - INV-TEST-6 (always-async): Returns Promise<void>
|
|
22
|
+
* - INV-TEST-7 (composable): No module-level mutable state
|
|
23
|
+
*/
|
|
24
|
+
import type { FileSystem } from './resolvers/types.js';
|
|
25
|
+
/**
|
|
26
|
+
* Options for assertMaxValue.
|
|
27
|
+
*
|
|
28
|
+
* Uses the options-object pattern (RFC 001 Design Decision 4: Clarity > Conciseness).
|
|
29
|
+
*/
|
|
30
|
+
export interface MaxValueOptions {
|
|
31
|
+
/** File paths or glob patterns to scan */
|
|
32
|
+
files: string[];
|
|
33
|
+
/** Regex with a capturing group for the numeric value */
|
|
34
|
+
pattern: RegExp;
|
|
35
|
+
/** Upper bound (inclusive) that values must not exceed */
|
|
36
|
+
maxValue: number;
|
|
37
|
+
/** Optional unit for error messages (e.g., "seconds", "bytes") */
|
|
38
|
+
unit?: string;
|
|
39
|
+
/** Optional working directory for glob resolution */
|
|
40
|
+
cwd?: string;
|
|
41
|
+
/** Optional FileSystem implementation (defaults to Node.js fs + fast-glob) */
|
|
42
|
+
fs?: FileSystem;
|
|
43
|
+
/**
|
|
44
|
+
* Require at least one value to be extracted (default: true).
|
|
45
|
+
* When true, throws if no files match the glob or no lines match the pattern.
|
|
46
|
+
* This prevents silent passes from typos in file globs or regex patterns.
|
|
47
|
+
* Set to false when the absence of matches is a valid (expected) outcome.
|
|
48
|
+
*/
|
|
49
|
+
requireMatches?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Error thrown when assertMaxValue encounters resolver-level errors
|
|
53
|
+
* (e.g., files not found, globs failing, non-numeric captures).
|
|
54
|
+
*/
|
|
55
|
+
export declare class MaxValueResolverError extends Error {
|
|
56
|
+
readonly resolverErrors: Array<{
|
|
57
|
+
file: string;
|
|
58
|
+
message: string;
|
|
59
|
+
}>;
|
|
60
|
+
constructor(errors: Array<{
|
|
61
|
+
file: string;
|
|
62
|
+
message: string;
|
|
63
|
+
}>);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Assert that numeric values extracted from files do not exceed a maximum.
|
|
67
|
+
*
|
|
68
|
+
* Workflow:
|
|
69
|
+
* 1. Expand glob patterns and read files (resolver layer)
|
|
70
|
+
* 2. Extract numeric values matching the pattern
|
|
71
|
+
* 3. Validate all values against maxValue (pure assertion)
|
|
72
|
+
*
|
|
73
|
+
* @param options - Configuration including files, pattern, maxValue, and optional fs/cwd/unit
|
|
74
|
+
* @throws {MaxValueResolverError} if files can't be read or values can't be extracted
|
|
75
|
+
* @throws {MaxValueAssertionError} if any value exceeds maxValue
|
|
76
|
+
*/
|
|
77
|
+
export declare function assertMaxValue(options: MaxValueOptions): Promise<void>;
|
|
78
|
+
export { MaxValueAssertionError } from './assertions/max-value.js';
|
|
79
|
+
//# sourceMappingURL=assert-max-value.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert-max-value.d.ts","sourceRoot":"","sources":["../../src/core/assert-max-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKvD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yDAAyD;IACzD,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,SAAgB,cAAc,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;gBAE7D,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAQ7D;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CAsCf;AAGD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* assertMaxValue — High-level assertion that combines file resolution with pure validation.
|
|
3
|
+
*
|
|
4
|
+
* This is the public API function users call in their tests:
|
|
5
|
+
* ```typescript
|
|
6
|
+
* await assertMaxValue({
|
|
7
|
+
* files: ['src/config/*.ts'],
|
|
8
|
+
* pattern: /ttl:\s*(\d+)/,
|
|
9
|
+
* maxValue: 86400,
|
|
10
|
+
* unit: 'seconds',
|
|
11
|
+
* });
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Architecture:
|
|
15
|
+
* - Uses resolvers/file-resolver.ts to read files and extract values (I/O layer)
|
|
16
|
+
* - Delegates to assertions/max-value.ts for pure validation (no I/O)
|
|
17
|
+
* - This module is the composition layer that wires I/O to pure logic
|
|
18
|
+
*
|
|
19
|
+
* Invariants:
|
|
20
|
+
* - INV-TEST-2 (fail-fast): Throws on violation or resolver errors
|
|
21
|
+
* - INV-TEST-6 (always-async): Returns Promise<void>
|
|
22
|
+
* - INV-TEST-7 (composable): No module-level mutable state
|
|
23
|
+
*/
|
|
24
|
+
import { resolveValues } from './resolvers/file-resolver.js';
|
|
25
|
+
import { validateMaxValue } from './assertions/max-value.js';
|
|
26
|
+
import { createNodeFileSystem } from './resolvers/node-fs.js';
|
|
27
|
+
/**
|
|
28
|
+
* Error thrown when assertMaxValue encounters resolver-level errors
|
|
29
|
+
* (e.g., files not found, globs failing, non-numeric captures).
|
|
30
|
+
*/
|
|
31
|
+
export class MaxValueResolverError extends Error {
|
|
32
|
+
resolverErrors;
|
|
33
|
+
constructor(errors) {
|
|
34
|
+
const details = errors
|
|
35
|
+
.map((e) => ` ${e.file}: ${e.message}`)
|
|
36
|
+
.join('\n');
|
|
37
|
+
super(`assertMaxValue resolver errors:\n${details}`);
|
|
38
|
+
this.name = 'MaxValueResolverError';
|
|
39
|
+
this.resolverErrors = errors;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Assert that numeric values extracted from files do not exceed a maximum.
|
|
44
|
+
*
|
|
45
|
+
* Workflow:
|
|
46
|
+
* 1. Expand glob patterns and read files (resolver layer)
|
|
47
|
+
* 2. Extract numeric values matching the pattern
|
|
48
|
+
* 3. Validate all values against maxValue (pure assertion)
|
|
49
|
+
*
|
|
50
|
+
* @param options - Configuration including files, pattern, maxValue, and optional fs/cwd/unit
|
|
51
|
+
* @throws {MaxValueResolverError} if files can't be read or values can't be extracted
|
|
52
|
+
* @throws {MaxValueAssertionError} if any value exceeds maxValue
|
|
53
|
+
*/
|
|
54
|
+
export async function assertMaxValue(options) {
|
|
55
|
+
const { files, pattern, maxValue, unit, cwd, fs, requireMatches = true } = options;
|
|
56
|
+
const resolvedFs = fs ?? createNodeFileSystem();
|
|
57
|
+
// 0. Fail-fast on empty files array (INV-TEST-2)
|
|
58
|
+
if (files.length === 0) {
|
|
59
|
+
throw new MaxValueResolverError([{
|
|
60
|
+
file: '(none)',
|
|
61
|
+
message: 'No file patterns provided. The files array must not be empty.',
|
|
62
|
+
}]);
|
|
63
|
+
}
|
|
64
|
+
// 1. Resolve files and extract values
|
|
65
|
+
const resolved = await resolveValues({ files, pattern, cwd }, resolvedFs);
|
|
66
|
+
// 2. Fail-fast on resolver errors (INV-TEST-2)
|
|
67
|
+
if (resolved.errors.length > 0) {
|
|
68
|
+
throw new MaxValueResolverError(resolved.errors);
|
|
69
|
+
}
|
|
70
|
+
// 3. Fail-fast when no values found and requireMatches is true (INV-TEST-2)
|
|
71
|
+
// Prevents silent passes from typos in file globs or regex patterns.
|
|
72
|
+
if (requireMatches && resolved.values.length === 0) {
|
|
73
|
+
const filesDetail = resolved.filesRead.length === 0
|
|
74
|
+
? 'No files matched the glob pattern(s).'
|
|
75
|
+
: `Searched ${resolved.filesRead.length} file(s) but pattern matched no lines.`;
|
|
76
|
+
throw new MaxValueResolverError([{
|
|
77
|
+
file: files.join(', '),
|
|
78
|
+
message: `No values extracted. ${filesDetail} Check your file globs and regex pattern.`,
|
|
79
|
+
}]);
|
|
80
|
+
}
|
|
81
|
+
// 4. Validate extracted values against the maximum (pure assertion, sync)
|
|
82
|
+
validateMaxValue({
|
|
83
|
+
values: resolved.values,
|
|
84
|
+
maxValue,
|
|
85
|
+
unit,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// Re-export assertion error for consumers
|
|
89
|
+
export { MaxValueAssertionError } from './assertions/max-value.js';
|
|
90
|
+
//# sourceMappingURL=assert-max-value.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert-max-value.js","sourceRoot":"","sources":["../../src/core/assert-max-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAA0B,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AA6B9D;;;GAGG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9B,cAAc,CAA2C;IAEzE,YAAY,MAAgD;QAC1D,MAAM,OAAO,GAAG,MAAM;aACnB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;aACvC,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,KAAK,CAAC,oCAAoC,OAAO,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAwB;IAExB,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,cAAc,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACnF,MAAM,UAAU,GAAG,EAAE,IAAI,oBAAoB,EAAE,CAAC;IAEhD,iDAAiD;IACjD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,qBAAqB,CAAC,CAAC;gBAC/B,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,+DAA+D;aACzE,CAAC,CAAC,CAAC;IACN,CAAC;IAED,sCAAsC;IACtC,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,UAAU,CAAC,CAAC;IAE1E,+CAA+C;IAC/C,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,qBAAqB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACnD,CAAC;IAED,4EAA4E;IAC5E,wEAAwE;IACxE,IAAI,cAAc,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnD,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YACjD,CAAC,CAAC,uCAAuC;YACzC,CAAC,CAAC,YAAY,QAAQ,CAAC,SAAS,CAAC,MAAM,wCAAwC,CAAC;QAClF,MAAM,IAAI,qBAAqB,CAAC,CAAC;gBAC/B,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;gBACtB,OAAO,EAAE,wBAAwB,WAAW,2CAA2C;aACxF,CAAC,CAAC,CAAC;IACN,CAAC;IAED,0EAA0E;IAC1E,gBAAgB,CAAC;QACf,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,QAAQ;QACR,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAED,0CAA0C;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* assertNamingConvention — High-level assertion that checks naming conventions.
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* - 'filenames': checks file stems (filename without extension) against the convention
|
|
6
|
+
* - 'identifiers': extracts identifiers from code via regex and checks them
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* - Uses resolvers/string-resolver.ts to extract strings (I/O layer)
|
|
10
|
+
* - Delegates to assertions/naming-convention.ts for pure validation (no I/O)
|
|
11
|
+
*
|
|
12
|
+
* Invariants:
|
|
13
|
+
* - INV-TEST-2 (fail-fast): Throws on violation or resolver errors
|
|
14
|
+
* - INV-TEST-6 (always-async): Returns Promise<void>
|
|
15
|
+
* - INV-TEST-7 (composable): No module-level mutable state
|
|
16
|
+
*/
|
|
17
|
+
import type { FileSystem } from './resolvers/types.js';
|
|
18
|
+
import { type Convention } from './assertions/naming-convention.js';
|
|
19
|
+
/**
|
|
20
|
+
* Options for assertNamingConvention.
|
|
21
|
+
*/
|
|
22
|
+
export interface NamingConventionOptions {
|
|
23
|
+
/** Check mode: 'filenames' checks file stems, 'identifiers' extracts from code */
|
|
24
|
+
mode: 'filenames' | 'identifiers';
|
|
25
|
+
/** File paths or glob patterns */
|
|
26
|
+
files: string[];
|
|
27
|
+
/** The naming convention to enforce */
|
|
28
|
+
convention: Convention;
|
|
29
|
+
/** Regex with capturing group for identifier extraction (required for 'identifiers' mode) */
|
|
30
|
+
pattern?: RegExp;
|
|
31
|
+
/** Names to exclude from validation */
|
|
32
|
+
exceptions?: string[];
|
|
33
|
+
/** Optional working directory */
|
|
34
|
+
cwd?: string;
|
|
35
|
+
/** Optional FileSystem implementation */
|
|
36
|
+
fs?: FileSystem;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Error thrown when assertNamingConvention encounters resolver-level errors.
|
|
40
|
+
*/
|
|
41
|
+
export declare class NamingConventionResolverError extends Error {
|
|
42
|
+
readonly resolverErrors: Array<{
|
|
43
|
+
file: string;
|
|
44
|
+
message: string;
|
|
45
|
+
}>;
|
|
46
|
+
constructor(errors: Array<{
|
|
47
|
+
file: string;
|
|
48
|
+
message: string;
|
|
49
|
+
}>);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Assert that names follow a specified naming convention.
|
|
53
|
+
*
|
|
54
|
+
* @param options - Configuration including mode, files, convention, and optional pattern
|
|
55
|
+
* @throws {NamingConventionResolverError} if files can't be resolved
|
|
56
|
+
* @throws {NamingConventionAssertionError} if any name violates the convention
|
|
57
|
+
*/
|
|
58
|
+
export declare function assertNamingConvention(options: NamingConventionOptions): Promise<void>;
|
|
59
|
+
export { NamingConventionAssertionError } from './assertions/naming-convention.js';
|
|
60
|
+
export type { Convention } from './assertions/naming-convention.js';
|
|
61
|
+
//# sourceMappingURL=assert-naming-convention.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert-naming-convention.d.ts","sourceRoot":"","sources":["../../src/core/assert-naming-convention.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGvD,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,mCAAmC,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,kFAAkF;IAClF,IAAI,EAAE,WAAW,GAAG,aAAa,CAAC;IAClC,kCAAkC;IAClC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,uCAAuC;IACvC,UAAU,EAAE,UAAU,CAAC;IACvB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,EAAE,CAAC,EAAE,UAAU,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,SAAgB,cAAc,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;gBAE7D,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAQ7D;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAwDf;AAGD,OAAO,EAAE,8BAA8B,EAAE,MAAM,mCAAmC,CAAC;AACnF,YAAY,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* assertNamingConvention — High-level assertion that checks naming conventions.
|
|
3
|
+
*
|
|
4
|
+
* Two modes:
|
|
5
|
+
* - 'filenames': checks file stems (filename without extension) against the convention
|
|
6
|
+
* - 'identifiers': extracts identifiers from code via regex and checks them
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* - Uses resolvers/string-resolver.ts to extract strings (I/O layer)
|
|
10
|
+
* - Delegates to assertions/naming-convention.ts for pure validation (no I/O)
|
|
11
|
+
*
|
|
12
|
+
* Invariants:
|
|
13
|
+
* - INV-TEST-2 (fail-fast): Throws on violation or resolver errors
|
|
14
|
+
* - INV-TEST-6 (always-async): Returns Promise<void>
|
|
15
|
+
* - INV-TEST-7 (composable): No module-level mutable state
|
|
16
|
+
*/
|
|
17
|
+
import { createNodeFileSystem } from './resolvers/node-fs.js';
|
|
18
|
+
import { resolveFileStems, resolveStringsByPattern } from './resolvers/string-resolver.js';
|
|
19
|
+
import { validateNamingConvention, } from './assertions/naming-convention.js';
|
|
20
|
+
/**
|
|
21
|
+
* Error thrown when assertNamingConvention encounters resolver-level errors.
|
|
22
|
+
*/
|
|
23
|
+
export class NamingConventionResolverError extends Error {
|
|
24
|
+
resolverErrors;
|
|
25
|
+
constructor(errors) {
|
|
26
|
+
const details = errors
|
|
27
|
+
.map((e) => ` ${e.file}: ${e.message}`)
|
|
28
|
+
.join('\n');
|
|
29
|
+
super(`assertNamingConvention resolver errors:\n${details}`);
|
|
30
|
+
this.name = 'NamingConventionResolverError';
|
|
31
|
+
this.resolverErrors = errors;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Assert that names follow a specified naming convention.
|
|
36
|
+
*
|
|
37
|
+
* @param options - Configuration including mode, files, convention, and optional pattern
|
|
38
|
+
* @throws {NamingConventionResolverError} if files can't be resolved
|
|
39
|
+
* @throws {NamingConventionAssertionError} if any name violates the convention
|
|
40
|
+
*/
|
|
41
|
+
export async function assertNamingConvention(options) {
|
|
42
|
+
const { mode, files, convention, pattern, exceptions, cwd, fs } = options;
|
|
43
|
+
const resolvedFs = fs ?? createNodeFileSystem();
|
|
44
|
+
// Fail-fast on empty files array (INV-TEST-2)
|
|
45
|
+
if (files.length === 0) {
|
|
46
|
+
throw new NamingConventionResolverError([{
|
|
47
|
+
file: '(none)',
|
|
48
|
+
message: 'No file patterns provided. The files array must not be empty.',
|
|
49
|
+
}]);
|
|
50
|
+
}
|
|
51
|
+
// Fail-fast on identifiers mode without pattern
|
|
52
|
+
if (mode === 'identifiers' && !pattern) {
|
|
53
|
+
throw new NamingConventionResolverError([{
|
|
54
|
+
file: '(none)',
|
|
55
|
+
message: 'The pattern option is required for identifiers mode.',
|
|
56
|
+
}]);
|
|
57
|
+
}
|
|
58
|
+
if (mode === 'filenames') {
|
|
59
|
+
const resolved = await resolveFileStems({ files, cwd, fs: resolvedFs });
|
|
60
|
+
if (resolved.errors.length > 0) {
|
|
61
|
+
throw new NamingConventionResolverError(resolved.errors);
|
|
62
|
+
}
|
|
63
|
+
if (resolved.strings.length === 0) {
|
|
64
|
+
throw new NamingConventionResolverError([{
|
|
65
|
+
file: files.join(', '),
|
|
66
|
+
message: 'No files matched the glob pattern(s). Check your file globs.',
|
|
67
|
+
}]);
|
|
68
|
+
}
|
|
69
|
+
validateNamingConvention(resolved.strings, convention, exceptions);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const resolved = await resolveStringsByPattern({
|
|
73
|
+
files,
|
|
74
|
+
pattern: pattern,
|
|
75
|
+
cwd,
|
|
76
|
+
fs: resolvedFs,
|
|
77
|
+
});
|
|
78
|
+
if (resolved.errors.length > 0) {
|
|
79
|
+
throw new NamingConventionResolverError(resolved.errors);
|
|
80
|
+
}
|
|
81
|
+
if (resolved.filesRead.length === 0) {
|
|
82
|
+
throw new NamingConventionResolverError([{
|
|
83
|
+
file: files.join(', '),
|
|
84
|
+
message: 'No files matched the glob pattern(s). Check your file globs.',
|
|
85
|
+
}]);
|
|
86
|
+
}
|
|
87
|
+
validateNamingConvention(resolved.strings, convention, exceptions);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Re-export for consumers
|
|
91
|
+
export { NamingConventionAssertionError } from './assertions/naming-convention.js';
|
|
92
|
+
//# sourceMappingURL=assert-naming-convention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert-naming-convention.js","sourceRoot":"","sources":["../../src/core/assert-naming-convention.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* assertNoSideEffects — High-level assertion that checks for forbidden imports.
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* - Uses resolvers/import-resolver.ts to scan files for imports (I/O layer)
|
|
6
|
+
* - Delegates to assertions/no-side-effects.ts for pure validation (no I/O)
|
|
7
|
+
* - This module is the composition layer that wires I/O to pure logic
|
|
8
|
+
*
|
|
9
|
+
* Invariants:
|
|
10
|
+
* - INV-TEST-2 (fail-fast): Throws on violation or resolver errors
|
|
11
|
+
* - INV-TEST-6 (always-async): Returns Promise<void>
|
|
12
|
+
* - INV-TEST-7 (composable): No module-level mutable state
|
|
13
|
+
*/
|
|
14
|
+
import type { FileSystem } from './resolvers/types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Options for assertNoSideEffects.
|
|
17
|
+
*/
|
|
18
|
+
export interface NoSideEffectsOptions {
|
|
19
|
+
/** File paths or glob patterns to scan */
|
|
20
|
+
files: string[];
|
|
21
|
+
/** Module names to forbid (e.g., ['fs', 'http', 'vitest']) */
|
|
22
|
+
forbiddenModules: string[];
|
|
23
|
+
/** Optional working directory for glob resolution */
|
|
24
|
+
cwd?: string;
|
|
25
|
+
/** Optional FileSystem implementation */
|
|
26
|
+
fs?: FileSystem;
|
|
27
|
+
/**
|
|
28
|
+
* Require at least one file to be scanned (default: true).
|
|
29
|
+
* When true, throws if no files match the glob patterns.
|
|
30
|
+
*/
|
|
31
|
+
requireMatches?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Error thrown when assertNoSideEffects encounters resolver-level errors.
|
|
35
|
+
*/
|
|
36
|
+
export declare class NoSideEffectsResolverError extends Error {
|
|
37
|
+
readonly resolverErrors: Array<{
|
|
38
|
+
file: string;
|
|
39
|
+
message: string;
|
|
40
|
+
}>;
|
|
41
|
+
constructor(errors: Array<{
|
|
42
|
+
file: string;
|
|
43
|
+
message: string;
|
|
44
|
+
}>);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Assert that files do not import any forbidden modules.
|
|
48
|
+
*
|
|
49
|
+
* @param options - Configuration including files, forbiddenModules, and optional fs/cwd
|
|
50
|
+
* @throws {NoSideEffectsResolverError} if files can't be read or globs fail
|
|
51
|
+
* @throws {NoSideEffectsAssertionError} if any forbidden import is found
|
|
52
|
+
*/
|
|
53
|
+
export declare function assertNoSideEffects(options: NoSideEffectsOptions): Promise<void>;
|
|
54
|
+
export { NoSideEffectsAssertionError } from './assertions/no-side-effects.js';
|
|
55
|
+
//# sourceMappingURL=assert-no-side-effects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert-no-side-effects.d.ts","sourceRoot":"","sources":["../../src/core/assert-no-side-effects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAQvD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,0CAA0C;IAC1C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8DAA8D;IAC9D,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,SAAgB,cAAc,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;gBAE7D,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAQ7D;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAqCf;AAGD,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* assertNoSideEffects — High-level assertion that checks for forbidden imports.
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* - Uses resolvers/import-resolver.ts to scan files for imports (I/O layer)
|
|
6
|
+
* - Delegates to assertions/no-side-effects.ts for pure validation (no I/O)
|
|
7
|
+
* - This module is the composition layer that wires I/O to pure logic
|
|
8
|
+
*
|
|
9
|
+
* Invariants:
|
|
10
|
+
* - INV-TEST-2 (fail-fast): Throws on violation or resolver errors
|
|
11
|
+
* - INV-TEST-6 (always-async): Returns Promise<void>
|
|
12
|
+
* - INV-TEST-7 (composable): No module-level mutable state
|
|
13
|
+
*/
|
|
14
|
+
import { createNodeFileSystem } from './resolvers/node-fs.js';
|
|
15
|
+
import { resolveImports } from './resolvers/import-resolver.js';
|
|
16
|
+
import { validateNoSideEffects, } from './assertions/no-side-effects.js';
|
|
17
|
+
/**
|
|
18
|
+
* Error thrown when assertNoSideEffects encounters resolver-level errors.
|
|
19
|
+
*/
|
|
20
|
+
export class NoSideEffectsResolverError extends Error {
|
|
21
|
+
resolverErrors;
|
|
22
|
+
constructor(errors) {
|
|
23
|
+
const details = errors
|
|
24
|
+
.map((e) => ` ${e.file}: ${e.message}`)
|
|
25
|
+
.join('\n');
|
|
26
|
+
super(`assertNoSideEffects resolver errors:\n${details}`);
|
|
27
|
+
this.name = 'NoSideEffectsResolverError';
|
|
28
|
+
this.resolverErrors = errors;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Assert that files do not import any forbidden modules.
|
|
33
|
+
*
|
|
34
|
+
* @param options - Configuration including files, forbiddenModules, and optional fs/cwd
|
|
35
|
+
* @throws {NoSideEffectsResolverError} if files can't be read or globs fail
|
|
36
|
+
* @throws {NoSideEffectsAssertionError} if any forbidden import is found
|
|
37
|
+
*/
|
|
38
|
+
export async function assertNoSideEffects(options) {
|
|
39
|
+
const { files, forbiddenModules, cwd, fs, requireMatches = true } = options;
|
|
40
|
+
const resolvedFs = fs ?? createNodeFileSystem();
|
|
41
|
+
// Fail-fast on empty inputs (INV-TEST-2)
|
|
42
|
+
if (files.length === 0) {
|
|
43
|
+
throw new NoSideEffectsResolverError([{
|
|
44
|
+
file: '(none)',
|
|
45
|
+
message: 'No file patterns provided. The files array must not be empty.',
|
|
46
|
+
}]);
|
|
47
|
+
}
|
|
48
|
+
if (forbiddenModules.length === 0) {
|
|
49
|
+
throw new NoSideEffectsResolverError([{
|
|
50
|
+
file: '(none)',
|
|
51
|
+
message: 'No forbidden modules provided. The forbiddenModules array must not be empty.',
|
|
52
|
+
}]);
|
|
53
|
+
}
|
|
54
|
+
// Resolve imports from files
|
|
55
|
+
const resolved = await resolveImports({ files, cwd, fs: resolvedFs });
|
|
56
|
+
// Fail-fast on resolver errors (INV-TEST-2)
|
|
57
|
+
if (resolved.errors.length > 0) {
|
|
58
|
+
throw new NoSideEffectsResolverError(resolved.errors);
|
|
59
|
+
}
|
|
60
|
+
// Fail-fast when no files found and requireMatches is true
|
|
61
|
+
if (requireMatches && resolved.filesRead.length === 0) {
|
|
62
|
+
throw new NoSideEffectsResolverError([{
|
|
63
|
+
file: files.join(', '),
|
|
64
|
+
message: 'No files matched the glob pattern(s). Check your file globs.',
|
|
65
|
+
}]);
|
|
66
|
+
}
|
|
67
|
+
// Delegate to pure validator
|
|
68
|
+
validateNoSideEffects(resolved.imports, forbiddenModules);
|
|
69
|
+
}
|
|
70
|
+
// Re-export assertion error for consumers
|
|
71
|
+
export { NoSideEffectsAssertionError } from './assertions/no-side-effects.js';
|
|
72
|
+
//# sourceMappingURL=assert-no-side-effects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert-no-side-effects.js","sourceRoot":"","sources":["../../src/core/assert-no-side-effects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EACL,qBAAqB,GAEtB,MAAM,iCAAiC,CAAC;AAqBzC;;GAEG;AACH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACnC,cAAc,CAA2C;IAEzE,YAAY,MAAgD;QAC1D,MAAM,OAAO,GAAG,MAAM;aACnB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;aACvC,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,KAAK,CAAC,yCAAyC,OAAO,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;QACzC,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA6B;IAE7B,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,EAAE,EAAE,cAAc,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAC5E,MAAM,UAAU,GAAG,EAAE,IAAI,oBAAoB,EAAE,CAAC;IAEhD,yCAAyC;IACzC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,0BAA0B,CAAC,CAAC;gBACpC,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,+DAA+D;aACzE,CAAC,CAAC,CAAC;IACN,CAAC;IAED,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,0BAA0B,CAAC,CAAC;gBACpC,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,8EAA8E;aACxF,CAAC,CAAC,CAAC;IACN,CAAC;IAED,6BAA6B;IAC7B,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;IAEtE,4CAA4C;IAC5C,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,0BAA0B,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC;IAED,2DAA2D;IAC3D,IAAI,cAAc,IAAI,QAAQ,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,0BAA0B,CAAC,CAAC;gBACpC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;gBACtB,OAAO,EAAE,8DAA8D;aACxE,CAAC,CAAC,CAAC;IACN,CAAC;IAED,6BAA6B;IAC7B,qBAAqB,CAAC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;AAC5D,CAAC;AAED,0CAA0C;AAC1C,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validateExportsPresent — Pure assertion that checks expected exports exist.
|
|
3
|
+
*
|
|
4
|
+
* Invariants enforced:
|
|
5
|
+
* - INV-TEST-1 (assertion-logic-pure): No I/O imports. Operates on pre-resolved data.
|
|
6
|
+
* - INV-TEST-2 (fail-fast): Throws on violation (collects all before throwing).
|
|
7
|
+
* - INV-TEST-7 (composable): No module-level mutable state.
|
|
8
|
+
*
|
|
9
|
+
* This module must NEVER import fs, http, process, or any I/O module.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* A missing export violation.
|
|
13
|
+
*/
|
|
14
|
+
export interface ExportsPresentViolation {
|
|
15
|
+
/** The expected export name that was not found */
|
|
16
|
+
name: string;
|
|
17
|
+
/** The file that was scanned */
|
|
18
|
+
file: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Error thrown when an exports-present assertion fails.
|
|
22
|
+
*/
|
|
23
|
+
export declare class ExportsPresentAssertionError extends Error {
|
|
24
|
+
readonly violations: ExportsPresentViolation[];
|
|
25
|
+
constructor(violations: ExportsPresentViolation[]);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Validate that all expected export names are present in the found exports list.
|
|
29
|
+
*
|
|
30
|
+
* This is a pure, synchronous function: no I/O, no side effects, deterministic.
|
|
31
|
+
*
|
|
32
|
+
* @param file - The file being checked (for error messages)
|
|
33
|
+
* @param expectedExports - Names that must be exported
|
|
34
|
+
* @param foundExports - Names that were actually found as exports
|
|
35
|
+
* @throws {ExportsPresentAssertionError} if any expected export is missing
|
|
36
|
+
*/
|
|
37
|
+
export declare function validateExportsPresent(file: string, expectedExports: string[], foundExports: string[]): void;
|
|
38
|
+
//# sourceMappingURL=exports-present.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports-present.d.ts","sourceRoot":"","sources":["../../../src/core/assertions/exports-present.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,SAAgB,UAAU,EAAE,uBAAuB,EAAE,CAAC;gBAE1C,UAAU,EAAE,uBAAuB,EAAE;CAYlD;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,EAAE,EACzB,YAAY,EAAE,MAAM,EAAE,GACrB,IAAI,CAaN"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validateExportsPresent — Pure assertion that checks expected exports exist.
|
|
3
|
+
*
|
|
4
|
+
* Invariants enforced:
|
|
5
|
+
* - INV-TEST-1 (assertion-logic-pure): No I/O imports. Operates on pre-resolved data.
|
|
6
|
+
* - INV-TEST-2 (fail-fast): Throws on violation (collects all before throwing).
|
|
7
|
+
* - INV-TEST-7 (composable): No module-level mutable state.
|
|
8
|
+
*
|
|
9
|
+
* This module must NEVER import fs, http, process, or any I/O module.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Error thrown when an exports-present assertion fails.
|
|
13
|
+
*/
|
|
14
|
+
export class ExportsPresentAssertionError extends Error {
|
|
15
|
+
violations;
|
|
16
|
+
constructor(violations) {
|
|
17
|
+
const details = violations
|
|
18
|
+
.map((v) => ` ${v.file} — missing export "${v.name}"`)
|
|
19
|
+
.join('\n');
|
|
20
|
+
super(`Exports present assertion failed: ${violations.length} missing export(s)\n${details}`);
|
|
21
|
+
this.name = 'ExportsPresentAssertionError';
|
|
22
|
+
this.violations = violations;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Validate that all expected export names are present in the found exports list.
|
|
27
|
+
*
|
|
28
|
+
* This is a pure, synchronous function: no I/O, no side effects, deterministic.
|
|
29
|
+
*
|
|
30
|
+
* @param file - The file being checked (for error messages)
|
|
31
|
+
* @param expectedExports - Names that must be exported
|
|
32
|
+
* @param foundExports - Names that were actually found as exports
|
|
33
|
+
* @throws {ExportsPresentAssertionError} if any expected export is missing
|
|
34
|
+
*/
|
|
35
|
+
export function validateExportsPresent(file, expectedExports, foundExports) {
|
|
36
|
+
const foundSet = new Set(foundExports);
|
|
37
|
+
const violations = [];
|
|
38
|
+
for (const name of expectedExports) {
|
|
39
|
+
if (!foundSet.has(name)) {
|
|
40
|
+
violations.push({ name, file });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (violations.length > 0) {
|
|
44
|
+
throw new ExportsPresentAssertionError(violations);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=exports-present.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports-present.js","sourceRoot":"","sources":["../../../src/core/assertions/exports-present.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAYH;;GAEG;AACH,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IACrC,UAAU,CAA4B;IAEtD,YAAY,UAAqC;QAC/C,MAAM,OAAO,GAAG,UAAU;aACvB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,sBAAsB,CAAC,CAAC,IAAI,GAAG,CAAC;aACtD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,KAAK,CACH,qCAAqC,UAAU,CAAC,MAAM,uBAAuB,OAAO,EAAE,CACvF,CAAC;QAEF,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;QAC3C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAY,EACZ,eAAyB,EACzB,YAAsB;IAEtB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACvC,MAAM,UAAU,GAA8B,EAAE,CAAC;IAEjD,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,4BAA4B,CAAC,UAAU,CAAC,CAAC;IACrD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validateFileExists — Pure assertion that validates file existence results.
|
|
3
|
+
*
|
|
4
|
+
* Invariants enforced:
|
|
5
|
+
* - INV-TEST-1 (assertion-logic-pure): No I/O imports. Operates on pre-resolved data.
|
|
6
|
+
* - INV-TEST-2 (fail-fast): Throws on violation (collects all before throwing for better diagnostics).
|
|
7
|
+
* - INV-TEST-6 (always-async): Public API is async; pure validators are sync.
|
|
8
|
+
* - INV-TEST-7 (composable): No module-level mutable state.
|
|
9
|
+
*
|
|
10
|
+
* This module must NEVER import fs, http, process, or any I/O module.
|
|
11
|
+
* File existence checking is handled by the resolver layer (core/resolvers/).
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* A single file existence check result fed by the resolver layer.
|
|
15
|
+
*/
|
|
16
|
+
export interface FileExistsEntry {
|
|
17
|
+
/** Path of the file that was checked */
|
|
18
|
+
file: string;
|
|
19
|
+
/** Whether the file exists */
|
|
20
|
+
exists: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A violation: a file that was expected to exist but doesn't.
|
|
24
|
+
*/
|
|
25
|
+
export interface FileExistsViolation {
|
|
26
|
+
/** Path of the missing file */
|
|
27
|
+
file: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Error thrown when a file-exists assertion fails.
|
|
31
|
+
* Contains structured violation data for programmatic access.
|
|
32
|
+
*/
|
|
33
|
+
export declare class FileExistsAssertionError extends Error {
|
|
34
|
+
readonly violations: FileExistsViolation[];
|
|
35
|
+
constructor(violations: FileExistsViolation[]);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validate that all checked files exist.
|
|
39
|
+
*
|
|
40
|
+
* This is a pure, synchronous function: no I/O, no side effects, deterministic.
|
|
41
|
+
*
|
|
42
|
+
* @throws {FileExistsAssertionError} if any file does not exist (INV-TEST-2: fail-fast)
|
|
43
|
+
*/
|
|
44
|
+
export declare function validateFileExists(entries: FileExistsEntry[]): void;
|
|
45
|
+
//# sourceMappingURL=file-exists.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-exists.d.ts","sourceRoot":"","sources":["../../../src/core/assertions/file-exists.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,SAAgB,UAAU,EAAE,mBAAmB,EAAE,CAAC;gBAEtC,UAAU,EAAE,mBAAmB,EAAE;CAY9C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAYnE"}
|