@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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/dist/adapters/vitest.d.ts +49 -0
  4. package/dist/adapters/vitest.d.ts.map +1 -0
  5. package/dist/adapters/vitest.js +60 -0
  6. package/dist/adapters/vitest.js.map +1 -0
  7. package/dist/core/assert-custom.d.ts +43 -0
  8. package/dist/core/assert-custom.d.ts.map +1 -0
  9. package/dist/core/assert-custom.js +48 -0
  10. package/dist/core/assert-custom.js.map +1 -0
  11. package/dist/core/assert-exports-present.d.ts +52 -0
  12. package/dist/core/assert-exports-present.d.ts.map +1 -0
  13. package/dist/core/assert-exports-present.js +125 -0
  14. package/dist/core/assert-exports-present.js.map +1 -0
  15. package/dist/core/assert-file-exists.d.ts +41 -0
  16. package/dist/core/assert-file-exists.d.ts.map +1 -0
  17. package/dist/core/assert-file-exists.js +52 -0
  18. package/dist/core/assert-file-exists.js.map +1 -0
  19. package/dist/core/assert-max-value.d.ts +79 -0
  20. package/dist/core/assert-max-value.d.ts.map +1 -0
  21. package/dist/core/assert-max-value.js +90 -0
  22. package/dist/core/assert-max-value.js.map +1 -0
  23. package/dist/core/assert-naming-convention.d.ts +61 -0
  24. package/dist/core/assert-naming-convention.d.ts.map +1 -0
  25. package/dist/core/assert-naming-convention.js +92 -0
  26. package/dist/core/assert-naming-convention.js.map +1 -0
  27. package/dist/core/assert-no-side-effects.d.ts +55 -0
  28. package/dist/core/assert-no-side-effects.d.ts.map +1 -0
  29. package/dist/core/assert-no-side-effects.js +72 -0
  30. package/dist/core/assert-no-side-effects.js.map +1 -0
  31. package/dist/core/assertions/exports-present.d.ts +38 -0
  32. package/dist/core/assertions/exports-present.d.ts.map +1 -0
  33. package/dist/core/assertions/exports-present.js +47 -0
  34. package/dist/core/assertions/exports-present.js.map +1 -0
  35. package/dist/core/assertions/file-exists.d.ts +45 -0
  36. package/dist/core/assertions/file-exists.d.ts.map +1 -0
  37. package/dist/core/assertions/file-exists.js +46 -0
  38. package/dist/core/assertions/file-exists.js.map +1 -0
  39. package/dist/core/assertions/max-value.d.ts +77 -0
  40. package/dist/core/assertions/max-value.d.ts.map +1 -0
  41. package/dist/core/assertions/max-value.js +60 -0
  42. package/dist/core/assertions/max-value.js.map +1 -0
  43. package/dist/core/assertions/naming-convention.d.ts +51 -0
  44. package/dist/core/assertions/naming-convention.d.ts.map +1 -0
  45. package/dist/core/assertions/naming-convention.js +73 -0
  46. package/dist/core/assertions/naming-convention.js.map +1 -0
  47. package/dist/core/assertions/no-side-effects.d.ts +47 -0
  48. package/dist/core/assertions/no-side-effects.d.ts.map +1 -0
  49. package/dist/core/assertions/no-side-effects.js +70 -0
  50. package/dist/core/assertions/no-side-effects.js.map +1 -0
  51. package/dist/core/invariant-test.d.ts +128 -0
  52. package/dist/core/invariant-test.d.ts.map +1 -0
  53. package/dist/core/invariant-test.js +174 -0
  54. package/dist/core/invariant-test.js.map +1 -0
  55. package/dist/core/resolvers/file-resolver.d.ts +92 -0
  56. package/dist/core/resolvers/file-resolver.d.ts.map +1 -0
  57. package/dist/core/resolvers/file-resolver.js +103 -0
  58. package/dist/core/resolvers/file-resolver.js.map +1 -0
  59. package/dist/core/resolvers/import-resolver.d.ts +55 -0
  60. package/dist/core/resolvers/import-resolver.d.ts.map +1 -0
  61. package/dist/core/resolvers/import-resolver.js +99 -0
  62. package/dist/core/resolvers/import-resolver.js.map +1 -0
  63. package/dist/core/resolvers/node-fs.d.ts +13 -0
  64. package/dist/core/resolvers/node-fs.d.ts.map +1 -0
  65. package/dist/core/resolvers/node-fs.js +32 -0
  66. package/dist/core/resolvers/node-fs.js.map +1 -0
  67. package/dist/core/resolvers/parallel-reader.d.ts +35 -0
  68. package/dist/core/resolvers/parallel-reader.d.ts.map +1 -0
  69. package/dist/core/resolvers/parallel-reader.js +56 -0
  70. package/dist/core/resolvers/parallel-reader.js.map +1 -0
  71. package/dist/core/resolvers/string-resolver.d.ts +66 -0
  72. package/dist/core/resolvers/string-resolver.d.ts.map +1 -0
  73. package/dist/core/resolvers/string-resolver.js +127 -0
  74. package/dist/core/resolvers/string-resolver.js.map +1 -0
  75. package/dist/core/resolvers/types.d.ts +16 -0
  76. package/dist/core/resolvers/types.d.ts.map +1 -0
  77. package/dist/core/resolvers/types.js +10 -0
  78. package/dist/core/resolvers/types.js.map +1 -0
  79. package/dist/index.d.ts +40 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +50 -0
  82. package/dist/index.js.map +1 -0
  83. package/package.json +67 -0
