@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,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"}