@outcomeeng/spx 0.6.18 → 0.6.20
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/README.md +14 -0
- package/dist/cli.js +1352 -775
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/cli.ts
|
|
2
|
-
import { createRequire as
|
|
2
|
+
import { createRequire as createRequire3 } from "module";
|
|
3
3
|
|
|
4
4
|
// src/interfaces/cli/program.ts
|
|
5
5
|
import { Command } from "commander";
|
|
@@ -10055,12 +10055,17 @@ var AGENT_RUN_TOOLS = {
|
|
|
10055
10055
|
WRITE: "Write",
|
|
10056
10056
|
EDIT: "Edit"
|
|
10057
10057
|
};
|
|
10058
|
+
var AGENT_FILE_TOOLS = [
|
|
10059
|
+
AGENT_RUN_TOOLS.READ,
|
|
10060
|
+
AGENT_RUN_TOOLS.WRITE,
|
|
10061
|
+
AGENT_RUN_TOOLS.EDIT
|
|
10062
|
+
];
|
|
10058
10063
|
var AGENT_TOOL_PERMISSION_BEHAVIOR = {
|
|
10059
10064
|
ALLOW: "allow",
|
|
10060
10065
|
DENY: "deny"
|
|
10061
10066
|
};
|
|
10062
10067
|
function authorizeAgentFileToolPath(workingDirectory, tool, filePath) {
|
|
10063
|
-
return (tool
|
|
10068
|
+
return AGENT_FILE_TOOLS.includes(tool) && filePath.length > 0 && isPathContained(workingDirectory, filePath) ? AGENT_TOOL_PERMISSION_BEHAVIOR.ALLOW : AGENT_TOOL_PERMISSION_BEHAVIOR.DENY;
|
|
10064
10069
|
}
|
|
10065
10070
|
var AGENT_PERMISSION_MODES = {
|
|
10066
10071
|
DONT_ASK: "dontAsk"
|
|
@@ -10068,6 +10073,7 @@ var AGENT_PERMISSION_MODES = {
|
|
|
10068
10073
|
|
|
10069
10074
|
// src/agent/claude-agent-runner.ts
|
|
10070
10075
|
var AGENT_FILE_TOOL_PATH_INPUT_FIELD = "file_path";
|
|
10076
|
+
var AGENT_PRE_TOOL_USE_HOOK_EVENT = "PreToolUse";
|
|
10071
10077
|
var AGENT_FILE_TOOL_PERMISSION_DENIED_MESSAGE = "Agent file tool target is outside its working directory";
|
|
10072
10078
|
var ClaudeAgentRunner = class {
|
|
10073
10079
|
async run(request) {
|
|
@@ -10096,41 +10102,54 @@ function createAgentRunOptions(request) {
|
|
|
10096
10102
|
cwd: request.workingDirectory,
|
|
10097
10103
|
settingSources: [],
|
|
10098
10104
|
tools: [...request.tools],
|
|
10099
|
-
allowedTools:
|
|
10100
|
-
|
|
10105
|
+
allowedTools: [...request.allowedTools],
|
|
10106
|
+
hooks: {
|
|
10107
|
+
PreToolUse: [{ hooks: [createAgentFileToolPermissionHook(request)] }]
|
|
10108
|
+
},
|
|
10101
10109
|
permissionMode: request.permissionMode,
|
|
10102
10110
|
maxTurns: request.maxTurns
|
|
10103
10111
|
};
|
|
10104
10112
|
}
|
|
10105
|
-
function
|
|
10106
|
-
return
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
return async (toolName, input) => {
|
|
10110
|
-
if (!isAgentRunTool(toolName) || !request.allowedTools.includes(toolName)) {
|
|
10111
|
-
return deniedAgentToolPermission();
|
|
10113
|
+
function createAgentFileToolPermissionHook(request) {
|
|
10114
|
+
return async (input) => {
|
|
10115
|
+
if (input.hook_event_name !== AGENT_PRE_TOOL_USE_HOOK_EVENT || !isAgentRunTool(input.tool_name) || !request.allowedTools.includes(input.tool_name) || !isRecord8(input.tool_input)) {
|
|
10116
|
+
return deniedAgentFileToolPermission();
|
|
10112
10117
|
}
|
|
10113
|
-
if (!
|
|
10114
|
-
return
|
|
10118
|
+
if (!isAgentFileTool(input.tool_name)) {
|
|
10119
|
+
return allowedAgentFileToolPermission();
|
|
10115
10120
|
}
|
|
10116
|
-
const filePath = input[AGENT_FILE_TOOL_PATH_INPUT_FIELD];
|
|
10117
|
-
if (typeof filePath !== "string" || authorizeAgentFileToolPath(request.workingDirectory,
|
|
10118
|
-
return
|
|
10121
|
+
const filePath = input.tool_input[AGENT_FILE_TOOL_PATH_INPUT_FIELD];
|
|
10122
|
+
if (typeof filePath !== "string" || authorizeAgentFileToolPath(request.workingDirectory, input.tool_name, filePath) === AGENT_TOOL_PERMISSION_BEHAVIOR.DENY) {
|
|
10123
|
+
return deniedAgentFileToolPermission();
|
|
10119
10124
|
}
|
|
10120
|
-
return
|
|
10125
|
+
return allowedAgentFileToolPermission();
|
|
10121
10126
|
};
|
|
10122
10127
|
}
|
|
10123
|
-
function
|
|
10128
|
+
function allowedAgentFileToolPermission() {
|
|
10124
10129
|
return {
|
|
10125
|
-
|
|
10126
|
-
|
|
10130
|
+
hookSpecificOutput: {
|
|
10131
|
+
hookEventName: AGENT_PRE_TOOL_USE_HOOK_EVENT,
|
|
10132
|
+
permissionDecision: AGENT_TOOL_PERMISSION_BEHAVIOR.ALLOW
|
|
10133
|
+
}
|
|
10134
|
+
};
|
|
10135
|
+
}
|
|
10136
|
+
function deniedAgentFileToolPermission() {
|
|
10137
|
+
return {
|
|
10138
|
+
hookSpecificOutput: {
|
|
10139
|
+
hookEventName: AGENT_PRE_TOOL_USE_HOOK_EVENT,
|
|
10140
|
+
permissionDecision: AGENT_TOOL_PERMISSION_BEHAVIOR.DENY,
|
|
10141
|
+
permissionDecisionReason: AGENT_FILE_TOOL_PERMISSION_DENIED_MESSAGE
|
|
10142
|
+
}
|
|
10127
10143
|
};
|
|
10128
10144
|
}
|
|
10145
|
+
function isRecord8(input) {
|
|
10146
|
+
return typeof input === "object" && input !== null;
|
|
10147
|
+
}
|
|
10129
10148
|
function isAgentRunTool(toolName) {
|
|
10130
10149
|
return Object.values(AGENT_RUN_TOOLS).some((tool) => tool === toolName);
|
|
10131
10150
|
}
|
|
10132
|
-
function
|
|
10133
|
-
return
|
|
10151
|
+
function isAgentFileTool(tool) {
|
|
10152
|
+
return AGENT_FILE_TOOLS.includes(tool);
|
|
10134
10153
|
}
|
|
10135
10154
|
async function runClaudeQuery(prompt, options) {
|
|
10136
10155
|
let result;
|
|
@@ -10302,7 +10321,9 @@ function toComponent(value) {
|
|
|
10302
10321
|
}
|
|
10303
10322
|
|
|
10304
10323
|
// src/domains/release/documentation-sync.ts
|
|
10305
|
-
var DOCUMENTATION_SYNC_PROMPT_INSTRUCTION = "
|
|
10324
|
+
var DOCUMENTATION_SYNC_PROMPT_INSTRUCTION = "Edit every staged documentation file so its version references and behavior descriptions match the supplied release data.";
|
|
10325
|
+
var DOCUMENTATION_SYNC_RELEASE_VERSION_INSTRUCTION = "The exact released version every staged document must contain is";
|
|
10326
|
+
var DOCUMENTATION_SYNC_VERSIONLESS_INSTRUCTION = "Replace every standalone previous product release-version reference. When a staged document has no such reference, add a concise current-release reference using the exact released version above.";
|
|
10306
10327
|
var DOCUMENTATION_SYNC_PROMPT_DATA_BLOCK_OPEN = "<documentation-sync-input>";
|
|
10307
10328
|
var DOCUMENTATION_SYNC_PROMPT_DATA_BLOCK_CLOSE = "</documentation-sync-input>";
|
|
10308
10329
|
var DOCUMENTATION_SYNC_AGENT_TOOLS = [
|
|
@@ -10315,11 +10336,15 @@ var DOCUMENTATION_SYNC_AGENT_MAX_TURNS = 10;
|
|
|
10315
10336
|
var DOCUMENTATION_SYNC_AUDIT_MAX_TURNS = 3;
|
|
10316
10337
|
var DOCUMENTATION_SYNC_AUDIT_APPROVED = "APPROVED";
|
|
10317
10338
|
var DOCUMENTATION_SYNC_AUDIT_REJECTED = "REJECTED";
|
|
10339
|
+
var DOCUMENTATION_SYNC_AUDIT_VERSIONLESS_INSTRUCTION = "When an original document has no previous-release reference, adding a concise current-release reference using the exact released version is a supported release update.";
|
|
10318
10340
|
var REGEXP_SPECIAL_CHARACTER_PATTERN = /[.*+?^${}()|[\]\\]/gu;
|
|
10319
10341
|
var REGEXP_ESCAPE_REPLACEMENT = String.raw`\$&`;
|
|
10320
10342
|
var VERSION_REFERENCE_NON_WHITESPACE_PATTERN = String.raw`\S`;
|
|
10321
10343
|
function buildDocumentationSyncPrompt(input) {
|
|
10344
|
+
const encodedVersion = encodeReleasePromptData(input.releaseData.version).slice(1, -1);
|
|
10322
10345
|
return `${DOCUMENTATION_SYNC_PROMPT_INSTRUCTION}
|
|
10346
|
+
${DOCUMENTATION_SYNC_RELEASE_VERSION_INSTRUCTION} ${encodedVersion}.
|
|
10347
|
+
${DOCUMENTATION_SYNC_VERSIONLESS_INSTRUCTION}
|
|
10323
10348
|
|
|
10324
10349
|
${DOCUMENTATION_SYNC_PROMPT_DATA_BLOCK_OPEN}
|
|
10325
10350
|
${encodeReleasePromptData(input)}
|
|
@@ -10407,6 +10432,7 @@ function containsReleaseVersionReference(content, version2) {
|
|
|
10407
10432
|
function buildDocumentationFaithfulnessAuditPrompt(input) {
|
|
10408
10433
|
return [
|
|
10409
10434
|
"Audit whether every original-to-updated documentation transformation faithfully applies the supplied release data, including updating each previous-release reference rather than deleting it.",
|
|
10435
|
+
DOCUMENTATION_SYNC_AUDIT_VERSIONLESS_INSTRUCTION,
|
|
10410
10436
|
`Return exactly ${DOCUMENTATION_SYNC_AUDIT_APPROVED} when every changed claim is supported and every previous-release reference remains represented by the released version.`,
|
|
10411
10437
|
`Return ${DOCUMENTATION_SYNC_AUDIT_REJECTED} followed by a concise reason for any unsupported claim, deleted previous-release reference, or omitted release update.`,
|
|
10412
10438
|
DOCUMENTATION_SYNC_PROMPT_DATA_BLOCK_OPEN,
|
|
@@ -14647,6 +14673,9 @@ function formatMissingCitedDecisionError(citedPath, citingPath) {
|
|
|
14647
14673
|
function specContextBootstrap(nodeCount) {
|
|
14648
14674
|
return nodeCount === 0;
|
|
14649
14675
|
}
|
|
14676
|
+
function compareSpecContextOrdinal(left, right) {
|
|
14677
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
14678
|
+
}
|
|
14650
14679
|
var SPEC_CONTEXT_DIGEST_ALGORITHM = "sha256";
|
|
14651
14680
|
function specContextDigest(rawBytes) {
|
|
14652
14681
|
return `${SPEC_CONTEXT_DIGEST_ALGORITHM}:${createHash4(SPEC_CONTEXT_DIGEST_ALGORITHM).update(rawBytes).digest("hex")}`;
|
|
@@ -14661,9 +14690,6 @@ function formatUnreadableContextDocumentError(path4) {
|
|
|
14661
14690
|
return `Spec context document unreadable: ${path4}`;
|
|
14662
14691
|
}
|
|
14663
14692
|
|
|
14664
|
-
// src/lib/node-status/ci-projection.ts
|
|
14665
|
-
import { parse as parseYaml3 } from "yaml";
|
|
14666
|
-
|
|
14667
14693
|
// src/lib/node-status/classify.ts
|
|
14668
14694
|
var NODE_STATUS_SCHEMA_VERSION = 1;
|
|
14669
14695
|
var NODE_STATUS_JSON_INDENT = 2;
|
|
@@ -14739,9 +14765,11 @@ function verificationPassed(verification) {
|
|
|
14739
14765
|
import { readFileSync } from "fs";
|
|
14740
14766
|
import { join as join19 } from "path";
|
|
14741
14767
|
var NODE_STATUS_EXCLUDE_FILENAME = "EXCLUDE";
|
|
14742
|
-
var
|
|
14743
|
-
|
|
14744
|
-
|
|
14768
|
+
var NODE_STATUS_EXCLUDE_PATH_GRAMMAR = {
|
|
14769
|
+
SEGMENT_SEPARATOR: "/",
|
|
14770
|
+
CURRENT_DIRECTORY_SEGMENT: ".",
|
|
14771
|
+
PARENT_DIRECTORY_SEGMENT: ".."
|
|
14772
|
+
};
|
|
14745
14773
|
function isNodeError(err) {
|
|
14746
14774
|
return err instanceof Error && "code" in err;
|
|
14747
14775
|
}
|
|
@@ -14752,14 +14780,17 @@ function parseExcludeEntries(content) {
|
|
|
14752
14780
|
return content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).map(validateExcludeEntry);
|
|
14753
14781
|
}
|
|
14754
14782
|
function validateExcludeEntry(entry) {
|
|
14755
|
-
const segments = entry.split(
|
|
14756
|
-
if (entry.startsWith(
|
|
14757
|
-
(segment) => segment.length === 0 || segment === CURRENT_DIRECTORY_SEGMENT || segment === PARENT_DIRECTORY_SEGMENT
|
|
14783
|
+
const segments = entry.split(NODE_STATUS_EXCLUDE_PATH_GRAMMAR.SEGMENT_SEPARATOR);
|
|
14784
|
+
if (entry.startsWith(NODE_STATUS_EXCLUDE_PATH_GRAMMAR.SEGMENT_SEPARATOR) || segments.some(
|
|
14785
|
+
(segment) => segment.length === 0 || segment === NODE_STATUS_EXCLUDE_PATH_GRAMMAR.CURRENT_DIRECTORY_SEGMENT || segment === NODE_STATUS_EXCLUDE_PATH_GRAMMAR.PARENT_DIRECTORY_SEGMENT
|
|
14758
14786
|
)) {
|
|
14759
|
-
throw new Error(
|
|
14787
|
+
throw new Error(nodeStatusInvalidExcludeEntryMessage(entry));
|
|
14760
14788
|
}
|
|
14761
14789
|
return entry;
|
|
14762
14790
|
}
|
|
14791
|
+
function nodeStatusInvalidExcludeEntryMessage(entry) {
|
|
14792
|
+
return `Invalid ${SPEC_TREE_CONFIG.ROOT_DIRECTORY}/${NODE_STATUS_EXCLUDE_FILENAME} entry: ${entry}`;
|
|
14793
|
+
}
|
|
14763
14794
|
function createNodeStatusExcludeReader(productDir) {
|
|
14764
14795
|
let content;
|
|
14765
14796
|
try {
|
|
@@ -14961,12 +14992,14 @@ async function updateNodeStatus(options) {
|
|
|
14961
14992
|
continue;
|
|
14962
14993
|
}
|
|
14963
14994
|
const evidence = evidenceByNode.get(node.id) ?? [];
|
|
14995
|
+
const statusPath = nodeStatusPath(productDir, node.id);
|
|
14996
|
+
const committedVerification = readNodeStatus(dirname11(statusPath))?.[NODE_STATUS_FIELD.VERIFICATION];
|
|
14964
14997
|
const verification = await resolveVerification(node, {
|
|
14965
14998
|
evidence,
|
|
14966
14999
|
isExcluded: excludeReader.isExcluded(node),
|
|
14967
|
-
resolveOutcome
|
|
15000
|
+
resolveOutcome,
|
|
15001
|
+
committedOutcomes: testOutcomes(committedVerification)
|
|
14968
15002
|
});
|
|
14969
|
-
const statusPath = nodeStatusPath(productDir, node.id);
|
|
14970
15003
|
liveStatusPaths.add(statusPath);
|
|
14971
15004
|
await writeNodeStatus(statusPath, verification);
|
|
14972
15005
|
}
|
|
@@ -14977,7 +15010,8 @@ async function resolveVerification(node, input) {
|
|
|
14977
15010
|
if (input.isExcluded) return createTestVerification(input.evidence, NODE_STATUS_EVIDENCE_OUTCOME.NOT_RUN);
|
|
14978
15011
|
return createTestVerificationFromOutcomes(
|
|
14979
15012
|
input.evidence,
|
|
14980
|
-
await input.resolveOutcome(node.id, evidencePaths(input.evidence))
|
|
15013
|
+
await input.resolveOutcome(node.id, evidencePaths(input.evidence)),
|
|
15014
|
+
input.committedOutcomes
|
|
14981
15015
|
);
|
|
14982
15016
|
}
|
|
14983
15017
|
function collectEvidenceByNode(snapshot) {
|
|
@@ -14993,16 +15027,23 @@ function collectEvidenceByNode(snapshot) {
|
|
|
14993
15027
|
}
|
|
14994
15028
|
function createTestVerification(evidence, outcome) {
|
|
14995
15029
|
const outcomes = Object.fromEntries(evidence.map((entry) => [evidencePath(entry), outcome]));
|
|
14996
|
-
return createTestVerificationFromOutcomes(evidence, outcomes);
|
|
15030
|
+
return createTestVerificationFromOutcomes(evidence, outcomes, {});
|
|
14997
15031
|
}
|
|
14998
|
-
function createTestVerificationFromOutcomes(evidence, resolvedOutcomes) {
|
|
15032
|
+
function createTestVerificationFromOutcomes(evidence, resolvedOutcomes, committedOutcomes) {
|
|
14999
15033
|
const outcomes = {};
|
|
15000
15034
|
for (const entry of evidence) {
|
|
15001
15035
|
const path4 = evidencePath(entry);
|
|
15002
|
-
outcomes[path4] = resolvedOutcomes[path4] ?? NODE_STATUS_EVIDENCE_OUTCOME.NOT_RUN;
|
|
15036
|
+
outcomes[path4] = resolvedOutcomes[path4] ?? committedOutcomes[path4] ?? NODE_STATUS_EVIDENCE_OUTCOME.NOT_RUN;
|
|
15003
15037
|
}
|
|
15004
15038
|
return { [NODE_STATUS_VERIFICATION_MECHANISM.TEST]: createNodeStatusMechanismRecord(outcomes) };
|
|
15005
15039
|
}
|
|
15040
|
+
function testOutcomes(verification) {
|
|
15041
|
+
const record7 = verification?.[NODE_STATUS_VERIFICATION_MECHANISM.TEST];
|
|
15042
|
+
if (record7 === void 0) return {};
|
|
15043
|
+
return Object.fromEntries(
|
|
15044
|
+
Object.entries(record7).filter(([reference]) => reference !== NODE_STATUS_FIELD.OVERALL)
|
|
15045
|
+
);
|
|
15046
|
+
}
|
|
15006
15047
|
function evidencePaths(evidence) {
|
|
15007
15048
|
return evidence.map(evidencePath);
|
|
15008
15049
|
}
|
|
@@ -15152,7 +15193,7 @@ function resolveSpecContextTarget(snapshot, input) {
|
|
|
15152
15193
|
if (candidates.length > 1) {
|
|
15153
15194
|
return {
|
|
15154
15195
|
failure: {
|
|
15155
|
-
candidates: candidates.map(nodeSegment).sort(
|
|
15196
|
+
candidates: candidates.map(nodeSegment).sort(compareSpecContextOrdinal),
|
|
15156
15197
|
input,
|
|
15157
15198
|
kind: SPEC_CONTEXT_TARGET_FAILURE_KIND.AMBIGUOUS_SEGMENT,
|
|
15158
15199
|
segment
|
|
@@ -15201,7 +15242,7 @@ function refPath(ref) {
|
|
|
15201
15242
|
return ref?.path;
|
|
15202
15243
|
}
|
|
15203
15244
|
function sortPaths(paths) {
|
|
15204
|
-
return [...paths].sort(
|
|
15245
|
+
return [...paths].sort(compareSpecContextOrdinal);
|
|
15205
15246
|
}
|
|
15206
15247
|
function fullSpecPath(path4) {
|
|
15207
15248
|
return path4.startsWith(SPEC_TREE_ROOT_PREFIX) ? path4 : `${SPEC_TREE_ROOT_PREFIX}${path4}`;
|
|
@@ -15247,11 +15288,11 @@ function lowerIndexSiblingsForContextNodes(snapshot, contextNodes) {
|
|
|
15247
15288
|
}
|
|
15248
15289
|
}
|
|
15249
15290
|
lowerSiblings.sort((left, right) => {
|
|
15250
|
-
const parentComparison = (left.parentId ?? ""
|
|
15291
|
+
const parentComparison = compareSpecContextOrdinal(left.parentId ?? "", right.parentId ?? "");
|
|
15251
15292
|
if (parentComparison !== 0) return parentComparison;
|
|
15252
15293
|
const orderComparison = left.order - right.order;
|
|
15253
15294
|
if (orderComparison !== 0) return orderComparison;
|
|
15254
|
-
return left.id
|
|
15295
|
+
return compareSpecContextOrdinal(left.id, right.id);
|
|
15255
15296
|
});
|
|
15256
15297
|
return lowerSiblings;
|
|
15257
15298
|
}
|
|
@@ -15386,9 +15427,7 @@ async function citedDecisionDocuments(productDir, sources, knownPaths, includePa
|
|
|
15386
15427
|
}
|
|
15387
15428
|
async function localOverlayPaths(productDir, trackedPaths) {
|
|
15388
15429
|
if (trackedPaths !== void 0) {
|
|
15389
|
-
return [...trackedPaths].filter((path4) => isLocalOverlayPath(path4)).sort(
|
|
15390
|
-
(left, right) => left.localeCompare(right)
|
|
15391
|
-
);
|
|
15430
|
+
return [...trackedPaths].filter((path4) => isLocalOverlayPath(path4)).sort(compareSpecContextOrdinal);
|
|
15392
15431
|
}
|
|
15393
15432
|
let entries;
|
|
15394
15433
|
try {
|
|
@@ -15396,7 +15435,7 @@ async function localOverlayPaths(productDir, trackedPaths) {
|
|
|
15396
15435
|
} catch {
|
|
15397
15436
|
return [];
|
|
15398
15437
|
}
|
|
15399
|
-
return entries.filter((name) => name.endsWith(SPEC_TREE_GRAMMAR.LOCAL_OVERLAYS.EXTENSION)).sort(
|
|
15438
|
+
return entries.filter((name) => name.endsWith(SPEC_TREE_GRAMMAR.LOCAL_OVERLAYS.EXTENSION)).sort(compareSpecContextOrdinal).map((name) => childSpecPath(SPEC_CONTEXT_LOCAL_OVERLAY_DIRECTORY, name));
|
|
15400
15439
|
}
|
|
15401
15440
|
async function withDocumentContent(productDir, read, scannedDocuments) {
|
|
15402
15441
|
const enriched = [];
|
|
@@ -15789,7 +15828,7 @@ function groupTestFiles(testFiles, languages) {
|
|
|
15789
15828
|
|
|
15790
15829
|
// src/domains/test/targeting.ts
|
|
15791
15830
|
var TESTS_DIRECTORY_NAME3 = SPEC_TREE_EVIDENCE_FILE.DIRECTORY_NAME;
|
|
15792
|
-
var
|
|
15831
|
+
var PATH_SEGMENT_SEPARATOR2 = "/";
|
|
15793
15832
|
function normalizeTargetOperand(operand) {
|
|
15794
15833
|
return normalizePathPrefix(operand);
|
|
15795
15834
|
}
|
|
@@ -15799,7 +15838,7 @@ function matchOperand(discovered, operand, recursive) {
|
|
|
15799
15838
|
return applyPathFilter(discovered, { include: [normalized] });
|
|
15800
15839
|
}
|
|
15801
15840
|
return applyPathFilter(discovered, {
|
|
15802
|
-
include: [`${normalized}${
|
|
15841
|
+
include: [`${normalized}${PATH_SEGMENT_SEPARATOR2}${TESTS_DIRECTORY_NAME3}`]
|
|
15803
15842
|
});
|
|
15804
15843
|
}
|
|
15805
15844
|
function resolveTargetedTestFiles(discovered, selection) {
|
|
@@ -15842,7 +15881,7 @@ async function runTests(options, deps) {
|
|
|
15842
15881
|
for (const group of groups) {
|
|
15843
15882
|
const invocation = await group.language.runTests(
|
|
15844
15883
|
{
|
|
15845
|
-
|
|
15884
|
+
productDir: options.productDir,
|
|
15846
15885
|
testPaths: group.testPaths,
|
|
15847
15886
|
excludedNodePaths: runnerExcludedNodePaths
|
|
15848
15887
|
},
|
|
@@ -16071,7 +16110,7 @@ async function readTestRunStatePath(runFilePath, fs4) {
|
|
|
16071
16110
|
return { ok: true, value: validated.value };
|
|
16072
16111
|
}
|
|
16073
16112
|
function validateTestRunState(value) {
|
|
16074
|
-
if (!
|
|
16113
|
+
if (!isRecord9(value)) return { ok: false, error: "testing run state must be an object" };
|
|
16075
16114
|
const branchName = readString2(value, TEST_RUN_STATE_FIELDS.BRANCH_NAME);
|
|
16076
16115
|
if (!branchName.ok) return branchName;
|
|
16077
16116
|
const headSha = readString2(value, TEST_RUN_STATE_FIELDS.HEAD_SHA);
|
|
@@ -16114,7 +16153,7 @@ function readRunnerOutcomes(raw) {
|
|
|
16114
16153
|
}
|
|
16115
16154
|
const outcomes = [];
|
|
16116
16155
|
for (const entry of raw) {
|
|
16117
|
-
if (!
|
|
16156
|
+
if (!isRecord9(entry)) {
|
|
16118
16157
|
return { ok: false, error: `${TEST_RUN_STATE_FIELDS.RUNNER_OUTCOMES} entries must be objects` };
|
|
16119
16158
|
}
|
|
16120
16159
|
const runnerId = readString2(entry, TEST_RUNNER_OUTCOME_FIELDS.RUNNER_ID);
|
|
@@ -16135,7 +16174,7 @@ function readProductInputDigests(raw) {
|
|
|
16135
16174
|
}
|
|
16136
16175
|
const digests = [];
|
|
16137
16176
|
for (const entry of raw) {
|
|
16138
|
-
if (!
|
|
16177
|
+
if (!isRecord9(entry)) {
|
|
16139
16178
|
return { ok: false, error: `${TEST_RUN_STATE_FIELDS.PRODUCT_INPUT_DIGESTS} entries must be objects` };
|
|
16140
16179
|
}
|
|
16141
16180
|
const descriptorId = readString2(entry, PRODUCT_INPUT_DIGEST_FIELDS.DESCRIPTOR_ID);
|
|
@@ -16197,7 +16236,7 @@ function testingWriteError(error) {
|
|
|
16197
16236
|
function withDomainErrorDetail(domainError, detail) {
|
|
16198
16237
|
return detail === void 0 ? domainError : `${domainError}: ${detail}`;
|
|
16199
16238
|
}
|
|
16200
|
-
function
|
|
16239
|
+
function isRecord9(value) {
|
|
16201
16240
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16202
16241
|
}
|
|
16203
16242
|
function sha256Hex2(value) {
|
|
@@ -16470,7 +16509,7 @@ async function relatedTestPaths(sourceFiles, options, baseRef, candidateTestPath
|
|
|
16470
16509
|
if (language.relatedTestPaths === void 0) continue;
|
|
16471
16510
|
const relatedDeps = deps.relatedDepsFor(language.name);
|
|
16472
16511
|
const languageResolution = await language.relatedTestPaths(
|
|
16473
|
-
{
|
|
16512
|
+
{ productDir: options.productDir, sourcePaths: sourceFiles, candidateTestPaths: candidateTestPaths2, baseRef },
|
|
16474
16513
|
options.staged === true ? { ...relatedDeps, readFile: (path4) => readStagedFile(options.productDir, path4, deps.git) } : relatedDeps
|
|
16475
16514
|
);
|
|
16476
16515
|
for (const sourceFile of languageResolution.resolvedSourcePaths) resolved.add(sourceFile);
|
|
@@ -16877,16 +16916,6 @@ async function runTestsCommand(options, deps) {
|
|
|
16877
16916
|
);
|
|
16878
16917
|
return { dispatch, runFile, recorded };
|
|
16879
16918
|
}
|
|
16880
|
-
async function runNodeCommand(options, deps) {
|
|
16881
|
-
const recording = resolveRecordingDependencies(deps);
|
|
16882
|
-
const runFile = await reserveRunFile(options.productDir, recording);
|
|
16883
|
-
const dispatch = await runTests(
|
|
16884
|
-
{ productDir: options.productDir, registry: deps.registry, passingScope: { include: [options.nodePath] } },
|
|
16885
|
-
{ runnerDepsFor: deps.runnerDepsFor }
|
|
16886
|
-
);
|
|
16887
|
-
const recorded = await recordRun(runFile, options.productDir, dispatch, recording, deps.registry);
|
|
16888
|
-
return { dispatch, runFile, recorded };
|
|
16889
|
-
}
|
|
16890
16919
|
|
|
16891
16920
|
// src/commands/spec/node-outcome-resolver.ts
|
|
16892
16921
|
var PATH_SEPARATOR3 = "/";
|
|
@@ -16895,9 +16924,6 @@ function createNodeOutcomeResolver(deps) {
|
|
|
16895
16924
|
let evidence;
|
|
16896
16925
|
const currentInputsByCoveredPaths = /* @__PURE__ */ new Map();
|
|
16897
16926
|
const sharedEvidence = () => evidence ??= loadResolverEvidence(deps);
|
|
16898
|
-
const refreshEvidence = () => {
|
|
16899
|
-
evidence = loadResolverEvidence(deps);
|
|
16900
|
-
};
|
|
16901
16927
|
const currentInputsFor = (coveredPaths) => {
|
|
16902
16928
|
const cacheKey = coveredPathCollectionKey(coveredPaths);
|
|
16903
16929
|
const cached = currentInputsByCoveredPaths.get(cacheKey);
|
|
@@ -16912,13 +16938,13 @@ function createNodeOutcomeResolver(deps) {
|
|
|
16912
16938
|
const { discoveredTestPaths, terminalRuns } = await sharedEvidence();
|
|
16913
16939
|
const nodePath = `${SPEC_TREE_CONFIG.ROOT_DIRECTORY}${PATH_SEPARATOR3}${nodeId}`;
|
|
16914
16940
|
const nodeTestPaths = filterNodeTestPaths(discoveredTestPaths, nodePath, evidencePaths2);
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
16920
|
-
|
|
16921
|
-
|
|
16941
|
+
return recordedOutcomes(
|
|
16942
|
+
discoveredTestPaths,
|
|
16943
|
+
terminalRuns,
|
|
16944
|
+
evidencePaths2,
|
|
16945
|
+
nodeTestPaths,
|
|
16946
|
+
currentInputsFor
|
|
16947
|
+
);
|
|
16922
16948
|
};
|
|
16923
16949
|
}
|
|
16924
16950
|
function coveredPathCollectionKey(coveredPaths) {
|
|
@@ -16934,24 +16960,27 @@ function filterNodeTestPaths(discoveredTestPaths, nodePath, evidencePaths2) {
|
|
|
16934
16960
|
const discovered = new Set(discoveredTestPaths.filter((path4) => path4.startsWith(prefix)));
|
|
16935
16961
|
return evidencePaths2.filter((path4) => discovered.has(path4));
|
|
16936
16962
|
}
|
|
16937
|
-
async function
|
|
16938
|
-
const
|
|
16939
|
-
|
|
16940
|
-
|
|
16941
|
-
}
|
|
16942
|
-
const runCoveredPaths = latest.state.runnerOutcomes.flatMap((outcome) => outcome.testPaths);
|
|
16963
|
+
async function recordedOutcomes(discoveredTestPaths, terminalRuns, evidencePaths2, nodeTestPaths, currentInputsFor) {
|
|
16964
|
+
const resolved = Object.fromEntries(
|
|
16965
|
+
evidencePaths2.map((path4) => [path4, NODE_STATUS_EVIDENCE_OUTCOME.NOT_RUN])
|
|
16966
|
+
);
|
|
16943
16967
|
const presentTestPaths = new Set(discoveredTestPaths);
|
|
16944
|
-
|
|
16945
|
-
|
|
16968
|
+
for (const path4 of nodeTestPaths) {
|
|
16969
|
+
const latest = selectLatestTerminalTestRunForNode(terminalRuns, [path4]);
|
|
16970
|
+
if (latest === void 0) continue;
|
|
16971
|
+
const runCoveredPaths = latest.state.runnerOutcomes.flatMap((outcome) => outcome.testPaths);
|
|
16972
|
+
if (!runCoveredPaths.every((coveredPath) => presentTestPaths.has(coveredPath))) {
|
|
16973
|
+
delete resolved[path4];
|
|
16974
|
+
continue;
|
|
16975
|
+
}
|
|
16976
|
+
const current = await currentInputsFor(runCoveredPaths);
|
|
16977
|
+
if (!isStalenessMatch(extractStalenessInputs(latest.state), current)) {
|
|
16978
|
+
delete resolved[path4];
|
|
16979
|
+
continue;
|
|
16980
|
+
}
|
|
16981
|
+
resolved[path4] = outcomeForPath(latest.state.runnerOutcomes, path4);
|
|
16946
16982
|
}
|
|
16947
|
-
|
|
16948
|
-
const fresh = isStalenessMatch(extractStalenessInputs(latest.state), current);
|
|
16949
|
-
return fresh && latest.state.status === TEST_RUN_STATE_STATUS.PASSED ? outcomesForPaths(latest.state.runnerOutcomes, nodeTestPaths) : void 0;
|
|
16950
|
-
}
|
|
16951
|
-
function outcomesForPaths(outcomes, nodeTestPaths) {
|
|
16952
|
-
return Object.fromEntries(
|
|
16953
|
-
nodeTestPaths.map((path4) => [path4, outcomeForPath(outcomes, path4)])
|
|
16954
|
-
);
|
|
16983
|
+
return resolved;
|
|
16955
16984
|
}
|
|
16956
16985
|
function outcomeForPath(outcomes, path4) {
|
|
16957
16986
|
const covering = outcomes.filter((outcome) => outcome.testPaths.includes(path4));
|
|
@@ -17173,11 +17202,11 @@ function coveredProductInputPaths(coveredTestPaths2) {
|
|
|
17173
17202
|
function excludeFlag(nodePath) {
|
|
17174
17203
|
return `${PYTHON_PYTEST_IGNORE_FLAG_PREFIX}${nodePath}${PYTHON_PYTEST_IGNORE_FLAG_SUFFIX}`;
|
|
17175
17204
|
}
|
|
17176
|
-
function detect(
|
|
17177
|
-
return deps?.isLanguagePresent?.(
|
|
17205
|
+
function detect(productDir, deps) {
|
|
17206
|
+
return deps?.isLanguagePresent?.(productDir) ?? detectPython(productDir).present;
|
|
17178
17207
|
}
|
|
17179
17208
|
async function runTests2(request, deps) {
|
|
17180
|
-
if (!detect(request.
|
|
17209
|
+
if (!detect(request.productDir, deps)) {
|
|
17181
17210
|
return { invoked: false };
|
|
17182
17211
|
}
|
|
17183
17212
|
const args = [
|
|
@@ -17248,7 +17277,7 @@ function createJournalReporter(sink) {
|
|
|
17248
17277
|
async function runTestsStreaming(request, deps) {
|
|
17249
17278
|
const reporter = createJournalReporter(deps.sink);
|
|
17250
17279
|
await deps.starter.start({
|
|
17251
|
-
|
|
17280
|
+
productDir: request.productDir,
|
|
17252
17281
|
testPaths: request.testPaths,
|
|
17253
17282
|
reporters: [reporter]
|
|
17254
17283
|
});
|
|
@@ -17261,7 +17290,7 @@ function createVitestRunStarter() {
|
|
|
17261
17290
|
const priorExitCode = process.exitCode;
|
|
17262
17291
|
try {
|
|
17263
17292
|
const vitest = await startVitest("test", [...options.testPaths], {
|
|
17264
|
-
root: options.
|
|
17293
|
+
root: options.productDir,
|
|
17265
17294
|
watch: false,
|
|
17266
17295
|
reporters: [...options.reporters]
|
|
17267
17296
|
});
|
|
@@ -17310,17 +17339,17 @@ function matchesTestFile2(filePath) {
|
|
|
17310
17339
|
function excludeFlag2(nodePath) {
|
|
17311
17340
|
return `${TYPESCRIPT_VITEST_EXCLUDE_FLAG_PREFIX}${nodePath}${TYPESCRIPT_VITEST_EXCLUDE_FLAG_SUFFIX}`;
|
|
17312
17341
|
}
|
|
17313
|
-
function detect2(
|
|
17314
|
-
return deps?.isLanguagePresent?.(
|
|
17342
|
+
function detect2(productDir, deps) {
|
|
17343
|
+
return deps?.isLanguagePresent?.(productDir) ?? detectTypeScript(productDir).present;
|
|
17315
17344
|
}
|
|
17316
17345
|
async function runTests3(request, deps) {
|
|
17317
|
-
if (!detect2(request.
|
|
17346
|
+
if (!detect2(request.productDir, deps)) {
|
|
17318
17347
|
return { invoked: false };
|
|
17319
17348
|
}
|
|
17320
17349
|
const args = [
|
|
17321
17350
|
...VITEST_INVOKE_ARGS,
|
|
17322
17351
|
VITEST_ROOT_FLAG,
|
|
17323
|
-
request.
|
|
17352
|
+
request.productDir,
|
|
17324
17353
|
...request.testPaths,
|
|
17325
17354
|
...request.excludedNodePaths.map(excludeFlag2)
|
|
17326
17355
|
];
|
|
@@ -17346,7 +17375,7 @@ function importSpecifiers(sourceText, testPath) {
|
|
|
17346
17375
|
}
|
|
17347
17376
|
return specifiers;
|
|
17348
17377
|
}
|
|
17349
|
-
function
|
|
17378
|
+
function isRecord10(value) {
|
|
17350
17379
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17351
17380
|
}
|
|
17352
17381
|
function hasErrorCode3(error, code) {
|
|
@@ -17381,11 +17410,11 @@ function pathMappingFromTsconfigPath(pathAlias, targets) {
|
|
|
17381
17410
|
};
|
|
17382
17411
|
}
|
|
17383
17412
|
function pathMappingsFromTsconfig(config) {
|
|
17384
|
-
if (!
|
|
17413
|
+
if (!isRecord10(config)) return [];
|
|
17385
17414
|
const compilerOptions = config[TSCONFIG_COMPILER_OPTIONS_KEY];
|
|
17386
|
-
if (!
|
|
17415
|
+
if (!isRecord10(compilerOptions)) return [];
|
|
17387
17416
|
const paths = compilerOptions[TSCONFIG_PATHS_KEY];
|
|
17388
|
-
if (!
|
|
17417
|
+
if (!isRecord10(paths)) return [];
|
|
17389
17418
|
return Object.entries(paths).flatMap(([pathAlias, targets]) => {
|
|
17390
17419
|
const mapping = pathMappingFromTsconfigPath(pathAlias, targets);
|
|
17391
17420
|
return mapping === null ? [] : [mapping];
|
|
@@ -17515,7 +17544,7 @@ async function readCandidateTest(path4, deps, moduleTextCache) {
|
|
|
17515
17544
|
return loaded;
|
|
17516
17545
|
}
|
|
17517
17546
|
async function relatedTestPaths2(request, deps) {
|
|
17518
|
-
if (!detect2(request.
|
|
17547
|
+
if (!detect2(request.productDir, deps)) {
|
|
17519
17548
|
return { testPaths: [], resolvedSourcePaths: [] };
|
|
17520
17549
|
}
|
|
17521
17550
|
const sourcePaths = new Set(request.sourcePaths);
|
|
@@ -17545,7 +17574,7 @@ async function relatedTestPaths2(request, deps) {
|
|
|
17545
17574
|
return { testPaths, resolvedSourcePaths: [...resolvedSourcePaths] };
|
|
17546
17575
|
}
|
|
17547
17576
|
async function runTestsStreaming2(request, deps) {
|
|
17548
|
-
if (!detect2(request.
|
|
17577
|
+
if (!detect2(request.productDir, deps)) {
|
|
17549
17578
|
return { invoked: false };
|
|
17550
17579
|
}
|
|
17551
17580
|
const terminalStatus = await runTestsStreaming(request, {
|
|
@@ -17571,141 +17600,13 @@ var testingRegistry = {
|
|
|
17571
17600
|
languages: [typescriptTestingLanguage, pythonTestingLanguage]
|
|
17572
17601
|
};
|
|
17573
17602
|
|
|
17574
|
-
// src/interfaces/cli/test-runner-deps.ts
|
|
17575
|
-
import { createWriteStream } from "fs";
|
|
17576
|
-
import { mkdtemp as mkdtemp3, readFile as readFile12 } from "fs/promises";
|
|
17577
|
-
import { tmpdir as tmpdir3 } from "os";
|
|
17578
|
-
import { join as join28 } from "path";
|
|
17579
|
-
import { finished } from "stream/promises";
|
|
17580
|
-
var PROCESS_FAILURE_EXIT_CODE = 1;
|
|
17581
|
-
var AGENT_ARTIFACT_DIR_PREFIX = "spx-test-agent-";
|
|
17582
|
-
var STDOUT_FILE_SUFFIX = "stdout.log";
|
|
17583
|
-
var STDERR_FILE_SUFFIX = "stderr.log";
|
|
17584
|
-
var ARTIFACT_INDEX_WIDTH = 3;
|
|
17585
|
-
var ARTIFACT_INDEX_RADIX = 10;
|
|
17586
|
-
var ARTIFACT_FILE_FLAGS = "wx";
|
|
17587
|
-
var EMPTY_RUNNER_ARGS = [];
|
|
17588
|
-
function createCommandRunner(productDir, outStream) {
|
|
17589
|
-
return (command, args) => new Promise((resolveResult) => {
|
|
17590
|
-
const child = spawnManagedSubprocess(lifecycleProcessRunner, command, args, {
|
|
17591
|
-
cwd: productDir
|
|
17592
|
-
});
|
|
17593
|
-
child.stdout?.pipe(outStream);
|
|
17594
|
-
child.stderr?.pipe(process.stderr);
|
|
17595
|
-
child.on("close", (code) => resolveResult({ exitCode: code ?? PROCESS_FAILURE_EXIT_CODE }));
|
|
17596
|
-
child.on("error", () => resolveResult({ exitCode: PROCESS_FAILURE_EXIT_CODE }));
|
|
17597
|
-
});
|
|
17598
|
-
}
|
|
17599
|
-
function createRelatedCommandRunner(productDir) {
|
|
17600
|
-
return (command, args) => new Promise((resolveResult) => {
|
|
17601
|
-
const stdout = [];
|
|
17602
|
-
const stderr = [];
|
|
17603
|
-
const child = spawnManagedSubprocess(lifecycleProcessRunner, command, args, {
|
|
17604
|
-
cwd: productDir
|
|
17605
|
-
});
|
|
17606
|
-
child.stdout?.on("data", (chunk) => stdout.push(String(chunk)));
|
|
17607
|
-
child.stderr?.on("data", (chunk) => stderr.push(String(chunk)));
|
|
17608
|
-
child.on("close", (code) => resolveResult({
|
|
17609
|
-
exitCode: code ?? PROCESS_FAILURE_EXIT_CODE,
|
|
17610
|
-
stdout: stdout.join(""),
|
|
17611
|
-
stderr: stderr.join("")
|
|
17612
|
-
}));
|
|
17613
|
-
child.on("error", (error) => resolveResult({
|
|
17614
|
-
exitCode: PROCESS_FAILURE_EXIT_CODE,
|
|
17615
|
-
stdout: stdout.join(""),
|
|
17616
|
-
stderr: error.message
|
|
17617
|
-
}));
|
|
17618
|
-
});
|
|
17619
|
-
}
|
|
17620
|
-
function createRunnerDepsFor(productDir, outStream = process.stdout) {
|
|
17621
|
-
const runCommand = createCommandRunner(productDir, outStream);
|
|
17622
|
-
return () => ({ runCommand });
|
|
17623
|
-
}
|
|
17624
|
-
function createRelatedDepsFor(productDir) {
|
|
17625
|
-
const runCommand = createRelatedCommandRunner(productDir);
|
|
17626
|
-
return () => ({ runCommand, readFile: (path4) => readFile12(join28(productDir, path4), "utf8") });
|
|
17627
|
-
}
|
|
17628
|
-
function artifactFileName(index, suffix) {
|
|
17629
|
-
return `${index.toString(ARTIFACT_INDEX_RADIX).padStart(ARTIFACT_INDEX_WIDTH, "0")}-${suffix}`;
|
|
17630
|
-
}
|
|
17631
|
-
function createArtifactWriters(root, index, createArtifactWriteStream) {
|
|
17632
|
-
const stdoutPath = join28(root, artifactFileName(index, STDOUT_FILE_SUFFIX));
|
|
17633
|
-
const stderrPath = join28(root, artifactFileName(index, STDERR_FILE_SUFFIX));
|
|
17634
|
-
const stdoutFile = createArtifactWriteStream(stdoutPath);
|
|
17635
|
-
const stderrFile = createArtifactWriteStream(stderrPath);
|
|
17636
|
-
return {
|
|
17637
|
-
stdoutPath,
|
|
17638
|
-
stderrPath,
|
|
17639
|
-
stdoutFile,
|
|
17640
|
-
stderrFile,
|
|
17641
|
-
completion: Promise.all([finished(stdoutFile), finished(stderrFile)])
|
|
17642
|
-
};
|
|
17643
|
-
}
|
|
17644
|
-
async function finishArtifactWriters(writers) {
|
|
17645
|
-
writers.stdoutFile.end();
|
|
17646
|
-
writers.stderrFile.end();
|
|
17647
|
-
await writers.completion;
|
|
17648
|
-
return {
|
|
17649
|
-
stdoutPath: writers.stdoutPath,
|
|
17650
|
-
stderrPath: writers.stderrPath
|
|
17651
|
-
};
|
|
17652
|
-
}
|
|
17653
|
-
function runCapturedCommand(request) {
|
|
17654
|
-
return new Promise((resolveResult) => {
|
|
17655
|
-
let settled = false;
|
|
17656
|
-
const resolveOnce = (result) => {
|
|
17657
|
-
if (settled) return;
|
|
17658
|
-
settled = true;
|
|
17659
|
-
resolveResult(result);
|
|
17660
|
-
};
|
|
17661
|
-
const child = spawnManagedSubprocess(request.processRunner, request.command, request.args, {
|
|
17662
|
-
cwd: request.productDir,
|
|
17663
|
-
env: request.inheritedEnv
|
|
17664
|
-
});
|
|
17665
|
-
child.stdout?.pipe(request.writers.stdoutFile);
|
|
17666
|
-
child.stderr?.pipe(request.writers.stderrFile);
|
|
17667
|
-
const resolveWithExitCode = (exitCode) => {
|
|
17668
|
-
finishArtifactWriters(request.writers).then((output) => resolveOnce({ exitCode, output })).catch(() => resolveOnce({ exitCode: PROCESS_FAILURE_EXIT_CODE }));
|
|
17669
|
-
};
|
|
17670
|
-
request.writers.completion.catch(() => {
|
|
17671
|
-
child.kill();
|
|
17672
|
-
resolveOnce({ exitCode: PROCESS_FAILURE_EXIT_CODE });
|
|
17673
|
-
});
|
|
17674
|
-
child.on("close", (code) => resolveWithExitCode(code ?? PROCESS_FAILURE_EXIT_CODE));
|
|
17675
|
-
child.on("error", () => resolveWithExitCode(PROCESS_FAILURE_EXIT_CODE));
|
|
17676
|
-
});
|
|
17677
|
-
}
|
|
17678
|
-
function createAgentOutputCommandRunner(productDir, options = {}) {
|
|
17679
|
-
let artifactRoot;
|
|
17680
|
-
const processRunner = options.processRunner ?? lifecycleProcessRunner;
|
|
17681
|
-
const inheritedEnv = options.env ?? process.env;
|
|
17682
|
-
const createArtifactWriteStream = options.createArtifactWriteStream ?? ((path4) => createWriteStream(path4, { flags: ARTIFACT_FILE_FLAGS }));
|
|
17683
|
-
let nextArtifactIndex = 0;
|
|
17684
|
-
return async (command, args = EMPTY_RUNNER_ARGS) => {
|
|
17685
|
-
nextArtifactIndex += 1;
|
|
17686
|
-
artifactRoot ??= mkdtemp3(join28(options.tmpDir ?? tmpdir3(), AGENT_ARTIFACT_DIR_PREFIX));
|
|
17687
|
-
const root = await artifactRoot;
|
|
17688
|
-
return runCapturedCommand({
|
|
17689
|
-
productDir,
|
|
17690
|
-
command,
|
|
17691
|
-
args,
|
|
17692
|
-
processRunner,
|
|
17693
|
-
inheritedEnv,
|
|
17694
|
-
writers: createArtifactWriters(root, nextArtifactIndex, createArtifactWriteStream)
|
|
17695
|
-
});
|
|
17696
|
-
};
|
|
17697
|
-
}
|
|
17698
|
-
function createAgentRunnerDepsFor(productDir, options = {}) {
|
|
17699
|
-
const runCommand = createAgentOutputCommandRunner(productDir, options);
|
|
17700
|
-
return () => ({ runCommand });
|
|
17701
|
-
}
|
|
17702
|
-
|
|
17703
17603
|
// src/interfaces/cli/spec.ts
|
|
17704
17604
|
var SPEC_DOMAIN_CLI = {
|
|
17705
17605
|
COMMAND: "spec",
|
|
17706
17606
|
STATUS_COMMAND: "status",
|
|
17707
17607
|
NEXT_COMMAND: "next",
|
|
17708
17608
|
CONTEXT_COMMAND: "context",
|
|
17609
|
+
RETIRED_APPLY_COMMAND: "apply",
|
|
17709
17610
|
JSON_OPTION: "--json",
|
|
17710
17611
|
CONTENT_OPTION: "--content",
|
|
17711
17612
|
FORMAT_OPTION_FLAG: "--format",
|
|
@@ -17826,8 +17727,7 @@ function registerSpecCommands(specCmd, invocation) {
|
|
|
17826
17727
|
update: true,
|
|
17827
17728
|
resolveOutcomeFor: (productDir2) => createNodeOutcomeResolver({
|
|
17828
17729
|
productDir: productDir2,
|
|
17829
|
-
registry: testingRegistry
|
|
17830
|
-
runnerDepsFor: createRunnerDepsFor(productDir2, process.stderr)
|
|
17730
|
+
registry: testingRegistry
|
|
17831
17731
|
})
|
|
17832
17732
|
}) : await statusCommand({ cwd: productDir(), format: format2, onWarning });
|
|
17833
17733
|
writeOutput3(invocation.io, output);
|
|
@@ -17951,70 +17851,199 @@ function formatAgentTestOutput(run) {
|
|
|
17951
17851
|
return `${lines.join(NEWLINE2)}${NEWLINE2}`;
|
|
17952
17852
|
}
|
|
17953
17853
|
|
|
17954
|
-
// src/interfaces/cli/test.ts
|
|
17955
|
-
|
|
17956
|
-
|
|
17957
|
-
|
|
17958
|
-
|
|
17959
|
-
|
|
17960
|
-
|
|
17961
|
-
|
|
17962
|
-
|
|
17963
|
-
|
|
17964
|
-
|
|
17965
|
-
|
|
17966
|
-
|
|
17967
|
-
|
|
17968
|
-
|
|
17969
|
-
|
|
17970
|
-
|
|
17971
|
-
|
|
17972
|
-
|
|
17973
|
-
|
|
17974
|
-
|
|
17975
|
-
|
|
17976
|
-
|
|
17977
|
-
|
|
17978
|
-
var UNRESOLVED_CHANGED_SOURCE_WARNING = "No related-test capability resolved these changed source files";
|
|
17979
|
-
var TESTING_PRODUCT_DIR_WARNING = {
|
|
17980
|
-
NOT_GIT_REPOSITORY: `Warning: Not in a git repository. Reading ${SPEC_TREE_CONFIG.ROOT_DIRECTORY} tests relative to the current working directory.`
|
|
17981
|
-
};
|
|
17982
|
-
async function resolveTestProductDir(cwd, writeWarning) {
|
|
17983
|
-
const { productDir, isGitRepo } = await detectWorktreeProductRoot(cwd);
|
|
17984
|
-
writeWarning(isGitRepo ? void 0 : TESTING_PRODUCT_DIR_WARNING.NOT_GIT_REPOSITORY);
|
|
17985
|
-
return productDir;
|
|
17986
|
-
}
|
|
17987
|
-
async function runTestsThroughCommand(productDir, passing, io, targets, changed) {
|
|
17988
|
-
try {
|
|
17989
|
-
return await runTestsCommand(
|
|
17990
|
-
{ productDir, passing, targets, changed },
|
|
17991
|
-
{
|
|
17992
|
-
registry: testingRegistry,
|
|
17993
|
-
runnerDepsFor: createRunnerDepsFor(productDir),
|
|
17994
|
-
relatedDepsFor: createRelatedDepsFor(productDir)
|
|
17995
|
-
}
|
|
17996
|
-
);
|
|
17997
|
-
} catch (error) {
|
|
17998
|
-
io.writeStderr(`${error instanceof Error ? error.message : String(error)}
|
|
17999
|
-
`);
|
|
18000
|
-
io.exit(PROCESS_FAILURE_EXIT_CODE);
|
|
18001
|
-
}
|
|
17854
|
+
// src/interfaces/cli/test-runner-deps.ts
|
|
17855
|
+
import { createWriteStream } from "fs";
|
|
17856
|
+
import { mkdtemp as mkdtemp3, readFile as readFile12 } from "fs/promises";
|
|
17857
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
17858
|
+
import { join as join28 } from "path";
|
|
17859
|
+
import { finished } from "stream/promises";
|
|
17860
|
+
var PROCESS_FAILURE_EXIT_CODE = 1;
|
|
17861
|
+
var AGENT_ARTIFACT_DIR_PREFIX = "spx-test-agent-";
|
|
17862
|
+
var STDOUT_FILE_SUFFIX = "stdout.log";
|
|
17863
|
+
var STDERR_FILE_SUFFIX = "stderr.log";
|
|
17864
|
+
var ARTIFACT_INDEX_WIDTH = 3;
|
|
17865
|
+
var ARTIFACT_INDEX_RADIX = 10;
|
|
17866
|
+
var ARTIFACT_FILE_FLAGS = "wx";
|
|
17867
|
+
var EMPTY_RUNNER_ARGS = [];
|
|
17868
|
+
function createCommandRunner(productDir, outStream, errStream, processRunner) {
|
|
17869
|
+
return (command, args) => new Promise((resolveResult) => {
|
|
17870
|
+
const child = spawnManagedSubprocess(processRunner, command, args, {
|
|
17871
|
+
cwd: productDir
|
|
17872
|
+
});
|
|
17873
|
+
child.stdout?.pipe(outStream);
|
|
17874
|
+
child.stderr?.pipe(errStream);
|
|
17875
|
+
child.on("close", (code) => resolveResult({ exitCode: code ?? PROCESS_FAILURE_EXIT_CODE }));
|
|
17876
|
+
child.on("error", () => resolveResult({ exitCode: PROCESS_FAILURE_EXIT_CODE }));
|
|
17877
|
+
});
|
|
18002
17878
|
}
|
|
18003
|
-
|
|
18004
|
-
|
|
18005
|
-
|
|
18006
|
-
|
|
18007
|
-
|
|
18008
|
-
|
|
18009
|
-
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
)
|
|
18013
|
-
|
|
18014
|
-
|
|
18015
|
-
|
|
18016
|
-
|
|
18017
|
-
|
|
17879
|
+
function createRelatedCommandRunner(productDir, processRunner) {
|
|
17880
|
+
return (command, args) => new Promise((resolveResult) => {
|
|
17881
|
+
const stdout = [];
|
|
17882
|
+
const stderr = [];
|
|
17883
|
+
const child = spawnManagedSubprocess(processRunner, command, args, {
|
|
17884
|
+
cwd: productDir
|
|
17885
|
+
});
|
|
17886
|
+
child.stdout?.on("data", (chunk) => stdout.push(String(chunk)));
|
|
17887
|
+
child.stderr?.on("data", (chunk) => stderr.push(String(chunk)));
|
|
17888
|
+
child.on("close", (code) => resolveResult({
|
|
17889
|
+
exitCode: code ?? PROCESS_FAILURE_EXIT_CODE,
|
|
17890
|
+
stdout: stdout.join(""),
|
|
17891
|
+
stderr: stderr.join("")
|
|
17892
|
+
}));
|
|
17893
|
+
child.on("error", (error) => resolveResult({
|
|
17894
|
+
exitCode: PROCESS_FAILURE_EXIT_CODE,
|
|
17895
|
+
stdout: stdout.join(""),
|
|
17896
|
+
stderr: error.message
|
|
17897
|
+
}));
|
|
17898
|
+
});
|
|
17899
|
+
}
|
|
17900
|
+
function createRunnerDepsFor(productDir, outStream = process.stdout, processRunner = lifecycleProcessRunner, errStream = process.stderr) {
|
|
17901
|
+
const runCommand = createCommandRunner(productDir, outStream, errStream, processRunner);
|
|
17902
|
+
return () => ({ runCommand });
|
|
17903
|
+
}
|
|
17904
|
+
function createRelatedDepsFor(productDir, processRunner = lifecycleProcessRunner) {
|
|
17905
|
+
const runCommand = createRelatedCommandRunner(productDir, processRunner);
|
|
17906
|
+
return () => ({ runCommand, readFile: (path4) => readFile12(join28(productDir, path4), "utf8") });
|
|
17907
|
+
}
|
|
17908
|
+
function artifactFileName(index, suffix) {
|
|
17909
|
+
return `${index.toString(ARTIFACT_INDEX_RADIX).padStart(ARTIFACT_INDEX_WIDTH, "0")}-${suffix}`;
|
|
17910
|
+
}
|
|
17911
|
+
function createArtifactWriters(root, index, createArtifactWriteStream) {
|
|
17912
|
+
const stdoutPath = join28(root, artifactFileName(index, STDOUT_FILE_SUFFIX));
|
|
17913
|
+
const stderrPath = join28(root, artifactFileName(index, STDERR_FILE_SUFFIX));
|
|
17914
|
+
const stdoutFile = createArtifactWriteStream(stdoutPath);
|
|
17915
|
+
const stderrFile = createArtifactWriteStream(stderrPath);
|
|
17916
|
+
return {
|
|
17917
|
+
stdoutPath,
|
|
17918
|
+
stderrPath,
|
|
17919
|
+
stdoutFile,
|
|
17920
|
+
stderrFile,
|
|
17921
|
+
completion: Promise.all([finished(stdoutFile), finished(stderrFile)])
|
|
17922
|
+
};
|
|
17923
|
+
}
|
|
17924
|
+
async function finishArtifactWriters(writers) {
|
|
17925
|
+
writers.stdoutFile.end();
|
|
17926
|
+
writers.stderrFile.end();
|
|
17927
|
+
await writers.completion;
|
|
17928
|
+
return {
|
|
17929
|
+
stdoutPath: writers.stdoutPath,
|
|
17930
|
+
stderrPath: writers.stderrPath
|
|
17931
|
+
};
|
|
17932
|
+
}
|
|
17933
|
+
function runCapturedCommand(request) {
|
|
17934
|
+
return new Promise((resolveResult) => {
|
|
17935
|
+
let settled = false;
|
|
17936
|
+
const resolveOnce = (result) => {
|
|
17937
|
+
if (settled) return;
|
|
17938
|
+
settled = true;
|
|
17939
|
+
resolveResult(result);
|
|
17940
|
+
};
|
|
17941
|
+
const child = spawnManagedSubprocess(request.processRunner, request.command, request.args, {
|
|
17942
|
+
cwd: request.productDir,
|
|
17943
|
+
env: request.inheritedEnv
|
|
17944
|
+
});
|
|
17945
|
+
child.stdout?.pipe(request.writers.stdoutFile);
|
|
17946
|
+
child.stderr?.pipe(request.writers.stderrFile);
|
|
17947
|
+
const resolveWithExitCode = (exitCode) => {
|
|
17948
|
+
finishArtifactWriters(request.writers).then((output) => resolveOnce({ exitCode, output })).catch(() => resolveOnce({ exitCode: PROCESS_FAILURE_EXIT_CODE }));
|
|
17949
|
+
};
|
|
17950
|
+
request.writers.completion.catch(() => {
|
|
17951
|
+
child.kill();
|
|
17952
|
+
resolveOnce({ exitCode: PROCESS_FAILURE_EXIT_CODE });
|
|
17953
|
+
});
|
|
17954
|
+
child.on("close", (code) => resolveWithExitCode(code ?? PROCESS_FAILURE_EXIT_CODE));
|
|
17955
|
+
child.on("error", () => resolveWithExitCode(PROCESS_FAILURE_EXIT_CODE));
|
|
17956
|
+
});
|
|
17957
|
+
}
|
|
17958
|
+
function createAgentOutputCommandRunner(productDir, options = {}) {
|
|
17959
|
+
let artifactRoot;
|
|
17960
|
+
const processRunner = options.processRunner ?? lifecycleProcessRunner;
|
|
17961
|
+
const inheritedEnv = options.env ?? process.env;
|
|
17962
|
+
const createArtifactWriteStream = options.createArtifactWriteStream ?? ((path4) => createWriteStream(path4, { flags: ARTIFACT_FILE_FLAGS }));
|
|
17963
|
+
let nextArtifactIndex = 0;
|
|
17964
|
+
return async (command, args = EMPTY_RUNNER_ARGS) => {
|
|
17965
|
+
nextArtifactIndex += 1;
|
|
17966
|
+
artifactRoot ??= mkdtemp3(join28(options.tmpDir ?? tmpdir3(), AGENT_ARTIFACT_DIR_PREFIX));
|
|
17967
|
+
const root = await artifactRoot;
|
|
17968
|
+
return runCapturedCommand({
|
|
17969
|
+
productDir,
|
|
17970
|
+
command,
|
|
17971
|
+
args,
|
|
17972
|
+
processRunner,
|
|
17973
|
+
inheritedEnv,
|
|
17974
|
+
writers: createArtifactWriters(root, nextArtifactIndex, createArtifactWriteStream)
|
|
17975
|
+
});
|
|
17976
|
+
};
|
|
17977
|
+
}
|
|
17978
|
+
function createAgentRunnerDepsFor(productDir, options = {}) {
|
|
17979
|
+
const runCommand = createAgentOutputCommandRunner(productDir, options);
|
|
17980
|
+
return () => ({ runCommand });
|
|
17981
|
+
}
|
|
17982
|
+
|
|
17983
|
+
// src/interfaces/cli/test.ts
|
|
17984
|
+
var TESTING_CLI = {
|
|
17985
|
+
commandName: "test",
|
|
17986
|
+
description: "Run spec-tree tests across product languages",
|
|
17987
|
+
agentOption: "--agent",
|
|
17988
|
+
agentDescription: "Capture raw runner output and print a compact agent summary",
|
|
17989
|
+
recursiveShortFlag: "-r",
|
|
17990
|
+
recursiveLongFlag: "--recursive",
|
|
17991
|
+
recursiveDescription: "Extend a node-path operand to its descendant nodes' tests",
|
|
17992
|
+
changedLongFlag: "--changed",
|
|
17993
|
+
changedDescription: "Run only tests affected by changes against the selected base",
|
|
17994
|
+
stagedLongFlag: "--staged",
|
|
17995
|
+
stagedDescription: "With --changed, diff the staged snapshot instead of the worktree",
|
|
17996
|
+
baseLongFlag: "--base",
|
|
17997
|
+
baseOperand: "<ref>",
|
|
17998
|
+
baseDescription: "Base ref for --changed; defaults to origin of the default branch",
|
|
17999
|
+
targetsArgument: "[targets...]",
|
|
18000
|
+
targetsDescription: "Node paths or test-file paths to run; omit to run the full discovered suite",
|
|
18001
|
+
passingSubcommand: "passing",
|
|
18002
|
+
passingDescription: "Run only the tests within the configured passing scope"
|
|
18003
|
+
};
|
|
18004
|
+
var UNMATCHED_TEST_FILES_WARNING = "Skipped test files with no registered runner";
|
|
18005
|
+
var GATED_TEST_RUNNERS_WARNING = "Skipped test files because their registered runner was gated out";
|
|
18006
|
+
var UNRESOLVED_TARGETS_WARNING = "No tests matched these operands";
|
|
18007
|
+
var UNRESOLVED_CHANGED_SOURCE_WARNING = "No related-test capability resolved these changed source files";
|
|
18008
|
+
var TESTING_PRODUCT_DIR_WARNING = {
|
|
18009
|
+
NOT_GIT_REPOSITORY: `Warning: Not in a git repository. Reading ${SPEC_TREE_CONFIG.ROOT_DIRECTORY} tests relative to the current working directory.`
|
|
18010
|
+
};
|
|
18011
|
+
async function resolveTestProductDir(cwd, writeWarning) {
|
|
18012
|
+
const { productDir, isGitRepo } = await detectWorktreeProductRoot(cwd);
|
|
18013
|
+
writeWarning(isGitRepo ? void 0 : TESTING_PRODUCT_DIR_WARNING.NOT_GIT_REPOSITORY);
|
|
18014
|
+
return productDir;
|
|
18015
|
+
}
|
|
18016
|
+
async function runTestsThroughCommand(productDir, passing, io, targets, changed) {
|
|
18017
|
+
try {
|
|
18018
|
+
return await runTestsCommand(
|
|
18019
|
+
{ productDir, passing, targets, changed },
|
|
18020
|
+
{
|
|
18021
|
+
registry: testingRegistry,
|
|
18022
|
+
runnerDepsFor: createRunnerDepsFor(productDir),
|
|
18023
|
+
relatedDepsFor: createRelatedDepsFor(productDir)
|
|
18024
|
+
}
|
|
18025
|
+
);
|
|
18026
|
+
} catch (error) {
|
|
18027
|
+
io.writeStderr(`${error instanceof Error ? error.message : String(error)}
|
|
18028
|
+
`);
|
|
18029
|
+
io.exit(PROCESS_FAILURE_EXIT_CODE);
|
|
18030
|
+
}
|
|
18031
|
+
}
|
|
18032
|
+
async function runAgentTestsThroughCommand(productDir, passing, io, targets, changed) {
|
|
18033
|
+
try {
|
|
18034
|
+
return await runTestsCommand(
|
|
18035
|
+
{ productDir, passing, targets, changed },
|
|
18036
|
+
{
|
|
18037
|
+
registry: testingRegistry,
|
|
18038
|
+
runnerDepsFor: createAgentRunnerDepsFor(productDir),
|
|
18039
|
+
relatedDepsFor: createRelatedDepsFor(productDir)
|
|
18040
|
+
}
|
|
18041
|
+
);
|
|
18042
|
+
} catch (error) {
|
|
18043
|
+
io.writeStderr(`${error instanceof Error ? error.message : String(error)}
|
|
18044
|
+
`);
|
|
18045
|
+
io.exit(PROCESS_FAILURE_EXIT_CODE);
|
|
18046
|
+
}
|
|
18018
18047
|
}
|
|
18019
18048
|
function unreportedGroups2(result) {
|
|
18020
18049
|
const reportedRunnerIds = new Set(result.reports.map((report2) => report2.runnerId));
|
|
@@ -18138,6 +18167,12 @@ var testingDomain = createTestingDomain();
|
|
|
18138
18167
|
import { existsSync as existsSync9, realpathSync } from "fs";
|
|
18139
18168
|
import { relative as relative11, resolve as resolve16 } from "path";
|
|
18140
18169
|
|
|
18170
|
+
// src/validation/languages/types.ts
|
|
18171
|
+
var VALIDATION_STAGE_PARTICIPATION = {
|
|
18172
|
+
RUN: "run",
|
|
18173
|
+
SKIP: "skip"
|
|
18174
|
+
};
|
|
18175
|
+
|
|
18141
18176
|
// src/commands/validation/formatting.ts
|
|
18142
18177
|
import { existsSync, statSync } from "fs";
|
|
18143
18178
|
import { isAbsolute as isAbsolute6, join as join29, relative as relative6 } from "path";
|
|
@@ -18153,8 +18188,8 @@ function unique(values) {
|
|
|
18153
18188
|
function nonEmpty(values) {
|
|
18154
18189
|
return values?.filter((value) => value.length > 0) ?? [];
|
|
18155
18190
|
}
|
|
18156
|
-
function
|
|
18157
|
-
return isAbsolute5(path4) ? relative5(
|
|
18191
|
+
function toProductRelativeValidationPath(productDir, path4) {
|
|
18192
|
+
return isAbsolute5(path4) ? relative5(productDir, path4) : path4;
|
|
18158
18193
|
}
|
|
18159
18194
|
function intersectIncludes(baseInclude, toolInclude) {
|
|
18160
18195
|
const base = nonEmpty(baseInclude);
|
|
@@ -18259,6 +18294,9 @@ function applyValidationPathFilterToScope(scopeConfig, filter) {
|
|
|
18259
18294
|
};
|
|
18260
18295
|
}
|
|
18261
18296
|
|
|
18297
|
+
// src/validation/steps/formatting.ts
|
|
18298
|
+
import { createRequire } from "module";
|
|
18299
|
+
|
|
18262
18300
|
// src/validation/steps/subprocess-output.ts
|
|
18263
18301
|
var VALIDATION_SUBPROCESS_EVENTS = {
|
|
18264
18302
|
CLOSE: "close",
|
|
@@ -18270,6 +18308,13 @@ var defaultValidationSubprocessOutputStreams = {
|
|
|
18270
18308
|
stdout: process.stdout,
|
|
18271
18309
|
stderr: process.stderr
|
|
18272
18310
|
};
|
|
18311
|
+
var discardValidationSubprocessOutputStream = {
|
|
18312
|
+
write: () => true
|
|
18313
|
+
};
|
|
18314
|
+
var discardValidationSubprocessOutputStreams = {
|
|
18315
|
+
stdout: discardValidationSubprocessOutputStream,
|
|
18316
|
+
stderr: discardValidationSubprocessOutputStream
|
|
18317
|
+
};
|
|
18273
18318
|
function forwardValidationSubprocessOutput(child, streams = defaultValidationSubprocessOutputStreams) {
|
|
18274
18319
|
child.stdout?.on(VALIDATION_SUBPROCESS_EVENTS.DATA, (chunk) => {
|
|
18275
18320
|
forwardChunkWithBackpressure(child.stdout, streams.stdout, chunk);
|
|
@@ -18290,7 +18335,12 @@ function forwardChunkWithBackpressure(source, stream, chunk) {
|
|
|
18290
18335
|
}
|
|
18291
18336
|
|
|
18292
18337
|
// src/validation/steps/formatting.ts
|
|
18293
|
-
var
|
|
18338
|
+
var DPRINT_EXECUTABLE_SPECIFIER = "dprint/bin.cjs";
|
|
18339
|
+
var cachedDprintCommand;
|
|
18340
|
+
function resolveDprintCommand() {
|
|
18341
|
+
cachedDprintCommand ??= createRequire(import.meta.url).resolve(DPRINT_EXECUTABLE_SPECIFIER);
|
|
18342
|
+
return cachedDprintCommand;
|
|
18343
|
+
}
|
|
18294
18344
|
var DPRINT_CHECK_SUBCOMMAND = "check";
|
|
18295
18345
|
var DPRINT_EXCLUDES_OPTION = "--excludes";
|
|
18296
18346
|
var DPRINT_OPTIONS_TERMINATOR = "--";
|
|
@@ -18306,16 +18356,17 @@ function buildDprintCheckArgs(options) {
|
|
|
18306
18356
|
...files
|
|
18307
18357
|
];
|
|
18308
18358
|
}
|
|
18309
|
-
async function validateFormatting(context, runner = defaultFormattingProcessRunner) {
|
|
18359
|
+
async function validateFormatting(context, runner = defaultFormattingProcessRunner, outputStreams) {
|
|
18310
18360
|
const args = buildDprintCheckArgs({ files: context.files, excludes: context.excludes });
|
|
18311
18361
|
return new Promise((resolve17) => {
|
|
18312
|
-
const child = spawnManagedSubprocess(runner,
|
|
18362
|
+
const child = spawnManagedSubprocess(runner, resolveDprintCommand(), args, { cwd: context.productDir });
|
|
18313
18363
|
const chunks = [];
|
|
18314
18364
|
const capture = (chunk) => {
|
|
18315
18365
|
chunks.push(typeof chunk === "string" ? chunk : Buffer.from(chunk).toString());
|
|
18316
18366
|
};
|
|
18317
18367
|
child.stdout?.on(VALIDATION_SUBPROCESS_EVENTS.DATA, capture);
|
|
18318
18368
|
child.stderr?.on(VALIDATION_SUBPROCESS_EVENTS.DATA, capture);
|
|
18369
|
+
forwardValidationSubprocessOutput(child, outputStreams);
|
|
18319
18370
|
child.on(VALIDATION_SUBPROCESS_EVENTS.CLOSE, (code) => {
|
|
18320
18371
|
resolve17({ success: code === 0, output: chunks.join("") });
|
|
18321
18372
|
});
|
|
@@ -18337,59 +18388,140 @@ var VALIDATION_STAGE_DISPLAY_NAMES = {
|
|
|
18337
18388
|
};
|
|
18338
18389
|
var VALIDATION_SKIP_LABELS = {
|
|
18339
18390
|
VERB: "Skipping",
|
|
18340
|
-
CIRCULAR_REASON: "skip-circular",
|
|
18341
|
-
LITERAL_REASON: "skip-literal",
|
|
18342
18391
|
DISABLED_BY_PREFIX: "disabled by",
|
|
18343
|
-
TYPESCRIPT_ABSENT_REASON: "TypeScript not detected in
|
|
18392
|
+
TYPESCRIPT_ABSENT_REASON: "TypeScript not detected in product",
|
|
18344
18393
|
VALIDATION_PATHS_NO_TARGETS_REASON: "validation paths matched no files",
|
|
18394
|
+
EXPLICIT_PATHS_NO_TARGETS_REASON: "explicit paths matched no files in tool scope",
|
|
18345
18395
|
MARKDOWN_NO_SCOPE_REASON: "no markdown files in explicit path scope",
|
|
18346
18396
|
MARKDOWN_NO_DEFAULT_DIRECTORIES_REASON: "no spx/ or docs/ directories found"
|
|
18347
18397
|
};
|
|
18398
|
+
var VALIDATION_STREAMED_STAGE_RESULT = "output streamed";
|
|
18399
|
+
var VALIDATION_PROBLEM_TERMS = {
|
|
18400
|
+
SINGULAR: "problem",
|
|
18401
|
+
PLURAL: "problems"
|
|
18402
|
+
};
|
|
18403
|
+
function formatValidationNoProblemsMessage(stageName) {
|
|
18404
|
+
return `${stageName}: \u2713 No ${VALIDATION_PROBLEM_TERMS.PLURAL}`;
|
|
18405
|
+
}
|
|
18406
|
+
function formatValidationProblemsFoundMessage(stageName, options = {}) {
|
|
18407
|
+
const countPrefix = options.count === void 0 ? "" : `${options.count} `;
|
|
18408
|
+
const term = options.count === 1 ? VALIDATION_PROBLEM_TERMS.SINGULAR : VALIDATION_PROBLEM_TERMS.PLURAL;
|
|
18409
|
+
const detailSuffix = options.detail === void 0 ? "" : ` (${options.detail})`;
|
|
18410
|
+
return `${stageName}: ${countPrefix}${term} found${detailSuffix}`;
|
|
18411
|
+
}
|
|
18412
|
+
function formatValidationConfigProblemMessage(stageName, detail) {
|
|
18413
|
+
return formatValidationProblemsFoundMessage(stageName, { count: 1, detail });
|
|
18414
|
+
}
|
|
18415
|
+
var VALIDATION_STAGE_PROBLEM_MESSAGES = {
|
|
18416
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR]: {
|
|
18417
|
+
clear: formatValidationNoProblemsMessage(VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR),
|
|
18418
|
+
attention: formatValidationProblemsFoundMessage(VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR, {
|
|
18419
|
+
detail: "circular dependencies"
|
|
18420
|
+
})
|
|
18421
|
+
},
|
|
18422
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.KNIP]: {
|
|
18423
|
+
clear: formatValidationNoProblemsMessage(VALIDATION_STAGE_DISPLAY_NAMES.KNIP),
|
|
18424
|
+
attention: formatValidationProblemsFoundMessage(VALIDATION_STAGE_DISPLAY_NAMES.KNIP, {
|
|
18425
|
+
detail: "unused code"
|
|
18426
|
+
})
|
|
18427
|
+
},
|
|
18428
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.ESLINT]: {
|
|
18429
|
+
clear: formatValidationNoProblemsMessage(VALIDATION_STAGE_DISPLAY_NAMES.ESLINT),
|
|
18430
|
+
attention: formatValidationProblemsFoundMessage(VALIDATION_STAGE_DISPLAY_NAMES.ESLINT)
|
|
18431
|
+
},
|
|
18432
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT]: {
|
|
18433
|
+
clear: formatValidationNoProblemsMessage(VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT),
|
|
18434
|
+
attention: formatValidationProblemsFoundMessage(VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT)
|
|
18435
|
+
},
|
|
18436
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.MARKDOWN]: {
|
|
18437
|
+
clear: formatValidationNoProblemsMessage(VALIDATION_STAGE_DISPLAY_NAMES.MARKDOWN),
|
|
18438
|
+
attention: formatValidationProblemsFoundMessage(VALIDATION_STAGE_DISPLAY_NAMES.MARKDOWN)
|
|
18439
|
+
},
|
|
18440
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.LITERAL]: {
|
|
18441
|
+
clear: formatValidationNoProblemsMessage(VALIDATION_STAGE_DISPLAY_NAMES.LITERAL),
|
|
18442
|
+
attention: formatValidationProblemsFoundMessage(VALIDATION_STAGE_DISPLAY_NAMES.LITERAL)
|
|
18443
|
+
},
|
|
18444
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.FORMATTING]: {
|
|
18445
|
+
clear: formatValidationNoProblemsMessage(VALIDATION_STAGE_DISPLAY_NAMES.FORMATTING),
|
|
18446
|
+
attention: formatValidationProblemsFoundMessage(VALIDATION_STAGE_DISPLAY_NAMES.FORMATTING, {
|
|
18447
|
+
detail: "unformatted files"
|
|
18448
|
+
})
|
|
18449
|
+
}
|
|
18450
|
+
};
|
|
18348
18451
|
var VALIDATION_COMMAND_OUTPUT = {
|
|
18349
|
-
CIRCULAR_FOUND:
|
|
18350
|
-
CIRCULAR_NONE_FOUND:
|
|
18351
|
-
KNIP_CONFIG_ERROR:
|
|
18452
|
+
CIRCULAR_FOUND: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR].attention,
|
|
18453
|
+
CIRCULAR_NONE_FOUND: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR].clear,
|
|
18454
|
+
KNIP_CONFIG_ERROR: formatValidationConfigProblemMessage(
|
|
18455
|
+
VALIDATION_STAGE_DISPLAY_NAMES.KNIP,
|
|
18456
|
+
"configuration error"
|
|
18457
|
+
),
|
|
18352
18458
|
KNIP_DISABLED: `${VALIDATION_STAGE_DISPLAY_NAMES.KNIP}: skipped (${VALIDATION_SKIP_LABELS.DISABLED_BY_PREFIX} validation.knip.enabled)`,
|
|
18353
|
-
KNIP_SUCCESS:
|
|
18354
|
-
KNIP_FAILURE:
|
|
18355
|
-
ESLINT_SUCCESS:
|
|
18356
|
-
ESLINT_FAILURE:
|
|
18357
|
-
ESLINT_MISSING_CONFIG:
|
|
18358
|
-
|
|
18359
|
-
|
|
18360
|
-
|
|
18361
|
-
|
|
18362
|
-
|
|
18363
|
-
|
|
18364
|
-
|
|
18365
|
-
|
|
18366
|
-
|
|
18367
|
-
|
|
18368
|
-
|
|
18369
|
-
}
|
|
18370
|
-
|
|
18371
|
-
|
|
18372
|
-
|
|
18373
|
-
reason: VALIDATION_SKIP_LABELS.LITERAL_REASON
|
|
18374
|
-
});
|
|
18459
|
+
KNIP_SUCCESS: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.KNIP].clear,
|
|
18460
|
+
KNIP_FAILURE: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.KNIP].attention,
|
|
18461
|
+
ESLINT_SUCCESS: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.ESLINT].clear,
|
|
18462
|
+
ESLINT_FAILURE: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.ESLINT].attention,
|
|
18463
|
+
ESLINT_MISSING_CONFIG: formatValidationConfigProblemMessage(
|
|
18464
|
+
VALIDATION_STAGE_DISPLAY_NAMES.ESLINT,
|
|
18465
|
+
"configuration missing: product has tsconfig.json but no eslint.config.{ts,js,mjs,cjs}"
|
|
18466
|
+
),
|
|
18467
|
+
TYPESCRIPT_SUCCESS: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT].clear,
|
|
18468
|
+
TYPESCRIPT_FAILURE: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT].attention,
|
|
18469
|
+
MARKDOWN_NO_ISSUES: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.MARKDOWN].clear,
|
|
18470
|
+
FORMATTING_NO_ISSUES: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.FORMATTING].clear,
|
|
18471
|
+
FORMATTING_FAILURE_SUMMARY: VALIDATION_STAGE_PROBLEM_MESSAGES[VALIDATION_STAGE_DISPLAY_NAMES.FORMATTING].attention
|
|
18472
|
+
};
|
|
18473
|
+
function formatValidationStageSkipOutput(stageName, reason) {
|
|
18474
|
+
return `${stageName}: skipped (${reason})`;
|
|
18475
|
+
}
|
|
18476
|
+
function formatValidationStageSkipJsonOutput(reason, durationMs) {
|
|
18477
|
+
return JSON.stringify({ skipped: true, reason, durationMs });
|
|
18478
|
+
}
|
|
18375
18479
|
function formatTypeScriptAbsentSkipMessage(stageName) {
|
|
18376
18480
|
return `\u23ED ${VALIDATION_SKIP_LABELS.VERB} ${stageName} (${VALIDATION_SKIP_LABELS.TYPESCRIPT_ABSENT_REASON})`;
|
|
18377
18481
|
}
|
|
18378
18482
|
function formatValidationPathsNoTargetsSkipMessage(stageName) {
|
|
18379
18483
|
return `\u23ED ${VALIDATION_SKIP_LABELS.VERB} ${stageName} (${VALIDATION_SKIP_LABELS.VALIDATION_PATHS_NO_TARGETS_REASON})`;
|
|
18380
18484
|
}
|
|
18485
|
+
function formatExplicitPathsNoTargetsSkipMessage(stageName) {
|
|
18486
|
+
return `\u23ED ${VALIDATION_SKIP_LABELS.VERB} ${stageName} (${VALIDATION_SKIP_LABELS.EXPLICIT_PATHS_NO_TARGETS_REASON})`;
|
|
18487
|
+
}
|
|
18488
|
+
function formatValidationScopeNoTargetsSkipMessage(stageName, metadata) {
|
|
18489
|
+
if (metadata.explicitPathNoMatches) {
|
|
18490
|
+
return formatExplicitPathsNoTargetsSkipMessage(stageName);
|
|
18491
|
+
}
|
|
18492
|
+
if (metadata.filteredByValidationPathNoMatches) {
|
|
18493
|
+
return formatValidationPathsNoTargetsSkipMessage(stageName);
|
|
18494
|
+
}
|
|
18495
|
+
return void 0;
|
|
18496
|
+
}
|
|
18497
|
+
|
|
18498
|
+
// src/commands/validation/types.ts
|
|
18499
|
+
var VALIDATION_OUTPUT_TARGET = {
|
|
18500
|
+
STDOUT: "stdout",
|
|
18501
|
+
STDERR: "stderr"
|
|
18502
|
+
};
|
|
18503
|
+
var VALIDATION_STREAMED_TERMINAL_OUTPUT = "";
|
|
18504
|
+
function streamedValidationTerminalOutput(subprocessOutput, json, streamedPipelineOutput) {
|
|
18505
|
+
return json !== true && streamedPipelineOutput === true && subprocessOutput !== void 0 && subprocessOutput.length > 0 ? VALIDATION_STREAMED_TERMINAL_OUTPUT : void 0;
|
|
18506
|
+
}
|
|
18381
18507
|
|
|
18382
18508
|
// src/commands/validation/formatting.ts
|
|
18509
|
+
var defaultFormattingCommandDependencies = {
|
|
18510
|
+
validateFormatting
|
|
18511
|
+
};
|
|
18383
18512
|
var FORMATTING_COMMAND_OUTPUT = {
|
|
18384
18513
|
NO_ISSUES: VALIDATION_COMMAND_OUTPUT.FORMATTING_NO_ISSUES,
|
|
18385
18514
|
FAILURE_SUMMARY: VALIDATION_COMMAND_OUTPUT.FORMATTING_FAILURE_SUMMARY,
|
|
18386
18515
|
EMPTY_SCOPE_REASON: "no files in scope",
|
|
18387
18516
|
NO_CONFIG_SKIP_REASON: `no ${DPRINT_CONFIG_FILENAME} at product root`
|
|
18388
18517
|
};
|
|
18389
|
-
var FORMATTING_CONFIG_ERROR_MESSAGE =
|
|
18518
|
+
var FORMATTING_CONFIG_ERROR_MESSAGE = formatValidationConfigProblemMessage(
|
|
18519
|
+
VALIDATION_STAGE_DISPLAY_NAMES.FORMATTING,
|
|
18520
|
+
"configuration error"
|
|
18521
|
+
);
|
|
18390
18522
|
var DPRINT_RECURSIVE_DIRECTORY_GLOB_SUFFIX = "/**/*";
|
|
18391
|
-
async function formattingCommand(options) {
|
|
18392
|
-
const { cwd, files, quiet } = options;
|
|
18523
|
+
async function formattingCommand(options, dependencies = defaultFormattingCommandDependencies) {
|
|
18524
|
+
const { cwd, files, json, outputStreams, quiet, streamedPipelineOutput } = options;
|
|
18393
18525
|
const startTime = Date.now();
|
|
18394
18526
|
const loaded = await resolveConfig(cwd, [validationConfigDescriptor]);
|
|
18395
18527
|
if (!loaded.ok) {
|
|
@@ -18409,32 +18541,52 @@ async function formattingCommand(options) {
|
|
|
18409
18541
|
VALIDATION_PATH_TOOL_SUBSECTIONS.FORMATTING
|
|
18410
18542
|
);
|
|
18411
18543
|
const hasExplicitScope = files !== void 0 && files.length > 0;
|
|
18412
|
-
const
|
|
18413
|
-
|
|
18414
|
-
|
|
18415
|
-
isAbsolute6(filePath) ? relative6(cwd, filePath) : filePath,
|
|
18416
|
-
pathFilter
|
|
18417
|
-
)
|
|
18418
|
-
) : void 0;
|
|
18419
|
-
const scopedExcludes = hasExplicitScope && files.some(
|
|
18420
|
-
(filePath) => isFormattingFileOperand(cwd, isAbsolute6(filePath) ? relative6(cwd, filePath) : filePath)
|
|
18421
|
-
) ? [] : validationPathFilterExcludes(pathFilter);
|
|
18422
|
-
if (hasExplicitScope && (scopedFiles === void 0 || scopedFiles.length === 0)) {
|
|
18544
|
+
const contexts = formattingValidationContexts(cwd, files, pathFilter);
|
|
18545
|
+
const scopedFiles = contexts.flatMap((context) => context.files ?? []);
|
|
18546
|
+
if (hasExplicitScope && scopedFiles.length === 0 || contexts.length === 0) {
|
|
18423
18547
|
const output2 = quiet ? "" : `${VALIDATION_STAGE_DISPLAY_NAMES.FORMATTING}: skipped (${FORMATTING_COMMAND_OUTPUT.EMPTY_SCOPE_REASON})`;
|
|
18424
18548
|
return { exitCode: 0, output: output2, durationMs: Date.now() - startTime };
|
|
18425
18549
|
}
|
|
18426
|
-
const
|
|
18427
|
-
|
|
18428
|
-
|
|
18429
|
-
|
|
18430
|
-
}
|
|
18550
|
+
const results = [];
|
|
18551
|
+
const subprocessOutputStreams = outputStreams ?? discardValidationSubprocessOutputStreams;
|
|
18552
|
+
for (const context of contexts) {
|
|
18553
|
+
results.push(await dependencies.validateFormatting(context, void 0, subprocessOutputStreams));
|
|
18554
|
+
}
|
|
18431
18555
|
const durationMs = Date.now() - startTime;
|
|
18432
|
-
if (result.success) {
|
|
18556
|
+
if (results.every((result) => result.success)) {
|
|
18433
18557
|
return { exitCode: 0, output: quiet ? "" : FORMATTING_COMMAND_OUTPUT.NO_ISSUES, durationMs };
|
|
18434
18558
|
}
|
|
18435
|
-
const detail = result.
|
|
18559
|
+
const detail = results.filter((result) => !result.success).flatMap((result) => [result.output, result.error]).filter((output2) => output2 !== void 0).filter((output2) => output2.length > 0).join("\n");
|
|
18436
18560
|
const output = [FORMATTING_COMMAND_OUTPUT.FAILURE_SUMMARY, detail].filter((line) => line.length > 0).join("\n");
|
|
18437
|
-
|
|
18561
|
+
const terminalOutput = formattingTerminalOutput(results, outputStreams, json, streamedPipelineOutput);
|
|
18562
|
+
return { exitCode: 1, output, terminalOutput, durationMs };
|
|
18563
|
+
}
|
|
18564
|
+
function formattingValidationContexts(productDir, files, pathFilter) {
|
|
18565
|
+
if (files === void 0 || files.length === 0) {
|
|
18566
|
+
if (validationPathFilterHasNoMatchingIncludes(pathFilter)) return [];
|
|
18567
|
+
const automaticFiles = pathFilter.include?.map((path4) => normalizeFormattingPathOperand(productDir, path4));
|
|
18568
|
+
return [{
|
|
18569
|
+
productDir,
|
|
18570
|
+
files: automaticFiles !== void 0 && automaticFiles.length > 0 ? automaticFiles : void 0,
|
|
18571
|
+
excludes: validationPathFilterExcludes(pathFilter)
|
|
18572
|
+
}];
|
|
18573
|
+
}
|
|
18574
|
+
const relativeFiles = files.map((filePath) => isAbsolute6(filePath) ? relative6(productDir, filePath) : filePath);
|
|
18575
|
+
return [{
|
|
18576
|
+
productDir,
|
|
18577
|
+
files: relativeFiles.map((filePath) => normalizeFormattingPathOperand(productDir, filePath)),
|
|
18578
|
+
excludes: []
|
|
18579
|
+
}];
|
|
18580
|
+
}
|
|
18581
|
+
function formattingTerminalOutput(results, outputStreams, json, streamedPipelineOutput) {
|
|
18582
|
+
if (json === true || outputStreams === void 0) {
|
|
18583
|
+
return void 0;
|
|
18584
|
+
}
|
|
18585
|
+
const errors = results.flatMap((result) => result.error === void 0 ? [] : [result.error]);
|
|
18586
|
+
if (errors.length > 0) {
|
|
18587
|
+
return [FORMATTING_COMMAND_OUTPUT.FAILURE_SUMMARY, ...errors].join("\n");
|
|
18588
|
+
}
|
|
18589
|
+
return streamedPipelineOutput === true ? VALIDATION_STREAMED_TERMINAL_OUTPUT : FORMATTING_COMMAND_OUTPUT.FAILURE_SUMMARY;
|
|
18438
18590
|
}
|
|
18439
18591
|
function normalizeFormattingPathOperand(productDir, relativePath) {
|
|
18440
18592
|
if (isFormattingFileOperand(productDir, relativePath)) {
|
|
@@ -18450,22 +18602,35 @@ function isFormattingFileOperand(productDir, relativePath) {
|
|
|
18450
18602
|
const absolutePath = join29(productDir, relativePath);
|
|
18451
18603
|
return !existsSync(absolutePath) || !statSync(absolutePath).isDirectory();
|
|
18452
18604
|
}
|
|
18453
|
-
function formattingPathOperandsForValidationPathFilter(productDir, relativePath, pathFilter) {
|
|
18454
|
-
if (isFormattingFileOperand(productDir, relativePath)) {
|
|
18455
|
-
return [relativePath];
|
|
18456
|
-
}
|
|
18457
|
-
return validationPathFilterIntersections(relativePath, pathFilter).map((path4) => normalizeFormattingPathOperand(productDir, path4));
|
|
18458
|
-
}
|
|
18459
18605
|
|
|
18460
18606
|
// src/validation/languages/formatting.ts
|
|
18461
18607
|
var FORMATTING_LANGUAGE_NAME = "formatting";
|
|
18608
|
+
var SKIP_FORMATTING_REASON = "skip-formatting";
|
|
18609
|
+
var FORMATTING_VALIDATION_STAGE_PARTICIPATION = {
|
|
18610
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.FORMATTING]: {
|
|
18611
|
+
default: VALIDATION_STAGE_PARTICIPATION.RUN,
|
|
18612
|
+
skipReason: SKIP_FORMATTING_REASON,
|
|
18613
|
+
override: {
|
|
18614
|
+
flag: "--skip-formatting",
|
|
18615
|
+
description: "Skip formatting validation for this validation all run"
|
|
18616
|
+
}
|
|
18617
|
+
}
|
|
18618
|
+
};
|
|
18462
18619
|
var formattingValidationLanguage = {
|
|
18463
18620
|
name: FORMATTING_LANGUAGE_NAME,
|
|
18464
18621
|
stages: [
|
|
18465
18622
|
{
|
|
18466
18623
|
name: VALIDATION_STAGE_DISPLAY_NAMES.FORMATTING,
|
|
18467
18624
|
failsPipeline: true,
|
|
18468
|
-
|
|
18625
|
+
participation: FORMATTING_VALIDATION_STAGE_PARTICIPATION[VALIDATION_STAGE_DISPLAY_NAMES.FORMATTING],
|
|
18626
|
+
run: (context) => formattingCommand({
|
|
18627
|
+
cwd: context.cwd,
|
|
18628
|
+
files: context.files,
|
|
18629
|
+
quiet: context.quiet,
|
|
18630
|
+
json: context.json,
|
|
18631
|
+
streamedPipelineOutput: true,
|
|
18632
|
+
outputStreams: context.outputStreams
|
|
18633
|
+
})
|
|
18469
18634
|
}
|
|
18470
18635
|
]
|
|
18471
18636
|
};
|
|
@@ -18506,6 +18671,11 @@ var MARKDOWN_VALIDATION_TARGET_DIAGNOSTICS = {
|
|
|
18506
18671
|
var defaultMarkdownValidationTargetDeps = {
|
|
18507
18672
|
statSync: statSync2
|
|
18508
18673
|
};
|
|
18674
|
+
var defaultMarkdownValidationDeps = {
|
|
18675
|
+
runMarkdownlint: async (options) => {
|
|
18676
|
+
await markdownlintMain(options);
|
|
18677
|
+
}
|
|
18678
|
+
};
|
|
18509
18679
|
function buildMarkdownlintConfig(directoryName) {
|
|
18510
18680
|
const md024Disabled = MD024_DISABLED_DIRECTORIES.includes(
|
|
18511
18681
|
directoryName
|
|
@@ -18517,8 +18687,8 @@ function buildMarkdownlintConfig(directoryName) {
|
|
|
18517
18687
|
[MARKDOWN_CONFIG_CONTROL_KEYS.CUSTOM_RULES]: [relativeLinksRule]
|
|
18518
18688
|
};
|
|
18519
18689
|
}
|
|
18520
|
-
function getDefaultDirectories(
|
|
18521
|
-
return MARKDOWN_DEFAULT_DIRECTORY_NAMES.map((name) => join30(
|
|
18690
|
+
function getDefaultDirectories(productDir) {
|
|
18691
|
+
return MARKDOWN_DEFAULT_DIRECTORY_NAMES.map((name) => join30(productDir, name)).filter((dir) => existsSync2(dir));
|
|
18522
18692
|
}
|
|
18523
18693
|
function resolveMarkdownValidationTarget(path4, deps = defaultMarkdownValidationTargetDeps) {
|
|
18524
18694
|
if (isExistingDirectory(path4, deps)) {
|
|
@@ -18534,10 +18704,10 @@ function resolveMarkdownValidationTarget(path4, deps = defaultMarkdownValidation
|
|
|
18534
18704
|
}
|
|
18535
18705
|
};
|
|
18536
18706
|
}
|
|
18537
|
-
function getExcludeGlobsForTarget(target,
|
|
18538
|
-
if (
|
|
18707
|
+
function getExcludeGlobsForTarget(target, productDir, entries) {
|
|
18708
|
+
if (productDir === void 0 || entries.length === 0) return [];
|
|
18539
18709
|
const directory = targetDirectory(target);
|
|
18540
|
-
const specTreeRoot = join30(
|
|
18710
|
+
const specTreeRoot = join30(productDir, SPEC_TREE_CONFIG.ROOT_DIRECTORY);
|
|
18541
18711
|
const targetPath = normalizePathPrefix(pathRelative(specTreeRoot, directory));
|
|
18542
18712
|
return entries.flatMap((entry) => {
|
|
18543
18713
|
const excludedPath = normalizePathPrefix(entry);
|
|
@@ -18615,24 +18785,24 @@ function isAsciiDigit(value) {
|
|
|
18615
18785
|
function isAsciiWhitespace(value) {
|
|
18616
18786
|
return value === " " || value === " ";
|
|
18617
18787
|
}
|
|
18618
|
-
async function validateMarkdown(options) {
|
|
18788
|
+
async function validateMarkdown(options, deps = defaultMarkdownValidationDeps) {
|
|
18619
18789
|
const {
|
|
18620
18790
|
targets,
|
|
18621
|
-
|
|
18791
|
+
productDir,
|
|
18622
18792
|
applyNodeStatusExcludes = true,
|
|
18623
18793
|
validationPathExcludes = []
|
|
18624
18794
|
} = options;
|
|
18625
18795
|
const errors = [];
|
|
18626
|
-
const specTreeExcludeEntries = applyNodeStatusExcludes ? getExcludeEntries(
|
|
18796
|
+
const specTreeExcludeEntries = applyNodeStatusExcludes ? getExcludeEntries(productDir) : [];
|
|
18627
18797
|
for (const target of targets) {
|
|
18628
18798
|
const directory = targetDirectory(target);
|
|
18629
|
-
const dirName = markdownlintConfigDirectoryName(directory,
|
|
18799
|
+
const dirName = markdownlintConfigDirectoryName(directory, productDir);
|
|
18630
18800
|
const config = buildMarkdownlintConfig(dirName);
|
|
18631
18801
|
const excludeGlobs = [
|
|
18632
|
-
...getExcludeGlobsForTarget(target,
|
|
18633
|
-
...validationPathExcludeGlobsForTarget(target,
|
|
18802
|
+
...getExcludeGlobsForTarget(target, productDir, specTreeExcludeEntries),
|
|
18803
|
+
...validationPathExcludeGlobsForTarget(target, productDir, validationPathExcludes)
|
|
18634
18804
|
];
|
|
18635
|
-
const dirErrors = await validateTarget(target, config,
|
|
18805
|
+
const dirErrors = await validateTarget(target, config, deps, productDir, excludeGlobs);
|
|
18636
18806
|
errors.push(...dirErrors);
|
|
18637
18807
|
}
|
|
18638
18808
|
return {
|
|
@@ -18640,11 +18810,11 @@ async function validateMarkdown(options) {
|
|
|
18640
18810
|
errors
|
|
18641
18811
|
};
|
|
18642
18812
|
}
|
|
18643
|
-
function getExcludeEntries(
|
|
18644
|
-
if (
|
|
18645
|
-
return createNodeStatusExcludeReader(
|
|
18813
|
+
function getExcludeEntries(productDir) {
|
|
18814
|
+
if (productDir === void 0) return [];
|
|
18815
|
+
return createNodeStatusExcludeReader(productDir).entries();
|
|
18646
18816
|
}
|
|
18647
|
-
async function validateTarget(target, config,
|
|
18817
|
+
async function validateTarget(target, config, deps, productDir, ignoreGlobs = []) {
|
|
18648
18818
|
const errors = [];
|
|
18649
18819
|
const directory = targetDirectory(target);
|
|
18650
18820
|
const argv = target.kind === MARKDOWN_VALIDATION_TARGET_KIND.FILE ? [basename7(target.path)] : [MARKDOWN_DIRECTORY_GLOB];
|
|
@@ -18652,14 +18822,14 @@ async function validateTarget(target, config, projectRoot, ignoreGlobs = []) {
|
|
|
18652
18822
|
const optionsOverride = {
|
|
18653
18823
|
config: {
|
|
18654
18824
|
...markdownlintConfig,
|
|
18655
|
-
"relative-links":
|
|
18825
|
+
"relative-links": productDir ? { root_path: productDir } : true
|
|
18656
18826
|
},
|
|
18657
18827
|
customRules,
|
|
18658
18828
|
noProgress: true,
|
|
18659
18829
|
noBanner: true,
|
|
18660
18830
|
...ignoreGlobs.length > 0 ? { ignores: ignoreGlobs } : {}
|
|
18661
18831
|
};
|
|
18662
|
-
await
|
|
18832
|
+
await deps.runMarkdownlint({
|
|
18663
18833
|
directory,
|
|
18664
18834
|
argv,
|
|
18665
18835
|
optionsOverride,
|
|
@@ -18681,10 +18851,10 @@ async function validateTarget(target, config, projectRoot, ignoreGlobs = []) {
|
|
|
18681
18851
|
function targetDirectory(target) {
|
|
18682
18852
|
return target.kind === MARKDOWN_VALIDATION_TARGET_KIND.FILE ? dirname13(target.path) : target.path;
|
|
18683
18853
|
}
|
|
18684
|
-
function validationPathExcludeGlobsForTarget(target,
|
|
18685
|
-
if (
|
|
18854
|
+
function validationPathExcludeGlobsForTarget(target, productDir, excludes) {
|
|
18855
|
+
if (productDir === void 0 || excludes.length === 0 || target.kind === MARKDOWN_VALIDATION_TARGET_KIND.FILE) return [];
|
|
18686
18856
|
const directory = targetDirectory(target);
|
|
18687
|
-
const targetPath = normalizePathPrefix(pathRelative(
|
|
18857
|
+
const targetPath = normalizePathPrefix(pathRelative(productDir, directory));
|
|
18688
18858
|
return excludes.flatMap((exclude) => {
|
|
18689
18859
|
const excludedPath = normalizePathPrefix(exclude);
|
|
18690
18860
|
if (targetPath === excludedPath) {
|
|
@@ -18693,11 +18863,11 @@ function validationPathExcludeGlobsForTarget(target, projectRoot, excludes) {
|
|
|
18693
18863
|
if (!pathContainsValidationPath(targetPath, excludedPath)) {
|
|
18694
18864
|
return [];
|
|
18695
18865
|
}
|
|
18696
|
-
const relativeExclude = normalizePathPrefix(pathRelative(directory, join30(
|
|
18866
|
+
const relativeExclude = normalizePathPrefix(pathRelative(directory, join30(productDir, excludedPath)));
|
|
18697
18867
|
if (relativeExclude.length === 0) {
|
|
18698
18868
|
return [MARKDOWN_DIRECTORY_GLOB];
|
|
18699
18869
|
}
|
|
18700
|
-
const absoluteExclude = join30(
|
|
18870
|
+
const absoluteExclude = join30(productDir, excludedPath);
|
|
18701
18871
|
return [
|
|
18702
18872
|
isExistingFile(absoluteExclude, defaultMarkdownValidationTargetDeps) ? relativeExclude : `${relativeExclude}/**`
|
|
18703
18873
|
];
|
|
@@ -18726,9 +18896,9 @@ function isExistingFile(path4, deps) {
|
|
|
18726
18896
|
return false;
|
|
18727
18897
|
}
|
|
18728
18898
|
}
|
|
18729
|
-
function markdownlintConfigDirectoryName(directory,
|
|
18730
|
-
if (
|
|
18731
|
-
const [rootSegment] = pathRelative(
|
|
18899
|
+
function markdownlintConfigDirectoryName(directory, productDir) {
|
|
18900
|
+
if (productDir !== void 0) {
|
|
18901
|
+
const [rootSegment] = pathRelative(productDir, directory).split(/[\\/]/);
|
|
18732
18902
|
if (MD024_DISABLED_DIRECTORIES.includes(rootSegment)) {
|
|
18733
18903
|
return rootSegment;
|
|
18734
18904
|
}
|
|
@@ -18738,11 +18908,14 @@ function markdownlintConfigDirectoryName(directory, projectRoot) {
|
|
|
18738
18908
|
|
|
18739
18909
|
// src/commands/validation/markdown.ts
|
|
18740
18910
|
var MARKDOWN_COMMAND_OUTPUT = {
|
|
18741
|
-
ERROR_SUMMARY_SUFFIX: VALIDATION_COMMAND_OUTPUT.MARKDOWN_ERROR_SUMMARY_SUFFIX,
|
|
18742
18911
|
NO_ISSUES: VALIDATION_COMMAND_OUTPUT.MARKDOWN_NO_ISSUES,
|
|
18912
|
+
PROBLEM_TERM: VALIDATION_PROBLEM_TERMS.SINGULAR,
|
|
18743
18913
|
SKIPPED_FILE_SCOPE_PREFIX: "Markdown skipped file scope"
|
|
18744
18914
|
};
|
|
18745
|
-
var MARKDOWN_CONFIG_ERROR_MESSAGE =
|
|
18915
|
+
var MARKDOWN_CONFIG_ERROR_MESSAGE = formatValidationConfigProblemMessage(
|
|
18916
|
+
VALIDATION_STAGE_DISPLAY_NAMES.MARKDOWN,
|
|
18917
|
+
"configuration error"
|
|
18918
|
+
);
|
|
18746
18919
|
async function markdownCommand(options) {
|
|
18747
18920
|
const { cwd, files, quiet } = options;
|
|
18748
18921
|
const startTime = Date.now();
|
|
@@ -18775,8 +18948,8 @@ async function markdownCommand(options) {
|
|
|
18775
18948
|
}
|
|
18776
18949
|
const result = await validateMarkdown({
|
|
18777
18950
|
targets,
|
|
18778
|
-
|
|
18779
|
-
validationPathExcludes: validationPathFilterExcludes(pathFilter)
|
|
18951
|
+
productDir: cwd,
|
|
18952
|
+
validationPathExcludes: targetResolutions === void 0 ? validationPathFilterExcludes(pathFilter) : []
|
|
18780
18953
|
});
|
|
18781
18954
|
const durationMs = Date.now() - startTime;
|
|
18782
18955
|
return formatMarkdownResult(result, skippedOutput, quiet, durationMs);
|
|
@@ -18786,7 +18959,7 @@ function markdownValidationOperandPath(productDir, filePath) {
|
|
|
18786
18959
|
}
|
|
18787
18960
|
function defaultMarkdownTargets(productDir, pathFilter) {
|
|
18788
18961
|
return getDefaultDirectories(productDir).flatMap(
|
|
18789
|
-
(directory) => validationPathFilterIntersections(
|
|
18962
|
+
(directory) => validationPathFilterIntersections(toProductRelativeValidationPath(productDir, directory), pathFilter).map((intersection) => resolveMarkdownValidationTarget(join31(productDir, intersection)).target).filter((target) => target !== void 0)
|
|
18790
18963
|
);
|
|
18791
18964
|
}
|
|
18792
18965
|
function formatSkippedFileScope(target) {
|
|
@@ -18802,7 +18975,9 @@ function formatMarkdownResult(result, skippedOutput, quiet, durationMs) {
|
|
|
18802
18975
|
);
|
|
18803
18976
|
const output = [
|
|
18804
18977
|
...skippedOutput,
|
|
18805
|
-
|
|
18978
|
+
formatValidationProblemsFoundMessage(VALIDATION_STAGE_DISPLAY_NAMES.MARKDOWN, {
|
|
18979
|
+
count: result.errors.length
|
|
18980
|
+
}),
|
|
18806
18981
|
...errorLines
|
|
18807
18982
|
].join("\n");
|
|
18808
18983
|
return { exitCode: 1, output, durationMs };
|
|
@@ -18810,12 +18985,24 @@ function formatMarkdownResult(result, skippedOutput, quiet, durationMs) {
|
|
|
18810
18985
|
|
|
18811
18986
|
// src/validation/languages/markdown.ts
|
|
18812
18987
|
var MARKDOWN_LANGUAGE_NAME = "markdown";
|
|
18988
|
+
var SKIP_MARKDOWN_REASON = "skip-markdown";
|
|
18989
|
+
var MARKDOWN_VALIDATION_STAGE_PARTICIPATION = {
|
|
18990
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.MARKDOWN]: {
|
|
18991
|
+
default: VALIDATION_STAGE_PARTICIPATION.RUN,
|
|
18992
|
+
skipReason: SKIP_MARKDOWN_REASON,
|
|
18993
|
+
override: {
|
|
18994
|
+
flag: "--skip-markdown",
|
|
18995
|
+
description: "Skip Markdown validation for this validation all run"
|
|
18996
|
+
}
|
|
18997
|
+
}
|
|
18998
|
+
};
|
|
18813
18999
|
var markdownValidationLanguage = {
|
|
18814
19000
|
name: MARKDOWN_LANGUAGE_NAME,
|
|
18815
19001
|
stages: [
|
|
18816
19002
|
{
|
|
18817
19003
|
name: VALIDATION_STAGE_DISPLAY_NAMES.MARKDOWN,
|
|
18818
19004
|
failsPipeline: true,
|
|
19005
|
+
participation: MARKDOWN_VALIDATION_STAGE_PARTICIPATION[VALIDATION_STAGE_DISPLAY_NAMES.MARKDOWN],
|
|
18819
19006
|
run: (context) => markdownCommand({ cwd: context.cwd, files: context.files, quiet: context.quiet })
|
|
18820
19007
|
}
|
|
18821
19008
|
]
|
|
@@ -19687,7 +19874,7 @@ var TSCONFIG_FILES = {
|
|
|
19687
19874
|
full: "tsconfig.json",
|
|
19688
19875
|
production: "tsconfig.production.json"
|
|
19689
19876
|
};
|
|
19690
|
-
var
|
|
19877
|
+
var PATH_SEGMENT_SEPARATOR3 = "/";
|
|
19691
19878
|
var GLOB_MARKER = "*";
|
|
19692
19879
|
var RECURSIVE_GLOB_SEGMENT = "**";
|
|
19693
19880
|
var SINGLE_CHARACTER_GLOB_MARKER = "?";
|
|
@@ -19718,8 +19905,8 @@ var EXPLICIT_TYPESCRIPT_SCOPE_TARGET_KIND = {
|
|
|
19718
19905
|
DIRECTORY: "directory",
|
|
19719
19906
|
FILE: "file"
|
|
19720
19907
|
};
|
|
19721
|
-
function
|
|
19722
|
-
return isAbsolute8(path4) ? path4 : join32(
|
|
19908
|
+
function resolveProductPath(productDir, path4) {
|
|
19909
|
+
return isAbsolute8(path4) ? path4 : join32(productDir, path4);
|
|
19723
19910
|
}
|
|
19724
19911
|
function parseTypeScriptConfig(configPath, deps = defaultScopeDeps) {
|
|
19725
19912
|
try {
|
|
@@ -19733,11 +19920,11 @@ function parseTypeScriptConfig(configPath, deps = defaultScopeDeps) {
|
|
|
19733
19920
|
};
|
|
19734
19921
|
}
|
|
19735
19922
|
}
|
|
19736
|
-
function resolveTypeScriptConfig(scope2,
|
|
19923
|
+
function resolveTypeScriptConfig(scope2, productDir, deps = defaultScopeDeps) {
|
|
19737
19924
|
const configFile = TSCONFIG_FILES[scope2];
|
|
19738
|
-
const config = parseTypeScriptConfig(
|
|
19925
|
+
const config = parseTypeScriptConfig(resolveProductPath(productDir, configFile), deps);
|
|
19739
19926
|
if (config.extends) {
|
|
19740
|
-
const baseConfigs = normalizeExtends(config.extends).map((extendedConfig) => parseTypeScriptConfig(
|
|
19927
|
+
const baseConfigs = normalizeExtends(config.extends).map((extendedConfig) => parseTypeScriptConfig(resolveProductPath(productDir, extendedConfig), deps));
|
|
19741
19928
|
const inheritedInclude = [...baseConfigs].reverse().find((baseConfig) => baseConfig.include !== void 0)?.include ?? [];
|
|
19742
19929
|
const inheritedExclude = [...baseConfigs].reverse().find((baseConfig) => baseConfig.exclude !== void 0)?.exclude ?? [];
|
|
19743
19930
|
return {
|
|
@@ -19773,48 +19960,48 @@ function hasTypeScriptFilesRecursive(dirPath, maxDepth = 2, deps = defaultScopeD
|
|
|
19773
19960
|
}
|
|
19774
19961
|
}
|
|
19775
19962
|
function pathPassesTypeScriptFileDiscoveryExcludes(path4, options) {
|
|
19776
|
-
const { excludePatterns = [],
|
|
19777
|
-
if (
|
|
19963
|
+
const { excludePatterns = [], productDir } = options;
|
|
19964
|
+
if (productDir === void 0) {
|
|
19778
19965
|
return true;
|
|
19779
19966
|
}
|
|
19780
|
-
const projectRelativePath =
|
|
19967
|
+
const projectRelativePath = toProductRelativeTypeScriptScopePath(productDir, path4);
|
|
19781
19968
|
return !excludePatterns.some((pattern) => pathMatchesTypeScriptPattern(projectRelativePath, pattern));
|
|
19782
19969
|
}
|
|
19783
|
-
function getTopLevelDirectoriesWithTypeScript(config,
|
|
19970
|
+
function getTopLevelDirectoriesWithTypeScript(config, productDir, deps = defaultScopeDeps) {
|
|
19784
19971
|
const directories = /* @__PURE__ */ new Set();
|
|
19785
|
-
for (const dir of listTopLevelDirectories(
|
|
19786
|
-
if (directoryContributesTypeScriptScope(dir, config,
|
|
19972
|
+
for (const dir of listTopLevelDirectories(productDir, deps)) {
|
|
19973
|
+
if (directoryContributesTypeScriptScope(dir, config, productDir, deps)) {
|
|
19787
19974
|
directories.add(dir);
|
|
19788
19975
|
}
|
|
19789
19976
|
}
|
|
19790
|
-
for (const dir of explicitIncludeTopLevelDirectories(config,
|
|
19977
|
+
for (const dir of explicitIncludeTopLevelDirectories(config, productDir, deps)) {
|
|
19791
19978
|
directories.add(dir);
|
|
19792
19979
|
}
|
|
19793
19980
|
return Array.from(directories).sort(compareAsciiStrings);
|
|
19794
19981
|
}
|
|
19795
|
-
function listTopLevelDirectories(
|
|
19796
|
-
return deps.readdirSync(
|
|
19982
|
+
function listTopLevelDirectories(productDir, deps) {
|
|
19983
|
+
return deps.readdirSync(productDir, { withFileTypes: true }).filter((item) => item.isDirectory()).map((item) => item.name).filter((name) => !name.startsWith("."));
|
|
19797
19984
|
}
|
|
19798
|
-
function directoryContributesTypeScriptScope(dir, config,
|
|
19799
|
-
if (!directoryPassesIncludePatterns(dir, config.include ?? [],
|
|
19985
|
+
function directoryContributesTypeScriptScope(dir, config, productDir, deps) {
|
|
19986
|
+
if (!directoryPassesIncludePatterns(dir, config.include ?? [], productDir, deps)) {
|
|
19800
19987
|
return false;
|
|
19801
19988
|
}
|
|
19802
19989
|
try {
|
|
19803
|
-
return hasTypeScriptFilesRecursive(join32(
|
|
19990
|
+
return hasTypeScriptFilesRecursive(join32(productDir, dir), 2, deps, {
|
|
19804
19991
|
excludePatterns: config.exclude,
|
|
19805
|
-
|
|
19992
|
+
productDir
|
|
19806
19993
|
});
|
|
19807
19994
|
} catch {
|
|
19808
19995
|
return false;
|
|
19809
19996
|
}
|
|
19810
19997
|
}
|
|
19811
|
-
function explicitIncludeTopLevelDirectories(config,
|
|
19998
|
+
function explicitIncludeTopLevelDirectories(config, productDir, deps) {
|
|
19812
19999
|
if (!config.include) {
|
|
19813
20000
|
return [];
|
|
19814
20001
|
}
|
|
19815
20002
|
const directories = [];
|
|
19816
20003
|
for (const pattern of config.include) {
|
|
19817
|
-
if (includePatternTargetsTypeScriptScope(pattern,
|
|
20004
|
+
if (includePatternTargetsTypeScriptScope(pattern, productDir, deps) && pattern.includes(PATH_SEGMENT_SEPARATOR3)) {
|
|
19818
20005
|
const topLevelDir = getLiteralTopLevelPatternDirectory(pattern);
|
|
19819
20006
|
if (topLevelDir) {
|
|
19820
20007
|
directories.push(topLevelDir);
|
|
@@ -19824,39 +20011,39 @@ function explicitIncludeTopLevelDirectories(config, projectRoot, deps) {
|
|
|
19824
20011
|
return directories;
|
|
19825
20012
|
}
|
|
19826
20013
|
function getLiteralTopLevelPatternDirectory(pattern) {
|
|
19827
|
-
const topLevelDir = pattern.split(
|
|
20014
|
+
const topLevelDir = pattern.split(PATH_SEGMENT_SEPARATOR3)[0];
|
|
19828
20015
|
if (!topLevelDir || typeScriptScopePatternHasGlob(topLevelDir) || topLevelDir.startsWith(HIDDEN_PATH_PREFIX)) {
|
|
19829
20016
|
return null;
|
|
19830
20017
|
}
|
|
19831
20018
|
return topLevelDir;
|
|
19832
20019
|
}
|
|
19833
|
-
function directoryPassesIncludePatterns(directory, patterns,
|
|
20020
|
+
function directoryPassesIncludePatterns(directory, patterns, productDir, deps) {
|
|
19834
20021
|
return patterns.length === 0 || patterns.some(
|
|
19835
|
-
(pattern) => includePatternTargetsTypeScriptScope(pattern,
|
|
20022
|
+
(pattern) => includePatternTargetsTypeScriptScope(pattern, productDir, deps) && typeScriptScopePatternIntersectsDirectory(pattern, directory)
|
|
19836
20023
|
);
|
|
19837
20024
|
}
|
|
19838
20025
|
function stripTrailingPathSeparators2(value) {
|
|
19839
20026
|
let end = value.length;
|
|
19840
|
-
while (end > 0 && value.charAt(end - 1) ===
|
|
20027
|
+
while (end > 0 && value.charAt(end - 1) === PATH_SEGMENT_SEPARATOR3) {
|
|
19841
20028
|
end -= 1;
|
|
19842
20029
|
}
|
|
19843
20030
|
return value.slice(0, end);
|
|
19844
20031
|
}
|
|
19845
20032
|
function normalizeTypeScriptScopePath(path4) {
|
|
19846
|
-
const joined = path4.split(/[\\/]/gu).join(
|
|
20033
|
+
const joined = path4.split(/[\\/]/gu).join(PATH_SEGMENT_SEPARATOR3).replace(/^\.\//u, "");
|
|
19847
20034
|
return stripTrailingPathSeparators2(joined);
|
|
19848
20035
|
}
|
|
19849
20036
|
function pathMatchesLiteralPrefix(path4, prefix) {
|
|
19850
20037
|
const normalizedPath = normalizeTypeScriptScopePath(path4);
|
|
19851
20038
|
const normalizedPrefix = normalizeTypeScriptScopePath(prefix);
|
|
19852
|
-
return normalizedPath === normalizedPrefix || normalizedPath.startsWith(`${normalizedPrefix}${
|
|
20039
|
+
return normalizedPath === normalizedPrefix || normalizedPath.startsWith(`${normalizedPrefix}${PATH_SEGMENT_SEPARATOR3}`);
|
|
19853
20040
|
}
|
|
19854
20041
|
function splitTypeScriptScopePathSegments(path4) {
|
|
19855
20042
|
const normalizedPath = normalizeTypeScriptScopePath(path4);
|
|
19856
20043
|
if (normalizedPath.length === 0 || normalizedPath === ".") {
|
|
19857
20044
|
return [];
|
|
19858
20045
|
}
|
|
19859
|
-
return normalizedPath.split(
|
|
20046
|
+
return normalizedPath.split(PATH_SEGMENT_SEPARATOR3);
|
|
19860
20047
|
}
|
|
19861
20048
|
function globLiteralPrefix(pattern) {
|
|
19862
20049
|
const normalizedPattern = normalizeTypeScriptScopePath(pattern);
|
|
@@ -19930,16 +20117,16 @@ function typeScriptScopeGlobPatternToRegExp(pattern) {
|
|
|
19930
20117
|
const character = normalizedPattern[index];
|
|
19931
20118
|
const nextCharacter = normalizedPattern[index + 1];
|
|
19932
20119
|
const followingCharacter = normalizedPattern[index + 2];
|
|
19933
|
-
if (character === GLOB_MARKER && nextCharacter === GLOB_MARKER && followingCharacter ===
|
|
19934
|
-
source += `(?:.*${
|
|
20120
|
+
if (character === GLOB_MARKER && nextCharacter === GLOB_MARKER && followingCharacter === PATH_SEGMENT_SEPARATOR3) {
|
|
20121
|
+
source += `(?:.*${PATH_SEGMENT_SEPARATOR3})?`;
|
|
19935
20122
|
index += 2;
|
|
19936
20123
|
} else if (character === GLOB_MARKER && nextCharacter === GLOB_MARKER) {
|
|
19937
20124
|
source += ".*";
|
|
19938
20125
|
index += 1;
|
|
19939
20126
|
} else if (character === GLOB_MARKER) {
|
|
19940
|
-
source += `[^${
|
|
20127
|
+
source += `[^${PATH_SEGMENT_SEPARATOR3}]*`;
|
|
19941
20128
|
} else if (character === SINGLE_CHARACTER_GLOB_MARKER) {
|
|
19942
|
-
source += `[^${
|
|
20129
|
+
source += `[^${PATH_SEGMENT_SEPARATOR3}]`;
|
|
19943
20130
|
} else {
|
|
19944
20131
|
source += character.replaceAll(GLOB_REGEX_SPECIAL_CHARACTER_PATTERN, REGEX_ESCAPE_REPLACEMENT);
|
|
19945
20132
|
}
|
|
@@ -20007,12 +20194,12 @@ function typeScriptScopePatternTargetsTypeScriptSource(pattern) {
|
|
|
20007
20194
|
const terminalSegment = splitTypeScriptScopePathSegments(normalizedPattern).at(-1) ?? normalizedPattern;
|
|
20008
20195
|
return typeScriptScopePatternHasGlob(terminalSegment) && !TERMINAL_EXTENSION_PATTERN.test(terminalSegment);
|
|
20009
20196
|
}
|
|
20010
|
-
function includePatternTargetsTypeScriptScope(pattern,
|
|
20011
|
-
return includePatternIsLiteralDirectory(pattern,
|
|
20197
|
+
function includePatternTargetsTypeScriptScope(pattern, productDir, deps) {
|
|
20198
|
+
return includePatternIsLiteralDirectory(pattern, productDir, deps) || typeScriptScopePatternTargetsTypeScriptSource(pattern);
|
|
20012
20199
|
}
|
|
20013
|
-
function includePatternIsLiteralDirectory(pattern,
|
|
20200
|
+
function includePatternIsLiteralDirectory(pattern, productDir, deps) {
|
|
20014
20201
|
const normalizedPattern = normalizeTypeScriptScopePath(pattern);
|
|
20015
|
-
return !typeScriptScopePatternHasGlob(normalizedPattern) && pathIsDirectory(
|
|
20202
|
+
return !typeScriptScopePatternHasGlob(normalizedPattern) && pathIsDirectory(resolveProductPath(productDir, normalizedPattern), deps);
|
|
20016
20203
|
}
|
|
20017
20204
|
function pathIsDirectory(path4, deps) {
|
|
20018
20205
|
try {
|
|
@@ -20022,28 +20209,28 @@ function pathIsDirectory(path4, deps) {
|
|
|
20022
20209
|
return false;
|
|
20023
20210
|
}
|
|
20024
20211
|
}
|
|
20025
|
-
function normalizeActiveIncludePattern(pattern,
|
|
20212
|
+
function normalizeActiveIncludePattern(pattern, productDir, deps) {
|
|
20026
20213
|
const normalizedPattern = normalizeTypeScriptScopePath(pattern);
|
|
20027
|
-
return includePatternIsLiteralDirectory(normalizedPattern,
|
|
20214
|
+
return includePatternIsLiteralDirectory(normalizedPattern, productDir, deps) ? `${normalizedPattern}${TYPESCRIPT_SCOPE_DIRECTORY_PATTERN_SUFFIX}` : pattern;
|
|
20028
20215
|
}
|
|
20029
|
-
function filterActiveIncludePatterns(patterns, excludePatterns,
|
|
20030
|
-
return patterns.map((pattern) => normalizeActiveIncludePattern(pattern,
|
|
20216
|
+
function filterActiveIncludePatterns(patterns, excludePatterns, productDir, deps) {
|
|
20217
|
+
return patterns.map((pattern) => normalizeActiveIncludePattern(pattern, productDir, deps)).filter((pattern) => typeScriptScopePatternTargetsTypeScriptSource(pattern)).filter((pattern) => {
|
|
20031
20218
|
const topLevelDir = getLiteralTopLevelPatternDirectory(pattern);
|
|
20032
|
-
return topLevelDir === null || deps.existsSync(join32(
|
|
20219
|
+
return topLevelDir === null || deps.existsSync(join32(productDir, topLevelDir));
|
|
20033
20220
|
}).filter((pattern) => pathPassesValidationFilter(pattern, { exclude: excludePatterns }));
|
|
20034
20221
|
}
|
|
20035
|
-
function getValidationDirectories(scope2,
|
|
20036
|
-
const config = resolveTypeScriptConfig(scope2,
|
|
20037
|
-
const configDirectories = getTopLevelDirectoriesWithTypeScript(config,
|
|
20038
|
-
const existingDirectories = configDirectories.filter((dir) => deps.existsSync(join32(
|
|
20222
|
+
function getValidationDirectories(scope2, productDir, deps = defaultScopeDeps) {
|
|
20223
|
+
const config = resolveTypeScriptConfig(scope2, productDir, deps);
|
|
20224
|
+
const configDirectories = getTopLevelDirectoriesWithTypeScript(config, productDir, deps);
|
|
20225
|
+
const existingDirectories = configDirectories.filter((dir) => deps.existsSync(join32(productDir, dir)));
|
|
20039
20226
|
return existingDirectories;
|
|
20040
20227
|
}
|
|
20041
|
-
function getTypeScriptScope(scope2,
|
|
20042
|
-
const directories = getValidationDirectories(scope2,
|
|
20043
|
-
const config = resolveTypeScriptConfig(scope2,
|
|
20228
|
+
function getTypeScriptScope(scope2, productDir, deps = defaultScopeDeps) {
|
|
20229
|
+
const directories = getValidationDirectories(scope2, productDir, deps);
|
|
20230
|
+
const config = resolveTypeScriptConfig(scope2, productDir, deps);
|
|
20044
20231
|
return {
|
|
20045
20232
|
directories,
|
|
20046
|
-
filePatterns: filterActiveIncludePatterns(config.include ?? [], config.exclude ?? [],
|
|
20233
|
+
filePatterns: filterActiveIncludePatterns(config.include ?? [], config.exclude ?? [], productDir, deps),
|
|
20047
20234
|
excludePatterns: config.exclude ?? []
|
|
20048
20235
|
};
|
|
20049
20236
|
}
|
|
@@ -20055,31 +20242,31 @@ function pathPassesTypeScriptScope(path4, scopeConfig) {
|
|
|
20055
20242
|
const excluded = scopeConfig.excludePatterns.some((pattern) => pathMatchesTypeScriptPattern(path4, pattern));
|
|
20056
20243
|
return included && !excluded;
|
|
20057
20244
|
}
|
|
20058
|
-
function pathStaysInsideTypeScriptScopeRoot(
|
|
20059
|
-
const resolvedPath = isAbsolute8(path4) ? resolve14(path4) : resolve14(
|
|
20060
|
-
const relativePath = relative7(
|
|
20061
|
-
const segments = normalizeTypeScriptScopePath(relativePath).split(
|
|
20245
|
+
function pathStaysInsideTypeScriptScopeRoot(productDir, path4) {
|
|
20246
|
+
const resolvedPath = isAbsolute8(path4) ? resolve14(path4) : resolve14(productDir, path4);
|
|
20247
|
+
const relativePath = relative7(productDir, resolvedPath);
|
|
20248
|
+
const segments = normalizeTypeScriptScopePath(relativePath).split(PATH_SEGMENT_SEPARATOR3);
|
|
20062
20249
|
return relativePath.length === 0 || !segments.includes("..") && !isAbsolute8(relativePath);
|
|
20063
20250
|
}
|
|
20064
|
-
function
|
|
20065
|
-
const resolvedPath = isAbsolute8(path4) ? resolve14(path4) : resolve14(
|
|
20066
|
-
const relativePath = relative7(
|
|
20251
|
+
function toProductRelativeTypeScriptScopePath(productDir, path4) {
|
|
20252
|
+
const resolvedPath = isAbsolute8(path4) ? resolve14(path4) : resolve14(productDir, path4);
|
|
20253
|
+
const relativePath = relative7(productDir, resolvedPath);
|
|
20067
20254
|
return relativePath.length === 0 ? TYPESCRIPT_SCOPE_PROJECT_ROOT : normalizeTypeScriptScopePath(relativePath);
|
|
20068
20255
|
}
|
|
20069
|
-
function toExplicitTypeScriptScopeTarget(
|
|
20070
|
-
const path4 =
|
|
20256
|
+
function toExplicitTypeScriptScopeTarget(productDir, originalPath, deps = defaultScopeDeps) {
|
|
20257
|
+
const path4 = toProductRelativeTypeScriptScopePath(productDir, originalPath);
|
|
20071
20258
|
return {
|
|
20072
|
-
kind: pathIsDirectory(
|
|
20259
|
+
kind: pathIsDirectory(resolveProductPath(productDir, path4), deps) ? EXPLICIT_TYPESCRIPT_SCOPE_TARGET_KIND.DIRECTORY : EXPLICIT_TYPESCRIPT_SCOPE_TARGET_KIND.FILE,
|
|
20073
20260
|
path: path4
|
|
20074
20261
|
};
|
|
20075
20262
|
}
|
|
20076
|
-
function explicitTypeScriptScopeTargetExists(
|
|
20077
|
-
return deps.existsSync(
|
|
20263
|
+
function explicitTypeScriptScopeTargetExists(productDir, target, deps) {
|
|
20264
|
+
return deps.existsSync(resolveProductPath(productDir, target.path));
|
|
20078
20265
|
}
|
|
20079
20266
|
function filterExplicitTypeScriptScopeTargets(filter, deps = defaultScopeDeps) {
|
|
20080
20267
|
const {
|
|
20081
20268
|
paths,
|
|
20082
|
-
|
|
20269
|
+
productDir,
|
|
20083
20270
|
requireExistingPaths = true,
|
|
20084
20271
|
scopeConfig,
|
|
20085
20272
|
validationPathFilter,
|
|
@@ -20088,7 +20275,7 @@ function filterExplicitTypeScriptScopeTargets(filter, deps = defaultScopeDeps) {
|
|
|
20088
20275
|
if (paths === void 0) {
|
|
20089
20276
|
return void 0;
|
|
20090
20277
|
}
|
|
20091
|
-
return paths.filter((path4) => pathStaysInsideTypeScriptScopeRoot(
|
|
20278
|
+
return paths.filter((path4) => pathStaysInsideTypeScriptScopeRoot(productDir, path4)).map((path4) => toExplicitTypeScriptScopeTarget(productDir, path4, deps)).filter((target) => !requireExistingPaths || explicitTypeScriptScopeTargetExists(productDir, target, deps)).filter((target) => explicitTypeScriptScopeTargetPassesSourceKind(target)).filter(
|
|
20092
20279
|
(target) => bypassValidationPathFilter || explicitTypeScriptScopeTargetIntersectsValidationPathFilter(target, validationPathFilter)
|
|
20093
20280
|
).filter((target) => explicitTypeScriptScopeTargetPassesScope(target, scopeConfig));
|
|
20094
20281
|
}
|
|
@@ -20157,7 +20344,7 @@ function constrainTypeScriptScopeToExplicitTargets(scopeConfig, targets) {
|
|
|
20157
20344
|
const retainedDirectoryOperandPatterns = scopeConfig.filePatterns.length === 0 ? retainedDirectories.map(typeScriptLiteralDirectoryPattern) : [];
|
|
20158
20345
|
const explicitFileTargets = targets.filter((target) => target.kind === EXPLICIT_TYPESCRIPT_SCOPE_TARGET_KIND.FILE).map((target) => target.path).filter(
|
|
20159
20346
|
(path4) => !retainedDirectories.some(
|
|
20160
|
-
(directory) => path4 === directory || path4.startsWith(`${directory}${
|
|
20347
|
+
(directory) => path4 === directory || path4.startsWith(`${directory}${PATH_SEGMENT_SEPARATOR3}`)
|
|
20161
20348
|
)
|
|
20162
20349
|
);
|
|
20163
20350
|
const uncoveredExplicitFileTargets = explicitFileTargets.filter(
|
|
@@ -20182,28 +20369,28 @@ function typeScriptLiteralDirectoryPattern(pattern) {
|
|
|
20182
20369
|
return pattern === TYPESCRIPT_SCOPE_PROJECT_ROOT ? TYPESCRIPT_SCOPE_DIRECTORY_PATTERN_SUFFIX.slice(1) : `${pattern}${TYPESCRIPT_SCOPE_DIRECTORY_PATTERN_SUFFIX}`;
|
|
20183
20370
|
}
|
|
20184
20371
|
function resolveTypeScriptValidationScope(filter, deps = defaultScopeDeps) {
|
|
20185
|
-
const baseScopeConfig = getTypeScriptScope(filter.scope, filter.
|
|
20372
|
+
const baseScopeConfig = getTypeScriptScope(filter.scope, filter.productDir, deps);
|
|
20186
20373
|
const scopeConfig = applyValidationPathFilterToScope(baseScopeConfig, filter.validationPathFilter);
|
|
20187
|
-
const explicitTargetScopeConfig = filter.bypassExplicitPathValidationFilter === true ? baseScopeConfig : scopeConfig;
|
|
20188
20374
|
const explicitTargets = filterExplicitTypeScriptScopeTargets({
|
|
20189
20375
|
paths: filter.paths,
|
|
20190
|
-
|
|
20376
|
+
productDir: filter.productDir,
|
|
20191
20377
|
validationPathFilter: filter.validationPathFilter,
|
|
20192
|
-
scopeConfig:
|
|
20193
|
-
bypassValidationPathFilter:
|
|
20378
|
+
scopeConfig: baseScopeConfig,
|
|
20379
|
+
bypassValidationPathFilter: true
|
|
20194
20380
|
}, deps);
|
|
20195
20381
|
if (filter.paths !== void 0 && filter.paths.length > 0 && explicitTargets?.length === 0) {
|
|
20196
20382
|
return {
|
|
20197
20383
|
...scopeConfig,
|
|
20198
20384
|
directories: [],
|
|
20199
20385
|
filePatterns: [],
|
|
20200
|
-
|
|
20201
|
-
|
|
20202
|
-
|
|
20386
|
+
explicitPathNoMatches: true,
|
|
20387
|
+
filteredByValidationPaths: void 0,
|
|
20388
|
+
filteredByValidationPathIncludes: void 0,
|
|
20389
|
+
filteredByValidationPathNoMatches: void 0
|
|
20203
20390
|
};
|
|
20204
20391
|
}
|
|
20205
20392
|
if (explicitTargets !== void 0 && explicitTargets.length > 0) {
|
|
20206
|
-
const explicitScopeConfig = constrainTypeScriptScopeToExplicitTargets(
|
|
20393
|
+
const explicitScopeConfig = constrainTypeScriptScopeToExplicitTargets(baseScopeConfig, explicitTargets);
|
|
20207
20394
|
return filter.markExplicitPathsAsValidationFilter === true ? {
|
|
20208
20395
|
...explicitScopeConfig,
|
|
20209
20396
|
filteredByValidationPaths: true,
|
|
@@ -20216,7 +20403,7 @@ function resolveTypeScriptValidationScope(filter, deps = defaultScopeDeps) {
|
|
|
20216
20403
|
function constrainTypeScriptPatternToDirectory(pattern, directory) {
|
|
20217
20404
|
const normalizedPattern = normalizeTypeScriptScopePath(pattern);
|
|
20218
20405
|
const normalizedDirectory = normalizeTypeScriptScopePath(directory);
|
|
20219
|
-
if (normalizedPattern === normalizedDirectory || normalizedPattern.startsWith(`${normalizedDirectory}${
|
|
20406
|
+
if (normalizedPattern === normalizedDirectory || normalizedPattern.startsWith(`${normalizedDirectory}${PATH_SEGMENT_SEPARATOR3}`)) {
|
|
20220
20407
|
return normalizedPattern;
|
|
20221
20408
|
}
|
|
20222
20409
|
const patternSegments = splitTypeScriptScopePathSegments(normalizedPattern);
|
|
@@ -20229,7 +20416,7 @@ function constrainTypeScriptPatternToDirectory(pattern, directory) {
|
|
|
20229
20416
|
const suffixSegments = patternSegments.slice(patternIndex);
|
|
20230
20417
|
const constrainedSuffixSegments = directoryAdvance.recursiveGlobConsumedDirectory && suffixSegments.length > 0 ? [RECURSIVE_GLOB_SEGMENT, ...suffixSegments] : suffixSegments;
|
|
20231
20418
|
if (constrainedSuffixSegments.length > 0) {
|
|
20232
|
-
return [normalizedDirectory, ...constrainedSuffixSegments].join(
|
|
20419
|
+
return [normalizedDirectory, ...constrainedSuffixSegments].join(PATH_SEGMENT_SEPARATOR3);
|
|
20233
20420
|
}
|
|
20234
20421
|
return typeScriptScopePatternHasGlob(normalizedPattern) && typeScriptScopePatternCoversDirectorySourceSet(normalizedPattern, normalizedDirectory) ? `${normalizedDirectory}${TYPESCRIPT_SCOPE_DIRECTORY_PATTERN_SUFFIX}` : normalizedDirectory;
|
|
20235
20422
|
}
|
|
@@ -20263,7 +20450,7 @@ function patternSegmentMatchesDirectorySegment(patternSegment, directorySegment)
|
|
|
20263
20450
|
|
|
20264
20451
|
// src/validation/discovery/tool-finder.ts
|
|
20265
20452
|
import fs3 from "fs";
|
|
20266
|
-
import { createRequire } from "module";
|
|
20453
|
+
import { createRequire as createRequire2 } from "module";
|
|
20267
20454
|
import path3 from "path";
|
|
20268
20455
|
import { fileURLToPath } from "url";
|
|
20269
20456
|
|
|
@@ -20298,7 +20485,11 @@ var TOOL_DISCOVERY = {
|
|
|
20298
20485
|
};
|
|
20299
20486
|
|
|
20300
20487
|
// src/validation/discovery/tool-finder.ts
|
|
20301
|
-
var
|
|
20488
|
+
var TOOL_DISCOVERY_PRIORITY = {
|
|
20489
|
+
BUNDLED_FIRST: "bundled-first",
|
|
20490
|
+
PRODUCT_FIRST: "product-first"
|
|
20491
|
+
};
|
|
20492
|
+
var require2 = createRequire2(import.meta.url);
|
|
20302
20493
|
var FILE_URL_PROTOCOL = new URL(import.meta.url).protocol;
|
|
20303
20494
|
var PACKAGE_MANIFEST_FILENAME = "package.json";
|
|
20304
20495
|
var defaultToolDiscoveryDeps = {
|
|
@@ -20345,30 +20536,44 @@ function bundledToolPath(resolvedPath, existsSync10) {
|
|
|
20345
20536
|
return nearestPackageRoot(bundledFilePath, existsSync10) ?? path3.dirname(bundledFilePath);
|
|
20346
20537
|
}
|
|
20347
20538
|
async function discoverTool(tool, options = {}) {
|
|
20348
|
-
const {
|
|
20349
|
-
|
|
20539
|
+
const {
|
|
20540
|
+
productDir = CONFIG_PROCESS_CWD.read(),
|
|
20541
|
+
executableName = tool,
|
|
20542
|
+
bundledExecutable,
|
|
20543
|
+
includeBundled = true,
|
|
20544
|
+
priority = TOOL_DISCOVERY_PRIORITY.BUNDLED_FIRST,
|
|
20545
|
+
deps = defaultToolDiscoveryDeps
|
|
20546
|
+
} = options;
|
|
20547
|
+
const productBinPath = path3.join(productDir, "node_modules", ".bin", executableName);
|
|
20548
|
+
const productLocation = () => deps.existsSync(productBinPath) ? {
|
|
20549
|
+
found: true,
|
|
20550
|
+
location: {
|
|
20551
|
+
tool,
|
|
20552
|
+
path: productBinPath,
|
|
20553
|
+
source: TOOL_DISCOVERY.SOURCES.PROJECT
|
|
20554
|
+
}
|
|
20555
|
+
} : null;
|
|
20556
|
+
if (priority === TOOL_DISCOVERY_PRIORITY.PRODUCT_FIRST) {
|
|
20557
|
+
const productResult = productLocation();
|
|
20558
|
+
if (productResult !== null) return productResult;
|
|
20559
|
+
}
|
|
20560
|
+
const bundledSpecifier = bundledExecutable ?? `${tool}/package.json`;
|
|
20561
|
+
const bundledPath = includeBundled ? deps.resolveModule(bundledSpecifier) ?? deps.resolveImport?.(bundledExecutable ?? tool) : null;
|
|
20350
20562
|
if (bundledPath) {
|
|
20351
20563
|
return {
|
|
20352
20564
|
found: true,
|
|
20353
20565
|
location: {
|
|
20354
20566
|
tool,
|
|
20355
|
-
path: bundledToolPath(bundledPath, deps.existsSync),
|
|
20567
|
+
path: bundledExecutable === void 0 ? bundledToolPath(bundledPath, deps.existsSync) : resolvedModulePath(bundledPath),
|
|
20356
20568
|
source: TOOL_DISCOVERY.SOURCES.BUNDLED
|
|
20357
20569
|
}
|
|
20358
20570
|
};
|
|
20359
20571
|
}
|
|
20360
|
-
|
|
20361
|
-
|
|
20362
|
-
return
|
|
20363
|
-
found: true,
|
|
20364
|
-
location: {
|
|
20365
|
-
tool,
|
|
20366
|
-
path: projectBinPath,
|
|
20367
|
-
source: TOOL_DISCOVERY.SOURCES.PROJECT
|
|
20368
|
-
}
|
|
20369
|
-
};
|
|
20572
|
+
if (priority === TOOL_DISCOVERY_PRIORITY.BUNDLED_FIRST) {
|
|
20573
|
+
const productResult = productLocation();
|
|
20574
|
+
if (productResult !== null) return productResult;
|
|
20370
20575
|
}
|
|
20371
|
-
const globalPath = deps.whichSync(
|
|
20576
|
+
const globalPath = deps.whichSync(executableName);
|
|
20372
20577
|
if (globalPath) {
|
|
20373
20578
|
return {
|
|
20374
20579
|
found: true,
|
|
@@ -20519,13 +20724,13 @@ function dependencyCruiserGlobSegmentToRegExpSource(segment) {
|
|
|
20519
20724
|
}
|
|
20520
20725
|
return source;
|
|
20521
20726
|
}
|
|
20522
|
-
function buildDependencyCruiserOptions(typescriptScope,
|
|
20727
|
+
function buildDependencyCruiserOptions(typescriptScope, productDir, tsConfigFile) {
|
|
20523
20728
|
const excludePatterns = [
|
|
20524
20729
|
DEPENDENCY_CRUISER_PACKAGE_EXCLUDE_PATTERN,
|
|
20525
20730
|
...toDependencyCruiserExcludePatterns(typescriptScope.excludePatterns)
|
|
20526
20731
|
];
|
|
20527
20732
|
return {
|
|
20528
|
-
baseDir:
|
|
20733
|
+
baseDir: productDir,
|
|
20529
20734
|
enhancedResolveOptions: { extensions: [...DEPENDENCY_CRUISER_TYPESCRIPT_RESOLVE_EXTENSIONS] },
|
|
20530
20735
|
exclude: { path: excludePatterns },
|
|
20531
20736
|
includeOnly: { path: DEPENDENCY_CRUISER_TYPESCRIPT_SOURCE_PATTERN },
|
|
@@ -20633,16 +20838,16 @@ function circularDependencyCycles(result) {
|
|
|
20633
20838
|
);
|
|
20634
20839
|
return uniqueCycles(cycles);
|
|
20635
20840
|
}
|
|
20636
|
-
async function validateCircularDependencies(scope2, typescriptScope,
|
|
20841
|
+
async function validateCircularDependencies(scope2, typescriptScope, productDir, deps = defaultCircularDeps) {
|
|
20637
20842
|
try {
|
|
20638
20843
|
const analyzeSourcePatterns = toDependencyCruiserSourcePatterns(typescriptScope);
|
|
20639
20844
|
if (analyzeSourcePatterns.length === 0) {
|
|
20640
20845
|
return { success: true };
|
|
20641
20846
|
}
|
|
20642
|
-
const tsConfigFile = join33(
|
|
20847
|
+
const tsConfigFile = join33(productDir, TSCONFIG_FILES[scope2]);
|
|
20643
20848
|
const result = await deps.dependencyCruiser(
|
|
20644
20849
|
analyzeSourcePatterns,
|
|
20645
|
-
buildDependencyCruiserOptions(typescriptScope,
|
|
20850
|
+
buildDependencyCruiserOptions(typescriptScope, productDir, tsConfigFile),
|
|
20646
20851
|
void 0,
|
|
20647
20852
|
{ tsConfig: deps.extractTypeScriptConfig(tsConfigFile) }
|
|
20648
20853
|
);
|
|
@@ -20681,9 +20886,9 @@ var EXECUTION_MODES = {
|
|
|
20681
20886
|
|
|
20682
20887
|
// src/commands/validation/circular.ts
|
|
20683
20888
|
var TYPESCRIPT_ABSENT_MESSAGE = formatTypeScriptAbsentSkipMessage(VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR);
|
|
20684
|
-
var CIRCULAR_CONFIG_ERROR_MESSAGE =
|
|
20685
|
-
|
|
20686
|
-
|
|
20889
|
+
var CIRCULAR_CONFIG_ERROR_MESSAGE = formatValidationConfigProblemMessage(
|
|
20890
|
+
VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR,
|
|
20891
|
+
"configuration error"
|
|
20687
20892
|
);
|
|
20688
20893
|
var CIRCULAR_DEPENDENCY_OUTPUT = {
|
|
20689
20894
|
FOUND: VALIDATION_COMMAND_OUTPUT.CIRCULAR_FOUND
|
|
@@ -20691,7 +20896,6 @@ var CIRCULAR_DEPENDENCY_OUTPUT = {
|
|
|
20691
20896
|
var defaultCircularCommandDeps = {
|
|
20692
20897
|
validateCircularDependencies
|
|
20693
20898
|
};
|
|
20694
|
-
var DEPENDENCY_CRUISER_PACKAGE_NAME = "dependency-cruiser";
|
|
20695
20899
|
function formatCircularValidationResult(result, quiet) {
|
|
20696
20900
|
if (result.success) {
|
|
20697
20901
|
return {
|
|
@@ -20723,11 +20927,6 @@ async function circularCommand(options, deps = defaultCircularCommandDeps) {
|
|
|
20723
20927
|
durationMs: Date.now() - startTime
|
|
20724
20928
|
};
|
|
20725
20929
|
}
|
|
20726
|
-
const toolResult = await discoverTool(DEPENDENCY_CRUISER_PACKAGE_NAME, { projectRoot: cwd });
|
|
20727
|
-
if (!toolResult.found) {
|
|
20728
|
-
const skipMessage = formatSkipMessage(VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR, toolResult);
|
|
20729
|
-
return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };
|
|
20730
|
-
}
|
|
20731
20930
|
const loaded = await resolveConfig(cwd, [validationConfigDescriptor]);
|
|
20732
20931
|
if (!loaded.ok) {
|
|
20733
20932
|
return {
|
|
@@ -20738,19 +20937,22 @@ async function circularCommand(options, deps = defaultCircularCommandDeps) {
|
|
|
20738
20937
|
}
|
|
20739
20938
|
const validationConfig = loaded.value[validationConfigDescriptor.section];
|
|
20740
20939
|
const effectiveScopeConfig = resolveTypeScriptValidationScope({
|
|
20741
|
-
|
|
20940
|
+
productDir: cwd,
|
|
20742
20941
|
scope: scope2,
|
|
20743
20942
|
paths: files,
|
|
20744
20943
|
validationPathFilter: validationPathFilterForTool(
|
|
20745
20944
|
validationConfig.paths,
|
|
20746
20945
|
VALIDATION_PATH_TOOL_SUBSECTIONS.CIRCULAR
|
|
20747
|
-
)
|
|
20748
|
-
bypassExplicitPathValidationFilter: true
|
|
20946
|
+
)
|
|
20749
20947
|
});
|
|
20750
|
-
|
|
20948
|
+
const noTargetsMessage = formatValidationScopeNoTargetsSkipMessage(
|
|
20949
|
+
VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR,
|
|
20950
|
+
effectiveScopeConfig
|
|
20951
|
+
);
|
|
20952
|
+
if (noTargetsMessage !== void 0) {
|
|
20751
20953
|
return {
|
|
20752
20954
|
exitCode: 0,
|
|
20753
|
-
output: quiet ? "" :
|
|
20955
|
+
output: quiet ? "" : noTargetsMessage,
|
|
20754
20956
|
durationMs: Date.now() - startTime
|
|
20755
20957
|
};
|
|
20756
20958
|
}
|
|
@@ -20770,6 +20972,7 @@ var KNIP_COMMAND_TOKENS = {
|
|
|
20770
20972
|
TSCONFIG_FLAG: "--tsConfig",
|
|
20771
20973
|
USE_TSCONFIG_FILES_FLAG: "--use-tsconfig-files"
|
|
20772
20974
|
};
|
|
20975
|
+
var KNIP_LOCAL_BIN_SEGMENTS = ["node_modules", ".bin", KNIP_COMMAND_TOKENS.COMMAND];
|
|
20773
20976
|
var defaultKnipDeps = {
|
|
20774
20977
|
existsSync: existsSync4,
|
|
20775
20978
|
mkdir: mkdir7,
|
|
@@ -20777,9 +20980,9 @@ var defaultKnipDeps = {
|
|
|
20777
20980
|
rm: rm4,
|
|
20778
20981
|
writeFile: writeFile5
|
|
20779
20982
|
};
|
|
20780
|
-
async function validateKnip2(context, runner = defaultKnipProcessRunner, deps = defaultKnipDeps) {
|
|
20983
|
+
async function validateKnip2(context, runner = defaultKnipProcessRunner, deps = defaultKnipDeps, outputStreams = defaultValidationSubprocessOutputStreams) {
|
|
20781
20984
|
try {
|
|
20782
|
-
const {
|
|
20985
|
+
const { productDir, typescriptScope, toolPath } = context;
|
|
20783
20986
|
const analyzeTargets = [
|
|
20784
20987
|
...typescriptScope.directories,
|
|
20785
20988
|
...typescriptScope.filePatterns
|
|
@@ -20787,16 +20990,16 @@ async function validateKnip2(context, runner = defaultKnipProcessRunner, deps =
|
|
|
20787
20990
|
if (analyzeTargets.length === 0) {
|
|
20788
20991
|
return { success: true };
|
|
20789
20992
|
}
|
|
20790
|
-
return await runKnipSubprocess(
|
|
20993
|
+
return await runKnipSubprocess(productDir, typescriptScope, runner, deps, outputStreams, toolPath);
|
|
20791
20994
|
} catch (error) {
|
|
20792
20995
|
const errorMessage2 = error instanceof Error ? error.message : String(error);
|
|
20793
20996
|
return { success: false, error: errorMessage2 };
|
|
20794
20997
|
}
|
|
20795
20998
|
}
|
|
20796
|
-
async function runKnipSubprocess(
|
|
20797
|
-
const scopedTsconfig = typescriptScope.filteredByValidationPaths ? await createScopedKnipTsconfig(
|
|
20798
|
-
const localBin = join34(
|
|
20799
|
-
const binary = deps.existsSync(localBin) ? localBin : KNIP_COMMAND_TOKENS.NPX_COMMAND;
|
|
20999
|
+
async function runKnipSubprocess(productDir, typescriptScope, runner, deps, outputStreams, toolPath) {
|
|
21000
|
+
const scopedTsconfig = typescriptScope.filteredByValidationPaths ? await createScopedKnipTsconfig(productDir, typescriptScope, deps) : void 0;
|
|
21001
|
+
const localBin = join34(productDir, ...KNIP_LOCAL_BIN_SEGMENTS);
|
|
21002
|
+
const binary = toolPath ?? (deps.existsSync(localBin) ? localBin : KNIP_COMMAND_TOKENS.NPX_COMMAND);
|
|
20800
21003
|
const baseArgs = scopedTsconfig === void 0 ? [] : [
|
|
20801
21004
|
KNIP_COMMAND_TOKENS.USE_TSCONFIG_FILES_FLAG,
|
|
20802
21005
|
KNIP_COMMAND_TOKENS.TSCONFIG_FLAG,
|
|
@@ -20804,8 +21007,9 @@ async function runKnipSubprocess(projectRoot, typescriptScope, runner, deps) {
|
|
|
20804
21007
|
];
|
|
20805
21008
|
const args = binary === KNIP_COMMAND_TOKENS.NPX_COMMAND ? [KNIP_COMMAND_TOKENS.COMMAND, ...baseArgs] : baseArgs;
|
|
20806
21009
|
const knipProcess = spawnManagedSubprocess(runner, binary, args, {
|
|
20807
|
-
cwd:
|
|
21010
|
+
cwd: productDir
|
|
20808
21011
|
});
|
|
21012
|
+
forwardValidationSubprocessOutput(knipProcess, outputStreams);
|
|
20809
21013
|
const cleanup = scopedTsconfig?.cleanup ?? (async () => {
|
|
20810
21014
|
});
|
|
20811
21015
|
let cleanupStarted = false;
|
|
@@ -20835,7 +21039,7 @@ async function runKnipSubprocess(projectRoot, typescriptScope, runner, deps) {
|
|
|
20835
21039
|
};
|
|
20836
21040
|
knipProcess.on("close", (code) => {
|
|
20837
21041
|
if (code === 0) {
|
|
20838
|
-
resolveAfterCleanup({ success: true });
|
|
21042
|
+
resolveAfterCleanup({ success: true, output: knipOutput });
|
|
20839
21043
|
} else {
|
|
20840
21044
|
const errorOutput = knipOutput || knipError || "Unused code detected";
|
|
20841
21045
|
resolveAfterCleanup({
|
|
@@ -20849,12 +21053,12 @@ async function runKnipSubprocess(projectRoot, typescriptScope, runner, deps) {
|
|
|
20849
21053
|
});
|
|
20850
21054
|
});
|
|
20851
21055
|
}
|
|
20852
|
-
async function createScopedKnipTsconfig(
|
|
20853
|
-
const tempParentDir = join34(
|
|
21056
|
+
async function createScopedKnipTsconfig(productDir, typescriptScope, deps) {
|
|
21057
|
+
const tempParentDir = join34(productDir, ...TEMPORARY_TSCONFIG_PARENT_SEGMENTS);
|
|
20854
21058
|
await deps.mkdir(tempParentDir, { recursive: true });
|
|
20855
21059
|
const tempDir = await deps.mkdtemp(join34(tempParentDir, "validate-knip-"));
|
|
20856
21060
|
const configPath = join34(tempDir, TSCONFIG_FILES.full);
|
|
20857
|
-
const toProjectPathPattern = (pattern) => isAbsolute9(pattern) ? pattern : join34(
|
|
21061
|
+
const toProjectPathPattern = (pattern) => isAbsolute9(pattern) ? pattern : join34(productDir, pattern);
|
|
20858
21062
|
const project = [
|
|
20859
21063
|
...typescriptScope.directories.flatMap(
|
|
20860
21064
|
(directory) => TYPESCRIPT_FALLBACK_INCLUDE_PATTERNS.map((pattern) => `${directory}/${pattern}`)
|
|
@@ -20862,7 +21066,7 @@ async function createScopedKnipTsconfig(projectRoot, typescriptScope, deps) {
|
|
|
20862
21066
|
...typescriptScope.filePatterns
|
|
20863
21067
|
];
|
|
20864
21068
|
const config = {
|
|
20865
|
-
extends: join34(
|
|
21069
|
+
extends: join34(productDir, TSCONFIG_FILES.full),
|
|
20866
21070
|
include: project.map(toProjectPathPattern),
|
|
20867
21071
|
exclude: typescriptScope.excludePatterns.map(toProjectPathPattern)
|
|
20868
21072
|
};
|
|
@@ -20879,17 +21083,25 @@ var defaultKnipCommandDeps = {
|
|
|
20879
21083
|
discoverTool,
|
|
20880
21084
|
validateKnip: validateKnip2
|
|
20881
21085
|
};
|
|
20882
|
-
var
|
|
20883
|
-
var
|
|
21086
|
+
var KNIP_VALIDATION_STEP_NAME = "unused code detection";
|
|
21087
|
+
var KNIP_TYPESCRIPT_ABSENT_MESSAGE = formatTypeScriptAbsentSkipMessage(
|
|
20884
21088
|
VALIDATION_STAGE_DISPLAY_NAMES.KNIP
|
|
20885
21089
|
);
|
|
20886
21090
|
async function knipCommand(options, deps = defaultKnipCommandDeps) {
|
|
20887
|
-
const {
|
|
21091
|
+
const {
|
|
21092
|
+
cwd,
|
|
21093
|
+
files,
|
|
21094
|
+
json,
|
|
21095
|
+
outputStreams,
|
|
21096
|
+
quiet,
|
|
21097
|
+
scope: scope2 = VALIDATION_SCOPES.FULL,
|
|
21098
|
+
streamedPipelineOutput
|
|
21099
|
+
} = options;
|
|
20888
21100
|
const startTime = Date.now();
|
|
20889
21101
|
if (!deps.detectTypeScript(cwd).present) {
|
|
20890
21102
|
return {
|
|
20891
21103
|
exitCode: 0,
|
|
20892
|
-
output: quiet ? "" :
|
|
21104
|
+
output: quiet ? "" : KNIP_TYPESCRIPT_ABSENT_MESSAGE,
|
|
20893
21105
|
durationMs: Date.now() - startTime
|
|
20894
21106
|
};
|
|
20895
21107
|
}
|
|
@@ -20906,34 +21118,51 @@ async function knipCommand(options, deps = defaultKnipCommandDeps) {
|
|
|
20906
21118
|
const output = quiet ? "" : VALIDATION_COMMAND_OUTPUT.KNIP_DISABLED;
|
|
20907
21119
|
return { exitCode: 0, output, durationMs: Date.now() - startTime };
|
|
20908
21120
|
}
|
|
20909
|
-
const toolResult = await deps.discoverTool(
|
|
21121
|
+
const toolResult = await deps.discoverTool(KNIP_COMMAND_TOKENS.COMMAND, {
|
|
21122
|
+
productDir: cwd,
|
|
21123
|
+
includeBundled: false
|
|
21124
|
+
});
|
|
20910
21125
|
if (!toolResult.found) {
|
|
20911
|
-
const skipMessage = formatSkipMessage(
|
|
21126
|
+
const skipMessage = formatSkipMessage(KNIP_VALIDATION_STEP_NAME, toolResult);
|
|
20912
21127
|
return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };
|
|
20913
21128
|
}
|
|
20914
21129
|
const scopeConfig = resolveTypeScriptValidationScope({
|
|
20915
|
-
|
|
21130
|
+
productDir: cwd,
|
|
20916
21131
|
scope: scope2,
|
|
20917
21132
|
paths: files,
|
|
20918
21133
|
validationPathFilter: validationPathFilterForTool(validationConfig.paths, VALIDATION_PATH_TOOL_SUBSECTIONS.KNIP),
|
|
20919
|
-
markExplicitPathsAsValidationFilter: true
|
|
20920
|
-
bypassExplicitPathValidationFilter: true
|
|
21134
|
+
markExplicitPathsAsValidationFilter: true
|
|
20921
21135
|
});
|
|
20922
|
-
|
|
21136
|
+
const noTargetsMessage = formatValidationScopeNoTargetsSkipMessage(
|
|
21137
|
+
VALIDATION_STAGE_DISPLAY_NAMES.KNIP,
|
|
21138
|
+
scopeConfig
|
|
21139
|
+
);
|
|
21140
|
+
if (noTargetsMessage !== void 0) {
|
|
20923
21141
|
return {
|
|
20924
21142
|
exitCode: 0,
|
|
20925
|
-
output: quiet ? "" :
|
|
21143
|
+
output: quiet ? "" : noTargetsMessage,
|
|
20926
21144
|
durationMs: Date.now() - startTime
|
|
20927
21145
|
};
|
|
20928
21146
|
}
|
|
20929
|
-
const result = await deps.validateKnip(
|
|
21147
|
+
const result = await deps.validateKnip(
|
|
21148
|
+
{
|
|
21149
|
+
productDir: cwd,
|
|
21150
|
+
typescriptScope: scopeConfig,
|
|
21151
|
+
toolPath: toolResult.location.path
|
|
21152
|
+
},
|
|
21153
|
+
void 0,
|
|
21154
|
+
void 0,
|
|
21155
|
+
outputStreams ?? discardValidationSubprocessOutputStreams
|
|
21156
|
+
);
|
|
20930
21157
|
const durationMs = Date.now() - startTime;
|
|
20931
21158
|
if (result.success) {
|
|
20932
|
-
const output = quiet ? "" : VALIDATION_COMMAND_OUTPUT.KNIP_SUCCESS;
|
|
20933
|
-
|
|
21159
|
+
const output = quiet ? "" : [VALIDATION_COMMAND_OUTPUT.KNIP_SUCCESS, result.output].filter((line) => line !== void 0 && line.length > 0).join("\n");
|
|
21160
|
+
const terminalOutput = streamedValidationTerminalOutput(result.output, json, streamedPipelineOutput);
|
|
21161
|
+
return { exitCode: 0, output, terminalOutput, durationMs };
|
|
20934
21162
|
} else {
|
|
20935
21163
|
const output = result.error ?? VALIDATION_COMMAND_OUTPUT.KNIP_FAILURE;
|
|
20936
|
-
|
|
21164
|
+
const terminalOutput = streamedValidationTerminalOutput(result.error, json, streamedPipelineOutput);
|
|
21165
|
+
return { exitCode: 1, output, terminalOutput, durationMs };
|
|
20937
21166
|
}
|
|
20938
21167
|
}
|
|
20939
21168
|
|
|
@@ -21193,8 +21422,7 @@ function validateLintPolicy(productDir) {
|
|
|
21193
21422
|
}
|
|
21194
21423
|
}
|
|
21195
21424
|
|
|
21196
|
-
// src/validation/steps/eslint.ts
|
|
21197
|
-
var defaultEslintProcessRunner = lifecycleProcessRunner;
|
|
21425
|
+
// src/validation/steps/eslint-contract.ts
|
|
21198
21426
|
var DEFAULT_ESLINT_CONFIG_FILE = "eslint.config.ts";
|
|
21199
21427
|
var ESLINT_COMMAND_TOKENS = {
|
|
21200
21428
|
COMMAND: "eslint",
|
|
@@ -21205,6 +21433,9 @@ var ESLINT_COMMAND_TOKENS = {
|
|
|
21205
21433
|
IGNORE_PATTERN_FLAG: "--ignore-pattern"
|
|
21206
21434
|
};
|
|
21207
21435
|
var ESLINT_LOCAL_BIN_SEGMENTS = ["node_modules", ".bin", ESLINT_COMMAND_TOKENS.COMMAND];
|
|
21436
|
+
|
|
21437
|
+
// src/validation/steps/eslint.ts
|
|
21438
|
+
var defaultEslintProcessRunner = lifecycleProcessRunner;
|
|
21208
21439
|
function buildEslintArgs(context) {
|
|
21209
21440
|
const {
|
|
21210
21441
|
validatedFiles,
|
|
@@ -21252,8 +21483,8 @@ function buildIgnorePatternArgs(patterns) {
|
|
|
21252
21483
|
return patterns.flatMap((pattern) => [ESLINT_COMMAND_TOKENS.IGNORE_PATTERN_FLAG, pattern]);
|
|
21253
21484
|
}
|
|
21254
21485
|
async function validateESLint(context, runner = defaultEslintProcessRunner, outputStreams = defaultValidationSubprocessOutputStreams) {
|
|
21255
|
-
const {
|
|
21256
|
-
const lintPolicy = validateLintPolicy(
|
|
21486
|
+
const { productDir, scope: scope2, validatedFiles, mode, eslintConfigFile, toolPath } = context;
|
|
21487
|
+
const lintPolicy = validateLintPolicy(productDir);
|
|
21257
21488
|
if (!lintPolicy.ok) {
|
|
21258
21489
|
return { success: false, error: lintPolicy.error };
|
|
21259
21490
|
}
|
|
@@ -21269,47 +21500,57 @@ async function validateESLint(context, runner = defaultEslintProcessRunner, outp
|
|
|
21269
21500
|
scopeConfig: context.scopeConfig
|
|
21270
21501
|
});
|
|
21271
21502
|
return new Promise((resolve17) => {
|
|
21272
|
-
const localBin = join36(
|
|
21273
|
-
const binary = existsSync6(localBin) ? localBin : "npx";
|
|
21503
|
+
const localBin = join36(productDir, ...ESLINT_LOCAL_BIN_SEGMENTS);
|
|
21504
|
+
const binary = toolPath ?? (existsSync6(localBin) ? localBin : "npx");
|
|
21274
21505
|
const spawnArgs = binary === "npx" ? eslintArgs : eslintArgs.slice(1);
|
|
21275
21506
|
const eslintProcess = spawnManagedSubprocess(runner, binary, spawnArgs, {
|
|
21276
|
-
cwd:
|
|
21507
|
+
cwd: productDir
|
|
21277
21508
|
});
|
|
21509
|
+
const chunks = [];
|
|
21510
|
+
const capture = (chunk) => {
|
|
21511
|
+
chunks.push(typeof chunk === "string" ? chunk : Buffer.from(chunk).toString());
|
|
21512
|
+
};
|
|
21513
|
+
eslintProcess.stdout?.on(VALIDATION_SUBPROCESS_EVENTS.DATA, capture);
|
|
21514
|
+
eslintProcess.stderr?.on(VALIDATION_SUBPROCESS_EVENTS.DATA, capture);
|
|
21278
21515
|
forwardValidationSubprocessOutput(eslintProcess, outputStreams);
|
|
21279
21516
|
eslintProcess.on(VALIDATION_SUBPROCESS_EVENTS.CLOSE, (code) => {
|
|
21517
|
+
const output = chunks.join("");
|
|
21280
21518
|
if (code === 0) {
|
|
21281
|
-
resolve17({ success: true });
|
|
21519
|
+
resolve17({ success: true, output });
|
|
21282
21520
|
} else {
|
|
21283
|
-
resolve17({ success: false, error: `ESLint exited with code ${code}` });
|
|
21521
|
+
resolve17({ success: false, output, error: `ESLint exited with code ${code}` });
|
|
21284
21522
|
}
|
|
21285
21523
|
});
|
|
21286
21524
|
eslintProcess.on(VALIDATION_SUBPROCESS_EVENTS.ERROR, (error) => {
|
|
21287
|
-
resolve17({ success: false, error: error.message });
|
|
21525
|
+
resolve17({ success: false, output: chunks.join(""), error: error.message });
|
|
21288
21526
|
});
|
|
21289
21527
|
});
|
|
21290
21528
|
}
|
|
21291
21529
|
|
|
21292
21530
|
// src/commands/validation/lint.ts
|
|
21293
|
-
var
|
|
21294
|
-
var MISSING_CONFIG_MESSAGE = VALIDATION_COMMAND_OUTPUT.ESLINT_MISSING_CONFIG;
|
|
21295
|
-
var ESLINT_CONFIG_ERROR_MESSAGE = `${VALIDATION_STAGE_DISPLAY_NAMES.ESLINT}: \u2717 config error`;
|
|
21296
|
-
var VALIDATION_PATHS_NO_TARGETS_MESSAGE = formatValidationPathsNoTargetsSkipMessage(
|
|
21297
|
-
VALIDATION_STAGE_DISPLAY_NAMES.ESLINT
|
|
21298
|
-
);
|
|
21299
|
-
var defaultLintCommandDependencies = {
|
|
21531
|
+
var defaultLintCommandDeps = {
|
|
21300
21532
|
detectTypeScript,
|
|
21301
21533
|
discoverTool,
|
|
21302
21534
|
resolveConfig,
|
|
21303
21535
|
validateESLint
|
|
21304
21536
|
};
|
|
21305
|
-
|
|
21306
|
-
|
|
21537
|
+
var TYPESCRIPT_ABSENT_MESSAGE2 = formatTypeScriptAbsentSkipMessage(VALIDATION_STAGE_DISPLAY_NAMES.ESLINT);
|
|
21538
|
+
var MISSING_CONFIG_MESSAGE = VALIDATION_COMMAND_OUTPUT.ESLINT_MISSING_CONFIG;
|
|
21539
|
+
var ESLINT_CONFIG_ERROR_MESSAGE = formatValidationConfigProblemMessage(
|
|
21540
|
+
VALIDATION_STAGE_DISPLAY_NAMES.ESLINT,
|
|
21541
|
+
"configuration error"
|
|
21542
|
+
);
|
|
21543
|
+
var VALIDATION_PATHS_NO_TARGETS_MESSAGE = formatValidationPathsNoTargetsSkipMessage(
|
|
21544
|
+
VALIDATION_STAGE_DISPLAY_NAMES.ESLINT
|
|
21545
|
+
);
|
|
21546
|
+
async function lintCommand(options, deps = defaultLintCommandDeps) {
|
|
21547
|
+
const { cwd, scope: scope2 = "full", files, fix, json, outputStreams, quiet, streamedPipelineOutput } = options;
|
|
21307
21548
|
const startTime = Date.now();
|
|
21308
21549
|
const tsDetection = deps.detectTypeScript(cwd);
|
|
21309
21550
|
if (!tsDetection.present) {
|
|
21310
21551
|
return {
|
|
21311
21552
|
exitCode: 0,
|
|
21312
|
-
output: quiet ? "" :
|
|
21553
|
+
output: quiet ? "" : TYPESCRIPT_ABSENT_MESSAGE2,
|
|
21313
21554
|
durationMs: Date.now() - startTime
|
|
21314
21555
|
};
|
|
21315
21556
|
}
|
|
@@ -21336,35 +21577,38 @@ async function lintCommand(options, deps = defaultLintCommandDependencies) {
|
|
|
21336
21577
|
);
|
|
21337
21578
|
const explicitMode = files !== void 0 && files.length > 0;
|
|
21338
21579
|
const scopeConfig = resolveTypeScriptValidationScope({
|
|
21339
|
-
|
|
21580
|
+
productDir: cwd,
|
|
21340
21581
|
scope: scope2,
|
|
21341
21582
|
paths: files,
|
|
21342
21583
|
validationPathFilter,
|
|
21343
|
-
markExplicitPathsAsValidationFilter: explicitMode
|
|
21344
|
-
bypassExplicitPathValidationFilter: true
|
|
21584
|
+
markExplicitPathsAsValidationFilter: explicitMode
|
|
21345
21585
|
});
|
|
21346
21586
|
const explicitTargets = explicitMode ? filterExplicitTypeScriptScopeTargets({
|
|
21347
21587
|
paths: files,
|
|
21348
|
-
|
|
21588
|
+
productDir: cwd,
|
|
21349
21589
|
validationPathFilter,
|
|
21350
21590
|
scopeConfig: getTypeScriptScope(scope2, cwd),
|
|
21351
21591
|
bypassValidationPathFilter: true
|
|
21352
21592
|
}) : void 0;
|
|
21353
|
-
const validatedFiles = explicitTargets?.every((target) => target.kind === EXPLICIT_TYPESCRIPT_SCOPE_TARGET_KIND.FILE) ? explicitTargets.map((target) => formatLintValidationOperand(
|
|
21354
|
-
|
|
21593
|
+
const validatedFiles = explicitTargets?.every((target) => target.kind === EXPLICIT_TYPESCRIPT_SCOPE_TARGET_KIND.FILE) ? explicitTargets.map((target) => formatLintValidationOperand(toProductRelativeValidationPath(cwd, target.path))) : void 0;
|
|
21594
|
+
const noTargetsMessage = formatValidationScopeNoTargetsSkipMessage(
|
|
21595
|
+
VALIDATION_STAGE_DISPLAY_NAMES.ESLINT,
|
|
21596
|
+
scopeConfig
|
|
21597
|
+
);
|
|
21598
|
+
if (noTargetsMessage !== void 0) {
|
|
21355
21599
|
return {
|
|
21356
21600
|
exitCode: 0,
|
|
21357
|
-
output: quiet ? "" :
|
|
21601
|
+
output: quiet ? "" : noTargetsMessage,
|
|
21358
21602
|
durationMs: Date.now() - startTime
|
|
21359
21603
|
};
|
|
21360
21604
|
}
|
|
21361
|
-
const toolResult = await deps.discoverTool("eslint", {
|
|
21605
|
+
const toolResult = await deps.discoverTool("eslint", { productDir: cwd, includeBundled: false });
|
|
21362
21606
|
if (!toolResult.found) {
|
|
21363
21607
|
const skipMessage = formatSkipMessage(VALIDATION_STAGE_DISPLAY_NAMES.ESLINT, toolResult);
|
|
21364
21608
|
return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };
|
|
21365
21609
|
}
|
|
21366
21610
|
const context = {
|
|
21367
|
-
|
|
21611
|
+
productDir: cwd,
|
|
21368
21612
|
scope: scope2,
|
|
21369
21613
|
scopeConfig,
|
|
21370
21614
|
mode: fix ? "write" : "read",
|
|
@@ -21372,26 +21616,35 @@ async function lintCommand(options, deps = defaultLintCommandDependencies) {
|
|
|
21372
21616
|
validatedFiles,
|
|
21373
21617
|
validatedFileIgnorePatterns: void 0,
|
|
21374
21618
|
isFileSpecificMode: Boolean(validatedFiles && validatedFiles.length > 0),
|
|
21375
|
-
eslintConfigFile
|
|
21619
|
+
eslintConfigFile,
|
|
21620
|
+
toolPath: toolResult.location.path
|
|
21376
21621
|
};
|
|
21377
|
-
const result = await deps.validateESLint(
|
|
21622
|
+
const result = await deps.validateESLint(
|
|
21623
|
+
context,
|
|
21624
|
+
void 0,
|
|
21625
|
+
outputStreams ?? discardValidationSubprocessOutputStreams
|
|
21626
|
+
);
|
|
21378
21627
|
const durationMs = Date.now() - startTime;
|
|
21379
|
-
return formatLintResult(result, quiet, durationMs);
|
|
21628
|
+
return formatLintResult(result, quiet, durationMs, json, streamedPipelineOutput);
|
|
21380
21629
|
}
|
|
21381
21630
|
function formatLintValidationOperand(path4) {
|
|
21382
21631
|
return path4.length === 0 ? "." : path4;
|
|
21383
21632
|
}
|
|
21384
|
-
function formatLintResult(result, quiet, durationMs) {
|
|
21633
|
+
function formatLintResult(result, quiet, durationMs, json, streamedPipelineOutput) {
|
|
21385
21634
|
if (result.skipped) {
|
|
21386
21635
|
const output2 = quiet ? "" : VALIDATION_PATHS_NO_TARGETS_MESSAGE;
|
|
21387
21636
|
return { exitCode: 0, output: output2, durationMs };
|
|
21388
21637
|
}
|
|
21389
21638
|
if (result.success) {
|
|
21390
|
-
const output2 = quiet ? "" : VALIDATION_COMMAND_OUTPUT.ESLINT_SUCCESS
|
|
21391
|
-
|
|
21639
|
+
const output2 = quiet ? "" : [VALIDATION_COMMAND_OUTPUT.ESLINT_SUCCESS, result.output].filter(
|
|
21640
|
+
(line) => line !== void 0 && line.length > 0
|
|
21641
|
+
).join("\n");
|
|
21642
|
+
const terminalOutput2 = streamedValidationTerminalOutput(result.output, json, streamedPipelineOutput);
|
|
21643
|
+
return { exitCode: 0, output: output2, terminalOutput: terminalOutput2, durationMs };
|
|
21392
21644
|
}
|
|
21393
|
-
const output = result.error ?? VALIDATION_COMMAND_OUTPUT.ESLINT_FAILURE;
|
|
21394
|
-
|
|
21645
|
+
const output = [result.output, result.error ?? VALIDATION_COMMAND_OUTPUT.ESLINT_FAILURE].filter((line) => line !== void 0 && line.length > 0).join("\n");
|
|
21646
|
+
const terminalOutput = streamedValidationTerminalOutput(result.output, json, streamedPipelineOutput);
|
|
21647
|
+
return { exitCode: 1, output, terminalOutput, durationMs };
|
|
21395
21648
|
}
|
|
21396
21649
|
|
|
21397
21650
|
// src/domains/validation/literal-problem-kind.ts
|
|
@@ -21443,7 +21696,7 @@ var GIT_DEFAULT_GLOBAL_IGNORE_PATH = {
|
|
|
21443
21696
|
GIT_DIRECTORY: "git",
|
|
21444
21697
|
IGNORE_FILE: "ignore"
|
|
21445
21698
|
};
|
|
21446
|
-
var
|
|
21699
|
+
var PATH_SEGMENT_SEPARATOR4 = "/";
|
|
21447
21700
|
var CURRENT_DIRECTORY_PREFIX2 = ".";
|
|
21448
21701
|
var GIT_SCOPE_FAILURE_MESSAGE = "failed to read git scope";
|
|
21449
21702
|
var GIT_MISSING_CONTEXT_MESSAGE = "missing git working tree";
|
|
@@ -21576,11 +21829,11 @@ function readGlobalExcludesPath(productDir) {
|
|
|
21576
21829
|
}
|
|
21577
21830
|
function parentPrefixes(path4) {
|
|
21578
21831
|
const prefixes = [];
|
|
21579
|
-
let index = path4.lastIndexOf(
|
|
21832
|
+
let index = path4.lastIndexOf(PATH_SEGMENT_SEPARATOR4);
|
|
21580
21833
|
while (index > 0) {
|
|
21581
21834
|
const parent = path4.slice(0, index);
|
|
21582
21835
|
prefixes.push(parent);
|
|
21583
|
-
index = parent.lastIndexOf(
|
|
21836
|
+
index = parent.lastIndexOf(PATH_SEGMENT_SEPARATOR4);
|
|
21584
21837
|
}
|
|
21585
21838
|
return prefixes;
|
|
21586
21839
|
}
|
|
@@ -21635,7 +21888,7 @@ function createIgnoreSourceReader(productDir, config) {
|
|
|
21635
21888
|
},
|
|
21636
21889
|
hasIncludedDescendant(relativePath) {
|
|
21637
21890
|
return descendantParents.has(
|
|
21638
|
-
relativePath.endsWith(
|
|
21891
|
+
relativePath.endsWith(PATH_SEGMENT_SEPARATOR4) ? relativePath.slice(0, -1) : relativePath
|
|
21639
21892
|
);
|
|
21640
21893
|
},
|
|
21641
21894
|
appliedOverrides() {
|
|
@@ -22340,7 +22593,8 @@ async function validateLiteralReuse(input) {
|
|
|
22340
22593
|
return {
|
|
22341
22594
|
findings,
|
|
22342
22595
|
indexedOccurrencesByFile,
|
|
22343
|
-
filteredByValidationPathNoMatches: input.scopeConfig?.filteredByValidationPathNoMatches
|
|
22596
|
+
filteredByValidationPathNoMatches: input.scopeConfig?.filteredByValidationPathNoMatches,
|
|
22597
|
+
explicitPathNoMatches: input.scopeConfig?.explicitPathNoMatches
|
|
22344
22598
|
};
|
|
22345
22599
|
}
|
|
22346
22600
|
async function readSafe(path4) {
|
|
@@ -22388,29 +22642,29 @@ var OUTPUT_MODE_NAME = {
|
|
|
22388
22642
|
JSON: "json"
|
|
22389
22643
|
};
|
|
22390
22644
|
var OUTPUT_MODE_NAMES = Object.values(OUTPUT_MODE_NAME);
|
|
22645
|
+
var defaultLiteralCommandDeps = {
|
|
22646
|
+
validateLiteralReuse
|
|
22647
|
+
};
|
|
22391
22648
|
var LITERAL_EXIT_CODES = {
|
|
22392
22649
|
OK: 0,
|
|
22393
22650
|
FINDINGS: 1,
|
|
22394
22651
|
CONFIG_ERROR: 2
|
|
22395
22652
|
};
|
|
22396
|
-
var
|
|
22397
|
-
VALIDATION_STAGE_DISPLAY_NAMES.LITERAL
|
|
22398
|
-
);
|
|
22399
|
-
var VALIDATION_PATHS_NO_TARGETS_MESSAGE2 = formatValidationPathsNoTargetsSkipMessage(
|
|
22653
|
+
var TYPESCRIPT_ABSENT_MESSAGE3 = formatTypeScriptAbsentSkipMessage(
|
|
22400
22654
|
VALIDATION_STAGE_DISPLAY_NAMES.LITERAL
|
|
22401
22655
|
);
|
|
22402
22656
|
var LITERAL_DISABLED_MESSAGE = `\u23ED ${VALIDATION_SKIP_LABELS.VERB} ${VALIDATION_STAGE_DISPLAY_NAMES.LITERAL} (${VALIDATION_SKIP_LABELS.DISABLED_BY_PREFIX} validation.literal.enabled)`;
|
|
22403
|
-
var NO_PROBLEMS_MESSAGE =
|
|
22657
|
+
var NO_PROBLEMS_MESSAGE = formatValidationNoProblemsMessage(VALIDATION_STAGE_DISPLAY_NAMES.LITERAL);
|
|
22404
22658
|
function formatNoProblemsOfKind(kind) {
|
|
22405
22659
|
return `Literal: No problems of type ${kind}`;
|
|
22406
22660
|
}
|
|
22407
|
-
async function literalCommand(options) {
|
|
22661
|
+
async function literalCommand(options, deps = defaultLiteralCommandDeps) {
|
|
22408
22662
|
const start = Date.now();
|
|
22409
22663
|
const tsDetection = detectTypeScript(options.cwd);
|
|
22410
22664
|
if (!tsDetection.present) {
|
|
22411
22665
|
return {
|
|
22412
22666
|
exitCode: LITERAL_EXIT_CODES.OK,
|
|
22413
|
-
output: options.quiet ? "" :
|
|
22667
|
+
output: options.quiet ? "" : TYPESCRIPT_ABSENT_MESSAGE3,
|
|
22414
22668
|
durationMs: Date.now() - start
|
|
22415
22669
|
};
|
|
22416
22670
|
}
|
|
@@ -22418,7 +22672,10 @@ async function literalCommand(options) {
|
|
|
22418
22672
|
if (typeof resolved === "string") {
|
|
22419
22673
|
return {
|
|
22420
22674
|
exitCode: LITERAL_EXIT_CODES.CONFIG_ERROR,
|
|
22421
|
-
output:
|
|
22675
|
+
output: `${formatValidationConfigProblemMessage(
|
|
22676
|
+
VALIDATION_STAGE_DISPLAY_NAMES.LITERAL,
|
|
22677
|
+
"configuration error"
|
|
22678
|
+
)} \u2014 ${resolved}`,
|
|
22422
22679
|
durationMs: Date.now() - start
|
|
22423
22680
|
};
|
|
22424
22681
|
}
|
|
@@ -22429,17 +22686,18 @@ async function literalCommand(options) {
|
|
|
22429
22686
|
durationMs: Date.now() - start
|
|
22430
22687
|
};
|
|
22431
22688
|
}
|
|
22432
|
-
const result = await validateLiteralReuse({
|
|
22689
|
+
const result = await deps.validateLiteralReuse({
|
|
22433
22690
|
productDir: options.cwd,
|
|
22434
22691
|
explicitFiles: explicitLiteralPaths(options.files),
|
|
22435
22692
|
config: resolved.literalConfig,
|
|
22436
22693
|
pathConfig: resolved.pathConfig,
|
|
22437
22694
|
scopeConfig: resolveExplicitLiteralTypeScriptScope(options, resolved.pathConfig)
|
|
22438
22695
|
});
|
|
22439
|
-
|
|
22696
|
+
const noTargetsMessage = explicitLiteralNoTargetsSkipMessage(options, result);
|
|
22697
|
+
if (noTargetsMessage !== void 0) {
|
|
22440
22698
|
return {
|
|
22441
22699
|
exitCode: LITERAL_EXIT_CODES.OK,
|
|
22442
|
-
output: options.quiet ? "" :
|
|
22700
|
+
output: options.quiet ? "" : noTargetsMessage,
|
|
22443
22701
|
durationMs: Date.now() - start
|
|
22444
22702
|
};
|
|
22445
22703
|
}
|
|
@@ -22454,7 +22712,18 @@ async function literalCommand(options) {
|
|
|
22454
22712
|
} else {
|
|
22455
22713
|
output = formatLiteralCommandOutput(filteredFindings, options);
|
|
22456
22714
|
}
|
|
22457
|
-
return {
|
|
22715
|
+
return {
|
|
22716
|
+
exitCode,
|
|
22717
|
+
output,
|
|
22718
|
+
durationMs: Date.now() - start,
|
|
22719
|
+
outputTarget: VALIDATION_OUTPUT_TARGET.STDOUT
|
|
22720
|
+
};
|
|
22721
|
+
}
|
|
22722
|
+
function explicitLiteralNoTargetsSkipMessage(options, result) {
|
|
22723
|
+
if (options.files === void 0 || options.files.length === 0) {
|
|
22724
|
+
return void 0;
|
|
22725
|
+
}
|
|
22726
|
+
return formatValidationScopeNoTargetsSkipMessage(VALIDATION_STAGE_DISPLAY_NAMES.LITERAL, result);
|
|
22458
22727
|
}
|
|
22459
22728
|
async function resolveLiteralCommandConfig(options) {
|
|
22460
22729
|
if (options.config !== void 0) {
|
|
@@ -22481,12 +22750,11 @@ function resolveExplicitLiteralTypeScriptScope(options, pathConfig) {
|
|
|
22481
22750
|
return void 0;
|
|
22482
22751
|
}
|
|
22483
22752
|
return resolveTypeScriptValidationScope({
|
|
22484
|
-
|
|
22753
|
+
productDir: options.cwd,
|
|
22485
22754
|
scope: options.scope ?? VALIDATION_SCOPES.FULL,
|
|
22486
22755
|
paths: options.files,
|
|
22487
22756
|
validationPathFilter: pathConfig,
|
|
22488
|
-
markExplicitPathsAsValidationFilter: true
|
|
22489
|
-
bypassExplicitPathValidationFilter: true
|
|
22757
|
+
markExplicitPathsAsValidationFilter: true
|
|
22490
22758
|
});
|
|
22491
22759
|
}
|
|
22492
22760
|
function explicitLiteralPaths(files) {
|
|
@@ -22630,8 +22898,8 @@ function formatTypeScriptExitCodeError(code) {
|
|
|
22630
22898
|
}
|
|
22631
22899
|
var TEMPORARY_TSCONFIG_COMPILER_OPTIONS = { noEmit: true };
|
|
22632
22900
|
var TEMPORARY_TSCONFIG_DIR_PREFIX = "validate-ts-";
|
|
22633
|
-
async function createTemporaryTsconfigDir(
|
|
22634
|
-
const parent = join39(
|
|
22901
|
+
async function createTemporaryTsconfigDir(productDir, deps) {
|
|
22902
|
+
const parent = join39(productDir, ...TEMPORARY_TSCONFIG_PARENT_SEGMENTS);
|
|
22635
22903
|
deps.mkdirSync(parent, { recursive: true });
|
|
22636
22904
|
return deps.mkdtemp(join39(parent, TEMPORARY_TSCONFIG_DIR_PREFIX));
|
|
22637
22905
|
}
|
|
@@ -22639,13 +22907,13 @@ function buildTypeScriptArgs(context) {
|
|
|
22639
22907
|
const { scope: scope2, configFile } = context;
|
|
22640
22908
|
return scope2 === VALIDATION_SCOPES.FULL ? ["tsc", "--noEmit"] : ["tsc", "--project", configFile];
|
|
22641
22909
|
}
|
|
22642
|
-
async function createFileSpecificTsconfig(scope2, files,
|
|
22643
|
-
const tempDir = await createTemporaryTsconfigDir(
|
|
22910
|
+
async function createFileSpecificTsconfig(scope2, files, productDir, deps = defaultTypeScriptDeps) {
|
|
22911
|
+
const tempDir = await createTemporaryTsconfigDir(productDir, deps);
|
|
22644
22912
|
const configPath = join39(tempDir, "tsconfig.json");
|
|
22645
22913
|
const baseConfigFile = TSCONFIG_FILES[scope2];
|
|
22646
|
-
const absoluteFiles = files.map((file) => isAbsolute12(file) ? file : join39(
|
|
22914
|
+
const absoluteFiles = files.map((file) => isAbsolute12(file) ? file : join39(productDir, file));
|
|
22647
22915
|
const tempConfig = {
|
|
22648
|
-
extends: join39(
|
|
22916
|
+
extends: join39(productDir, baseConfigFile),
|
|
22649
22917
|
files: absoluteFiles,
|
|
22650
22918
|
include: [],
|
|
22651
22919
|
exclude: [],
|
|
@@ -22655,16 +22923,16 @@ async function createFileSpecificTsconfig(scope2, files, projectRoot, deps = def
|
|
|
22655
22923
|
const cleanup = createTemporaryTsconfigCleanup(tempDir, deps);
|
|
22656
22924
|
return { configPath, tempDir, cleanup };
|
|
22657
22925
|
}
|
|
22658
|
-
async function createScopeFilteredTsconfig(scope2,
|
|
22659
|
-
const tempDir = await createTemporaryTsconfigDir(
|
|
22926
|
+
async function createScopeFilteredTsconfig(scope2, productDir, scopeConfig, deps = defaultTypeScriptDeps) {
|
|
22927
|
+
const tempDir = await createTemporaryTsconfigDir(productDir, deps);
|
|
22660
22928
|
const configPath = join39(tempDir, "tsconfig.json");
|
|
22661
22929
|
const baseConfigFile = TSCONFIG_FILES[scope2];
|
|
22662
22930
|
const toTemporaryConfigPathPattern = (pattern) => {
|
|
22663
|
-
const absolutePattern = isAbsolute12(pattern) ? pattern : join39(
|
|
22931
|
+
const absolutePattern = isAbsolute12(pattern) ? pattern : join39(productDir, pattern);
|
|
22664
22932
|
return relative10(tempDir, absolutePattern);
|
|
22665
22933
|
};
|
|
22666
22934
|
const tempConfig = {
|
|
22667
|
-
extends: join39(
|
|
22935
|
+
extends: join39(productDir, baseConfigFile),
|
|
22668
22936
|
include: scopeConfigToTemporaryIncludes(scopeConfig).map(toTemporaryConfigPathPattern),
|
|
22669
22937
|
exclude: scopeConfig.excludePatterns.map(toTemporaryConfigPathPattern),
|
|
22670
22938
|
compilerOptions: TEMPORARY_TSCONFIG_COMPILER_OPTIONS
|
|
@@ -22693,19 +22961,20 @@ function createTemporaryTsconfigCleanup(tempDir, deps) {
|
|
|
22693
22961
|
};
|
|
22694
22962
|
}
|
|
22695
22963
|
async function validateTypeScript(context, options = {}) {
|
|
22696
|
-
const { scope: scope2,
|
|
22964
|
+
const { scope: scope2, productDir, files, scopeConfig } = context;
|
|
22697
22965
|
const {
|
|
22698
22966
|
runner = defaultTypeScriptProcessRunner,
|
|
22699
22967
|
deps = defaultTypeScriptDeps,
|
|
22968
|
+
toolPath,
|
|
22700
22969
|
outputStreams = defaultValidationSubprocessOutputStreams
|
|
22701
22970
|
} = options;
|
|
22702
22971
|
const configFile = TSCONFIG_FILES[scope2];
|
|
22703
22972
|
if (files && files.length > 0) {
|
|
22704
|
-
const { configPath, cleanup } = await createFileSpecificTsconfig(scope2, files,
|
|
22973
|
+
const { configPath, cleanup } = await createFileSpecificTsconfig(scope2, files, productDir, deps);
|
|
22705
22974
|
try {
|
|
22706
22975
|
return await runTypeScriptInvocation(
|
|
22707
|
-
|
|
22708
|
-
|
|
22976
|
+
productDir,
|
|
22977
|
+
resolveTscInvocation(productDir, deps, ["--project", configPath], toolPath),
|
|
22709
22978
|
runner,
|
|
22710
22979
|
outputStreams,
|
|
22711
22980
|
cleanup
|
|
@@ -22722,64 +22991,89 @@ async function validateTypeScript(context, options = {}) {
|
|
|
22722
22991
|
if (scopeConfig.filePatterns.length === 0 && scopeConfig.directories.length === 0) {
|
|
22723
22992
|
return { success: true, skipped: true };
|
|
22724
22993
|
}
|
|
22725
|
-
const { configPath, cleanup } = await createScopeFilteredTsconfig(scope2,
|
|
22994
|
+
const { configPath, cleanup } = await createScopeFilteredTsconfig(scope2, productDir, scopeConfig, deps);
|
|
22726
22995
|
return runTypeScriptInvocation(
|
|
22727
|
-
|
|
22728
|
-
|
|
22996
|
+
productDir,
|
|
22997
|
+
resolveTscInvocation(productDir, deps, ["--project", configPath], toolPath),
|
|
22729
22998
|
runner,
|
|
22730
22999
|
outputStreams,
|
|
22731
23000
|
cleanup
|
|
22732
23001
|
);
|
|
22733
23002
|
}
|
|
22734
23003
|
return runTypeScriptInvocation(
|
|
22735
|
-
|
|
22736
|
-
|
|
23004
|
+
productDir,
|
|
23005
|
+
resolveTscInvocation(productDir, deps, buildTypeScriptArgs({ scope: scope2, configFile }).slice(1), toolPath),
|
|
22737
23006
|
runner,
|
|
22738
23007
|
outputStreams
|
|
22739
23008
|
);
|
|
22740
23009
|
}
|
|
22741
|
-
function
|
|
22742
|
-
|
|
23010
|
+
function resolveTscInvocation(productDir, deps, tscArgs, toolPath) {
|
|
23011
|
+
if (toolPath !== void 0) {
|
|
23012
|
+
return { tool: toolPath, args: tscArgs };
|
|
23013
|
+
}
|
|
23014
|
+
const tscBin = join39(productDir, "node_modules", ".bin", "tsc");
|
|
22743
23015
|
const tool = deps.existsSync(tscBin) ? tscBin : "npx";
|
|
22744
23016
|
return {
|
|
22745
23017
|
tool,
|
|
22746
23018
|
args: tool === "npx" ? ["tsc", ...tscArgs] : tscArgs
|
|
22747
23019
|
};
|
|
22748
23020
|
}
|
|
22749
|
-
function runTypeScriptInvocation(
|
|
23021
|
+
function runTypeScriptInvocation(productDir, invocation, runner, outputStreams, cleanup = () => {
|
|
22750
23022
|
}) {
|
|
22751
23023
|
return new Promise((resolve17) => {
|
|
22752
23024
|
const tscProcess = spawnManagedSubprocess(runner, invocation.tool, invocation.args, {
|
|
22753
|
-
cwd:
|
|
23025
|
+
cwd: productDir
|
|
22754
23026
|
});
|
|
23027
|
+
const chunks = [];
|
|
23028
|
+
const capture = (chunk) => {
|
|
23029
|
+
chunks.push(typeof chunk === "string" ? chunk : Buffer.from(chunk).toString());
|
|
23030
|
+
};
|
|
23031
|
+
tscProcess.stdout?.on(VALIDATION_SUBPROCESS_EVENTS.DATA, capture);
|
|
23032
|
+
tscProcess.stderr?.on(VALIDATION_SUBPROCESS_EVENTS.DATA, capture);
|
|
22755
23033
|
forwardValidationSubprocessOutput(tscProcess, outputStreams);
|
|
22756
23034
|
tscProcess.on(VALIDATION_SUBPROCESS_EVENTS.CLOSE, (code) => {
|
|
22757
23035
|
cleanup();
|
|
23036
|
+
const output = chunks.join("");
|
|
22758
23037
|
if (code === 0) {
|
|
22759
|
-
resolve17({ success: true, skipped: false });
|
|
23038
|
+
resolve17({ success: true, skipped: false, output });
|
|
22760
23039
|
} else {
|
|
22761
|
-
resolve17({ success: false, error: formatTypeScriptExitCodeError(code) });
|
|
23040
|
+
resolve17({ success: false, output, error: formatTypeScriptExitCodeError(code) });
|
|
22762
23041
|
}
|
|
22763
23042
|
});
|
|
22764
23043
|
tscProcess.on(VALIDATION_SUBPROCESS_EVENTS.ERROR, (error) => {
|
|
22765
23044
|
cleanup();
|
|
22766
|
-
resolve17({ success: false, error: error.message });
|
|
23045
|
+
resolve17({ success: false, output: chunks.join(""), error: error.message });
|
|
22767
23046
|
});
|
|
22768
23047
|
});
|
|
22769
23048
|
}
|
|
22770
23049
|
|
|
22771
23050
|
// src/commands/validation/typescript.ts
|
|
23051
|
+
var defaultTypeScriptCommandDeps = {
|
|
23052
|
+
detectTypeScript,
|
|
23053
|
+
discoverTool,
|
|
23054
|
+
validateTypeScript
|
|
23055
|
+
};
|
|
22772
23056
|
var TYPESCRIPT_VALIDATION_MESSAGES = {
|
|
22773
23057
|
ABSENT: formatTypeScriptAbsentSkipMessage(VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT),
|
|
22774
|
-
CONFIG_ERROR:
|
|
23058
|
+
CONFIG_ERROR: formatValidationConfigProblemMessage(
|
|
23059
|
+
VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT,
|
|
23060
|
+
"configuration error"
|
|
23061
|
+
),
|
|
22775
23062
|
NO_VALIDATION_PATH_TARGETS: formatValidationPathsNoTargetsSkipMessage(VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT),
|
|
23063
|
+
NO_EXPLICIT_PATH_TARGETS: formatExplicitPathsNoTargetsSkipMessage(VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT),
|
|
22776
23064
|
SUCCESS: VALIDATION_COMMAND_OUTPUT.TYPESCRIPT_SUCCESS,
|
|
22777
23065
|
TOOL_LABEL: VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT
|
|
22778
23066
|
};
|
|
22779
|
-
|
|
22780
|
-
|
|
23067
|
+
var TYPESCRIPT_TOOL_DISCOVERY = {
|
|
23068
|
+
TOOL: "typescript",
|
|
23069
|
+
EXECUTABLE_NAME: "tsc",
|
|
23070
|
+
BUNDLED_EXECUTABLE: "typescript/bin/tsc",
|
|
23071
|
+
PRODUCT_EXECUTABLE_SEGMENTS: ["node_modules", ".bin", "tsc"]
|
|
23072
|
+
};
|
|
23073
|
+
async function typescriptCommand(options, deps = defaultTypeScriptCommandDeps) {
|
|
23074
|
+
const { cwd, scope: scope2 = "full", files, json, outputStreams, quiet, streamedPipelineOutput } = options;
|
|
22781
23075
|
const startTime = Date.now();
|
|
22782
|
-
const tsDetection = detectTypeScript(cwd);
|
|
23076
|
+
const tsDetection = deps.detectTypeScript(cwd);
|
|
22783
23077
|
if (!tsDetection.present) {
|
|
22784
23078
|
return {
|
|
22785
23079
|
exitCode: 0,
|
|
@@ -22797,53 +23091,69 @@ async function typescriptCommand(options) {
|
|
|
22797
23091
|
}
|
|
22798
23092
|
const validationConfig = loaded.value[validationConfigDescriptor.section];
|
|
22799
23093
|
const scopeConfig = resolveTypeScriptValidationScope({
|
|
22800
|
-
|
|
23094
|
+
productDir: cwd,
|
|
22801
23095
|
scope: scope2,
|
|
22802
23096
|
paths: files,
|
|
22803
23097
|
validationPathFilter: validationPathFilterForTool(
|
|
22804
23098
|
validationConfig.paths,
|
|
22805
23099
|
VALIDATION_PATH_TOOL_SUBSECTIONS.TYPESCRIPT
|
|
22806
23100
|
),
|
|
22807
|
-
markExplicitPathsAsValidationFilter: true
|
|
22808
|
-
bypassExplicitPathValidationFilter: true
|
|
23101
|
+
markExplicitPathsAsValidationFilter: true
|
|
22809
23102
|
});
|
|
22810
|
-
|
|
23103
|
+
const noTargetsMessage = formatValidationScopeNoTargetsSkipMessage(
|
|
23104
|
+
VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT,
|
|
23105
|
+
scopeConfig
|
|
23106
|
+
);
|
|
23107
|
+
if (noTargetsMessage !== void 0) {
|
|
22811
23108
|
return {
|
|
22812
23109
|
exitCode: 0,
|
|
22813
|
-
output: quiet ? "" :
|
|
23110
|
+
output: quiet ? "" : noTargetsMessage,
|
|
22814
23111
|
durationMs: Date.now() - startTime
|
|
22815
23112
|
};
|
|
22816
23113
|
}
|
|
22817
|
-
const toolResult = await discoverTool(
|
|
23114
|
+
const toolResult = await deps.discoverTool(TYPESCRIPT_TOOL_DISCOVERY.TOOL, {
|
|
23115
|
+
productDir: cwd,
|
|
23116
|
+
executableName: TYPESCRIPT_TOOL_DISCOVERY.EXECUTABLE_NAME,
|
|
23117
|
+
bundledExecutable: TYPESCRIPT_TOOL_DISCOVERY.BUNDLED_EXECUTABLE,
|
|
23118
|
+
priority: TOOL_DISCOVERY_PRIORITY.PRODUCT_FIRST
|
|
23119
|
+
});
|
|
22818
23120
|
if (!toolResult.found) {
|
|
22819
23121
|
const skipMessage = formatSkipMessage(VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT, toolResult);
|
|
22820
23122
|
return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };
|
|
22821
23123
|
}
|
|
22822
|
-
const result = await validateTypeScript({
|
|
23124
|
+
const result = await deps.validateTypeScript({
|
|
22823
23125
|
scope: scope2,
|
|
22824
|
-
|
|
23126
|
+
productDir: cwd,
|
|
22825
23127
|
scopeConfig
|
|
22826
23128
|
}, {
|
|
22827
|
-
|
|
23129
|
+
toolPath: toolResult.location.path,
|
|
23130
|
+
outputStreams: outputStreams ?? discardValidationSubprocessOutputStreams
|
|
22828
23131
|
});
|
|
22829
23132
|
const durationMs = Date.now() - startTime;
|
|
22830
|
-
return formatTypeScriptResult(result, quiet, durationMs);
|
|
23133
|
+
return formatTypeScriptResult(result, quiet, durationMs, json, streamedPipelineOutput);
|
|
22831
23134
|
}
|
|
22832
|
-
function formatTypeScriptResult(result, quiet, durationMs) {
|
|
23135
|
+
function formatTypeScriptResult(result, quiet, durationMs, json, streamedPipelineOutput) {
|
|
22833
23136
|
if (result.skipped) {
|
|
22834
23137
|
const output2 = quiet ? "" : TYPESCRIPT_VALIDATION_MESSAGES.NO_VALIDATION_PATH_TARGETS;
|
|
22835
23138
|
return { exitCode: 0, output: output2, durationMs };
|
|
22836
23139
|
}
|
|
22837
23140
|
if (result.success) {
|
|
22838
|
-
const output2 = quiet ? "" : TYPESCRIPT_VALIDATION_MESSAGES.SUCCESS;
|
|
22839
|
-
|
|
23141
|
+
const output2 = quiet ? "" : [TYPESCRIPT_VALIDATION_MESSAGES.SUCCESS, result.output].filter((line) => line !== void 0 && line.length > 0).join("\n");
|
|
23142
|
+
const terminalOutput2 = streamedValidationTerminalOutput(result.output, json, streamedPipelineOutput);
|
|
23143
|
+
return { exitCode: 0, output: output2, terminalOutput: terminalOutput2, durationMs };
|
|
22840
23144
|
}
|
|
22841
|
-
const output = result.error ?? VALIDATION_COMMAND_OUTPUT.TYPESCRIPT_FAILURE;
|
|
22842
|
-
|
|
23145
|
+
const output = [result.output, result.error ?? VALIDATION_COMMAND_OUTPUT.TYPESCRIPT_FAILURE].filter((line) => line !== void 0 && line.length > 0).join("\n");
|
|
23146
|
+
const terminalOutput = streamedValidationTerminalOutput(result.output, json, streamedPipelineOutput);
|
|
23147
|
+
return { exitCode: 1, output, terminalOutput, durationMs };
|
|
22843
23148
|
}
|
|
22844
23149
|
|
|
22845
23150
|
// src/validation/languages/typescript.ts
|
|
22846
23151
|
var TYPESCRIPT_LANGUAGE_NAME = "typescript";
|
|
23152
|
+
var SKIP_CIRCULAR_REASON = "skip-circular";
|
|
23153
|
+
var SKIP_KNIP_REASON = "skip-knip";
|
|
23154
|
+
var SKIP_LINT_REASON = "skip-lint";
|
|
23155
|
+
var SKIP_TYPESCRIPT_REASON = "skip-typescript";
|
|
23156
|
+
var SKIP_LITERAL_REASON = "skip-literal";
|
|
22847
23157
|
var TYPESCRIPT_VALIDATION_CONCERN = {
|
|
22848
23158
|
LINT: "lint",
|
|
22849
23159
|
TYPE_CHECK: "type-check",
|
|
@@ -22852,14 +23162,60 @@ var TYPESCRIPT_VALIDATION_CONCERN = {
|
|
|
22852
23162
|
LITERAL_REUSE: "literal-reuse",
|
|
22853
23163
|
UNUSED_CODE: "unused-code"
|
|
22854
23164
|
};
|
|
23165
|
+
var TYPESCRIPT_VALIDATION_STAGE_BY_CONCERN = {
|
|
23166
|
+
[TYPESCRIPT_VALIDATION_CONCERN.LINT]: VALIDATION_STAGE_DISPLAY_NAMES.ESLINT,
|
|
23167
|
+
[TYPESCRIPT_VALIDATION_CONCERN.TYPE_CHECK]: VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT,
|
|
23168
|
+
[TYPESCRIPT_VALIDATION_CONCERN.AST_ENFORCEMENT]: VALIDATION_STAGE_DISPLAY_NAMES.ESLINT,
|
|
23169
|
+
[TYPESCRIPT_VALIDATION_CONCERN.CIRCULAR_DEPS]: VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR,
|
|
23170
|
+
[TYPESCRIPT_VALIDATION_CONCERN.LITERAL_REUSE]: VALIDATION_STAGE_DISPLAY_NAMES.LITERAL,
|
|
23171
|
+
[TYPESCRIPT_VALIDATION_CONCERN.UNUSED_CODE]: VALIDATION_STAGE_DISPLAY_NAMES.KNIP
|
|
23172
|
+
};
|
|
23173
|
+
var TYPESCRIPT_VALIDATION_STAGE_PARTICIPATION = {
|
|
23174
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR]: {
|
|
23175
|
+
default: VALIDATION_STAGE_PARTICIPATION.RUN,
|
|
23176
|
+
skipReason: SKIP_CIRCULAR_REASON,
|
|
23177
|
+
override: {
|
|
23178
|
+
flag: "--skip-circular",
|
|
23179
|
+
description: "Skip circular dependency detection for this validation all run"
|
|
23180
|
+
}
|
|
23181
|
+
},
|
|
23182
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.KNIP]: {
|
|
23183
|
+
default: VALIDATION_STAGE_PARTICIPATION.RUN,
|
|
23184
|
+
skipReason: SKIP_KNIP_REASON,
|
|
23185
|
+
override: {
|
|
23186
|
+
flag: "--skip-knip",
|
|
23187
|
+
description: "Skip unused-code detection for this validation all run"
|
|
23188
|
+
}
|
|
23189
|
+
},
|
|
23190
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.ESLINT]: {
|
|
23191
|
+
default: VALIDATION_STAGE_PARTICIPATION.RUN,
|
|
23192
|
+
skipReason: SKIP_LINT_REASON,
|
|
23193
|
+
override: {
|
|
23194
|
+
flag: "--skip-lint",
|
|
23195
|
+
description: "Skip ESLint validation for this validation all run"
|
|
23196
|
+
}
|
|
23197
|
+
},
|
|
23198
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT]: {
|
|
23199
|
+
default: VALIDATION_STAGE_PARTICIPATION.RUN,
|
|
23200
|
+
skipReason: SKIP_TYPESCRIPT_REASON,
|
|
23201
|
+
override: {
|
|
23202
|
+
flag: "--skip-typescript",
|
|
23203
|
+
description: "Skip TypeScript validation for this validation all run"
|
|
23204
|
+
}
|
|
23205
|
+
},
|
|
23206
|
+
[VALIDATION_STAGE_DISPLAY_NAMES.LITERAL]: {
|
|
23207
|
+
default: VALIDATION_STAGE_PARTICIPATION.RUN,
|
|
23208
|
+
skipReason: SKIP_LITERAL_REASON,
|
|
23209
|
+
override: {
|
|
23210
|
+
flag: "--skip-literal",
|
|
23211
|
+
description: "Skip literal reuse detection for this validation all run"
|
|
23212
|
+
}
|
|
23213
|
+
}
|
|
23214
|
+
};
|
|
22855
23215
|
var defaultKnipStageDeps = {
|
|
22856
23216
|
knipCommand
|
|
22857
23217
|
};
|
|
22858
23218
|
async function runCircularStage(context) {
|
|
22859
|
-
if (context.skipCircular) {
|
|
22860
|
-
const skipOutput = context.json ? CIRCULAR_SKIP_JSON_OUTPUT : CIRCULAR_SKIP_OUTPUT;
|
|
22861
|
-
return { exitCode: 0, output: context.quiet ? "" : skipOutput };
|
|
22862
|
-
}
|
|
22863
23219
|
return circularCommand({
|
|
22864
23220
|
cwd: context.cwd,
|
|
22865
23221
|
scope: context.scope,
|
|
@@ -22869,10 +23225,6 @@ async function runCircularStage(context) {
|
|
|
22869
23225
|
});
|
|
22870
23226
|
}
|
|
22871
23227
|
async function runLiteralStage(context) {
|
|
22872
|
-
if (context.skipLiteral) {
|
|
22873
|
-
const skipOutput = context.json ? LITERAL_SKIP_JSON_OUTPUT : LITERAL_SKIP_OUTPUT;
|
|
22874
|
-
return { exitCode: 0, output: context.quiet ? "" : skipOutput };
|
|
22875
|
-
}
|
|
22876
23228
|
return literalCommand({
|
|
22877
23229
|
cwd: context.cwd,
|
|
22878
23230
|
scope: context.scope,
|
|
@@ -22887,27 +23239,32 @@ async function runKnipStage(context, deps = defaultKnipStageDeps) {
|
|
|
22887
23239
|
scope: context.scope,
|
|
22888
23240
|
files: context.files,
|
|
22889
23241
|
quiet: context.quiet,
|
|
22890
|
-
json: context.json
|
|
23242
|
+
json: context.json,
|
|
23243
|
+
streamedPipelineOutput: true,
|
|
23244
|
+
outputStreams: context.outputStreams
|
|
22891
23245
|
});
|
|
22892
23246
|
}
|
|
22893
23247
|
var typescriptValidationLanguage = {
|
|
22894
23248
|
name: TYPESCRIPT_LANGUAGE_NAME,
|
|
22895
23249
|
concerns: Object.values(TYPESCRIPT_VALIDATION_CONCERN),
|
|
23250
|
+
stageByConcern: TYPESCRIPT_VALIDATION_STAGE_BY_CONCERN,
|
|
22896
23251
|
stages: [
|
|
22897
23252
|
{
|
|
22898
23253
|
name: VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR,
|
|
22899
23254
|
failsPipeline: true,
|
|
23255
|
+
participation: TYPESCRIPT_VALIDATION_STAGE_PARTICIPATION[VALIDATION_STAGE_DISPLAY_NAMES.CIRCULAR],
|
|
22900
23256
|
run: runCircularStage
|
|
22901
23257
|
},
|
|
22902
23258
|
{
|
|
22903
23259
|
name: VALIDATION_STAGE_DISPLAY_NAMES.KNIP,
|
|
22904
|
-
|
|
22905
|
-
|
|
23260
|
+
failsPipeline: true,
|
|
23261
|
+
participation: TYPESCRIPT_VALIDATION_STAGE_PARTICIPATION[VALIDATION_STAGE_DISPLAY_NAMES.KNIP],
|
|
22906
23262
|
run: runKnipStage
|
|
22907
23263
|
},
|
|
22908
23264
|
{
|
|
22909
23265
|
name: VALIDATION_STAGE_DISPLAY_NAMES.ESLINT,
|
|
22910
23266
|
failsPipeline: true,
|
|
23267
|
+
participation: TYPESCRIPT_VALIDATION_STAGE_PARTICIPATION[VALIDATION_STAGE_DISPLAY_NAMES.ESLINT],
|
|
22911
23268
|
run: (context) => lintCommand({
|
|
22912
23269
|
cwd: context.cwd,
|
|
22913
23270
|
scope: context.scope,
|
|
@@ -22915,32 +23272,46 @@ var typescriptValidationLanguage = {
|
|
|
22915
23272
|
fix: context.fix,
|
|
22916
23273
|
quiet: context.quiet,
|
|
22917
23274
|
json: context.json,
|
|
23275
|
+
streamedPipelineOutput: true,
|
|
22918
23276
|
outputStreams: context.outputStreams
|
|
22919
23277
|
})
|
|
22920
23278
|
},
|
|
22921
23279
|
{
|
|
22922
23280
|
name: VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT,
|
|
22923
23281
|
failsPipeline: true,
|
|
23282
|
+
participation: TYPESCRIPT_VALIDATION_STAGE_PARTICIPATION[VALIDATION_STAGE_DISPLAY_NAMES.TYPESCRIPT],
|
|
22924
23283
|
run: (context) => typescriptCommand({
|
|
22925
23284
|
cwd: context.cwd,
|
|
22926
23285
|
scope: context.scope,
|
|
22927
23286
|
files: context.files,
|
|
22928
23287
|
quiet: context.quiet,
|
|
22929
23288
|
json: context.json,
|
|
23289
|
+
streamedPipelineOutput: true,
|
|
22930
23290
|
outputStreams: context.outputStreams
|
|
22931
23291
|
})
|
|
22932
23292
|
},
|
|
22933
23293
|
{
|
|
22934
23294
|
name: VALIDATION_STAGE_DISPLAY_NAMES.LITERAL,
|
|
22935
23295
|
failsPipeline: true,
|
|
23296
|
+
participation: TYPESCRIPT_VALIDATION_STAGE_PARTICIPATION[VALIDATION_STAGE_DISPLAY_NAMES.LITERAL],
|
|
22936
23297
|
run: runLiteralStage
|
|
22937
23298
|
}
|
|
22938
23299
|
]
|
|
22939
23300
|
};
|
|
22940
23301
|
|
|
22941
23302
|
// src/validation/registry.ts
|
|
23303
|
+
var VALIDATION_STAGE_PARTICIPATION_POLICIES = {
|
|
23304
|
+
...TYPESCRIPT_VALIDATION_STAGE_PARTICIPATION,
|
|
23305
|
+
...MARKDOWN_VALIDATION_STAGE_PARTICIPATION,
|
|
23306
|
+
...FORMATTING_VALIDATION_STAGE_PARTICIPATION
|
|
23307
|
+
};
|
|
23308
|
+
var VALIDATION_REGISTRY_LANGUAGES = [
|
|
23309
|
+
typescriptValidationLanguage,
|
|
23310
|
+
markdownValidationLanguage,
|
|
23311
|
+
formattingValidationLanguage
|
|
23312
|
+
];
|
|
22942
23313
|
var validationRegistry = {
|
|
22943
|
-
languages:
|
|
23314
|
+
languages: VALIDATION_REGISTRY_LANGUAGES
|
|
22944
23315
|
};
|
|
22945
23316
|
function composeValidationPipelineStages(languages) {
|
|
22946
23317
|
return languages.flatMap((language) => language.stages);
|
|
@@ -22974,10 +23345,17 @@ function formatSummary(options) {
|
|
|
22974
23345
|
}
|
|
22975
23346
|
|
|
22976
23347
|
// src/commands/validation/all.ts
|
|
22977
|
-
function formatStepWithTiming(stepNumber, totalSteps, result, quiet) {
|
|
22978
|
-
|
|
23348
|
+
function formatStepWithTiming(stepNumber, totalSteps, stageName, result, quiet) {
|
|
23349
|
+
const output = result.terminalOutput ?? result.output;
|
|
23350
|
+
if (quiet) return "";
|
|
23351
|
+
if (result.terminalOutput === VALIDATION_STREAMED_TERMINAL_OUTPUT) {
|
|
23352
|
+
const verdict = result.exitCode === 0 ? VALIDATION_SYMBOLS.SUCCESS : VALIDATION_SYMBOLS.FAILURE;
|
|
23353
|
+
const timing2 = result.durationMs === void 0 ? "" : ` (${formatDuration(result.durationMs)})`;
|
|
23354
|
+
return `[${stepNumber}/${totalSteps}] ${stageName}: ${verdict} ${VALIDATION_STREAMED_STAGE_RESULT}${timing2}`;
|
|
23355
|
+
}
|
|
23356
|
+
if (!output) return "";
|
|
22979
23357
|
const timing = result.durationMs === void 0 ? "" : ` (${formatDuration(result.durationMs)})`;
|
|
22980
|
-
return `[${stepNumber}/${totalSteps}] ${
|
|
23358
|
+
return `[${stepNumber}/${totalSteps}] ${output}${timing}`;
|
|
22981
23359
|
}
|
|
22982
23360
|
function parseStageOutput(output) {
|
|
22983
23361
|
if (output.length === 0) return null;
|
|
@@ -23011,12 +23389,39 @@ function recordStageResult(options) {
|
|
|
23011
23389
|
});
|
|
23012
23390
|
return;
|
|
23013
23391
|
}
|
|
23014
|
-
const stepOutput = formatStepWithTiming(stepNumber, totalSteps, result, quiet);
|
|
23392
|
+
const stepOutput = formatStepWithTiming(stepNumber, totalSteps, stage.name, result, quiet);
|
|
23015
23393
|
if (stepOutput) {
|
|
23016
23394
|
outputs.push(stepOutput);
|
|
23017
23395
|
writeOutput5?.(stepOutput);
|
|
23018
23396
|
}
|
|
23019
23397
|
}
|
|
23398
|
+
function resolveStageParticipation(stage, participationOverrides) {
|
|
23399
|
+
const override = stage.participation.override;
|
|
23400
|
+
if (participationOverrides.has(override.flag)) {
|
|
23401
|
+
const participation = stage.participation.default === VALIDATION_STAGE_PARTICIPATION.RUN ? VALIDATION_STAGE_PARTICIPATION.SKIP : VALIDATION_STAGE_PARTICIPATION.RUN;
|
|
23402
|
+
return {
|
|
23403
|
+
participation,
|
|
23404
|
+
reason: participation === VALIDATION_STAGE_PARTICIPATION.SKIP ? stage.participation.skipReason : void 0,
|
|
23405
|
+
flag: override.flag
|
|
23406
|
+
};
|
|
23407
|
+
}
|
|
23408
|
+
return {
|
|
23409
|
+
participation: stage.participation.default,
|
|
23410
|
+
reason: stage.participation.default === VALIDATION_STAGE_PARTICIPATION.SKIP ? stage.participation.skipReason : void 0
|
|
23411
|
+
};
|
|
23412
|
+
}
|
|
23413
|
+
function skippedStageResult(stage, participation, json, durationMs) {
|
|
23414
|
+
const reason = participation.reason;
|
|
23415
|
+
if (reason === void 0) {
|
|
23416
|
+
throw new Error(`validation stage ${stage.name} skipped without a configured reason`);
|
|
23417
|
+
}
|
|
23418
|
+
return {
|
|
23419
|
+
exitCode: 0,
|
|
23420
|
+
output: json ? formatValidationStageSkipJsonOutput(reason, durationMs) : formatValidationStageSkipOutput(stage.name, participation.flag ?? reason),
|
|
23421
|
+
structuredOutput: json,
|
|
23422
|
+
durationMs
|
|
23423
|
+
};
|
|
23424
|
+
}
|
|
23020
23425
|
function createCapturedSubprocessOutput() {
|
|
23021
23426
|
const stdout = [];
|
|
23022
23427
|
const stderr = [];
|
|
@@ -23037,14 +23442,72 @@ function createCaptureStream(chunks) {
|
|
|
23037
23442
|
}
|
|
23038
23443
|
};
|
|
23039
23444
|
}
|
|
23445
|
+
function resolveFullPipelineStages(validationStages, dependencyStages) {
|
|
23446
|
+
return validationStages ?? dependencyStages ?? validationPipelineStages;
|
|
23447
|
+
}
|
|
23448
|
+
async function executeValidationStages(options) {
|
|
23449
|
+
let hasFailure = false;
|
|
23450
|
+
for (const [index, stage] of options.stages.entries()) {
|
|
23451
|
+
const stepNumber = index + 1;
|
|
23452
|
+
const execution = await executeValidationStage(stage, options);
|
|
23453
|
+
recordStageResult({
|
|
23454
|
+
json: options.json,
|
|
23455
|
+
stepNumber,
|
|
23456
|
+
totalSteps: options.stages.length,
|
|
23457
|
+
stage,
|
|
23458
|
+
result: execution.result,
|
|
23459
|
+
quiet: options.quiet,
|
|
23460
|
+
outputs: options.outputs,
|
|
23461
|
+
jsonSteps: options.jsonSteps,
|
|
23462
|
+
subprocessOutput: execution.subprocessOutput,
|
|
23463
|
+
writeOutput: options.writeOutput
|
|
23464
|
+
});
|
|
23465
|
+
notifyStageCompletion(stage, execution.result, stepNumber, options);
|
|
23466
|
+
hasFailure ||= stage.failsPipeline && execution.result.exitCode !== 0;
|
|
23467
|
+
}
|
|
23468
|
+
return hasFailure;
|
|
23469
|
+
}
|
|
23470
|
+
async function executeValidationStage(stage, options) {
|
|
23471
|
+
const subprocessOutput = options.json ? createCapturedSubprocessOutput() : void 0;
|
|
23472
|
+
const stageStartTime = options.now();
|
|
23473
|
+
const participation = resolveStageParticipation(stage, options.participationOverrides);
|
|
23474
|
+
const stageResult = participation.participation === VALIDATION_STAGE_PARTICIPATION.RUN ? await stage.run({
|
|
23475
|
+
...options.context,
|
|
23476
|
+
outputStreams: subprocessOutput?.streams ?? options.outputStreams
|
|
23477
|
+
}) : skippedStageResult(stage, participation, options.json, options.now() - stageStartTime);
|
|
23478
|
+
const result = stageResult.durationMs === void 0 ? { ...stageResult, durationMs: options.now() - stageStartTime } : stageResult;
|
|
23479
|
+
return { result, subprocessOutput };
|
|
23480
|
+
}
|
|
23481
|
+
function notifyStageCompletion(stage, result, stepNumber, options) {
|
|
23482
|
+
if (options.json || options.onStageComplete === void 0) return;
|
|
23483
|
+
const output = formatStepWithTiming(stepNumber, options.stages.length, stage.name, result, options.quiet);
|
|
23484
|
+
if (output.length === 0) return;
|
|
23485
|
+
options.onStageComplete({
|
|
23486
|
+
stepNumber,
|
|
23487
|
+
totalSteps: options.stages.length,
|
|
23488
|
+
stageName: stage.name,
|
|
23489
|
+
result,
|
|
23490
|
+
output
|
|
23491
|
+
});
|
|
23492
|
+
}
|
|
23040
23493
|
async function allCommand(options, deps = {}) {
|
|
23041
|
-
const {
|
|
23042
|
-
|
|
23494
|
+
const {
|
|
23495
|
+
cwd,
|
|
23496
|
+
scope: scope2,
|
|
23497
|
+
files,
|
|
23498
|
+
fix,
|
|
23499
|
+
quiet = false,
|
|
23500
|
+
json,
|
|
23501
|
+
validationStages,
|
|
23502
|
+
participationOverrides = [],
|
|
23503
|
+
onStageComplete,
|
|
23504
|
+
outputStreams
|
|
23505
|
+
} = options;
|
|
23506
|
+
const stages = resolveFullPipelineStages(validationStages, deps.stages);
|
|
23043
23507
|
const now = deps.now ?? Date.now;
|
|
23044
23508
|
const startTime = now();
|
|
23045
23509
|
const outputs = [];
|
|
23046
23510
|
const jsonSteps = [];
|
|
23047
|
-
let hasFailure = false;
|
|
23048
23511
|
const context = {
|
|
23049
23512
|
cwd,
|
|
23050
23513
|
scope: scope2,
|
|
@@ -23052,28 +23515,21 @@ async function allCommand(options, deps = {}) {
|
|
|
23052
23515
|
fix,
|
|
23053
23516
|
quiet: json === true ? false : quiet,
|
|
23054
23517
|
json,
|
|
23055
|
-
|
|
23056
|
-
skipLiteral
|
|
23518
|
+
outputStreams
|
|
23057
23519
|
};
|
|
23058
|
-
|
|
23059
|
-
|
|
23060
|
-
|
|
23061
|
-
|
|
23062
|
-
|
|
23063
|
-
|
|
23064
|
-
|
|
23065
|
-
|
|
23066
|
-
|
|
23067
|
-
|
|
23068
|
-
|
|
23069
|
-
|
|
23070
|
-
|
|
23071
|
-
jsonSteps,
|
|
23072
|
-
subprocessOutput,
|
|
23073
|
-
writeOutput: deps.writeOutput
|
|
23074
|
-
});
|
|
23075
|
-
if (stage.failsPipeline && result.exitCode !== 0) hasFailure = true;
|
|
23076
|
-
}
|
|
23520
|
+
const hasFailure = await executeValidationStages({
|
|
23521
|
+
stages,
|
|
23522
|
+
context,
|
|
23523
|
+
participationOverrides: new Set(participationOverrides),
|
|
23524
|
+
json: json === true,
|
|
23525
|
+
quiet,
|
|
23526
|
+
outputs,
|
|
23527
|
+
jsonSteps,
|
|
23528
|
+
onStageComplete,
|
|
23529
|
+
outputStreams,
|
|
23530
|
+
writeOutput: deps.writeOutput,
|
|
23531
|
+
now
|
|
23532
|
+
});
|
|
23077
23533
|
const totalDurationMs = now() - startTime;
|
|
23078
23534
|
if (json === true) {
|
|
23079
23535
|
const jsonOutput = {
|
|
@@ -23086,18 +23542,26 @@ async function allCommand(options, deps = {}) {
|
|
|
23086
23542
|
return {
|
|
23087
23543
|
exitCode: hasFailure ? 1 : 0,
|
|
23088
23544
|
output,
|
|
23545
|
+
outputTarget: VALIDATION_OUTPUT_TARGET.STDOUT,
|
|
23089
23546
|
durationMs: totalDurationMs
|
|
23090
23547
|
};
|
|
23091
23548
|
}
|
|
23549
|
+
let terminalOutput;
|
|
23092
23550
|
if (!quiet) {
|
|
23093
23551
|
const summary = formatSummary({ success: !hasFailure, totalDurationMs });
|
|
23094
|
-
outputs.push("", summary);
|
|
23095
23552
|
deps.writeOutput?.(`
|
|
23096
23553
|
${summary}`);
|
|
23554
|
+
if (onStageComplete !== void 0) {
|
|
23555
|
+
terminalOutput = `
|
|
23556
|
+
${summary}`;
|
|
23557
|
+
} else {
|
|
23558
|
+
outputs.push("", summary);
|
|
23559
|
+
}
|
|
23097
23560
|
}
|
|
23098
23561
|
return {
|
|
23099
23562
|
exitCode: hasFailure ? 1 : 0,
|
|
23100
23563
|
output: outputs.join("\n"),
|
|
23564
|
+
terminalOutput,
|
|
23101
23565
|
durationMs: totalDurationMs
|
|
23102
23566
|
};
|
|
23103
23567
|
}
|
|
@@ -23117,36 +23581,44 @@ var validationCliDefinition = {
|
|
|
23117
23581
|
typescript: {
|
|
23118
23582
|
commandName: "typescript",
|
|
23119
23583
|
alias: "ts",
|
|
23120
|
-
description: "Run TypeScript type checking"
|
|
23584
|
+
description: "Run TypeScript type checking",
|
|
23585
|
+
options: { scope: true, json: false }
|
|
23121
23586
|
},
|
|
23122
23587
|
lint: {
|
|
23123
23588
|
commandName: "lint",
|
|
23124
|
-
description: "Run ESLint"
|
|
23589
|
+
description: "Run ESLint",
|
|
23590
|
+
options: { scope: true, json: false }
|
|
23125
23591
|
},
|
|
23126
23592
|
circular: {
|
|
23127
23593
|
commandName: "circular",
|
|
23128
|
-
description: "Check for circular dependencies"
|
|
23594
|
+
description: "Check for circular dependencies",
|
|
23595
|
+
options: { scope: true, json: false }
|
|
23129
23596
|
},
|
|
23130
23597
|
knip: {
|
|
23131
23598
|
commandName: "knip",
|
|
23132
|
-
description: "Detect unused code"
|
|
23599
|
+
description: "Detect unused code",
|
|
23600
|
+
options: { scope: true, json: false }
|
|
23133
23601
|
},
|
|
23134
23602
|
literal: {
|
|
23135
23603
|
commandName: "literal",
|
|
23136
|
-
description: "Detect cross-file literal reuse between source and tests"
|
|
23604
|
+
description: "Detect cross-file literal reuse between source and tests",
|
|
23605
|
+
options: { scope: true, json: true }
|
|
23137
23606
|
},
|
|
23138
23607
|
markdown: {
|
|
23139
23608
|
commandName: "markdown",
|
|
23140
23609
|
alias: "md",
|
|
23141
|
-
description: "Validate markdown link integrity and structure"
|
|
23610
|
+
description: "Validate markdown link integrity and structure",
|
|
23611
|
+
options: { scope: false, json: false }
|
|
23142
23612
|
},
|
|
23143
23613
|
format: {
|
|
23144
23614
|
commandName: "format",
|
|
23145
|
-
description: "Check code formatting with dprint"
|
|
23615
|
+
description: "Check code formatting with dprint",
|
|
23616
|
+
options: { scope: false, json: false }
|
|
23146
23617
|
},
|
|
23147
23618
|
all: {
|
|
23148
23619
|
commandName: "all",
|
|
23149
|
-
description: "Run all validations"
|
|
23620
|
+
description: "Run all validations",
|
|
23621
|
+
options: { scope: true, json: true }
|
|
23150
23622
|
}
|
|
23151
23623
|
},
|
|
23152
23624
|
commanderHelpOperands: {
|
|
@@ -23196,16 +23668,25 @@ var literalValidationCliOptions = {
|
|
|
23196
23668
|
description: "Print grouped problem details"
|
|
23197
23669
|
}
|
|
23198
23670
|
};
|
|
23199
|
-
var
|
|
23200
|
-
|
|
23201
|
-
flag: "--
|
|
23202
|
-
description: "Skip circular dependency detection for this validation all run"
|
|
23671
|
+
var validationCommonCliOptions = {
|
|
23672
|
+
scope: {
|
|
23673
|
+
flag: "--scope"
|
|
23203
23674
|
},
|
|
23204
|
-
|
|
23205
|
-
flag: "--
|
|
23206
|
-
|
|
23675
|
+
quiet: {
|
|
23676
|
+
flag: "--quiet"
|
|
23677
|
+
},
|
|
23678
|
+
json: {
|
|
23679
|
+
flag: "--json"
|
|
23680
|
+
}
|
|
23681
|
+
};
|
|
23682
|
+
var validationAllBuiltInCliOptions = {
|
|
23683
|
+
fix: {
|
|
23684
|
+
flag: "--fix"
|
|
23207
23685
|
}
|
|
23208
23686
|
};
|
|
23687
|
+
function isValidationLiteralProblemKind(value) {
|
|
23688
|
+
return validationLiteralProblemKinds.some((kind) => kind === value);
|
|
23689
|
+
}
|
|
23209
23690
|
var validationSubcommandOperands = Object.values(validationCliDefinition.subcommands).flatMap(
|
|
23210
23691
|
(subcommand) => {
|
|
23211
23692
|
const operands = [subcommand.commandName];
|
|
@@ -23218,6 +23699,7 @@ var validationKnownOperands = /* @__PURE__ */ new Set([
|
|
|
23218
23699
|
...Object.values(validationCliDefinition.commanderHelpOperands)
|
|
23219
23700
|
]);
|
|
23220
23701
|
var validationOptionPrefix = validationCliDefinition.commanderHelpOperands.longFlag.slice(0, 2);
|
|
23702
|
+
var validationShortOptionPrefix = validationCliDefinition.commanderHelpOperands.shortFlag.slice(0, 1);
|
|
23221
23703
|
|
|
23222
23704
|
// src/validation/literal/allowlist-existing.ts
|
|
23223
23705
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
@@ -23304,27 +23786,86 @@ function serializeWithUpdatedInclude(target, include) {
|
|
|
23304
23786
|
}
|
|
23305
23787
|
|
|
23306
23788
|
// src/interfaces/cli/validation.ts
|
|
23307
|
-
var
|
|
23308
|
-
|
|
23309
|
-
|
|
23310
|
-
|
|
23311
|
-
|
|
23312
|
-
|
|
23313
|
-
|
|
23314
|
-
|
|
23315
|
-
|
|
23316
|
-
|
|
23789
|
+
var LONG_OPTION_PREFIX = "--";
|
|
23790
|
+
var OPTION_PROPERTY_WORD_SEPARATOR_PATTERN = /-([a-z0-9])/g;
|
|
23791
|
+
var VALIDATION_ALL_OVERRIDE_FLAG_PATTERN = /^--(?!no-)[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
|
|
23792
|
+
var validationAllReservedOverrideFlags = /* @__PURE__ */ new Set([
|
|
23793
|
+
...Object.values(validationCommonCliOptions).map((option) => option.flag),
|
|
23794
|
+
...Object.values(validationAllBuiltInCliOptions).map((option) => option.flag),
|
|
23795
|
+
validationCliDefinition.commanderHelpOperands.longFlag
|
|
23796
|
+
]);
|
|
23797
|
+
function validationOptionPropertyName(flag) {
|
|
23798
|
+
return flag.slice(LONG_OPTION_PREFIX.length).replace(OPTION_PROPERTY_WORD_SEPARATOR_PATTERN, (_match, character) => character.toUpperCase());
|
|
23799
|
+
}
|
|
23800
|
+
function deriveValidationAllOverrideCliOptions(stages) {
|
|
23801
|
+
const optionPropertyNames = /* @__PURE__ */ new Set();
|
|
23802
|
+
return stages.flatMap((stage) => {
|
|
23803
|
+
validateStageParticipationMetadata(stage);
|
|
23804
|
+
const override = stage.participation.override;
|
|
23805
|
+
const optionPropertyName = validationOptionPropertyName(override.flag);
|
|
23806
|
+
if (optionPropertyNames.has(optionPropertyName)) {
|
|
23807
|
+
throw new Error(`duplicate validation all override option property: ${optionPropertyName}`);
|
|
23808
|
+
}
|
|
23809
|
+
optionPropertyNames.add(optionPropertyName);
|
|
23810
|
+
return [{
|
|
23811
|
+
stageName: stage.name,
|
|
23812
|
+
flag: override.flag,
|
|
23813
|
+
description: override.description,
|
|
23814
|
+
reason: stage.participation.skipReason,
|
|
23815
|
+
optionPropertyName
|
|
23816
|
+
}];
|
|
23817
|
+
});
|
|
23818
|
+
}
|
|
23819
|
+
function validateStageParticipationMetadata(stage) {
|
|
23820
|
+
if (stage.participation.skipReason.length === 0) {
|
|
23821
|
+
throw new Error(`validation stage ${stage.name} skip participation requires a reason`);
|
|
23822
|
+
}
|
|
23823
|
+
const override = stage.participation.override;
|
|
23824
|
+
if (!VALIDATION_ALL_OVERRIDE_FLAG_PATTERN.test(override.flag)) {
|
|
23825
|
+
throw new Error(`validation stage ${stage.name} override flag must be a bare long kebab-case boolean flag`);
|
|
23826
|
+
}
|
|
23827
|
+
if (validationAllReservedOverrideFlags.has(override.flag)) {
|
|
23828
|
+
throw new Error(`validation stage ${stage.name} override flag collides with a validation all built-in option`);
|
|
23829
|
+
}
|
|
23830
|
+
if (override.description.length === 0) {
|
|
23831
|
+
throw new Error(`validation stage ${stage.name} override flag requires a description`);
|
|
23832
|
+
}
|
|
23833
|
+
}
|
|
23834
|
+
var validationAllOverrideCliOptions = deriveValidationAllOverrideCliOptions(validationPipelineStages);
|
|
23835
|
+
var defaultValidationCommandHandlers = {
|
|
23836
|
+
typescript: typescriptCommand,
|
|
23837
|
+
lint: lintCommand,
|
|
23838
|
+
circular: circularCommand,
|
|
23839
|
+
knip: knipCommand,
|
|
23840
|
+
literal: literalCommand,
|
|
23841
|
+
markdown: markdownCommand,
|
|
23842
|
+
format: formattingCommand,
|
|
23843
|
+
all: allCommand
|
|
23317
23844
|
};
|
|
23318
23845
|
function emitValidationResult(result, io) {
|
|
23319
|
-
|
|
23320
|
-
|
|
23846
|
+
const output = result.terminalOutput ?? result.output;
|
|
23847
|
+
if (output.length > 0) {
|
|
23848
|
+
const outputTarget = result.outputTarget ?? (result.exitCode === 0 ? VALIDATION_OUTPUT_TARGET.STDOUT : VALIDATION_OUTPUT_TARGET.STDERR);
|
|
23849
|
+
const writeOutput5 = outputTarget === VALIDATION_OUTPUT_TARGET.STDOUT ? io.writeStdout : io.writeStderr;
|
|
23850
|
+
writeOutput5(`${output}
|
|
23321
23851
|
`);
|
|
23322
23852
|
}
|
|
23323
23853
|
return io.exit(result.exitCode);
|
|
23324
23854
|
}
|
|
23325
|
-
function addCommonOptions(cmd) {
|
|
23855
|
+
function addCommonOptions(cmd, definition) {
|
|
23326
23856
|
const { pathOperands } = validationCliDefinition;
|
|
23327
|
-
|
|
23857
|
+
let configured = cmd.argument(pathOperands.optionalVariadic, pathOperands.description).option(validationCommonCliOptions.quiet.flag, "Suppress progress output");
|
|
23858
|
+
if (definition.options.scope) {
|
|
23859
|
+
configured = configured.option(
|
|
23860
|
+
`${validationCommonCliOptions.scope.flag} <scope>`,
|
|
23861
|
+
"Validation scope (full|production)",
|
|
23862
|
+
"full"
|
|
23863
|
+
);
|
|
23864
|
+
}
|
|
23865
|
+
if (definition.options.json) {
|
|
23866
|
+
configured = configured.option(validationCommonCliOptions.json.flag, "Output results as JSON");
|
|
23867
|
+
}
|
|
23868
|
+
return configured;
|
|
23328
23869
|
}
|
|
23329
23870
|
async function normalizeProductPathOperand(productDir, effectiveInvocationDir, operand) {
|
|
23330
23871
|
const resolvedProductDir = await canonicalPathThroughExistingAncestor(resolve16(productDir));
|
|
@@ -23384,57 +23925,65 @@ function addValidationSubcommand(validationCmd, definition) {
|
|
|
23384
23925
|
}
|
|
23385
23926
|
return subcommand;
|
|
23386
23927
|
}
|
|
23387
|
-
function
|
|
23928
|
+
function selectedValidationAllOverrides(options, allOverrideCliOptions = validationAllOverrideCliOptions) {
|
|
23929
|
+
return allOverrideCliOptions.filter((option) => options[option.optionPropertyName] === true).map((option) => option.flag);
|
|
23930
|
+
}
|
|
23931
|
+
function registerValidationCommands(validationCmd, invocation, options = {}) {
|
|
23388
23932
|
const { subcommands } = validationCliDefinition;
|
|
23389
|
-
const
|
|
23933
|
+
const commandHandlers = {
|
|
23934
|
+
...defaultValidationCommandHandlers,
|
|
23935
|
+
...options.commandHandlers
|
|
23936
|
+
};
|
|
23937
|
+
const runAllowlistExisting = options.allowlistExisting ?? allowlistExisting;
|
|
23938
|
+
const validationStages = options.validationStages ?? validationPipelineStages;
|
|
23939
|
+
const allOverrideCliOptions = deriveValidationAllOverrideCliOptions(
|
|
23940
|
+
validationStages
|
|
23941
|
+
);
|
|
23942
|
+
const tsCmd = addValidationSubcommand(validationCmd, subcommands.typescript).action(async (pathOperands, options2) => {
|
|
23390
23943
|
const paths = await resolveValidationPaths(invocation, pathOperands);
|
|
23391
|
-
const result = await
|
|
23944
|
+
const result = await commandHandlers.typescript({
|
|
23392
23945
|
cwd: paths.productDir,
|
|
23393
|
-
scope:
|
|
23946
|
+
scope: options2.scope,
|
|
23394
23947
|
files: paths.files,
|
|
23395
|
-
quiet:
|
|
23396
|
-
json: options.json
|
|
23948
|
+
quiet: options2.quiet
|
|
23397
23949
|
});
|
|
23398
23950
|
emitValidationResult(result, invocation.io);
|
|
23399
23951
|
});
|
|
23400
|
-
addCommonOptions(tsCmd);
|
|
23401
|
-
const lintCmd = addValidationSubcommand(validationCmd, subcommands.lint).option("--fix", "Auto-fix issues").action(async (pathOperands,
|
|
23952
|
+
addCommonOptions(tsCmd, subcommands.typescript);
|
|
23953
|
+
const lintCmd = addValidationSubcommand(validationCmd, subcommands.lint).option("--fix", "Auto-fix issues").action(async (pathOperands, options2) => {
|
|
23402
23954
|
const paths = await resolveValidationPaths(invocation, pathOperands);
|
|
23403
|
-
const result = await
|
|
23955
|
+
const result = await commandHandlers.lint({
|
|
23404
23956
|
cwd: paths.productDir,
|
|
23405
|
-
scope:
|
|
23957
|
+
scope: options2.scope,
|
|
23406
23958
|
files: paths.files,
|
|
23407
|
-
fix:
|
|
23408
|
-
quiet:
|
|
23409
|
-
json: options.json
|
|
23959
|
+
fix: options2.fix,
|
|
23960
|
+
quiet: options2.quiet
|
|
23410
23961
|
});
|
|
23411
23962
|
emitValidationResult(result, invocation.io);
|
|
23412
23963
|
});
|
|
23413
|
-
addCommonOptions(lintCmd);
|
|
23414
|
-
const circularCmd = addValidationSubcommand(validationCmd, subcommands.circular).action(async (pathOperands,
|
|
23964
|
+
addCommonOptions(lintCmd, subcommands.lint);
|
|
23965
|
+
const circularCmd = addValidationSubcommand(validationCmd, subcommands.circular).action(async (pathOperands, options2) => {
|
|
23415
23966
|
const paths = await resolveValidationPaths(invocation, pathOperands);
|
|
23416
|
-
const result = await
|
|
23967
|
+
const result = await commandHandlers.circular({
|
|
23417
23968
|
cwd: paths.productDir,
|
|
23418
|
-
scope:
|
|
23969
|
+
scope: options2.scope,
|
|
23419
23970
|
files: paths.files,
|
|
23420
|
-
quiet:
|
|
23421
|
-
json: options.json
|
|
23971
|
+
quiet: options2.quiet
|
|
23422
23972
|
});
|
|
23423
23973
|
emitValidationResult(result, invocation.io);
|
|
23424
23974
|
});
|
|
23425
|
-
addCommonOptions(circularCmd);
|
|
23426
|
-
const knipCmd = addValidationSubcommand(validationCmd, subcommands.knip).action(async (pathOperands,
|
|
23975
|
+
addCommonOptions(circularCmd, subcommands.circular);
|
|
23976
|
+
const knipCmd = addValidationSubcommand(validationCmd, subcommands.knip).action(async (pathOperands, options2) => {
|
|
23427
23977
|
const paths = await resolveValidationPaths(invocation, pathOperands);
|
|
23428
|
-
const result = await
|
|
23978
|
+
const result = await commandHandlers.knip({
|
|
23429
23979
|
cwd: paths.productDir,
|
|
23430
|
-
scope:
|
|
23980
|
+
scope: options2.scope,
|
|
23431
23981
|
files: paths.files,
|
|
23432
|
-
quiet:
|
|
23433
|
-
json: options.json
|
|
23982
|
+
quiet: options2.quiet
|
|
23434
23983
|
});
|
|
23435
23984
|
emitValidationResult(result, invocation.io);
|
|
23436
23985
|
});
|
|
23437
|
-
addCommonOptions(knipCmd);
|
|
23986
|
+
addCommonOptions(knipCmd, subcommands.knip);
|
|
23438
23987
|
const literalCmd = addValidationSubcommand(validationCmd, subcommands.literal).option(
|
|
23439
23988
|
literalValidationCliOptions.allowlistExisting.flag,
|
|
23440
23989
|
literalValidationCliOptions.allowlistExisting.description
|
|
@@ -23444,106 +23993,127 @@ function registerValidationCommands(validationCmd, invocation, deps) {
|
|
|
23444
23993
|
).option(literalValidationCliOptions.literals.flag, literalValidationCliOptions.literals.description).option(literalValidationCliOptions.verbose.flag, literalValidationCliOptions.verbose.description).addHelpText(
|
|
23445
23994
|
"after",
|
|
23446
23995
|
"\nEnabled for TypeScript projects by default. Set validation.literal.enabled=false\nin spx.config.* to skip during migration."
|
|
23447
|
-
).action(async (pathOperands,
|
|
23996
|
+
).action(async (pathOperands, options2) => {
|
|
23448
23997
|
const paths = await resolveValidationPaths(invocation, pathOperands);
|
|
23449
|
-
if (
|
|
23450
|
-
const result2 = await
|
|
23998
|
+
if (options2.allowlistExisting) {
|
|
23999
|
+
const result2 = await runAllowlistExisting({ productDir: paths.productDir });
|
|
23451
24000
|
emitValidationResult(result2, invocation.io);
|
|
23452
24001
|
}
|
|
23453
24002
|
let kind;
|
|
23454
|
-
if (
|
|
23455
|
-
kind = parseLiteralProblemKind(
|
|
24003
|
+
if (options2.kind !== void 0) {
|
|
24004
|
+
kind = parseLiteralProblemKind(options2.kind);
|
|
23456
24005
|
if (kind === void 0) {
|
|
23457
24006
|
const { unknownLiteralProblemKind } = validationCliDefinition.diagnostics;
|
|
23458
24007
|
invocation.io.writeStderr(
|
|
23459
|
-
`spx validation literal: ${unknownLiteralProblemKind.messageLabel}: ${sanitizeCliArgument(
|
|
24008
|
+
`spx validation literal: ${unknownLiteralProblemKind.messageLabel}: ${sanitizeCliArgument(options2.kind)}
|
|
23460
24009
|
`
|
|
23461
24010
|
);
|
|
23462
24011
|
invocation.io.exit(unknownLiteralProblemKind.exitCode);
|
|
23463
24012
|
}
|
|
23464
24013
|
}
|
|
23465
|
-
const result = await
|
|
24014
|
+
const result = await commandHandlers.literal({
|
|
23466
24015
|
cwd: paths.productDir,
|
|
23467
|
-
scope:
|
|
24016
|
+
scope: options2.scope,
|
|
23468
24017
|
files: paths.files,
|
|
23469
24018
|
kind,
|
|
23470
|
-
filesWithProblems:
|
|
23471
|
-
literals:
|
|
23472
|
-
verbose:
|
|
23473
|
-
quiet:
|
|
23474
|
-
json:
|
|
24019
|
+
filesWithProblems: options2.filesWithProblems,
|
|
24020
|
+
literals: options2.literals,
|
|
24021
|
+
verbose: options2.verbose,
|
|
24022
|
+
quiet: options2.quiet,
|
|
24023
|
+
json: options2.json
|
|
23475
24024
|
});
|
|
23476
24025
|
emitValidationResult(result, invocation.io);
|
|
23477
24026
|
});
|
|
23478
|
-
addCommonOptions(literalCmd);
|
|
24027
|
+
addCommonOptions(literalCmd, subcommands.literal);
|
|
23479
24028
|
const markdownCmd = addValidationSubcommand(validationCmd, subcommands.markdown).addHelpText(
|
|
23480
24029
|
"after",
|
|
23481
24030
|
"\nValidates spx/ and docs/ by default. For nodes listed in spx/EXCLUDE,\nonly direct markdown files in that node directory are skipped;\nchild-node markdown remains in scope."
|
|
23482
|
-
).action(async (pathOperands,
|
|
24031
|
+
).action(async (pathOperands, options2) => {
|
|
23483
24032
|
const paths = await resolveValidationPaths(invocation, pathOperands);
|
|
23484
|
-
const result = await
|
|
24033
|
+
const result = await commandHandlers.markdown({
|
|
23485
24034
|
cwd: paths.productDir,
|
|
23486
24035
|
files: paths.files,
|
|
23487
|
-
quiet:
|
|
24036
|
+
quiet: options2.quiet
|
|
23488
24037
|
});
|
|
23489
24038
|
emitValidationResult(result, invocation.io);
|
|
23490
24039
|
});
|
|
23491
|
-
addCommonOptions(markdownCmd);
|
|
23492
|
-
const formatCmd = addValidationSubcommand(validationCmd, subcommands.format).action(async (pathOperands,
|
|
24040
|
+
addCommonOptions(markdownCmd, subcommands.markdown);
|
|
24041
|
+
const formatCmd = addValidationSubcommand(validationCmd, subcommands.format).action(async (pathOperands, options2) => {
|
|
23493
24042
|
const paths = await resolveValidationPaths(invocation, pathOperands);
|
|
23494
|
-
const result = await
|
|
24043
|
+
const result = await commandHandlers.format({
|
|
23495
24044
|
cwd: paths.productDir,
|
|
23496
24045
|
files: paths.files,
|
|
23497
|
-
quiet:
|
|
24046
|
+
quiet: options2.quiet
|
|
23498
24047
|
});
|
|
23499
24048
|
emitValidationResult(result, invocation.io);
|
|
23500
24049
|
});
|
|
23501
|
-
addCommonOptions(formatCmd);
|
|
23502
|
-
|
|
24050
|
+
addCommonOptions(formatCmd, subcommands.format);
|
|
24051
|
+
let allCmd = addValidationSubcommand(validationCmd, subcommands.all).option(validationAllBuiltInCliOptions.fix.flag, "Auto-fix ESLint issues");
|
|
24052
|
+
for (const option of allOverrideCliOptions) {
|
|
24053
|
+
allCmd = allCmd.option(option.flag, option.description);
|
|
24054
|
+
}
|
|
24055
|
+
allCmd = allCmd.action(async (pathOperands, options2) => {
|
|
23503
24056
|
const paths = await resolveValidationPaths(invocation, pathOperands);
|
|
23504
|
-
const result = await
|
|
24057
|
+
const result = await commandHandlers.all({
|
|
23505
24058
|
cwd: paths.productDir,
|
|
23506
|
-
scope:
|
|
24059
|
+
scope: options2.scope,
|
|
23507
24060
|
files: paths.files,
|
|
23508
|
-
fix:
|
|
23509
|
-
|
|
23510
|
-
|
|
23511
|
-
quiet:
|
|
23512
|
-
json:
|
|
23513
|
-
|
|
23514
|
-
|
|
23515
|
-
|
|
24061
|
+
fix: options2.fix,
|
|
24062
|
+
validationStages,
|
|
24063
|
+
participationOverrides: selectedValidationAllOverrides(options2, allOverrideCliOptions),
|
|
24064
|
+
quiet: options2.quiet,
|
|
24065
|
+
json: options2.json,
|
|
24066
|
+
onStageComplete: ({ output }) => invocation.io.writeStdout(`${output}
|
|
24067
|
+
`),
|
|
24068
|
+
outputStreams: validationSubprocessOutputStreams(invocation.io, options2.json)
|
|
23516
24069
|
});
|
|
23517
|
-
|
|
24070
|
+
emitValidationResult(result, invocation.io);
|
|
23518
24071
|
});
|
|
23519
|
-
addCommonOptions(allCmd);
|
|
24072
|
+
addCommonOptions(allCmd, subcommands.all);
|
|
24073
|
+
}
|
|
24074
|
+
function validationSubprocessOutputStreams(io, json) {
|
|
24075
|
+
if (json === true) return discardValidationSubprocessOutputStreams;
|
|
24076
|
+
return {
|
|
24077
|
+
stdout: {
|
|
24078
|
+
write: (chunk) => {
|
|
24079
|
+
io.writeStdout(Buffer.from(chunk).toString());
|
|
24080
|
+
return true;
|
|
24081
|
+
}
|
|
24082
|
+
},
|
|
24083
|
+
stderr: {
|
|
24084
|
+
write: (chunk) => {
|
|
24085
|
+
io.writeStderr(Buffer.from(chunk).toString());
|
|
24086
|
+
return true;
|
|
24087
|
+
}
|
|
24088
|
+
}
|
|
24089
|
+
};
|
|
23520
24090
|
}
|
|
23521
24091
|
function parseLiteralProblemKind(value) {
|
|
23522
|
-
|
|
24092
|
+
if (isValidationLiteralProblemKind(value)) {
|
|
24093
|
+
return value;
|
|
24094
|
+
}
|
|
24095
|
+
return void 0;
|
|
23523
24096
|
}
|
|
23524
24097
|
function handleUnknownSubcommand(operands, io) {
|
|
23525
24098
|
const [first] = operands;
|
|
23526
24099
|
const sanitized = sanitizeCliArgument(first);
|
|
23527
24100
|
const { domain, diagnostics } = validationCliDefinition;
|
|
23528
24101
|
const { unknownSubcommand } = diagnostics;
|
|
23529
|
-
io.writeStderr(
|
|
23530
|
-
|
|
23531
|
-
`
|
|
23532
|
-
);
|
|
24102
|
+
io.writeStderr(`${SPX_PROGRAM_NAME} ${domain.commandName}: ${unknownSubcommand.messageLabel}: ${sanitized}
|
|
24103
|
+
`);
|
|
23533
24104
|
return io.exit(unknownSubcommand.exitCode);
|
|
23534
24105
|
}
|
|
23535
|
-
function createValidationDomain(
|
|
23536
|
-
const deps = { ...defaultValidationCliDependencies, ...overrides };
|
|
24106
|
+
function createValidationDomain(options = {}) {
|
|
23537
24107
|
return {
|
|
23538
24108
|
name: validationCliDefinition.domain.commandName,
|
|
23539
24109
|
description: validationCliDefinition.domain.description,
|
|
23540
24110
|
register: (program, invocation) => {
|
|
23541
24111
|
const { domain } = validationCliDefinition;
|
|
23542
|
-
const validationCmd = program.command(domain.commandName).alias(domain.alias).description(domain.description);
|
|
24112
|
+
const validationCmd = program.command(domain.commandName).alias(domain.alias).description(domain.description).addHelpCommand(false);
|
|
23543
24113
|
validationCmd.on("command:*", (operands) => {
|
|
23544
24114
|
handleUnknownSubcommand(operands, invocation.io);
|
|
23545
24115
|
});
|
|
23546
|
-
registerValidationCommands(validationCmd, invocation,
|
|
24116
|
+
registerValidationCommands(validationCmd, invocation, options);
|
|
23547
24117
|
}
|
|
23548
24118
|
};
|
|
23549
24119
|
}
|
|
@@ -23850,6 +24420,10 @@ var REVIEW_TERMINAL_STATE = {
|
|
|
23850
24420
|
CHANGES_REQUESTED: "changes_requested",
|
|
23851
24421
|
COMMENTED: "commented"
|
|
23852
24422
|
};
|
|
24423
|
+
var REVIEW_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
24424
|
+
JOURNAL_RUN_STATE_STATUS.APPROVED,
|
|
24425
|
+
JOURNAL_RUN_STATE_STATUS.REJECTED
|
|
24426
|
+
]);
|
|
23853
24427
|
var AUDIT_CLASS = {
|
|
23854
24428
|
IMPLEMENTATION: "implementation",
|
|
23855
24429
|
INSTRUCTIONS: "instructions",
|
|
@@ -24154,6 +24728,9 @@ function validateReviewTerminal(input) {
|
|
|
24154
24728
|
if (input.metadata !== void 0 && validated === void 0) {
|
|
24155
24729
|
return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.METADATA_INVALID };
|
|
24156
24730
|
}
|
|
24731
|
+
if (!REVIEW_TERMINAL_STATUSES.has(input.terminalStatus)) {
|
|
24732
|
+
return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.STATUS_CONFLICT };
|
|
24733
|
+
}
|
|
24157
24734
|
const evidenceStatus = expectedReviewEvidenceTerminalStatus(input.events);
|
|
24158
24735
|
const metadataStatus = expectedReviewMetadataTerminalStatus(validated);
|
|
24159
24736
|
if (evidenceStatus !== void 0 && metadataStatus !== void 0 && evidenceStatus !== metadataStatus) {
|
|
@@ -25685,7 +26262,7 @@ function createCliProgram(options = {}) {
|
|
|
25685
26262
|
|
|
25686
26263
|
// src/cli.ts
|
|
25687
26264
|
installLifecycle();
|
|
25688
|
-
var require3 =
|
|
26265
|
+
var require3 = createRequire3(import.meta.url);
|
|
25689
26266
|
var { version } = require3("../package.json");
|
|
25690
26267
|
createCliProgram({ version }).parse();
|
|
25691
26268
|
//# sourceMappingURL=cli.js.map
|