@@ -0,0 +1,174 @@
1
+ /**
2
+ * testInvariant — Wrapper that links tests to invariant IDs.
3
+ *
4
+ * Invariants enforced:
5
+ * - INV-TEST-3 (invariant-id-required): Every test must link to an invariant ID.
6
+ * - INV-TEST-4 (framework-agnostic-core): Core logic has zero test-framework deps.
7
+ * - INV-TEST-6 (always-async): Test function is always async.
8
+ * - INV-TEST-7 (composable): No module-level mutable state that affects test outcomes.
9
+ *
10
+ * Design:
11
+ * - The metadata registry is a read-only record of test registrations.
12
+ * It stores what tests were registered but does not affect test execution.
13
+ * Tests execute identically regardless of registry state (INV-TEST-7).
14
+ * - The wrapper delegates to a configurable test runner function.
15
+ * By default, it uses a pass-through runner that just calls the test function.
16
+ * Adapters (e.g., vitest.ts) provide framework-specific runners.
17
+ */
18
+ // ---------------------------------------------------------------------------
19
+ // Validation
20
+ // ---------------------------------------------------------------------------
21
+ /**
22
+ * Error thrown when testInvariant is called with invalid arguments.
23
+ */
24
+ export class InvariantTestError extends Error {
25
+ constructor(message) {
26
+ super(message);
27
+ this.name = 'InvariantTestError';
28
+ }
29
+ }
30
+ /**
31
+ * Validate an invariant ID format.
32
+ *
33
+ * Valid format: PREFIX-WORD-NUMBER (e.g., "INV-CACHE-1", "INV-TEST-42")
34
+ * Must be non-empty and follow the ID convention.
35
+ */
36
+ export function validateInvariantId(id) {
37
+ if (!id || typeof id !== 'string') {
38
+ throw new InvariantTestError('Invariant ID is required. Provide a non-empty string (e.g., "INV-CACHE-1").');
39
+ }
40
+ const trimmed = id.trim();
41
+ if (trimmed.length === 0) {
42
+ throw new InvariantTestError('Invariant ID must not be empty or whitespace-only.');
43
+ }
44
+ if (trimmed !== id) {
45
+ throw new InvariantTestError(`Invariant ID "${id}" contains leading or trailing whitespace. Use "${trimmed}" instead.`);
46
+ }
47
+ }
48
+ /**
49
+ * Validate a test description.
50
+ */
51
+ export function validateDescription(description) {
52
+ if (!description || typeof description !== 'string') {
53
+ throw new InvariantTestError('Test description is required. Provide a non-empty string describing what the test verifies.');
54
+ }
55
+ const trimmed = description.trim();
56
+ if (trimmed.length === 0) {
57
+ throw new InvariantTestError('Test description must not be empty or whitespace-only.');
58
+ }
59
+ }
60
+ /**
61
+ * Validate a test function.
62
+ */
63
+ export function validateTestFn(testFn) {
64
+ if (typeof testFn !== 'function') {
65
+ throw new InvariantTestError(`Test function is required. Got ${typeof testFn} instead of a function.`);
66
+ }
67
+ }
68
+ /**
69
+ * Create a new empty registry instance.
70
+ */
71
+ export function createRegistry() {
72
+ const entries = [];
73
+ return {
74
+ register(metadata) {
75
+ entries.push({ ...metadata });
76
+ },
77
+ getAll() {
78
+ return entries.map((e) => ({ ...e }));
79
+ },
80
+ has(invariantId) {
81
+ return entries.some((e) => e.invariantId === invariantId);
82
+ },
83
+ size() {
84
+ return entries.length;
85
+ },
86
+ coveredCount() {
87
+ return new Set(entries.map((e) => e.invariantId)).size;
88
+ },
89
+ clear() {
90
+ entries.length = 0;
91
+ },
92
+ };
93
+ }
94
+ // ---------------------------------------------------------------------------
95
+ // Default registry (module-scoped singleton for convenience)
96
+ // ---------------------------------------------------------------------------
97
+ /**
98
+ * The default global registry. Used by testInvariant() when no custom
99
+ * registry is provided. Can be accessed via getDefaultRegistry() for
100
+ * coverage reporting.
101
+ */
102
+ const defaultRegistry = createRegistry();
103
+ /**
104
+ * Get the default global registry for coverage reporting.
105
+ */
106
+ export function getDefaultRegistry() {
107
+ return defaultRegistry;
108
+ }
109
+ // ---------------------------------------------------------------------------
110
+ // Core: testInvariant()
111
+ // ---------------------------------------------------------------------------
112
+ /**
113
+ * Default test runner: executes the async test function directly.
114
+ * Used when no framework-specific adapter is configured.
115
+ * Framework adapters (vitest, jest) replace this with their own `it()`/`test()` wrapper.
116
+ *
117
+ * Since TestRunner is synchronous (for framework compatibility) but testFn is async,
118
+ * failures surface as unhandled promise rejections. In Node.js 15+, unhandled
119
+ * rejections crash the process with a clear error. A .catch() handler wraps the
120
+ * error with the test name for better diagnostics.
121
+ */
122
+ const defaultRunner = (testName, testFn, _metadata) => {
123
+ testFn().catch((err) => {
124
+ const wrapped = err instanceof Error
125
+ ? err
126
+ : new Error(String(err));
127
+ wrapped.message = `[${testName}] ${wrapped.message}`;
128
+ // Re-throw as unhandled rejection so Node.js exits non-zero
129
+ queueMicrotask(() => { throw wrapped; });
130
+ });
131
+ };
132
+ /**
133
+ * Register and declare an invariant test.
134
+ *
135
+ * This is the primary API for linking tests to invariant IDs (INV-TEST-3).
136
+ *
137
+ * Usage:
138
+ * ```typescript
139
+ * testInvariant('INV-CACHE-1', 'cache TTL max 24h', async () => {
140
+ * await assertMaxValue({ ... });
141
+ * });
142
+ * ```
143
+ *
144
+ * What it does:
145
+ * 1. Validates inputs (invariant ID, description, test function)
146
+ * 2. Registers the test in the metadata registry (for coverage tracking)
147
+ * 3. Delegates to the configured test runner (framework adapter)
148
+ *
149
+ * @param invariantId - The invariant ID this test verifies (e.g., "INV-CACHE-1")
150
+ * @param description - Human-readable description of what the test checks
151
+ * @param testFn - Async function that performs assertions
152
+ * @param options - Optional configuration (custom runner, custom registry)
153
+ *
154
+ * @throws {InvariantTestError} if inputs are invalid
155
+ */
156
+ export function testInvariant(invariantId, description, testFn, options) {
157
+ // 1. Validate inputs (INV-TEST-2: fail-fast on bad input)
158
+ validateInvariantId(invariantId);
159
+ validateDescription(description);
160
+ validateTestFn(testFn);
161
+ // 2. Build metadata
162
+ const metadata = {
163
+ invariantId,
164
+ description,
165
+ };
166
+ // 3. Register in the registry (for coverage tracking)
167
+ const registry = options?.registry ?? defaultRegistry;
168
+ registry.register(metadata);
169
+ // 4. Delegate to test runner
170
+ const runner = options?.runner ?? defaultRunner;
171
+ const testName = `[${invariantId}] ${description}`;
172
+ runner(testName, testFn, metadata);
173
+ }
174
+ //# sourceMappingURL=invariant-test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariant-test.js","sourceRoot":"","sources":["../../src/core/invariant-test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * File resolver — I/O layer that reads files and feeds data to pure assertions.
3
+ *
4
+ * This module handles all file system interactions for assertions.
5
+ * It expands globs, reads file contents, and extracts pattern matches
6
+ * that are then validated by pure assertion functions in core/assertions/.
7
+ *
8
+ * Design:
9
+ * - Depends on FileSystem interface (mockable for tests)
10
+ * - Returns structured data, never throws on I/O errors (wraps them)
11
+ * - Assertions receive pre-resolved data, never file paths
12
+ */
13
+ import type { FileSystem } from './types.js';
14
+ /**
15
+ * A single match found in a file by the resolver.
16
+ */
17
+ export interface FileMatch {
18
+ /** Path of the file where the match was found */
19
+ file: string;
20
+ /** The line number (1-based) where the match occurred */
21
+ line: number;
22
+ /** The full line of text containing the match */
23
+ lineText: string;
24
+ /** The raw matched string from the capturing group */
25
+ rawMatch: string;
26
+ }
27
+ /**
28
+ * A numeric value extracted from a file by pattern matching.
29
+ */
30
+ export interface ExtractedValue {
31
+ /** Path of the file where the value was found */
32
+ file: string;
33
+ /** The line number (1-based) where the value was found */
34
+ line: number;
35
+ /** The full line of text containing the value */
36
+ lineText: string;
37
+ /** The extracted numeric value */
38
+ value: number;
39
+ /** The raw string that was parsed as a number */
40
+ rawValue: string;
41
+ }
42
+ /**
43
+ * Result of resolving files and extracting numeric values by pattern.
44
+ */
45
+ export interface ResolvedValues {
46
+ /** Successfully extracted numeric values */
47
+ values: ExtractedValue[];
48
+ /** Files that were resolved and read */
49
+ filesRead: string[];
50
+ /** Errors encountered during resolution (e.g., file not found) */
51
+ errors: ResolverError[];
52
+ }
53
+ /**
54
+ * An error encountered during file resolution.
55
+ */
56
+ export interface ResolverError {
57
+ file: string;
58
+ message: string;
59
+ }
60
+ /**
61
+ * Options for resolving numeric values from files.
62
+ */
63
+ export interface ResolveValuesOptions {
64
+ /** File paths or glob patterns to scan */
65
+ files: string[];
66
+ /** Regex pattern with at least one capturing group for the numeric value */
67
+ pattern: RegExp;
68
+ /** Working directory for glob resolution */
69
+ cwd?: string;
70
+ }
71
+ /**
72
+ * Expand glob patterns to concrete file paths.
73
+ *
74
+ * Non-glob paths (no * or ? characters) are returned as-is.
75
+ */
76
+ export declare function expandGlobs(files: string[], fs: FileSystem, cwd?: string): Promise<{
77
+ paths: string[];
78
+ errors: ResolverError[];
79
+ }>;
80
+ /**
81
+ * Resolve files and extract numeric values matching a pattern.
82
+ *
83
+ * This function:
84
+ * 1. Expands glob patterns to concrete file paths
85
+ * 2. Reads each file
86
+ * 3. Scans each line for the regex pattern
87
+ * 4. Extracts numeric values from the first capturing group
88
+ *
89
+ * Non-numeric captures are reported as errors rather than silently skipped.
90
+ */
91
+ export declare function resolveValues(options: ResolveValuesOptions, fs: FileSystem): Promise<ResolvedValues>;
92
+ //# sourceMappingURL=file-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-resolver.d.ts","sourceRoot":"","sources":["../../../src/core/resolvers/file-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,wCAAwC;IACxC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kEAAkE;IAClE,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,0CAA0C;IAC1C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,EAAE,EAAE,UAAU,EACd,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,CAAC,CAqBvD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,oBAAoB,EAC7B,EAAE,EAAE,UAAU,GACb,OAAO,CAAC,cAAc,CAAC,CA0DzB"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * File resolver — I/O layer that reads files and feeds data to pure assertions.
3
+ *
4
+ * This module handles all file system interactions for assertions.
5
+ * It expands globs, reads file contents, and extracts pattern matches
6
+ * that are then validated by pure assertion functions in core/assertions/.
7
+ *
8
+ * Design:
9
+ * - Depends on FileSystem interface (mockable for tests)
10
+ * - Returns structured data, never throws on I/O errors (wraps them)
11
+ * - Assertions receive pre-resolved data, never file paths
12
+ */
13
+ import { join } from 'node:path';
14
+ import { readFilesParallel } from './parallel-reader.js';
15
+ /**
16
+ * Expand glob patterns to concrete file paths.
17
+ *
18
+ * Non-glob paths (no * or ? characters) are returned as-is.
19
+ */
20
+ export async function expandGlobs(files, fs, cwd) {
21
+ const paths = [];
22
+ const errors = [];
23
+ for (const file of files) {
24
+ if (file.includes('*') || file.includes('?')) {
25
+ try {
26
+ const expanded = await fs.glob(file, cwd ? { cwd } : undefined);
27
+ paths.push(...expanded);
28
+ }
29
+ catch (err) {
30
+ errors.push({
31
+ file,
32
+ message: `Failed to expand glob: ${err instanceof Error ? err.message : String(err)}`,
33
+ });
34
+ }
35
+ }
36
+ else {
37
+ paths.push(file);
38
+ }
39
+ }
40
+ return { paths, errors };
41
+ }
42
+ /**
43
+ * Resolve files and extract numeric values matching a pattern.
44
+ *
45
+ * This function:
46
+ * 1. Expands glob patterns to concrete file paths
47
+ * 2. Reads each file
48
+ * 3. Scans each line for the regex pattern
49
+ * 4. Extracts numeric values from the first capturing group
50
+ *
51
+ * Non-numeric captures are reported as errors rather than silently skipped.
52
+ */
53
+ export async function resolveValues(options, fs) {
54
+ const { files, pattern, cwd } = options;
55
+ const { paths, errors } = await expandGlobs(files, fs, cwd);
56
+ const values = [];
57
+ const filesRead = [];
58
+ // Build read paths (prepend cwd when set)
59
+ const readPaths = paths.map((p) => cwd ? join(cwd, p) : p);
60
+ // Read all files in parallel with concurrency control
61
+ const readResults = await readFilesParallel(readPaths, fs);
62
+ for (let idx = 0; idx < readResults.length; idx++) {
63
+ const result = readResults[idx];
64
+ const filePath = paths[idx];
65
+ if (result.error) {
66
+ errors.push({
67
+ file: filePath,
68
+ message: `Failed to read file: ${result.error}`,
69
+ });
70
+ continue;
71
+ }
72
+ filesRead.push(filePath);
73
+ const content = result.content;
74
+ const lines = content.split('\n');
75
+ for (let i = 0; i < lines.length; i++) {
76
+ const lineText = lines[i];
77
+ // Reset regex state for global patterns
78
+ const localPattern = new RegExp(pattern.source, pattern.flags.replace('g', ''));
79
+ const match = localPattern.exec(lineText);
80
+ if (match && match[1] !== undefined) {
81
+ const rawValue = match[1];
82
+ const parsed = Number(rawValue);
83
+ if (Number.isNaN(parsed)) {
84
+ errors.push({
85
+ file: filePath,
86
+ message: `Line ${i + 1}: Captured "${rawValue}" is not a valid number`,
87
+ });
88
+ }
89
+ else {
90
+ values.push({
91
+ file: filePath,
92
+ line: i + 1,
93
+ lineText,
94
+ value: parsed,
95
+ rawValue,
96
+ });
97
+ }
98
+ }
99
+ }
100
+ }
101
+ return { values, filesRead, errors };
102
+ }
103
+ //# sourceMappingURL=file-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-resolver.js","sourceRoot":"","sources":["../../../src/core/resolvers/file-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Import resolver — scans files for import/require statements.
3
+ *
4
+ * Extracts structured import data from TypeScript/JavaScript files.
5
+ * Used by assertNoSideEffects to check for forbidden module imports.
6
+ *
7
+ * Design:
8
+ * - Depends on FileSystem interface (mockable for tests)
9
+ * - Returns structured data for pure assertion validation
10
+ */
11
+ import type { FileSystem } from './types.js';
12
+ /**
13
+ * A single import/require match found in a file.
14
+ */
15
+ export interface ImportMatch {
16
+ /** Path of the file containing the import */
17
+ file: string;
18
+ /** The line number (1-based) where the import was found */
19
+ line: number;
20
+ /** The full line of text containing the import */
21
+ lineText: string;
22
+ /** The module specifier (e.g., 'fs', 'node:http', './utils') */
23
+ module: string;
24
+ }
25
+ /**
26
+ * Extract all import/require module specifiers from a file's content.
27
+ *
28
+ * This is a pure function — no I/O. Takes content string, returns matches.
29
+ */
30
+ export declare function extractImports(file: string, content: string): ImportMatch[];
31
+ /**
32
+ * Result of resolving imports across multiple files.
33
+ */
34
+ export interface ResolvedImports {
35
+ /** All import matches found across files */
36
+ imports: ImportMatch[];
37
+ /** Files that were successfully read */
38
+ filesRead: string[];
39
+ /** Errors encountered during resolution */
40
+ errors: Array<{
41
+ file: string;
42
+ message: string;
43
+ }>;
44
+ }
45
+ /**
46
+ * Resolve imports from files matching glob patterns.
47
+ *
48
+ * Expands globs, reads files, and extracts all imports.
49
+ */
50
+ export declare function resolveImports(options: {
51
+ files: string[];
52
+ cwd?: string;
53
+ fs: FileSystem;
54
+ }): Promise<ResolvedImports>;
55
+ //# sourceMappingURL=import-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-resolver.d.ts","sourceRoot":"","sources":["../../../src/core/resolvers/import-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;CAChB;AAiBD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,WAAW,EAAE,CAsBf;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,wCAAwC;IACxC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,2CAA2C;IAC3C,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClD;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,UAAU,CAAC;CAChB,GAAG,OAAO,CAAC,eAAe,CAAC,CA0C3B"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Import resolver — scans files for import/require statements.
3
+ *
4
+ * Extracts structured import data from TypeScript/JavaScript files.
5
+ * Used by assertNoSideEffects to check for forbidden module imports.
6
+ *
7
+ * Design:
8
+ * - Depends on FileSystem interface (mockable for tests)
9
+ * - Returns structured data for pure assertion validation
10
+ */
11
+ import { join } from 'node:path';
12
+ /**
13
+ * Patterns to match import/require statements.
14
+ * Captures the module specifier from:
15
+ * - import ... from 'module'
16
+ * - import 'module'
17
+ * - require('module')
18
+ * - import('module') (dynamic import)
19
+ */
20
+ const IMPORT_PATTERNS = [
21
+ /import\s+.*?\s+from\s+['"]([^'"]+)['"]/,
22
+ /import\s+['"]([^'"]+)['"]/,
23
+ /require\(\s*['"]([^'"]+)['"]\s*\)/,
24
+ /import\(\s*['"]([^'"]+)['"]\s*\)/,
25
+ ];
26
+ /**
27
+ * Extract all import/require module specifiers from a file's content.
28
+ *
29
+ * This is a pure function — no I/O. Takes content string, returns matches.
30
+ */
31
+ export function extractImports(file, content) {
32
+ const matches = [];
33
+ const lines = content.split('\n');
34
+ for (let i = 0; i < lines.length; i++) {
35
+ const lineText = lines[i];
36
+ for (const pattern of IMPORT_PATTERNS) {
37
+ const match = pattern.exec(lineText);
38
+ if (match && match[1]) {
39
+ matches.push({
40
+ file,
41
+ line: i + 1,
42
+ lineText,
43
+ module: match[1],
44
+ });
45
+ break; // One match per line is sufficient
46
+ }
47
+ }
48
+ }
49
+ return matches;
50
+ }
51
+ /**
52
+ * Resolve imports from files matching glob patterns.
53
+ *
54
+ * Expands globs, reads files, and extracts all imports.
55
+ */
56
+ export async function resolveImports(options) {
57
+ const { files, cwd, fs } = options;
58
+ const imports = [];
59
+ const filesRead = [];
60
+ const errors = [];
61
+ // Expand globs
62
+ const expandedPaths = [];
63
+ for (const file of files) {
64
+ if (file.includes('*') || file.includes('?')) {
65
+ try {
66
+ const expanded = await fs.glob(file, cwd ? { cwd } : undefined);
67
+ expandedPaths.push(...expanded);
68
+ }
69
+ catch (err) {
70
+ errors.push({
71
+ file,
72
+ message: `Failed to expand glob: ${err instanceof Error ? err.message : String(err)}`,
73
+ });
74
+ }
75
+ }
76
+ else {
77
+ expandedPaths.push(file);
78
+ }
79
+ }
80
+ // Read files and extract imports
81
+ for (const filePath of expandedPaths) {
82
+ const readPath = cwd ? join(cwd, filePath) : filePath;
83
+ let content;
84
+ try {
85
+ content = await fs.readFile(readPath);
86
+ }
87
+ catch (err) {
88
+ errors.push({
89
+ file: filePath,
90
+ message: `Failed to read file: ${err instanceof Error ? err.message : String(err)}`,
91
+ });
92
+ continue;
93
+ }
94
+ filesRead.push(filePath);
95
+ imports.push(...extractImports(filePath, content));
96
+ }
97
+ return { imports, filesRead, errors };
98
+ }
99
+ //# sourceMappingURL=import-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-resolver.js","sourceRoot":"","sources":["../../../src/core/resolvers/import-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Default Node.js FileSystem implementation.
3
+ *
4
+ * Uses node:fs/promises for file reading and fast-glob for glob expansion.
5
+ * This is the default filesystem used by assertMaxValue when no custom
6
+ * FileSystem is provided.
7
+ */
8
+ import type { FileSystem } from './types.js';
9
+ /**
10
+ * Create a FileSystem backed by Node.js built-in modules + fast-glob.
11
+ */
12
+ export declare function createNodeFileSystem(): FileSystem;
13
+ //# sourceMappingURL=node-fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-fs.d.ts","sourceRoot":"","sources":["../../../src/core/resolvers/node-fs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,CAmBjD"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Default Node.js FileSystem implementation.
3
+ *
4
+ * Uses node:fs/promises for file reading and fast-glob for glob expansion.
5
+ * This is the default filesystem used by assertMaxValue when no custom
6
+ * FileSystem is provided.
7
+ */
8
+ import { readFile, access } from 'node:fs/promises';
9
+ import fg from 'fast-glob';
10
+ /**
11
+ * Create a FileSystem backed by Node.js built-in modules + fast-glob.
12
+ */
13
+ export function createNodeFileSystem() {
14
+ return {
15
+ async readFile(path) {
16
+ return readFile(path, 'utf-8');
17
+ },
18
+ async glob(pattern, options) {
19
+ return fg(pattern, { cwd: options?.cwd });
20
+ },
21
+ async exists(path) {
22
+ try {
23
+ await access(path);
24
+ return true;
25
+ }
26
+ catch {
27
+ return false;
28
+ }
29
+ },
30
+ };
31
+ }
32
+ //# sourceMappingURL=node-fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-fs.js","sourceRoot":"","sources":["../../../src/core/resolvers/node-fs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,MAAM,WAAW,CAAC;AAG3B;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,IAAY;YACzB,OAAO,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACjC,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,OAAe,EAAE,OAA0B;YACpD,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5C,CAAC;QAED,KAAK,CAAC,MAAM,CAAC,IAAY;YACvB,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;gBACnB,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Parallel reader — batched file reading with concurrency control.
3
+ *
4
+ * Provides a shared utility for reading multiple files in parallel
5
+ * using Promise.allSettled with a configurable concurrency limit
6
+ * to avoid file descriptor exhaustion.
7
+ *
8
+ * Used by file-resolver.ts and other resolvers for efficient I/O.
9
+ */
10
+ import type { FileSystem } from './types.js';
11
+ /**
12
+ * Result of reading a single file.
13
+ */
14
+ export interface FileReadResult {
15
+ /** The file path that was read */
16
+ path: string;
17
+ /** The file content (undefined if reading failed) */
18
+ content?: string;
19
+ /** Error message if reading failed */
20
+ error?: string;
21
+ }
22
+ /**
23
+ * Read multiple files in parallel with concurrency control.
24
+ *
25
+ * Uses Promise.allSettled to ensure all reads complete (or fail)
26
+ * without aborting on the first error. Files are processed in
27
+ * batches to avoid exhausting file descriptors.
28
+ *
29
+ * @param paths - File paths to read
30
+ * @param fs - FileSystem implementation
31
+ * @param concurrency - Maximum number of concurrent reads (default: 50)
32
+ * @returns Results for each file (success or error)
33
+ */
34
+ export declare function readFilesParallel(paths: string[], fs: FileSystem, concurrency?: number): Promise<FileReadResult[]>;
35
+ //# sourceMappingURL=parallel-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parallel-reader.d.ts","sourceRoot":"","sources":["../../../src/core/resolvers/parallel-reader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO7C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EAAE,EACf,EAAE,EAAE,UAAU,EACd,WAAW,GAAE,MAA4B,GACxC,OAAO,CAAC,cAAc,EAAE,CAAC,CAkC3B"}