autodocs-engine 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +185 -0
- package/dist/analysis-builder.d.ts +13 -0
- package/dist/analysis-builder.js +268 -0
- package/dist/analysis-builder.js.map +1 -0
- package/dist/anti-pattern-detector.d.ts +9 -0
- package/dist/anti-pattern-detector.js +58 -0
- package/dist/anti-pattern-detector.js.map +1 -0
- package/dist/architecture-detector.d.ts +7 -0
- package/dist/architecture-detector.js +212 -0
- package/dist/architecture-detector.js.map +1 -0
- package/dist/ast-parser.d.ts +5 -0
- package/dist/ast-parser.js +635 -0
- package/dist/ast-parser.js.map +1 -0
- package/dist/benchmark/code-generator.d.ts +20 -0
- package/dist/benchmark/code-generator.js +206 -0
- package/dist/benchmark/code-generator.js.map +1 -0
- package/dist/benchmark/pr-miner.d.ts +61 -0
- package/dist/benchmark/pr-miner.js +304 -0
- package/dist/benchmark/pr-miner.js.map +1 -0
- package/dist/benchmark/pr-runner.d.ts +58 -0
- package/dist/benchmark/pr-runner.js +346 -0
- package/dist/benchmark/pr-runner.js.map +1 -0
- package/dist/benchmark/pr-scorer.d.ts +48 -0
- package/dist/benchmark/pr-scorer.js +222 -0
- package/dist/benchmark/pr-scorer.js.map +1 -0
- package/dist/benchmark/pr-task-gen.d.ts +16 -0
- package/dist/benchmark/pr-task-gen.js +129 -0
- package/dist/benchmark/pr-task-gen.js.map +1 -0
- package/dist/benchmark/report.d.ts +9 -0
- package/dist/benchmark/report.js +131 -0
- package/dist/benchmark/report.js.map +1 -0
- package/dist/benchmark/runner.d.ts +6 -0
- package/dist/benchmark/runner.js +183 -0
- package/dist/benchmark/runner.js.map +1 -0
- package/dist/benchmark/scorer.d.ts +6 -0
- package/dist/benchmark/scorer.js +549 -0
- package/dist/benchmark/scorer.js.map +1 -0
- package/dist/benchmark/shuffler.d.ts +5 -0
- package/dist/benchmark/shuffler.js +70 -0
- package/dist/benchmark/shuffler.js.map +1 -0
- package/dist/benchmark/statistics.d.ts +36 -0
- package/dist/benchmark/statistics.js +159 -0
- package/dist/benchmark/statistics.js.map +1 -0
- package/dist/benchmark/task-generator.d.ts +20 -0
- package/dist/benchmark/task-generator.js +388 -0
- package/dist/benchmark/task-generator.js.map +1 -0
- package/dist/benchmark/types.d.ts +111 -0
- package/dist/benchmark/types.js +3 -0
- package/dist/benchmark/types.js.map +1 -0
- package/dist/bin/autodocs-engine.d.ts +2 -0
- package/dist/bin/autodocs-engine.js +296 -0
- package/dist/bin/autodocs-engine.js.map +1 -0
- package/dist/bin/benchmark.d.ts +14 -0
- package/dist/bin/benchmark.js +172 -0
- package/dist/bin/benchmark.js.map +1 -0
- package/dist/bin/check.d.ts +13 -0
- package/dist/bin/check.js +79 -0
- package/dist/bin/check.js.map +1 -0
- package/dist/bin/init.d.ts +11 -0
- package/dist/bin/init.js +268 -0
- package/dist/bin/init.js.map +1 -0
- package/dist/bin/serve.d.ts +4 -0
- package/dist/bin/serve.js +29 -0
- package/dist/bin/serve.js.map +1 -0
- package/dist/budget-validator.d.ts +22 -0
- package/dist/budget-validator.js +119 -0
- package/dist/budget-validator.js.map +1 -0
- package/dist/command-extractor.d.ts +10 -0
- package/dist/command-extractor.js +276 -0
- package/dist/command-extractor.js.map +1 -0
- package/dist/config-analyzer.d.ts +5 -0
- package/dist/config-analyzer.js +364 -0
- package/dist/config-analyzer.js.map +1 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.js +172 -0
- package/dist/config.js.map +1 -0
- package/dist/contribution-patterns.d.ts +6 -0
- package/dist/contribution-patterns.js +263 -0
- package/dist/contribution-patterns.js.map +1 -0
- package/dist/convention-extractor.d.ts +17 -0
- package/dist/convention-extractor.js +90 -0
- package/dist/convention-extractor.js.map +1 -0
- package/dist/cross-package.d.ts +5 -0
- package/dist/cross-package.js +71 -0
- package/dist/cross-package.js.map +1 -0
- package/dist/dependency-analyzer.d.ts +5 -0
- package/dist/dependency-analyzer.js +233 -0
- package/dist/dependency-analyzer.js.map +1 -0
- package/dist/detectors/build-tool.d.ts +2 -0
- package/dist/detectors/build-tool.js +67 -0
- package/dist/detectors/build-tool.js.map +1 -0
- package/dist/detectors/component-patterns.d.ts +2 -0
- package/dist/detectors/component-patterns.js +49 -0
- package/dist/detectors/component-patterns.js.map +1 -0
- package/dist/detectors/data-fetching.d.ts +2 -0
- package/dist/detectors/data-fetching.js +127 -0
- package/dist/detectors/data-fetching.js.map +1 -0
- package/dist/detectors/database.d.ts +2 -0
- package/dist/detectors/database.js +54 -0
- package/dist/detectors/database.js.map +1 -0
- package/dist/detectors/error-handling.d.ts +2 -0
- package/dist/detectors/error-handling.js +47 -0
- package/dist/detectors/error-handling.js.map +1 -0
- package/dist/detectors/export-patterns.d.ts +2 -0
- package/dist/detectors/export-patterns.js +64 -0
- package/dist/detectors/export-patterns.js.map +1 -0
- package/dist/detectors/file-naming.d.ts +2 -0
- package/dist/detectors/file-naming.js +74 -0
- package/dist/detectors/file-naming.js.map +1 -0
- package/dist/detectors/graphql-patterns.d.ts +2 -0
- package/dist/detectors/graphql-patterns.js +47 -0
- package/dist/detectors/graphql-patterns.js.map +1 -0
- package/dist/detectors/hook-patterns.d.ts +2 -0
- package/dist/detectors/hook-patterns.js +105 -0
- package/dist/detectors/hook-patterns.js.map +1 -0
- package/dist/detectors/import-patterns.d.ts +2 -0
- package/dist/detectors/import-patterns.js +88 -0
- package/dist/detectors/import-patterns.js.map +1 -0
- package/dist/detectors/telemetry-patterns.d.ts +2 -0
- package/dist/detectors/telemetry-patterns.js +42 -0
- package/dist/detectors/telemetry-patterns.js.map +1 -0
- package/dist/detectors/test-framework-ecosystem.d.ts +2 -0
- package/dist/detectors/test-framework-ecosystem.js +95 -0
- package/dist/detectors/test-framework-ecosystem.js.map +1 -0
- package/dist/detectors/test-patterns.d.ts +2 -0
- package/dist/detectors/test-patterns.js +60 -0
- package/dist/detectors/test-patterns.js.map +1 -0
- package/dist/detectors/web-framework.d.ts +2 -0
- package/dist/detectors/web-framework.js +51 -0
- package/dist/detectors/web-framework.js.map +1 -0
- package/dist/deterministic-formatter.d.ts +54 -0
- package/dist/deterministic-formatter.js +922 -0
- package/dist/deterministic-formatter.js.map +1 -0
- package/dist/diff-analyzer.d.ts +7 -0
- package/dist/diff-analyzer.js +126 -0
- package/dist/diff-analyzer.js.map +1 -0
- package/dist/example-extractor.d.ts +6 -0
- package/dist/example-extractor.js +115 -0
- package/dist/example-extractor.js.map +1 -0
- package/dist/existing-docs.d.ts +36 -0
- package/dist/existing-docs.js +257 -0
- package/dist/existing-docs.js.map +1 -0
- package/dist/file-discovery.d.ts +6 -0
- package/dist/file-discovery.js +154 -0
- package/dist/file-discovery.js.map +1 -0
- package/dist/git-history.d.ts +41 -0
- package/dist/git-history.js +401 -0
- package/dist/git-history.js.map +1 -0
- package/dist/impact-classifier.d.ts +22 -0
- package/dist/impact-classifier.js +87 -0
- package/dist/impact-classifier.js.map +1 -0
- package/dist/impact-radius.d.ts +23 -0
- package/dist/impact-radius.js +130 -0
- package/dist/impact-radius.js.map +1 -0
- package/dist/import-chain.d.ts +12 -0
- package/dist/import-chain.js +93 -0
- package/dist/import-chain.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/inferability.d.ts +16 -0
- package/dist/inferability.js +142 -0
- package/dist/inferability.js.map +1 -0
- package/dist/llm/adapter.d.ts +33 -0
- package/dist/llm/adapter.js +202 -0
- package/dist/llm/adapter.js.map +1 -0
- package/dist/llm/client.d.ts +5 -0
- package/dist/llm/client.js +68 -0
- package/dist/llm/client.js.map +1 -0
- package/dist/llm/hierarchical.d.ts +23 -0
- package/dist/llm/hierarchical.js +126 -0
- package/dist/llm/hierarchical.js.map +1 -0
- package/dist/llm/serializer.d.ts +19 -0
- package/dist/llm/serializer.js +363 -0
- package/dist/llm/serializer.js.map +1 -0
- package/dist/llm/template-selector.d.ts +7 -0
- package/dist/llm/template-selector.js +21 -0
- package/dist/llm/template-selector.js.map +1 -0
- package/dist/llm-adapter.d.ts +2 -0
- package/dist/llm-adapter.js +5 -0
- package/dist/llm-adapter.js.map +1 -0
- package/dist/mcp/cache.d.ts +30 -0
- package/dist/mcp/cache.js +112 -0
- package/dist/mcp/cache.js.map +1 -0
- package/dist/mcp/errors.d.ts +21 -0
- package/dist/mcp/errors.js +27 -0
- package/dist/mcp/errors.js.map +1 -0
- package/dist/mcp/queries.d.ts +27 -0
- package/dist/mcp/queries.js +121 -0
- package/dist/mcp/queries.js.map +1 -0
- package/dist/mcp/server.d.ts +14 -0
- package/dist/mcp/server.js +131 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +39 -0
- package/dist/mcp/tools.js +249 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mermaid-generator.d.ts +6 -0
- package/dist/mermaid-generator.js +59 -0
- package/dist/mermaid-generator.js.map +1 -0
- package/dist/meta-tool-detector.d.ts +23 -0
- package/dist/meta-tool-detector.js +177 -0
- package/dist/meta-tool-detector.js.map +1 -0
- package/dist/output-validator.d.ts +6 -0
- package/dist/output-validator.js +471 -0
- package/dist/output-validator.js.map +1 -0
- package/dist/pattern-fingerprinter.d.ts +7 -0
- package/dist/pattern-fingerprinter.js +241 -0
- package/dist/pattern-fingerprinter.js.map +1 -0
- package/dist/pipeline.d.ts +5 -0
- package/dist/pipeline.js +374 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/plugin-loader.d.ts +19 -0
- package/dist/plugin-loader.js +124 -0
- package/dist/plugin-loader.js.map +1 -0
- package/dist/role-inferrer.d.ts +5 -0
- package/dist/role-inferrer.js +159 -0
- package/dist/role-inferrer.js.map +1 -0
- package/dist/symbol-graph.d.ts +11 -0
- package/dist/symbol-graph.js +613 -0
- package/dist/symbol-graph.js.map +1 -0
- package/dist/templates/agents-md.d.ts +20 -0
- package/dist/templates/agents-md.js +346 -0
- package/dist/templates/agents-md.js.map +1 -0
- package/dist/templates/claude-md.d.ts +4 -0
- package/dist/templates/claude-md.js +23 -0
- package/dist/templates/claude-md.js.map +1 -0
- package/dist/templates/cursorrules.d.ts +4 -0
- package/dist/templates/cursorrules.js +18 -0
- package/dist/templates/cursorrules.js.map +1 -0
- package/dist/tier-classifier.d.ts +7 -0
- package/dist/tier-classifier.js +32 -0
- package/dist/tier-classifier.js.map +1 -0
- package/dist/types.d.ts +428 -0
- package/dist/types.js +42 -0
- package/dist/types.js.map +1 -0
- package/dist/workflow-rules.d.ts +18 -0
- package/dist/workflow-rules.js +131 -0
- package/dist/workflow-rules.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// src/pattern-fingerprinter.ts — W2-2: Pattern Fingerprinting (W5-B3: Simplified)
|
|
2
|
+
// For the top N exports (by import count), analyze the function body AST to
|
|
3
|
+
// extract concrete patterns: actual parameter names, return value keys, internal calls.
|
|
4
|
+
// W5-B3: Removed abstract shapes (error pattern, async pattern, complexity).
|
|
5
|
+
// Produces 1-line summaries per export with concrete details.
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
import { resolve, extname } from "node:path";
|
|
8
|
+
import ts from "typescript";
|
|
9
|
+
/**
|
|
10
|
+
* Fingerprint the top N public API exports by analyzing their function bodies.
|
|
11
|
+
* Returns fingerprints for exports where the source file can be parsed and
|
|
12
|
+
* the function body can be found.
|
|
13
|
+
*/
|
|
14
|
+
export function fingerprintTopExports(publicAPI, packageDir, topN = 5, warnings = []) {
|
|
15
|
+
// Select top N non-type exports by import count
|
|
16
|
+
const candidates = publicAPI
|
|
17
|
+
.filter((e) => !e.isTypeOnly && e.kind !== "type" && e.kind !== "interface" && e.kind !== "enum")
|
|
18
|
+
.sort((a, b) => (b.importCount ?? 0) - (a.importCount ?? 0))
|
|
19
|
+
.slice(0, topN);
|
|
20
|
+
if (candidates.length === 0)
|
|
21
|
+
return [];
|
|
22
|
+
// Group by source file to parse each file once
|
|
23
|
+
const byFile = new Map();
|
|
24
|
+
for (const entry of candidates) {
|
|
25
|
+
const file = entry.sourceFile;
|
|
26
|
+
if (!byFile.has(file))
|
|
27
|
+
byFile.set(file, []);
|
|
28
|
+
byFile.get(file).push(entry);
|
|
29
|
+
}
|
|
30
|
+
const fingerprints = [];
|
|
31
|
+
for (const [relFile, entries] of byFile) {
|
|
32
|
+
const absPath = resolve(packageDir, relFile);
|
|
33
|
+
let content;
|
|
34
|
+
try {
|
|
35
|
+
content = readFileSync(absPath, "utf-8");
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const ext = extname(absPath).toLowerCase();
|
|
41
|
+
const scriptKind = ext === ".tsx" ? ts.ScriptKind.TSX :
|
|
42
|
+
ext === ".jsx" ? ts.ScriptKind.JSX :
|
|
43
|
+
ext === ".js" ? ts.ScriptKind.JS :
|
|
44
|
+
ts.ScriptKind.TS;
|
|
45
|
+
const sourceFile = ts.createSourceFile(absPath, content, ts.ScriptTarget.Latest, true, scriptKind);
|
|
46
|
+
for (const entry of entries) {
|
|
47
|
+
try {
|
|
48
|
+
const fp = fingerprintExport(sourceFile, entry, relFile);
|
|
49
|
+
if (fp)
|
|
50
|
+
fingerprints.push(fp);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
warnings.push({
|
|
54
|
+
level: "info",
|
|
55
|
+
module: "pattern-fingerprinter",
|
|
56
|
+
message: `Could not fingerprint ${entry.name}: ${err instanceof Error ? err.message : String(err)}`,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return fingerprints;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Analyze a single exported function/hook/component to produce a PatternFingerprint.
|
|
65
|
+
* W5-B3: Simplified — only extracts params, return shape, internal calls.
|
|
66
|
+
*/
|
|
67
|
+
function fingerprintExport(sourceFile, entry, relFile) {
|
|
68
|
+
const funcInfo = findExportedFunction(sourceFile, entry.name);
|
|
69
|
+
if (!funcInfo)
|
|
70
|
+
return null;
|
|
71
|
+
const { params, body, returnType } = funcInfo;
|
|
72
|
+
const parameterShape = analyzeParameterShape(params);
|
|
73
|
+
const returnShape = returnType
|
|
74
|
+
? returnType.getText()
|
|
75
|
+
: analyzeReturnShape(body);
|
|
76
|
+
const internalCalls = extractInternalCalls(body);
|
|
77
|
+
const summary = composeSummary(entry, parameterShape, returnShape, internalCalls);
|
|
78
|
+
return {
|
|
79
|
+
exportName: entry.name,
|
|
80
|
+
sourceFile: relFile,
|
|
81
|
+
parameterShape,
|
|
82
|
+
returnShape,
|
|
83
|
+
internalCalls,
|
|
84
|
+
// W5-B3: Deprecated fields kept for backward compatibility, set to defaults
|
|
85
|
+
errorPattern: "none",
|
|
86
|
+
asyncPattern: "sync",
|
|
87
|
+
complexity: "simple",
|
|
88
|
+
summary,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function findExportedFunction(sourceFile, name) {
|
|
92
|
+
for (const stmt of sourceFile.statements) {
|
|
93
|
+
if (!ts.canHaveModifiers(stmt))
|
|
94
|
+
continue;
|
|
95
|
+
const modifiers = ts.getModifiers(stmt);
|
|
96
|
+
const hasExport = modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
|
|
97
|
+
if (!hasExport)
|
|
98
|
+
continue;
|
|
99
|
+
// export function foo(...)
|
|
100
|
+
if (ts.isFunctionDeclaration(stmt) && stmt.name?.text === name && stmt.body) {
|
|
101
|
+
return {
|
|
102
|
+
params: stmt.parameters,
|
|
103
|
+
body: stmt.body,
|
|
104
|
+
returnType: stmt.type,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
// export const foo = (...) => ...
|
|
108
|
+
if (ts.isVariableStatement(stmt)) {
|
|
109
|
+
for (const decl of stmt.declarationList.declarations) {
|
|
110
|
+
if (!ts.isIdentifier(decl.name) || decl.name.text !== name)
|
|
111
|
+
continue;
|
|
112
|
+
if (!decl.initializer)
|
|
113
|
+
continue;
|
|
114
|
+
let func;
|
|
115
|
+
if (ts.isArrowFunction(decl.initializer)) {
|
|
116
|
+
func = decl.initializer;
|
|
117
|
+
}
|
|
118
|
+
else if (ts.isFunctionExpression(decl.initializer)) {
|
|
119
|
+
func = decl.initializer;
|
|
120
|
+
}
|
|
121
|
+
else if (ts.isCallExpression(decl.initializer)) {
|
|
122
|
+
// React.memo(() => ...) or similar wrapper
|
|
123
|
+
const arg = decl.initializer.arguments[0];
|
|
124
|
+
if (arg && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))) {
|
|
125
|
+
func = arg;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (func) {
|
|
129
|
+
return {
|
|
130
|
+
params: func.parameters,
|
|
131
|
+
body: func.body,
|
|
132
|
+
returnType: func.type,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
// ---- Parameter Shape Analysis ----
|
|
141
|
+
function analyzeParameterShape(params) {
|
|
142
|
+
if (params.length === 0)
|
|
143
|
+
return "no params";
|
|
144
|
+
if (params.length === 1) {
|
|
145
|
+
const param = params[0];
|
|
146
|
+
// Destructured object: ({ foo, bar })
|
|
147
|
+
if (ts.isObjectBindingPattern(param.name)) {
|
|
148
|
+
const props = param.name.elements.map((e) => e.name.getText());
|
|
149
|
+
return `{ ${props.join(", ")} }`;
|
|
150
|
+
}
|
|
151
|
+
// Object type annotation
|
|
152
|
+
if (param.type && ts.isTypeLiteralNode(param.type)) {
|
|
153
|
+
const props = param.type.members
|
|
154
|
+
.filter(ts.isPropertySignature)
|
|
155
|
+
.map((m) => m.name?.getText() ?? "?");
|
|
156
|
+
return `{ ${props.join(", ")} }`;
|
|
157
|
+
}
|
|
158
|
+
// Type reference (e.g., Options, Config)
|
|
159
|
+
if (param.type && ts.isTypeReferenceNode(param.type)) {
|
|
160
|
+
return `${param.name.getText()}: ${param.type.getText()}`;
|
|
161
|
+
}
|
|
162
|
+
return `${param.name.getText()}: ${param.type?.getText() ?? "unknown"}`;
|
|
163
|
+
}
|
|
164
|
+
return `(${params.map((p) => p.name.getText()).join(", ")})`;
|
|
165
|
+
}
|
|
166
|
+
// ---- Return Shape Analysis ----
|
|
167
|
+
function analyzeReturnShape(body) {
|
|
168
|
+
const returnExprs = [];
|
|
169
|
+
function walk(node) {
|
|
170
|
+
if (ts.isReturnStatement(node) && node.expression) {
|
|
171
|
+
// Object literal return
|
|
172
|
+
if (ts.isObjectLiteralExpression(node.expression)) {
|
|
173
|
+
const props = node.expression.properties
|
|
174
|
+
.map((p) => {
|
|
175
|
+
if (ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) {
|
|
176
|
+
return p.name?.getText() ?? "?";
|
|
177
|
+
}
|
|
178
|
+
if (ts.isSpreadAssignment(p))
|
|
179
|
+
return "...spread";
|
|
180
|
+
return "?";
|
|
181
|
+
});
|
|
182
|
+
returnExprs.push(`{ ${props.join(", ")} }`);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// JSX return
|
|
186
|
+
if (ts.isJsxElement(node.expression) || ts.isJsxSelfClosingElement(node.expression) || ts.isJsxFragment(node.expression)) {
|
|
187
|
+
returnExprs.push("JSX.Element");
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
// Parenthesized JSX
|
|
191
|
+
if (ts.isParenthesizedExpression(node.expression)) {
|
|
192
|
+
const inner = node.expression.expression;
|
|
193
|
+
if (ts.isJsxElement(inner) || ts.isJsxSelfClosingElement(inner) || ts.isJsxFragment(inner)) {
|
|
194
|
+
returnExprs.push("JSX.Element");
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
returnExprs.push("value");
|
|
199
|
+
}
|
|
200
|
+
ts.forEachChild(node, walk);
|
|
201
|
+
}
|
|
202
|
+
walk(body);
|
|
203
|
+
if (returnExprs.length === 0)
|
|
204
|
+
return "void";
|
|
205
|
+
const unique = [...new Set(returnExprs)];
|
|
206
|
+
return unique[0];
|
|
207
|
+
}
|
|
208
|
+
// ---- Internal Calls ----
|
|
209
|
+
function extractInternalCalls(body) {
|
|
210
|
+
const calls = new Set();
|
|
211
|
+
function walk(node) {
|
|
212
|
+
if (ts.isCallExpression(node)) {
|
|
213
|
+
if (ts.isIdentifier(node.expression)) {
|
|
214
|
+
calls.add(node.expression.text);
|
|
215
|
+
}
|
|
216
|
+
else if (ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.name)) {
|
|
217
|
+
const name = node.expression.name.text;
|
|
218
|
+
const obj = node.expression.expression;
|
|
219
|
+
if (ts.isIdentifier(obj)) {
|
|
220
|
+
calls.add(`${obj.text}.${name}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
ts.forEachChild(node, walk);
|
|
225
|
+
}
|
|
226
|
+
walk(body);
|
|
227
|
+
return [...calls].slice(0, 15);
|
|
228
|
+
}
|
|
229
|
+
// ---- Summary Composition ----
|
|
230
|
+
function composeSummary(entry, parameterShape, returnShape, internalCalls) {
|
|
231
|
+
const kind = entry.kind === "hook" ? "Custom hook" :
|
|
232
|
+
entry.kind === "component" ? "React component" :
|
|
233
|
+
entry.kind === "function" ? "Function" : "Export";
|
|
234
|
+
const paramPart = parameterShape === "no params" ? "" : ` accepting ${parameterShape}`;
|
|
235
|
+
const callPart = internalCalls.length > 0
|
|
236
|
+
? `, uses ${internalCalls.slice(0, 4).join(", ")}`
|
|
237
|
+
: "";
|
|
238
|
+
const returnPart = returnShape !== "void" ? `, returns ${returnShape}` : "";
|
|
239
|
+
return `${kind}${paramPart}${callPart}${returnPart}`;
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=pattern-fingerprinter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pattern-fingerprinter.js","sourceRoot":"","sources":["../src/pattern-fingerprinter.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,4EAA4E;AAC5E,wFAAwF;AACxF,6EAA6E;AAC7E,8DAA8D;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5B;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAA2B,EAC3B,UAAkB,EAClB,OAAe,CAAC,EAChB,WAAsB,EAAE;IAExB,gDAAgD;IAChD,MAAM,UAAU,GAAG,SAAS;SACzB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;SAChG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;SAC3D,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAElB,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEvC,+CAA+C;IAC/C,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;IACnD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,YAAY,GAAyB,EAAE,CAAC;IAE9C,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,MAAM,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC7C,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;QAC3C,MAAM,UAAU,GACd,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACpC,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;gBACpC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;oBAClC,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;QAEnB,MAAM,UAAU,GAAG,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QAEnG,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,iBAAiB,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;gBACzD,IAAI,EAAE;oBAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAChC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,QAAQ,CAAC,IAAI,CAAC;oBACZ,KAAK,EAAE,MAAM;oBACb,MAAM,EAAE,uBAAuB;oBAC/B,OAAO,EAAE,yBAAyB,KAAK,CAAC,IAAI,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;iBACpG,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,SAAS,iBAAiB,CACxB,UAAyB,EACzB,KAAqB,EACrB,OAAe;IAEf,MAAM,QAAQ,GAAG,oBAAoB,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9D,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE3B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC;IAE9C,MAAM,cAAc,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,UAAU;QAC5B,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE;QACtB,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,aAAa,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAEjD,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;IAElF,OAAO;QACL,UAAU,EAAE,KAAK,CAAC,IAAI;QACtB,UAAU,EAAE,OAAO;QACnB,cAAc;QACd,WAAW;QACX,aAAa;QACb,4EAA4E;QAC5E,YAAY,EAAE,MAAM;QACpB,YAAY,EAAE,MAAM;QACpB,UAAU,EAAE,QAAQ;QACpB,OAAO;KACR,CAAC;AACJ,CAAC;AAUD,SAAS,oBAAoB,CAAC,UAAyB,EAAE,IAAY;IACnE,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,UAAU,EAAE,CAAC;QACzC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC;YAAE,SAAS;QACzC,MAAM,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QACjF,IAAI,CAAC,SAAS;YAAE,SAAS;QAEzB,2BAA2B;QAC3B,IAAI,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5E,OAAO;gBACL,MAAM,EAAE,IAAI,CAAC,UAAU;gBACvB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,UAAU,EAAE,IAAI,CAAC,IAAI;aACtB,CAAC;QACJ,CAAC;QAED,kCAAkC;QAClC,IAAI,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,CAAC;gBACrD,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI;oBAAE,SAAS;gBACrE,IAAI,CAAC,IAAI,CAAC,WAAW;oBAAE,SAAS;gBAEhC,IAAI,IAA0D,CAAC;gBAE/D,IAAI,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBACzC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;gBAC1B,CAAC;qBAAM,IAAI,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBACrD,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;gBAC1B,CAAC;qBAAM,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBACjD,2CAA2C;oBAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;oBAC1C,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;wBACrE,IAAI,GAAG,GAAG,CAAC;oBACb,CAAC;gBACH,CAAC;gBAED,IAAI,IAAI,EAAE,CAAC;oBACT,OAAO;wBACL,MAAM,EAAE,IAAI,CAAC,UAAU;wBACvB,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,UAAU,EAAE,IAAI,CAAC,IAAI;qBACtB,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,qCAAqC;AAErC,SAAS,qBAAqB,CAAC,MAA6C;IAC1E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAE5C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,sCAAsC;QACtC,IAAI,EAAE,CAAC,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YAC/D,OAAO,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QACnC,CAAC;QACD,yBAAyB;QACzB,IAAI,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO;iBAC7B,MAAM,CAAC,EAAE,CAAC,mBAAmB,CAAC;iBAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,CAAC,CAAC;YACxC,OAAO,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QACnC,CAAC;QACD,yCAAyC;QACzC,IAAI,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACrD,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QAC5D,CAAC;QACD,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,SAAS,EAAE,CAAC;IAC1E,CAAC;IAED,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAC/D,CAAC;AAED,kCAAkC;AAElC,SAAS,kBAAkB,CAAC,IAAa;IACvC,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,SAAS,IAAI,CAAC,IAAa;QACzB,IAAI,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAClD,wBAAwB;YACxB,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU;qBACrC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;oBACT,IAAI,EAAE,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,6BAA6B,CAAC,CAAC,CAAC,EAAE,CAAC;wBACtE,OAAO,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,CAAC;oBAClC,CAAC;oBACD,IAAI,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC;wBAAE,OAAO,WAAW,CAAC;oBACjD,OAAO,GAAG,CAAC;gBACb,CAAC,CAAC,CAAC;gBACL,WAAW,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC5C,OAAO;YACT,CAAC;YACD,aAAa;YACb,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;gBACzH,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBAChC,OAAO;YACT,CAAC;YACD,oBAAoB;YACpB,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClD,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;gBACzC,IAAI,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,uBAAuB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC3F,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;oBAChC,OAAO;gBACT,CAAC;YACH,CAAC;YACD,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;QACD,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEX,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAC5C,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC;AAED,2BAA2B;AAE3B,SAAS,oBAAoB,CAAC,IAAa;IACzC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAEhC,SAAS,IAAI,CAAC,IAAa;QACzB,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;gBACrC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAClC,CAAC;iBAAM,IAAI,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACnG,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;gBACvC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;gBACvC,IAAI,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;oBACzB,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;QACD,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEX,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,gCAAgC;AAEhC,SAAS,cAAc,CACrB,KAAqB,EACrB,cAAsB,EACtB,WAAmB,EACnB,aAAuB;IAEvB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QAClD,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;YAChD,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEpD,MAAM,SAAS,GAAG,cAAc,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,cAAc,EAAE,CAAC;IACvF,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC;QACvC,CAAC,CAAC,UAAU,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAClD,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,UAAU,GAAG,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,aAAa,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5E,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,EAAE,CAAC;AACvD,CAAC"}
|
package/dist/pipeline.js
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
// src/pipeline.ts — Pipeline Orchestrator
|
|
2
|
+
// Errata applied: E-31 (publicAPI before Architecture Detector), E-39 (warnings to all modules)
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { basename, join } from "node:path";
|
|
5
|
+
import { discoverFiles } from "./file-discovery.js";
|
|
6
|
+
import { parseFile } from "./ast-parser.js";
|
|
7
|
+
import { buildSymbolGraph } from "./symbol-graph.js";
|
|
8
|
+
import { classifyTiers } from "./tier-classifier.js";
|
|
9
|
+
import { extractConventions } from "./convention-extractor.js";
|
|
10
|
+
import { extractCommands, scanWorkspaceCommands } from "./command-extractor.js";
|
|
11
|
+
import { detectArchitecture } from "./architecture-detector.js";
|
|
12
|
+
import { buildPublicAPI, buildPackageAnalysis, buildStructuredAnalysis } from "./analysis-builder.js";
|
|
13
|
+
import { analyzeCrossPackage } from "./cross-package.js";
|
|
14
|
+
import { inferRole } from "./role-inferrer.js";
|
|
15
|
+
import { deriveAntiPatterns } from "./anti-pattern-detector.js";
|
|
16
|
+
import { detectContributionPatterns } from "./contribution-patterns.js";
|
|
17
|
+
import { classifyImpacts } from "./impact-classifier.js";
|
|
18
|
+
import { analyzeConfig } from "./config-analyzer.js";
|
|
19
|
+
import { generateWorkflowRules } from "./workflow-rules.js";
|
|
20
|
+
import { fingerprintTopExports } from "./pattern-fingerprinter.js";
|
|
21
|
+
import { analyzeDependencies } from "./dependency-analyzer.js";
|
|
22
|
+
import { detectExistingDocs } from "./existing-docs.js";
|
|
23
|
+
import { extractExamples } from "./example-extractor.js";
|
|
24
|
+
import { generateDependencyDiagram } from "./mermaid-generator.js";
|
|
25
|
+
import { detectMetaTool } from "./meta-tool-detector.js";
|
|
26
|
+
import { computeImportChain, generateImportChainRules } from "./import-chain.js";
|
|
27
|
+
import { mineGitHistory, generateCoChangeRules } from "./git-history.js";
|
|
28
|
+
/** Verbose logger — writes to stderr only when verbose is enabled. */
|
|
29
|
+
function vlog(verbose, msg) {
|
|
30
|
+
if (verbose)
|
|
31
|
+
process.stderr.write(`[INFO] ${msg}\n`);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Run the full analysis pipeline for all packages.
|
|
35
|
+
*/
|
|
36
|
+
export async function runPipeline(config) {
|
|
37
|
+
const warnings = [];
|
|
38
|
+
const startTime = performance.now();
|
|
39
|
+
const packageAnalyses = [];
|
|
40
|
+
const verbose = config.verbose;
|
|
41
|
+
// Git history mining — run once at repo level, distribute to packages
|
|
42
|
+
const gitHistoryMap = mineGitHistory(config.rootDir ?? config.packages[0], config.packages, warnings);
|
|
43
|
+
if (gitHistoryMap) {
|
|
44
|
+
vlog(verbose, `Git history: mined for ${gitHistoryMap.size} package(s)`);
|
|
45
|
+
}
|
|
46
|
+
for (const pkgPath of config.packages) {
|
|
47
|
+
try {
|
|
48
|
+
const analysis = analyzePackage(pkgPath, config, warnings);
|
|
49
|
+
// Attach pre-computed git history for this package
|
|
50
|
+
const pkgGitHistory = gitHistoryMap?.get(pkgPath);
|
|
51
|
+
if (pkgGitHistory) {
|
|
52
|
+
analysis.gitHistory = pkgGitHistory;
|
|
53
|
+
vlog(verbose, ` Git co-change: ${pkgGitHistory.coChangeEdges.length} edges (${pkgGitHistory.totalCommitsAnalyzed} commits analyzed)`);
|
|
54
|
+
}
|
|
55
|
+
packageAnalyses.push(analysis);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
59
|
+
warnings.push({
|
|
60
|
+
level: "error",
|
|
61
|
+
module: "pipeline",
|
|
62
|
+
message: `Failed to analyze ${pkgPath}: ${msg}`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Cross-package analysis (if >1 package)
|
|
67
|
+
let crossPackage;
|
|
68
|
+
let workspaceCommands = [];
|
|
69
|
+
let rootCommands;
|
|
70
|
+
if (packageAnalyses.length > 1) {
|
|
71
|
+
vlog(verbose, `Running cross-package analysis for ${packageAnalyses.length} packages...`);
|
|
72
|
+
rootCommands = config.rootDir
|
|
73
|
+
? extractCommands(config.rootDir, undefined, warnings)
|
|
74
|
+
: undefined;
|
|
75
|
+
crossPackage = analyzeCrossPackage(packageAnalyses, rootCommands);
|
|
76
|
+
if (crossPackage) {
|
|
77
|
+
vlog(verbose, ` Dependency edges: ${crossPackage.dependencyGraph.length}`);
|
|
78
|
+
vlog(verbose, ` Shared conventions: ${crossPackage.sharedConventions.length}`);
|
|
79
|
+
vlog(verbose, ` Divergent conventions: ${crossPackage.divergentConventions.length}`);
|
|
80
|
+
}
|
|
81
|
+
// W5-C3: Generate Mermaid dependency diagram
|
|
82
|
+
if (crossPackage && crossPackage.dependencyGraph.length > 0) {
|
|
83
|
+
const mermaidDiagram = generateDependencyDiagram(packageAnalyses, crossPackage.dependencyGraph);
|
|
84
|
+
if (mermaidDiagram) {
|
|
85
|
+
crossPackage.mermaidDiagram = mermaidDiagram;
|
|
86
|
+
vlog(verbose, ` Mermaid diagram: ${crossPackage.dependencyGraph.length} edges rendered`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// W3-1: Workspace-wide command scanning (multi-package only)
|
|
90
|
+
if (config.rootDir) {
|
|
91
|
+
const analyzedPkgNames = new Set(packageAnalyses.map((p) => p.name));
|
|
92
|
+
workspaceCommands = scanWorkspaceCommands(config.rootDir, warnings, analyzedPkgNames);
|
|
93
|
+
if (workspaceCommands.length > 0) {
|
|
94
|
+
vlog(verbose, ` Workspace commands: ${workspaceCommands.length} operational commands found`);
|
|
95
|
+
if (crossPackage) {
|
|
96
|
+
crossPackage.workspaceCommands = workspaceCommands;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Workflow rule generation — runs for ALL analyses (single and multi-package)
|
|
102
|
+
const firstConfig = packageAnalyses.find((p) => p.configAnalysis)?.configAnalysis;
|
|
103
|
+
const workflowRules = generateWorkflowRules({
|
|
104
|
+
workspaceCommands,
|
|
105
|
+
rootCommands,
|
|
106
|
+
packageCommands: packageAnalyses.map((p) => ({
|
|
107
|
+
packageName: p.name,
|
|
108
|
+
commands: p.commands,
|
|
109
|
+
})),
|
|
110
|
+
configAnalysis: firstConfig,
|
|
111
|
+
allDependencyInsights: packageAnalyses
|
|
112
|
+
.map((p) => p.dependencyInsights)
|
|
113
|
+
.filter((d) => d != null),
|
|
114
|
+
allConventions: packageAnalyses.flatMap((p) => p.conventions),
|
|
115
|
+
});
|
|
116
|
+
// Add import-chain rules (from file-to-file coupling analysis)
|
|
117
|
+
const allImportChainEdges = packageAnalyses.flatMap((p) => p.importChain ?? []);
|
|
118
|
+
const importChainRules = generateImportChainRules(allImportChainEdges);
|
|
119
|
+
if (importChainRules.length > 0) {
|
|
120
|
+
vlog(verbose, `Import chain rules: ${importChainRules.length} high-coupling rules generated`);
|
|
121
|
+
workflowRules.push(...importChainRules);
|
|
122
|
+
}
|
|
123
|
+
// Add co-change rules from git history (structured dedup against import-chain)
|
|
124
|
+
const importChainCoveredFiles = new Set(allImportChainEdges.map((e) => e.source));
|
|
125
|
+
const coChangeRules = generateCoChangeRules(packageAnalyses.flatMap((p) => p.gitHistory?.coChangeEdges ?? []), importChainCoveredFiles);
|
|
126
|
+
if (coChangeRules.length > 0) {
|
|
127
|
+
vlog(verbose, `Co-change rules: ${coChangeRules.length} rules from git history`);
|
|
128
|
+
workflowRules.push(...coChangeRules);
|
|
129
|
+
}
|
|
130
|
+
if (workflowRules.length > 0) {
|
|
131
|
+
vlog(verbose, `Workflow rules: ${workflowRules.length} total rules generated`);
|
|
132
|
+
// For single-package, create a minimal crossPackage to hold the rules
|
|
133
|
+
if (!crossPackage) {
|
|
134
|
+
crossPackage = {
|
|
135
|
+
dependencyGraph: [],
|
|
136
|
+
sharedConventions: [],
|
|
137
|
+
divergentConventions: [],
|
|
138
|
+
sharedAntiPatterns: [],
|
|
139
|
+
workflowRules,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
crossPackage.workflowRules = workflowRules;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const totalMs = Math.round(performance.now() - startTime);
|
|
147
|
+
vlog(verbose, `Total analysis time: ${totalMs}ms`);
|
|
148
|
+
return buildStructuredAnalysis(packageAnalyses, crossPackage, config, warnings, startTime);
|
|
149
|
+
}
|
|
150
|
+
function analyzePackage(pkgPath, config, warnings) {
|
|
151
|
+
const verbose = config.verbose;
|
|
152
|
+
const pkgStart = performance.now();
|
|
153
|
+
vlog(verbose, `Analyzing ${basename(pkgPath)}...`);
|
|
154
|
+
// Step 1: File Discovery (E-39: pass warnings)
|
|
155
|
+
const files = discoverFiles(pkgPath, config.exclude, warnings);
|
|
156
|
+
// Step 2: AST Parser (E-39: pass warnings)
|
|
157
|
+
const parsed = files
|
|
158
|
+
.map((f) => {
|
|
159
|
+
try {
|
|
160
|
+
return parseFile(f, pkgPath, warnings);
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
164
|
+
warnings.push({
|
|
165
|
+
level: "warn",
|
|
166
|
+
module: "ast-parser",
|
|
167
|
+
message: msg,
|
|
168
|
+
file: f,
|
|
169
|
+
});
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
.filter(Boolean);
|
|
174
|
+
// Step 3: Symbol Graph Builder (E-39: pass warnings)
|
|
175
|
+
const symbolGraph = buildSymbolGraph(parsed, pkgPath, warnings);
|
|
176
|
+
// Compute file-to-file import coupling before symbolGraph is discarded
|
|
177
|
+
const importChain = computeImportChain(symbolGraph, pkgPath, warnings);
|
|
178
|
+
if (importChain.length > 0) {
|
|
179
|
+
vlog(verbose, ` Import chain: ${importChain.length} high-coupling file pairs`);
|
|
180
|
+
}
|
|
181
|
+
// Step 4: Tier Classifier
|
|
182
|
+
const tiers = classifyTiers(parsed, symbolGraph, symbolGraph.barrelFile);
|
|
183
|
+
// Verbose: tier counts
|
|
184
|
+
if (verbose) {
|
|
185
|
+
let t1 = 0, t2 = 0, t3 = 0;
|
|
186
|
+
for (const [, info] of tiers) {
|
|
187
|
+
if (info.tier === 1)
|
|
188
|
+
t1++;
|
|
189
|
+
else if (info.tier === 2)
|
|
190
|
+
t2++;
|
|
191
|
+
else
|
|
192
|
+
t3++;
|
|
193
|
+
}
|
|
194
|
+
vlog(verbose, ` Files discovered: ${parsed.length} (${t1} T1, ${t2} T2, ${t3} T3)`);
|
|
195
|
+
}
|
|
196
|
+
// E-31: Compute publicAPI BEFORE Architecture Detector
|
|
197
|
+
const publicAPI = buildPublicAPI(symbolGraph, parsed, config.maxPublicAPIEntries, warnings);
|
|
198
|
+
vlog(verbose, ` Public API: ${publicAPI.length} exports`);
|
|
199
|
+
// Steps 5-7: Run analysis modules (E-39: pass warnings)
|
|
200
|
+
// Improvement 1 & 2: Config and dependency analysis needed before convention extraction
|
|
201
|
+
// (moved up so detectors can use context)
|
|
202
|
+
const configAnalysis = analyzeConfig(pkgPath, config.rootDir, warnings);
|
|
203
|
+
vlog(verbose, ` Config: build=${configAnalysis.buildTool?.name ?? "none"}, linter=${configAnalysis.linter?.name ?? "none"}, formatter=${configAnalysis.formatter?.name ?? "none"}`);
|
|
204
|
+
// Collect all imported module specifiers from source files for import-verified framework detection
|
|
205
|
+
// Excludes type-only imports — they don't indicate runtime framework usage
|
|
206
|
+
const allImportedModules = new Set();
|
|
207
|
+
for (const pf of parsed) {
|
|
208
|
+
for (const imp of pf.imports) {
|
|
209
|
+
if (imp.isTypeOnly)
|
|
210
|
+
continue;
|
|
211
|
+
const spec = imp.moduleSpecifier;
|
|
212
|
+
if (spec.startsWith(".") || spec.startsWith("/"))
|
|
213
|
+
continue;
|
|
214
|
+
const parts = spec.split("/");
|
|
215
|
+
const basePkg = spec.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
|
|
216
|
+
allImportedModules.add(basePkg);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const dependencyInsights = analyzeDependencies(pkgPath, config.rootDir, warnings, allImportedModules);
|
|
220
|
+
vlog(verbose, ` Dependencies: ${dependencyInsights.frameworks.length} frameworks, runtime=${dependencyInsights.runtime.map((r) => r.name).join("+") || "node"}`);
|
|
221
|
+
// Meta-tool detection (before conventions — informs format-time reclassification)
|
|
222
|
+
let pkgJsonRaw = null;
|
|
223
|
+
try {
|
|
224
|
+
pkgJsonRaw = JSON.parse(readFileSync(join(pkgPath, "package.json"), "utf-8"));
|
|
225
|
+
}
|
|
226
|
+
catch { /* no package.json */ }
|
|
227
|
+
const metaToolResult = (!config.noMetaTool && pkgJsonRaw)
|
|
228
|
+
? detectMetaTool({
|
|
229
|
+
parsedFiles: parsed,
|
|
230
|
+
tiers,
|
|
231
|
+
dependencies: (pkgJsonRaw.dependencies ?? {}),
|
|
232
|
+
devDependencies: (pkgJsonRaw.devDependencies ?? {}),
|
|
233
|
+
peerDeps: (pkgJsonRaw.peerDependencies ?? {}),
|
|
234
|
+
threshold: config.metaToolThreshold,
|
|
235
|
+
}, warnings)
|
|
236
|
+
: { isMetaTool: false, signal: "none", supportedFamilies: [], coreFamilies: [] };
|
|
237
|
+
if (metaToolResult.isMetaTool) {
|
|
238
|
+
vlog(verbose, ` Meta-tool: ${metaToolResult.signal} (${metaToolResult.supportedFamilies.length} families, core: ${metaToolResult.coreFamilies.join(", ") || "none"})`);
|
|
239
|
+
}
|
|
240
|
+
// Read root devDeps for test framework fallback in monorepos
|
|
241
|
+
let rootDevDeps;
|
|
242
|
+
if (config.rootDir) {
|
|
243
|
+
try {
|
|
244
|
+
const rootPkg = JSON.parse(readFileSync(join(config.rootDir, "package.json"), "utf-8"));
|
|
245
|
+
rootDevDeps = rootPkg.devDependencies;
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
// skip
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// W2-3: Pass dependency and config context to convention detectors
|
|
252
|
+
const conventions = extractConventions(parsed, tiers, config.conventions.disable, warnings, { dependencies: dependencyInsights, config: configAnalysis, rootDevDeps });
|
|
253
|
+
vlog(verbose, ` Conventions: ${conventions.length} detected`);
|
|
254
|
+
// Improvement 4: Existing docs detection
|
|
255
|
+
const existingDocs = detectExistingDocs(pkgPath, warnings);
|
|
256
|
+
if (existingDocs.hasAgentsMd || existingDocs.hasClaudeMd) {
|
|
257
|
+
vlog(verbose, ` Existing docs: ${existingDocs.hasAgentsMd ? "AGENTS.md" : ""}${existingDocs.hasClaudeMd ? " CLAUDE.md" : ""}`);
|
|
258
|
+
}
|
|
259
|
+
const commands = extractCommands(pkgPath, config.rootDir, warnings);
|
|
260
|
+
// Improvement 1 integration: Override commands with build tool info (turbo, nx)
|
|
261
|
+
if (configAnalysis.buildTool && configAnalysis.buildTool.name !== "none") {
|
|
262
|
+
adjustCommandsForBuildTool(commands, configAnalysis.buildTool, warnings);
|
|
263
|
+
}
|
|
264
|
+
const cmdList = [
|
|
265
|
+
commands.build && "build",
|
|
266
|
+
commands.test && "test",
|
|
267
|
+
commands.lint && "lint",
|
|
268
|
+
commands.start && "start",
|
|
269
|
+
].filter(Boolean);
|
|
270
|
+
vlog(verbose, ` Commands: ${commands.packageManager} (${cmdList.join(", ") || "none"})`);
|
|
271
|
+
const architecture = detectArchitecture(parsed, pkgPath, publicAPI, symbolGraph.barrelFile, warnings);
|
|
272
|
+
// Enhancement 1: Role inference
|
|
273
|
+
const partialAnalysis = buildPackageAnalysis(pkgPath, config.rootDir, parsed, symbolGraph, tiers, conventions, commands, architecture, publicAPI, warnings);
|
|
274
|
+
const role = inferRole(partialAnalysis);
|
|
275
|
+
if (metaToolResult.isMetaTool) {
|
|
276
|
+
role.summary += ` — integrates with ${metaToolResult.supportedFamilies.length} framework ecosystems`;
|
|
277
|
+
}
|
|
278
|
+
vlog(verbose, ` Role: ${role.summary}`);
|
|
279
|
+
// Enhancement 3: Anti-pattern derivation
|
|
280
|
+
const antiPatterns = deriveAntiPatterns(conventions);
|
|
281
|
+
vlog(verbose, ` Anti-patterns: ${antiPatterns.length} derived`);
|
|
282
|
+
// Enhancement 4: Contribution patterns
|
|
283
|
+
const contributionPatterns = detectContributionPatterns(parsed, publicAPI, tiers, architecture.directories, symbolGraph.barrelFile);
|
|
284
|
+
vlog(verbose, ` Contribution patterns: ${contributionPatterns.length} detected`);
|
|
285
|
+
// Impact classification
|
|
286
|
+
const classified = classifyImpacts(conventions, antiPatterns);
|
|
287
|
+
vlog(verbose, ` Impact: ${classified.conventions.filter((c) => c.impact === "high").length} high, ${classified.conventions.filter((c) => c.impact === "medium").length} medium, ${classified.conventions.filter((c) => c.impact === "low").length} low`);
|
|
288
|
+
// Improvement 3: Call graph logging
|
|
289
|
+
if (symbolGraph.callGraph.length > 0) {
|
|
290
|
+
vlog(verbose, ` Call graph: ${symbolGraph.callGraph.length} edges`);
|
|
291
|
+
}
|
|
292
|
+
// W2-2: Pattern fingerprinting for top exports
|
|
293
|
+
const patternFingerprints = fingerprintTopExports(publicAPI, pkgPath, 5, warnings);
|
|
294
|
+
if (patternFingerprints.length > 0) {
|
|
295
|
+
vlog(verbose, ` Pattern fingerprints: ${patternFingerprints.length} exports analyzed`);
|
|
296
|
+
}
|
|
297
|
+
// W5-C1: Extract usage examples from test files
|
|
298
|
+
const examples = extractExamples(publicAPI, parsed, pkgPath, 10, warnings);
|
|
299
|
+
if (examples.length > 0) {
|
|
300
|
+
vlog(verbose, ` Usage examples: ${examples.length} extracted from test files`);
|
|
301
|
+
}
|
|
302
|
+
const pkgMs = Math.round(performance.now() - pkgStart);
|
|
303
|
+
vlog(verbose, ` Analysis time: ${pkgMs}ms`);
|
|
304
|
+
return {
|
|
305
|
+
...partialAnalysis,
|
|
306
|
+
conventions: classified.conventions,
|
|
307
|
+
role,
|
|
308
|
+
antiPatterns: classified.antiPatterns,
|
|
309
|
+
contributionPatterns,
|
|
310
|
+
configAnalysis,
|
|
311
|
+
dependencyInsights,
|
|
312
|
+
existingDocs,
|
|
313
|
+
callGraph: symbolGraph.callGraph.length > 0 ? symbolGraph.callGraph : undefined,
|
|
314
|
+
importChain: importChain.length > 0 ? importChain : undefined,
|
|
315
|
+
patternFingerprints: patternFingerprints.length > 0 ? patternFingerprints : undefined,
|
|
316
|
+
examples: examples.length > 0 ? examples : undefined,
|
|
317
|
+
isMetaTool: metaToolResult.isMetaTool || undefined,
|
|
318
|
+
metaToolInfo: metaToolResult.isMetaTool ? {
|
|
319
|
+
signal: metaToolResult.signal,
|
|
320
|
+
supportedFamilies: metaToolResult.supportedFamilies,
|
|
321
|
+
coreFamilies: metaToolResult.coreFamilies,
|
|
322
|
+
} : undefined,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Improvement 1: Adjust commands based on detected build tool (turbo, nx).
|
|
327
|
+
* If turbo.json defines tasks like "build", "test", "lint", "dev",
|
|
328
|
+
* use "turbo run <task>" instead of "<pm> run <script>".
|
|
329
|
+
*/
|
|
330
|
+
function adjustCommandsForBuildTool(commands, buildTool, _warnings) {
|
|
331
|
+
if (buildTool.name !== "turbo" && buildTool.name !== "nx")
|
|
332
|
+
return;
|
|
333
|
+
const prefix = buildTool.name === "turbo" ? "turbo run" : "nx run";
|
|
334
|
+
const taskSet = new Set(buildTool.taskNames);
|
|
335
|
+
const mapping = {
|
|
336
|
+
build: "build",
|
|
337
|
+
test: "test",
|
|
338
|
+
lint: "lint",
|
|
339
|
+
dev: "start",
|
|
340
|
+
start: "start",
|
|
341
|
+
};
|
|
342
|
+
for (const [taskName, cmdField] of Object.entries(mapping)) {
|
|
343
|
+
if (!taskSet.has(taskName))
|
|
344
|
+
continue;
|
|
345
|
+
const existing = commands[cmdField];
|
|
346
|
+
if (existing) {
|
|
347
|
+
// Keep the existing as a variant, use turbo as primary
|
|
348
|
+
const turboCmd = `${prefix} ${taskName}`;
|
|
349
|
+
if (existing.run !== turboCmd) {
|
|
350
|
+
if (!existing.variants)
|
|
351
|
+
existing.variants = [];
|
|
352
|
+
existing.variants.push({ name: "package-level", run: existing.run });
|
|
353
|
+
existing.run = turboCmd;
|
|
354
|
+
existing.source = `${buildTool.configFile} tasks.${taskName}`;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
// Create new command from turbo task
|
|
359
|
+
const newCmd = {
|
|
360
|
+
run: `${prefix} ${taskName}`,
|
|
361
|
+
source: `${buildTool.configFile} tasks.${taskName}`,
|
|
362
|
+
};
|
|
363
|
+
if (cmdField === "build")
|
|
364
|
+
commands.build = newCmd;
|
|
365
|
+
else if (cmdField === "test")
|
|
366
|
+
commands.test = newCmd;
|
|
367
|
+
else if (cmdField === "lint")
|
|
368
|
+
commands.lint = newCmd;
|
|
369
|
+
else if (cmdField === "start")
|
|
370
|
+
commands.start = newCmd;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
//# sourceMappingURL=pipeline.js.map
|