@lumenflow/core 1.0.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 +190 -0
- package/README.md +119 -0
- package/dist/active-wu-detector.d.ts +33 -0
- package/dist/active-wu-detector.js +106 -0
- package/dist/adapters/filesystem-metrics.adapter.d.ts +108 -0
- package/dist/adapters/filesystem-metrics.adapter.js +519 -0
- package/dist/adapters/terminal-renderer.adapter.d.ts +106 -0
- package/dist/adapters/terminal-renderer.adapter.js +337 -0
- package/dist/arg-parser.d.ts +63 -0
- package/dist/arg-parser.js +560 -0
- package/dist/backlog-editor.d.ts +98 -0
- package/dist/backlog-editor.js +179 -0
- package/dist/backlog-generator.d.ts +111 -0
- package/dist/backlog-generator.js +381 -0
- package/dist/backlog-parser.d.ts +45 -0
- package/dist/backlog-parser.js +102 -0
- package/dist/backlog-sync-validator.d.ts +78 -0
- package/dist/backlog-sync-validator.js +294 -0
- package/dist/branch-drift.d.ts +34 -0
- package/dist/branch-drift.js +51 -0
- package/dist/cleanup-install-config.d.ts +33 -0
- package/dist/cleanup-install-config.js +37 -0
- package/dist/cleanup-lock.d.ts +139 -0
- package/dist/cleanup-lock.js +313 -0
- package/dist/code-path-validator.d.ts +146 -0
- package/dist/code-path-validator.js +537 -0
- package/dist/code-paths-overlap.d.ts +55 -0
- package/dist/code-paths-overlap.js +245 -0
- package/dist/commands-logger.d.ts +77 -0
- package/dist/commands-logger.js +254 -0
- package/dist/commit-message-utils.d.ts +25 -0
- package/dist/commit-message-utils.js +41 -0
- package/dist/compliance-parser.d.ts +150 -0
- package/dist/compliance-parser.js +507 -0
- package/dist/constants/backlog-patterns.d.ts +20 -0
- package/dist/constants/backlog-patterns.js +23 -0
- package/dist/constants/dora-constants.d.ts +49 -0
- package/dist/constants/dora-constants.js +53 -0
- package/dist/constants/gate-constants.d.ts +15 -0
- package/dist/constants/gate-constants.js +15 -0
- package/dist/constants/linter-constants.d.ts +16 -0
- package/dist/constants/linter-constants.js +16 -0
- package/dist/constants/tokenizer-constants.d.ts +15 -0
- package/dist/constants/tokenizer-constants.js +15 -0
- package/dist/core/scope-checker.d.ts +97 -0
- package/dist/core/scope-checker.js +163 -0
- package/dist/core/tool-runner.d.ts +161 -0
- package/dist/core/tool-runner.js +393 -0
- package/dist/core/tool.constants.d.ts +105 -0
- package/dist/core/tool.constants.js +101 -0
- package/dist/core/tool.schemas.d.ts +226 -0
- package/dist/core/tool.schemas.js +226 -0
- package/dist/core/worktree-guard.d.ts +130 -0
- package/dist/core/worktree-guard.js +242 -0
- package/dist/coverage-gate.d.ts +108 -0
- package/dist/coverage-gate.js +196 -0
- package/dist/date-utils.d.ts +75 -0
- package/dist/date-utils.js +140 -0
- package/dist/dependency-graph.d.ts +142 -0
- package/dist/dependency-graph.js +550 -0
- package/dist/dependency-guard.d.ts +54 -0
- package/dist/dependency-guard.js +142 -0
- package/dist/dependency-validator.d.ts +105 -0
- package/dist/dependency-validator.js +154 -0
- package/dist/docs-path-validator.d.ts +36 -0
- package/dist/docs-path-validator.js +95 -0
- package/dist/domain/orchestration.constants.d.ts +99 -0
- package/dist/domain/orchestration.constants.js +97 -0
- package/dist/domain/orchestration.schemas.d.ts +280 -0
- package/dist/domain/orchestration.schemas.js +211 -0
- package/dist/domain/orchestration.types.d.ts +133 -0
- package/dist/domain/orchestration.types.js +12 -0
- package/dist/error-handler.d.ts +116 -0
- package/dist/error-handler.js +136 -0
- package/dist/file-classifiers.d.ts +62 -0
- package/dist/file-classifiers.js +108 -0
- package/dist/gates-agent-mode.d.ts +81 -0
- package/dist/gates-agent-mode.js +94 -0
- package/dist/generate-traceability.d.ts +107 -0
- package/dist/generate-traceability.js +411 -0
- package/dist/git-adapter.d.ts +395 -0
- package/dist/git-adapter.js +649 -0
- package/dist/git-staged-validator.d.ts +32 -0
- package/dist/git-staged-validator.js +48 -0
- package/dist/hardcoded-strings.d.ts +61 -0
- package/dist/hardcoded-strings.js +270 -0
- package/dist/incremental-lint.d.ts +78 -0
- package/dist/incremental-lint.js +129 -0
- package/dist/incremental-test.d.ts +39 -0
- package/dist/incremental-test.js +61 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +61 -0
- package/dist/invariants/check-automated-tests.d.ts +50 -0
- package/dist/invariants/check-automated-tests.js +166 -0
- package/dist/invariants-runner.d.ts +103 -0
- package/dist/invariants-runner.js +527 -0
- package/dist/lane-checker.d.ts +50 -0
- package/dist/lane-checker.js +319 -0
- package/dist/lane-inference.d.ts +39 -0
- package/dist/lane-inference.js +195 -0
- package/dist/lane-lock.d.ts +211 -0
- package/dist/lane-lock.js +474 -0
- package/dist/lane-validator.d.ts +48 -0
- package/dist/lane-validator.js +114 -0
- package/dist/logs-lib.d.ts +104 -0
- package/dist/logs-lib.js +207 -0
- package/dist/lumenflow-config-schema.d.ts +272 -0
- package/dist/lumenflow-config-schema.js +207 -0
- package/dist/lumenflow-config.d.ts +95 -0
- package/dist/lumenflow-config.js +236 -0
- package/dist/manual-test-validator.d.ts +80 -0
- package/dist/manual-test-validator.js +200 -0
- package/dist/merge-lock.d.ts +115 -0
- package/dist/merge-lock.js +251 -0
- package/dist/micro-worktree.d.ts +159 -0
- package/dist/micro-worktree.js +427 -0
- package/dist/migration-deployer.d.ts +69 -0
- package/dist/migration-deployer.js +151 -0
- package/dist/orchestration-advisory-loader.d.ts +28 -0
- package/dist/orchestration-advisory-loader.js +87 -0
- package/dist/orchestration-advisory.d.ts +58 -0
- package/dist/orchestration-advisory.js +94 -0
- package/dist/orchestration-di.d.ts +48 -0
- package/dist/orchestration-di.js +57 -0
- package/dist/orchestration-rules.d.ts +57 -0
- package/dist/orchestration-rules.js +201 -0
- package/dist/orphan-detector.d.ts +131 -0
- package/dist/orphan-detector.js +226 -0
- package/dist/path-classifiers.d.ts +57 -0
- package/dist/path-classifiers.js +93 -0
- package/dist/piped-command-detector.d.ts +34 -0
- package/dist/piped-command-detector.js +64 -0
- package/dist/ports/dashboard-renderer.port.d.ts +112 -0
- package/dist/ports/dashboard-renderer.port.js +25 -0
- package/dist/ports/metrics-collector.port.d.ts +132 -0
- package/dist/ports/metrics-collector.port.js +26 -0
- package/dist/process-detector.d.ts +84 -0
- package/dist/process-detector.js +172 -0
- package/dist/prompt-linter.d.ts +72 -0
- package/dist/prompt-linter.js +312 -0
- package/dist/prompt-monitor.d.ts +15 -0
- package/dist/prompt-monitor.js +205 -0
- package/dist/rebase-artifact-cleanup.d.ts +145 -0
- package/dist/rebase-artifact-cleanup.js +433 -0
- package/dist/retry-strategy.d.ts +189 -0
- package/dist/retry-strategy.js +283 -0
- package/dist/risk-detector.d.ts +108 -0
- package/dist/risk-detector.js +252 -0
- package/dist/rollback-utils.d.ts +76 -0
- package/dist/rollback-utils.js +104 -0
- package/dist/section-headings.d.ts +43 -0
- package/dist/section-headings.js +49 -0
- package/dist/spawn-escalation.d.ts +90 -0
- package/dist/spawn-escalation.js +253 -0
- package/dist/spawn-monitor.d.ts +229 -0
- package/dist/spawn-monitor.js +672 -0
- package/dist/spawn-recovery.d.ts +82 -0
- package/dist/spawn-recovery.js +298 -0
- package/dist/spawn-registry-schema.d.ts +98 -0
- package/dist/spawn-registry-schema.js +108 -0
- package/dist/spawn-registry-store.d.ts +146 -0
- package/dist/spawn-registry-store.js +273 -0
- package/dist/spawn-tree.d.ts +121 -0
- package/dist/spawn-tree.js +285 -0
- package/dist/stamp-status-validator.d.ts +84 -0
- package/dist/stamp-status-validator.js +134 -0
- package/dist/stamp-utils.d.ts +100 -0
- package/dist/stamp-utils.js +229 -0
- package/dist/state-machine.d.ts +26 -0
- package/dist/state-machine.js +83 -0
- package/dist/system-map-validator.d.ts +80 -0
- package/dist/system-map-validator.js +272 -0
- package/dist/telemetry.d.ts +80 -0
- package/dist/telemetry.js +213 -0
- package/dist/token-counter.d.ts +51 -0
- package/dist/token-counter.js +145 -0
- package/dist/usecases/get-dashboard-data.usecase.d.ts +52 -0
- package/dist/usecases/get-dashboard-data.usecase.js +61 -0
- package/dist/usecases/get-suggestions.usecase.d.ts +100 -0
- package/dist/usecases/get-suggestions.usecase.js +153 -0
- package/dist/user-normalizer.d.ts +41 -0
- package/dist/user-normalizer.js +141 -0
- package/dist/validators/phi-constants.d.ts +97 -0
- package/dist/validators/phi-constants.js +152 -0
- package/dist/validators/phi-scanner.d.ts +58 -0
- package/dist/validators/phi-scanner.js +215 -0
- package/dist/worktree-ownership.d.ts +50 -0
- package/dist/worktree-ownership.js +74 -0
- package/dist/worktree-scanner.d.ts +103 -0
- package/dist/worktree-scanner.js +168 -0
- package/dist/worktree-symlink.d.ts +99 -0
- package/dist/worktree-symlink.js +359 -0
- package/dist/wu-backlog-updater.d.ts +17 -0
- package/dist/wu-backlog-updater.js +37 -0
- package/dist/wu-checkpoint.d.ts +124 -0
- package/dist/wu-checkpoint.js +233 -0
- package/dist/wu-claim-helpers.d.ts +26 -0
- package/dist/wu-claim-helpers.js +63 -0
- package/dist/wu-claim-resume.d.ts +106 -0
- package/dist/wu-claim-resume.js +276 -0
- package/dist/wu-consistency-checker.d.ts +95 -0
- package/dist/wu-consistency-checker.js +567 -0
- package/dist/wu-constants.d.ts +1275 -0
- package/dist/wu-constants.js +1382 -0
- package/dist/wu-create-validators.d.ts +42 -0
- package/dist/wu-create-validators.js +93 -0
- package/dist/wu-done-branch-only.d.ts +63 -0
- package/dist/wu-done-branch-only.js +191 -0
- package/dist/wu-done-messages.d.ts +119 -0
- package/dist/wu-done-messages.js +185 -0
- package/dist/wu-done-pr.d.ts +72 -0
- package/dist/wu-done-pr.js +174 -0
- package/dist/wu-done-retry-helpers.d.ts +85 -0
- package/dist/wu-done-retry-helpers.js +172 -0
- package/dist/wu-done-ui.d.ts +37 -0
- package/dist/wu-done-ui.js +69 -0
- package/dist/wu-done-validators.d.ts +411 -0
- package/dist/wu-done-validators.js +1229 -0
- package/dist/wu-done-worktree.d.ts +182 -0
- package/dist/wu-done-worktree.js +1097 -0
- package/dist/wu-helpers.d.ts +128 -0
- package/dist/wu-helpers.js +248 -0
- package/dist/wu-lint.d.ts +70 -0
- package/dist/wu-lint.js +234 -0
- package/dist/wu-paths.d.ts +171 -0
- package/dist/wu-paths.js +178 -0
- package/dist/wu-preflight-validators.d.ts +86 -0
- package/dist/wu-preflight-validators.js +251 -0
- package/dist/wu-recovery.d.ts +138 -0
- package/dist/wu-recovery.js +341 -0
- package/dist/wu-repair-core.d.ts +131 -0
- package/dist/wu-repair-core.js +669 -0
- package/dist/wu-schema-normalization.d.ts +17 -0
- package/dist/wu-schema-normalization.js +82 -0
- package/dist/wu-schema.d.ts +793 -0
- package/dist/wu-schema.js +881 -0
- package/dist/wu-spawn-helpers.d.ts +121 -0
- package/dist/wu-spawn-helpers.js +271 -0
- package/dist/wu-spawn.d.ts +158 -0
- package/dist/wu-spawn.js +1306 -0
- package/dist/wu-state-schema.d.ts +213 -0
- package/dist/wu-state-schema.js +156 -0
- package/dist/wu-state-store.d.ts +264 -0
- package/dist/wu-state-store.js +691 -0
- package/dist/wu-status-transition.d.ts +63 -0
- package/dist/wu-status-transition.js +382 -0
- package/dist/wu-status-updater.d.ts +25 -0
- package/dist/wu-status-updater.js +116 -0
- package/dist/wu-transaction-collectors.d.ts +116 -0
- package/dist/wu-transaction-collectors.js +272 -0
- package/dist/wu-transaction.d.ts +170 -0
- package/dist/wu-transaction.js +273 -0
- package/dist/wu-validation-constants.d.ts +60 -0
- package/dist/wu-validation-constants.js +66 -0
- package/dist/wu-validation.d.ts +118 -0
- package/dist/wu-validation.js +243 -0
- package/dist/wu-validator.d.ts +62 -0
- package/dist/wu-validator.js +325 -0
- package/dist/wu-yaml-fixer.d.ts +97 -0
- package/dist/wu-yaml-fixer.js +264 -0
- package/dist/wu-yaml.d.ts +86 -0
- package/dist/wu-yaml.js +222 -0
- package/package.json +114 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { getGitForCwd } from './git-adapter.js';
|
|
2
|
+
import { die } from './error-handler.js';
|
|
3
|
+
/**
|
|
4
|
+
* Git Staged Files Validator
|
|
5
|
+
*
|
|
6
|
+
* Centralized validation for staged files requirement.
|
|
7
|
+
* Extracted from duplicate implementations in wu-block and wu-unblock (WU-1341).
|
|
8
|
+
*
|
|
9
|
+
* Used in --no-auto mode to enforce that required files are staged before commit.
|
|
10
|
+
*
|
|
11
|
+
* @module git-staged-validator
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Ensure all required paths are staged in git index
|
|
15
|
+
*
|
|
16
|
+
* Validates that specified files/directories are staged for commit.
|
|
17
|
+
* Supports exact path matching and directory prefix matching.
|
|
18
|
+
*
|
|
19
|
+
* @param {Array<string|null|undefined>} paths - Paths to check (null/undefined values filtered out)
|
|
20
|
+
* @throws {Error} If any required paths are not staged
|
|
21
|
+
* @returns {Array<string>} List of all staged files
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* // All files staged - success
|
|
25
|
+
* ensureStaged(['docs/file.md', 'tools/script.js']);
|
|
26
|
+
*
|
|
27
|
+
* // Directory prefix - matches all files under directory
|
|
28
|
+
* ensureStaged(['docs/04-operations/']);
|
|
29
|
+
*
|
|
30
|
+
* // Missing files - throws error
|
|
31
|
+
* ensureStaged(['docs/file1.md', 'docs/file2.md']);
|
|
32
|
+
* // Error: Stage updates for: docs/file2.md
|
|
33
|
+
*/
|
|
34
|
+
export function ensureStaged(paths) {
|
|
35
|
+
const git = getGitForCwd();
|
|
36
|
+
const raw = git.run('git diff --cached --name-only');
|
|
37
|
+
const staged = raw ? raw.split(/\r?\n/).filter((s) => Boolean(s)) : [];
|
|
38
|
+
// Filter out null/undefined and check each path
|
|
39
|
+
const missing = paths.filter(Boolean).filter((p) => {
|
|
40
|
+
// Normalize path: remove trailing slash for directory checks
|
|
41
|
+
const pathToCheck = p.endsWith('/') ? p.slice(0, -1) : p;
|
|
42
|
+
return !staged.some((name) => name === pathToCheck || name.startsWith(`${pathToCheck}/`));
|
|
43
|
+
});
|
|
44
|
+
if (missing.length) {
|
|
45
|
+
die(`Stage updates for: ${missing.join(', ')}`);
|
|
46
|
+
}
|
|
47
|
+
return staged;
|
|
48
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hardcoded String Detection Module
|
|
3
|
+
*
|
|
4
|
+
* Provides classification of hardcoded path strings to distinguish between:
|
|
5
|
+
* - Route paths (API endpoints, webhooks, etc.) - should use endpoint constants
|
|
6
|
+
* - Filesystem paths (absolute paths, config files) - should use path.join()
|
|
7
|
+
*
|
|
8
|
+
* This enables Gate 13 to provide accurate, actionable remediation messages.
|
|
9
|
+
*
|
|
10
|
+
* @see WU-1788 - Improve hardcoded-string gate messaging for route paths
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Path type constants
|
|
14
|
+
* @type {Object}
|
|
15
|
+
*/
|
|
16
|
+
export declare const PATH_TYPES: Readonly<{
|
|
17
|
+
ROUTE: "route";
|
|
18
|
+
FILESYSTEM: "filesystem";
|
|
19
|
+
UNKNOWN: "unknown";
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Classify a path string as route, filesystem, or unknown
|
|
23
|
+
*
|
|
24
|
+
* @param {string} pathStr - The path string to classify
|
|
25
|
+
* @returns {string} One of PATH_TYPES values
|
|
26
|
+
*/
|
|
27
|
+
export declare function classifyPath(pathStr: any): "unknown" | "route" | "filesystem";
|
|
28
|
+
/**
|
|
29
|
+
* Get the appropriate remediation message for a path type
|
|
30
|
+
*
|
|
31
|
+
* @param {string} pathType - One of PATH_TYPES values
|
|
32
|
+
* @returns {string} Remediation message
|
|
33
|
+
*/
|
|
34
|
+
export declare function getRemediation(pathType: any): any;
|
|
35
|
+
/**
|
|
36
|
+
* Options for hardcoded path violation detection
|
|
37
|
+
*/
|
|
38
|
+
export interface FindHardcodedPathViolationsOptions {
|
|
39
|
+
/** Whether this is a test file (skip detection) */
|
|
40
|
+
isTestFile?: boolean;
|
|
41
|
+
/** Whether this is a config file (skip detection) */
|
|
42
|
+
isConfigFile?: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Find hardcoded path violations in a line of code
|
|
46
|
+
*
|
|
47
|
+
* @param {string} line - The line of code to check
|
|
48
|
+
* @param {FindHardcodedPathViolationsOptions} options - Options for detection
|
|
49
|
+
* @returns {Array<{line: string, fix: string, pathType: string, path: string}>} Array of violations
|
|
50
|
+
*/
|
|
51
|
+
export declare function findHardcodedPathViolations(line: any, options?: FindHardcodedPathViolationsOptions): any[];
|
|
52
|
+
/**
|
|
53
|
+
* Legacy function for backwards compatibility with gates-pre-commit.mjs
|
|
54
|
+
* Detects all hardcoded string patterns (not just paths)
|
|
55
|
+
*
|
|
56
|
+
* @deprecated Use findHardcodedPathViolations for path-specific detection
|
|
57
|
+
*/
|
|
58
|
+
export declare const HARDCODED_PATTERNS: {
|
|
59
|
+
pattern: RegExp;
|
|
60
|
+
message: string;
|
|
61
|
+
}[];
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hardcoded String Detection Module
|
|
3
|
+
*
|
|
4
|
+
* Provides classification of hardcoded path strings to distinguish between:
|
|
5
|
+
* - Route paths (API endpoints, webhooks, etc.) - should use endpoint constants
|
|
6
|
+
* - Filesystem paths (absolute paths, config files) - should use path.join()
|
|
7
|
+
*
|
|
8
|
+
* This enables Gate 13 to provide accurate, actionable remediation messages.
|
|
9
|
+
*
|
|
10
|
+
* @see WU-1788 - Improve hardcoded-string gate messaging for route paths
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Path type constants
|
|
14
|
+
* @type {Object}
|
|
15
|
+
*/
|
|
16
|
+
export const PATH_TYPES = Object.freeze({
|
|
17
|
+
ROUTE: 'route',
|
|
18
|
+
FILESYSTEM: 'filesystem',
|
|
19
|
+
UNKNOWN: 'unknown',
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Route path prefixes that indicate API/web endpoints
|
|
23
|
+
* These should use endpoint constants, not path.join()
|
|
24
|
+
*/
|
|
25
|
+
const ROUTE_PREFIXES = [
|
|
26
|
+
'/api/',
|
|
27
|
+
'/api?', // API with query params
|
|
28
|
+
'/auth/',
|
|
29
|
+
'/v1/',
|
|
30
|
+
'/v2/',
|
|
31
|
+
'/v3/',
|
|
32
|
+
'/graphql',
|
|
33
|
+
'/webhook/',
|
|
34
|
+
'/webhooks/',
|
|
35
|
+
'/trpc/',
|
|
36
|
+
'/rest/',
|
|
37
|
+
'/rpc/',
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* Filesystem path prefixes that indicate absolute paths
|
|
41
|
+
* These should use path.join() with constants
|
|
42
|
+
*/
|
|
43
|
+
const FILESYSTEM_PREFIXES = [
|
|
44
|
+
'/home/',
|
|
45
|
+
'/usr/',
|
|
46
|
+
'/etc/',
|
|
47
|
+
'/var/',
|
|
48
|
+
'/tmp/',
|
|
49
|
+
'/opt/',
|
|
50
|
+
'/bin/',
|
|
51
|
+
'/sbin/',
|
|
52
|
+
'/lib/',
|
|
53
|
+
'/proc/',
|
|
54
|
+
'/sys/',
|
|
55
|
+
'/dev/',
|
|
56
|
+
'/mnt/',
|
|
57
|
+
'/media/',
|
|
58
|
+
'/srv/',
|
|
59
|
+
'/root/',
|
|
60
|
+
];
|
|
61
|
+
/**
|
|
62
|
+
* Common file extensions that indicate filesystem paths
|
|
63
|
+
*/
|
|
64
|
+
const FILE_EXTENSIONS = [
|
|
65
|
+
'.json',
|
|
66
|
+
'.yaml',
|
|
67
|
+
'.yml',
|
|
68
|
+
'.xml',
|
|
69
|
+
'.conf',
|
|
70
|
+
'.config',
|
|
71
|
+
'.cfg',
|
|
72
|
+
'.ini',
|
|
73
|
+
'.env',
|
|
74
|
+
'.log',
|
|
75
|
+
'.txt',
|
|
76
|
+
'.md',
|
|
77
|
+
'.csv',
|
|
78
|
+
'.tsv',
|
|
79
|
+
'.sql',
|
|
80
|
+
'.sh',
|
|
81
|
+
'.bash',
|
|
82
|
+
'.zsh',
|
|
83
|
+
'.py',
|
|
84
|
+
'.rb',
|
|
85
|
+
'.pl',
|
|
86
|
+
'.js',
|
|
87
|
+
'.ts',
|
|
88
|
+
'.jsx',
|
|
89
|
+
'.tsx',
|
|
90
|
+
'.js',
|
|
91
|
+
'.cjs',
|
|
92
|
+
'.png',
|
|
93
|
+
'.jpg',
|
|
94
|
+
'.jpeg',
|
|
95
|
+
'.gif',
|
|
96
|
+
'.svg',
|
|
97
|
+
'.ico',
|
|
98
|
+
'.pdf',
|
|
99
|
+
'.doc',
|
|
100
|
+
'.docx',
|
|
101
|
+
'.xls',
|
|
102
|
+
'.xlsx',
|
|
103
|
+
'.pem',
|
|
104
|
+
'.key',
|
|
105
|
+
'.crt',
|
|
106
|
+
'.cer',
|
|
107
|
+
];
|
|
108
|
+
/**
|
|
109
|
+
* Patterns that indicate filesystem paths
|
|
110
|
+
*/
|
|
111
|
+
const FILESYSTEM_PATTERNS = [
|
|
112
|
+
/^[A-Z]:[/\\]/, // Windows drive letter (C:\, D:/)
|
|
113
|
+
/node_modules/, // Node.js modules directory
|
|
114
|
+
/\.\.\//, // Relative path traversal
|
|
115
|
+
/~\//, // Home directory shorthand
|
|
116
|
+
];
|
|
117
|
+
/**
|
|
118
|
+
* Classify a path string as route, filesystem, or unknown
|
|
119
|
+
*
|
|
120
|
+
* @param {string} pathStr - The path string to classify
|
|
121
|
+
* @returns {string} One of PATH_TYPES values
|
|
122
|
+
*/
|
|
123
|
+
export function classifyPath(pathStr) {
|
|
124
|
+
if (!pathStr || pathStr === '/') {
|
|
125
|
+
return PATH_TYPES.UNKNOWN;
|
|
126
|
+
}
|
|
127
|
+
const normalizedPath = pathStr.toLowerCase();
|
|
128
|
+
// Check for route path indicators first (more specific)
|
|
129
|
+
for (const prefix of ROUTE_PREFIXES) {
|
|
130
|
+
if (normalizedPath.startsWith(prefix) || normalizedPath.includes(prefix)) {
|
|
131
|
+
return PATH_TYPES.ROUTE;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Check for query parameters (indicates a route/URL)
|
|
135
|
+
if (pathStr.includes('?') && pathStr.startsWith('/')) {
|
|
136
|
+
return PATH_TYPES.ROUTE;
|
|
137
|
+
}
|
|
138
|
+
// Check for filesystem path prefixes
|
|
139
|
+
for (const prefix of FILESYSTEM_PREFIXES) {
|
|
140
|
+
if (normalizedPath.startsWith(prefix)) {
|
|
141
|
+
return PATH_TYPES.FILESYSTEM;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Check for file extensions
|
|
145
|
+
for (const ext of FILE_EXTENSIONS) {
|
|
146
|
+
if (normalizedPath.endsWith(ext)) {
|
|
147
|
+
return PATH_TYPES.FILESYSTEM;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Check for filesystem patterns
|
|
151
|
+
for (const pattern of FILESYSTEM_PATTERNS) {
|
|
152
|
+
if (pattern.test(pathStr)) {
|
|
153
|
+
return PATH_TYPES.FILESYSTEM;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Default to unknown for ambiguous paths
|
|
157
|
+
return PATH_TYPES.UNKNOWN;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Remediation messages for each path type
|
|
161
|
+
*/
|
|
162
|
+
const REMEDIATION_MESSAGES = Object.freeze({
|
|
163
|
+
[PATH_TYPES.ROUTE]: 'Route path - use an endpoint constant or config (e.g., BEACON_API_ENDPOINT, API_ROUTES.ASSISTANT)',
|
|
164
|
+
[PATH_TYPES.FILESYSTEM]: 'File path - use path.join() with constants',
|
|
165
|
+
[PATH_TYPES.UNKNOWN]: 'Path string - use a constant or configuration value',
|
|
166
|
+
});
|
|
167
|
+
/**
|
|
168
|
+
* Get the appropriate remediation message for a path type
|
|
169
|
+
*
|
|
170
|
+
* @param {string} pathType - One of PATH_TYPES values
|
|
171
|
+
* @returns {string} Remediation message
|
|
172
|
+
*/
|
|
173
|
+
export function getRemediation(pathType) {
|
|
174
|
+
// Validate pathType to prevent object injection
|
|
175
|
+
const validTypes = Object.values(PATH_TYPES);
|
|
176
|
+
if (validTypes.includes(pathType)) {
|
|
177
|
+
// eslint-disable-next-line security/detect-object-injection -- Safe: pathType validated against known values above
|
|
178
|
+
return REMEDIATION_MESSAGES[pathType];
|
|
179
|
+
}
|
|
180
|
+
return REMEDIATION_MESSAGES[PATH_TYPES.UNKNOWN];
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Pattern to match path-like strings in code
|
|
184
|
+
* Matches quoted strings that:
|
|
185
|
+
* - Start with /
|
|
186
|
+
* - Have at least one path segment after the initial /
|
|
187
|
+
* - May include alphanumeric characters, underscores, hyphens, dots
|
|
188
|
+
* - May include query parameters
|
|
189
|
+
*
|
|
190
|
+
* Note: Uses non-greedy quantifiers and avoids nested quantifiers to prevent ReDoS
|
|
191
|
+
*/
|
|
192
|
+
// eslint-disable-next-line security/detect-unsafe-regex -- Intentionally simplified pattern, not user-controlled
|
|
193
|
+
const PATH_PATTERN = /['"](\/[\w./-]+(?:\?[^'"]*)?)['"]/gi;
|
|
194
|
+
/**
|
|
195
|
+
* Check if a line contains a constant definition (SCREAMING_SNAKE_CASE)
|
|
196
|
+
*
|
|
197
|
+
* @param {string} line - The line to check
|
|
198
|
+
* @returns {boolean} True if line defines a constant
|
|
199
|
+
*/
|
|
200
|
+
function isConstantDefinition(line) {
|
|
201
|
+
if (!line.includes('const '))
|
|
202
|
+
return false;
|
|
203
|
+
const afterConst = line.split('const ')[1];
|
|
204
|
+
if (!afterConst)
|
|
205
|
+
return false;
|
|
206
|
+
const identifier = afterConst.trim().split(/[\s=]/)[0];
|
|
207
|
+
return identifier && identifier === identifier.toUpperCase() && identifier.length > 1;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Find hardcoded path violations in a line of code
|
|
211
|
+
*
|
|
212
|
+
* @param {string} line - The line of code to check
|
|
213
|
+
* @param {FindHardcodedPathViolationsOptions} options - Options for detection
|
|
214
|
+
* @returns {Array<{line: string, fix: string, pathType: string, path: string}>} Array of violations
|
|
215
|
+
*/
|
|
216
|
+
export function findHardcodedPathViolations(line, options = {}) {
|
|
217
|
+
const { isTestFile = false, isConfigFile = false } = options;
|
|
218
|
+
// Skip test files and config files
|
|
219
|
+
if (isTestFile || isConfigFile) {
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
// Skip constant definitions (they ARE the constants we want people to create)
|
|
223
|
+
if (isConstantDefinition(line)) {
|
|
224
|
+
return [];
|
|
225
|
+
}
|
|
226
|
+
// Skip lines that look like test context
|
|
227
|
+
if (line.includes('.test.') || line.includes('.spec.')) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
const violations = [];
|
|
231
|
+
let match;
|
|
232
|
+
// Reset regex lastIndex for global matching
|
|
233
|
+
PATH_PATTERN.lastIndex = 0;
|
|
234
|
+
while ((match = PATH_PATTERN.exec(line)) !== null) {
|
|
235
|
+
const pathStr = match[1];
|
|
236
|
+
// Only flag paths that start with /
|
|
237
|
+
if (!pathStr.startsWith('/')) {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
const pathType = classifyPath(pathStr);
|
|
241
|
+
const remediation = getRemediation(pathType);
|
|
242
|
+
violations.push({
|
|
243
|
+
line: line.substring(0, 80),
|
|
244
|
+
fix: remediation,
|
|
245
|
+
pathType,
|
|
246
|
+
path: pathStr,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
return violations;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Legacy function for backwards compatibility with gates-pre-commit.mjs
|
|
253
|
+
* Detects all hardcoded string patterns (not just paths)
|
|
254
|
+
*
|
|
255
|
+
* @deprecated Use findHardcodedPathViolations for path-specific detection
|
|
256
|
+
*/
|
|
257
|
+
export const HARDCODED_PATTERNS = [
|
|
258
|
+
{
|
|
259
|
+
pattern: /['"]https?:\/\/[^'"]+\/api\//i,
|
|
260
|
+
message: 'API endpoint - use environment variable or config',
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
pattern: /throw new Error\s*\(\s*['"][^'"]{50,}['"]\s*\)/i,
|
|
264
|
+
message: 'Long error message - use error constants',
|
|
265
|
+
},
|
|
266
|
+
// WU-1788: Path pattern now uses classifier for accurate messages
|
|
267
|
+
// The old pattern is replaced by findHardcodedPathViolations
|
|
268
|
+
{ pattern: /['"]#[0-9a-fA-F]{6}['"]/i, message: 'Color value - use theme/design tokens' },
|
|
269
|
+
{ pattern: /if\s*\(\s*['"]feature_/i, message: 'Feature flag - use feature flag service' },
|
|
270
|
+
];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file incremental-lint.mjs
|
|
3
|
+
* @description Incremental linting utilities for gates
|
|
4
|
+
* WU-1304: Optimise ESLint gates performance
|
|
5
|
+
*
|
|
6
|
+
* Provides utilities to determine which files need linting based on
|
|
7
|
+
* changes since branching from main, enabling faster gate execution.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* File extensions that should be linted by ESLint
|
|
11
|
+
* @type {string[]}
|
|
12
|
+
*/
|
|
13
|
+
export declare const LINTABLE_EXTENSIONS: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Check if a file path should be linted
|
|
16
|
+
* @param {string} filePath - File path to check
|
|
17
|
+
* @returns {boolean} True if file should be linted
|
|
18
|
+
*/
|
|
19
|
+
export declare function isLintableFile(filePath: any): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Git adapter interface for testing
|
|
22
|
+
*/
|
|
23
|
+
interface GitAdapter {
|
|
24
|
+
mergeBase: (ref1: string, ref2: string) => Promise<string>;
|
|
25
|
+
raw: (args: string[]) => Promise<string>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Options for getting changed lintable files
|
|
29
|
+
*/
|
|
30
|
+
export interface GetChangedLintableFilesOptions {
|
|
31
|
+
/** GitAdapter instance (for testing) */
|
|
32
|
+
git?: GitAdapter;
|
|
33
|
+
/** Base branch to compare against */
|
|
34
|
+
baseBranch?: string;
|
|
35
|
+
/** Optional path prefix to filter files */
|
|
36
|
+
filterPath?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get list of changed files that should be linted
|
|
40
|
+
* Includes:
|
|
41
|
+
* - Committed changes since branching from main (git diff merge-base...HEAD)
|
|
42
|
+
* - Modified but unstaged files (git diff --name-only)
|
|
43
|
+
* - Untracked files (git ls-files --others --exclude-standard)
|
|
44
|
+
*
|
|
45
|
+
* WU-1784: Extended to include untracked and unstaged files to prevent
|
|
46
|
+
* lint gaps when gates are run before staging/committing changes.
|
|
47
|
+
*
|
|
48
|
+
* @param {GetChangedLintableFilesOptions} [options] - Options
|
|
49
|
+
* @returns {Promise<string[]>} List of file paths to lint
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // Get all changed lintable files
|
|
53
|
+
* const files = await getChangedLintableFiles();
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* // Get only files in apps/web/
|
|
57
|
+
* const files = await getChangedLintableFiles({ filterPath: 'apps/web/' });
|
|
58
|
+
*/
|
|
59
|
+
export declare function getChangedLintableFiles(options?: GetChangedLintableFilesOptions): Promise<any[]>;
|
|
60
|
+
/**
|
|
61
|
+
* Convert repo-relative file paths to package-relative paths
|
|
62
|
+
*
|
|
63
|
+
* WU-2571: ESLint runs from package directory (e.g., apps/web/) where
|
|
64
|
+
* repo-relative paths (e.g., apps/web/src/file.ts) don't exist.
|
|
65
|
+
* This function strips the package prefix to produce paths that
|
|
66
|
+
* work correctly when ESLint is run from the package directory.
|
|
67
|
+
*
|
|
68
|
+
* @param {string[]} repoRelativePaths - Paths relative to repo root (e.g., ['apps/web/src/app.ts'])
|
|
69
|
+
* @param {string} packagePrefix - Package directory prefix (e.g., 'apps/web/' or 'apps/web')
|
|
70
|
+
* @returns {string[]} Paths relative to package directory (e.g., ['src/app.ts'])
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* const repoRelative = ['apps/web/src/app.ts', 'apps/web/src/lib.tsx'];
|
|
74
|
+
* const packageRelative = convertToPackageRelativePaths(repoRelative, 'apps/web/');
|
|
75
|
+
* // Returns: ['src/app.ts', 'src/lib.tsx']
|
|
76
|
+
*/
|
|
77
|
+
export declare function convertToPackageRelativePaths(repoRelativePaths: any, packagePrefix: any): any;
|
|
78
|
+
export {};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file incremental-lint.mjs
|
|
3
|
+
* @description Incremental linting utilities for gates
|
|
4
|
+
* WU-1304: Optimise ESLint gates performance
|
|
5
|
+
*
|
|
6
|
+
* Provides utilities to determine which files need linting based on
|
|
7
|
+
* changes since branching from main, enabling faster gate execution.
|
|
8
|
+
*/
|
|
9
|
+
import { getGitForCwd } from './git-adapter.js';
|
|
10
|
+
import { STRING_LITERALS } from './wu-constants.js';
|
|
11
|
+
/**
|
|
12
|
+
* File extensions that should be linted by ESLint
|
|
13
|
+
* @type {string[]}
|
|
14
|
+
*/
|
|
15
|
+
export const LINTABLE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.js'];
|
|
16
|
+
/**
|
|
17
|
+
* Directory patterns that should be ignored
|
|
18
|
+
* Matches ESLint ignores in apps/web/eslint.config.mjs
|
|
19
|
+
* @type {string[]}
|
|
20
|
+
*/
|
|
21
|
+
const IGNORED_DIRECTORIES = [
|
|
22
|
+
'node_modules/',
|
|
23
|
+
'.next/',
|
|
24
|
+
'.expo/',
|
|
25
|
+
'dist/',
|
|
26
|
+
'build/',
|
|
27
|
+
'.turbo/',
|
|
28
|
+
'coverage/',
|
|
29
|
+
'worktrees/',
|
|
30
|
+
];
|
|
31
|
+
/**
|
|
32
|
+
* Check if a file path should be linted
|
|
33
|
+
* @param {string} filePath - File path to check
|
|
34
|
+
* @returns {boolean} True if file should be linted
|
|
35
|
+
*/
|
|
36
|
+
export function isLintableFile(filePath) {
|
|
37
|
+
// Check if in ignored directory
|
|
38
|
+
for (const ignored of IGNORED_DIRECTORIES) {
|
|
39
|
+
if (filePath.includes(ignored)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Check if has lintable extension
|
|
44
|
+
for (const ext of LINTABLE_EXTENSIONS) {
|
|
45
|
+
if (filePath.endsWith(ext)) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Parse git output into a list of file paths
|
|
53
|
+
* @param {string} output - Git command output
|
|
54
|
+
* @returns {string[]} List of file paths
|
|
55
|
+
*/
|
|
56
|
+
function parseGitFileList(output) {
|
|
57
|
+
return output
|
|
58
|
+
.split(STRING_LITERALS.NEWLINE)
|
|
59
|
+
.map((f) => f.trim())
|
|
60
|
+
.filter((f) => f.length > 0);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get list of changed files that should be linted
|
|
64
|
+
* Includes:
|
|
65
|
+
* - Committed changes since branching from main (git diff merge-base...HEAD)
|
|
66
|
+
* - Modified but unstaged files (git diff --name-only)
|
|
67
|
+
* - Untracked files (git ls-files --others --exclude-standard)
|
|
68
|
+
*
|
|
69
|
+
* WU-1784: Extended to include untracked and unstaged files to prevent
|
|
70
|
+
* lint gaps when gates are run before staging/committing changes.
|
|
71
|
+
*
|
|
72
|
+
* @param {GetChangedLintableFilesOptions} [options] - Options
|
|
73
|
+
* @returns {Promise<string[]>} List of file paths to lint
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // Get all changed lintable files
|
|
77
|
+
* const files = await getChangedLintableFiles();
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* // Get only files in apps/web/
|
|
81
|
+
* const files = await getChangedLintableFiles({ filterPath: 'apps/web/' });
|
|
82
|
+
*/
|
|
83
|
+
export async function getChangedLintableFiles(options = {}) {
|
|
84
|
+
const { git = getGitForCwd(), baseBranch = 'origin/main', filterPath } = options;
|
|
85
|
+
// Get the merge base (common ancestor) with the base branch
|
|
86
|
+
const mergeBase = await git.mergeBase('HEAD', baseBranch);
|
|
87
|
+
// 1. Get committed changes since the merge base
|
|
88
|
+
const committedOutput = await git.raw(['diff', '--name-only', `${mergeBase}...HEAD`]);
|
|
89
|
+
const committedFiles = parseGitFileList(committedOutput);
|
|
90
|
+
// 2. Get modified but unstaged files (WU-1784)
|
|
91
|
+
const unstagedOutput = await git.raw(['diff', '--name-only']);
|
|
92
|
+
const unstagedFiles = parseGitFileList(unstagedOutput);
|
|
93
|
+
// 3. Get untracked files (WU-1784)
|
|
94
|
+
const untrackedOutput = await git.raw(['ls-files', '--others', '--exclude-standard']);
|
|
95
|
+
const untrackedFiles = parseGitFileList(untrackedOutput);
|
|
96
|
+
// Combine all sources and deduplicate using Set
|
|
97
|
+
const allFiles = [...new Set([...committedFiles, ...unstagedFiles, ...untrackedFiles])];
|
|
98
|
+
// Filter to lintable files
|
|
99
|
+
let lintableFiles = allFiles.filter(isLintableFile);
|
|
100
|
+
// Apply path filter if specified
|
|
101
|
+
if (filterPath) {
|
|
102
|
+
lintableFiles = lintableFiles.filter((f) => f.startsWith(filterPath));
|
|
103
|
+
}
|
|
104
|
+
return lintableFiles;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Convert repo-relative file paths to package-relative paths
|
|
108
|
+
*
|
|
109
|
+
* WU-2571: ESLint runs from package directory (e.g., apps/web/) where
|
|
110
|
+
* repo-relative paths (e.g., apps/web/src/file.ts) don't exist.
|
|
111
|
+
* This function strips the package prefix to produce paths that
|
|
112
|
+
* work correctly when ESLint is run from the package directory.
|
|
113
|
+
*
|
|
114
|
+
* @param {string[]} repoRelativePaths - Paths relative to repo root (e.g., ['apps/web/src/app.ts'])
|
|
115
|
+
* @param {string} packagePrefix - Package directory prefix (e.g., 'apps/web/' or 'apps/web')
|
|
116
|
+
* @returns {string[]} Paths relative to package directory (e.g., ['src/app.ts'])
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* const repoRelative = ['apps/web/src/app.ts', 'apps/web/src/lib.tsx'];
|
|
120
|
+
* const packageRelative = convertToPackageRelativePaths(repoRelative, 'apps/web/');
|
|
121
|
+
* // Returns: ['src/app.ts', 'src/lib.tsx']
|
|
122
|
+
*/
|
|
123
|
+
export function convertToPackageRelativePaths(repoRelativePaths, packagePrefix) {
|
|
124
|
+
// Normalize the prefix to ensure it ends with a slash
|
|
125
|
+
const normalizedPrefix = packagePrefix.endsWith('/') ? packagePrefix : `${packagePrefix}/`;
|
|
126
|
+
return repoRelativePaths
|
|
127
|
+
.filter((filePath) => filePath.startsWith(normalizedPrefix))
|
|
128
|
+
.map((filePath) => filePath.slice(normalizedPrefix.length));
|
|
129
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file incremental-test.mjs
|
|
3
|
+
* @description Helpers for Vitest --changed execution
|
|
4
|
+
*
|
|
5
|
+
* WU-1920: Add incremental test execution to gates
|
|
6
|
+
* WU-2504: Use Vitest --changed instead of custom file diff logic
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Glob patterns to exclude slow integration/golden tests from changed runs.
|
|
10
|
+
* @type {string[]}
|
|
11
|
+
*/
|
|
12
|
+
export declare const VITEST_CHANGED_EXCLUDES: readonly string[];
|
|
13
|
+
/**
|
|
14
|
+
* File extensions considered executable code for test runs.
|
|
15
|
+
* @type {string[]}
|
|
16
|
+
*/
|
|
17
|
+
export declare const CODE_FILE_EXTENSIONS: readonly string[];
|
|
18
|
+
/**
|
|
19
|
+
* Check if a path points to a code file that should trigger full tests.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} filePath - Path to check
|
|
22
|
+
* @returns {boolean} True if the path has a code extension
|
|
23
|
+
*/
|
|
24
|
+
export declare function isCodeFilePath(filePath: any): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Options for building Vitest changed args
|
|
27
|
+
*/
|
|
28
|
+
interface BuildVitestChangedArgsOptions {
|
|
29
|
+
/** Base branch for diff */
|
|
30
|
+
baseBranch?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build Vitest CLI args for --changed runs.
|
|
34
|
+
*
|
|
35
|
+
* @param {BuildVitestChangedArgsOptions} [options]
|
|
36
|
+
* @returns {string[]} Vitest args for changed test runs
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildVitestChangedArgs(options?: BuildVitestChangedArgsOptions): string[];
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file incremental-test.mjs
|
|
3
|
+
* @description Helpers for Vitest --changed execution
|
|
4
|
+
*
|
|
5
|
+
* WU-1920: Add incremental test execution to gates
|
|
6
|
+
* WU-2504: Use Vitest --changed instead of custom file diff logic
|
|
7
|
+
*/
|
|
8
|
+
import { GIT_REFS } from './wu-constants.js';
|
|
9
|
+
/**
|
|
10
|
+
* Glob patterns to exclude slow integration/golden tests from changed runs.
|
|
11
|
+
* @type {string[]}
|
|
12
|
+
*/
|
|
13
|
+
export const VITEST_CHANGED_EXCLUDES = Object.freeze(['**/*.integration.*', '**/golden-*.test.*']);
|
|
14
|
+
/**
|
|
15
|
+
* File extensions considered executable code for test runs.
|
|
16
|
+
* @type {string[]}
|
|
17
|
+
*/
|
|
18
|
+
export const CODE_FILE_EXTENSIONS = Object.freeze([
|
|
19
|
+
'.ts',
|
|
20
|
+
'.tsx',
|
|
21
|
+
'.js',
|
|
22
|
+
'.jsx',
|
|
23
|
+
'.js',
|
|
24
|
+
'.cjs',
|
|
25
|
+
'.mts',
|
|
26
|
+
'.cts',
|
|
27
|
+
]);
|
|
28
|
+
/**
|
|
29
|
+
* Check if a path points to a code file that should trigger full tests.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} filePath - Path to check
|
|
32
|
+
* @returns {boolean} True if the path has a code extension
|
|
33
|
+
*/
|
|
34
|
+
export function isCodeFilePath(filePath) {
|
|
35
|
+
if (!filePath || typeof filePath !== 'string') {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const normalized = filePath.replace(/\\/g, '/').toLowerCase();
|
|
39
|
+
return CODE_FILE_EXTENSIONS.some((ext) => normalized.endsWith(ext));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build Vitest CLI args for --changed runs.
|
|
43
|
+
*
|
|
44
|
+
* @param {BuildVitestChangedArgsOptions} [options]
|
|
45
|
+
* @returns {string[]} Vitest args for changed test runs
|
|
46
|
+
*/
|
|
47
|
+
export function buildVitestChangedArgs(options = {}) {
|
|
48
|
+
const { baseBranch = GIT_REFS.ORIGIN_MAIN } = options;
|
|
49
|
+
const args = [
|
|
50
|
+
'--changed',
|
|
51
|
+
baseBranch,
|
|
52
|
+
'--run',
|
|
53
|
+
'--passWithNoTests',
|
|
54
|
+
'--maxWorkers=1',
|
|
55
|
+
'--teardownTimeout=30000',
|
|
56
|
+
];
|
|
57
|
+
for (const pattern of VITEST_CHANGED_EXCLUDES) {
|
|
58
|
+
args.push(`--exclude='${pattern}'`);
|
|
59
|
+
}
|
|
60
|
+
return args;
|
|
61
|
+
}
|