@invariant-ui/cli 0.0.0-stage → 0.1.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 +105 -0
- package/README.md +248 -2
- package/dist/agent-kit/apply.js +232 -0
- package/dist/agent-kit/guidance.js +236 -0
- package/dist/agent-kit/index.js +5 -0
- package/dist/agent-kit/integrations.js +121 -0
- package/dist/agent-kit/plugin.js +115 -0
- package/dist/artifact-generator/index.js +75 -0
- package/dist/browser-verify/driver.js +2 -0
- package/dist/browser-verify/index.js +4 -0
- package/dist/browser-verify/playwright.js +82 -0
- package/dist/browser-verify/runner.js +175 -0
- package/dist/browser-verify/spec.js +103 -0
- package/dist/cli/args.js +77 -0
- package/dist/cli/baseline.js +64 -0
- package/dist/cli/cli.js +121 -0
- package/dist/cli/commands-browser.js +104 -0
- package/dist/cli/commands-discover.js +312 -0
- package/dist/cli/commands-enforcement.js +35 -0
- package/dist/cli/commands-governance.js +179 -0
- package/dist/cli/commands-hook.js +269 -0
- package/dist/cli/commands-patterns.js +324 -0
- package/dist/cli/commands-setup.js +485 -0
- package/dist/cli/commands-validate.js +157 -0
- package/dist/cli/commands.js +517 -0
- package/dist/cli/config.js +197 -0
- package/dist/cli/diff.js +66 -0
- package/dist/cli/enforcement-log.js +83 -0
- package/dist/cli/enforcement-report.js +96 -0
- package/dist/cli/errors.js +10 -0
- package/dist/cli/format.js +22 -0
- package/dist/cli/index.js +5 -0
- package/dist/cli/io.js +2 -0
- package/dist/cli/main.js +31 -0
- package/dist/cli/pipeline.js +262 -0
- package/dist/cli/publish.js +77 -0
- package/dist/cli/report.js +127 -0
- package/dist/cli/starter-rules.js +57 -0
- package/dist/cli/store.js +60 -0
- package/dist/cli/version.js +5 -0
- package/dist/cli/watch.js +68 -0
- package/dist/cli/workflow.js +52 -0
- package/dist/compiler-angular/adapter.js +115 -0
- package/dist/compiler-angular/analyze.js +222 -0
- package/dist/compiler-angular/classes.js +446 -0
- package/dist/compiler-angular/declared.js +285 -0
- package/dist/compiler-angular/emit.js +183 -0
- package/dist/compiler-angular/index.js +4 -0
- package/dist/compiler-angular/template.js +142 -0
- package/dist/compiler-core/adapter.js +2 -0
- package/dist/compiler-core/adapters/inventory.js +312 -0
- package/dist/compiler-core/compile.js +148 -0
- package/dist/compiler-core/component-facts.js +123 -0
- package/dist/compiler-core/discovery/docs.js +66 -0
- package/dist/compiler-core/discovery/entries.js +270 -0
- package/dist/compiler-core/discovery/exports.js +207 -0
- package/dist/compiler-core/discovery/graph.js +59 -0
- package/dist/compiler-core/discovery/index.js +103 -0
- package/dist/compiler-core/discovery/packages.js +148 -0
- package/dist/compiler-core/discovery/schema.js +144 -0
- package/dist/compiler-core/discovery/storybook.js +232 -0
- package/dist/compiler-core/discovery/support.js +82 -0
- package/dist/compiler-core/discovery/tokens.js +186 -0
- package/dist/compiler-core/discovery/tooling.js +146 -0
- package/dist/compiler-core/fs.js +89 -0
- package/dist/compiler-core/glob.js +3 -0
- package/dist/compiler-core/index.js +16 -0
- package/dist/compiler-core/ir-builder.js +68 -0
- package/dist/compiler-core/json-schema.js +11 -0
- package/dist/compiler-core/testing/index.js +81 -0
- package/dist/compiler-core/ts/ast.js +166 -0
- package/dist/compiler-core/ts/members.js +163 -0
- package/dist/compiler-core/ts/program.js +81 -0
- package/dist/compiler-core/ts/static-eval.js +145 -0
- package/dist/compiler-core/ts/tsconfig-paths.js +60 -0
- package/dist/compiler-core/walk.js +46 -0
- package/dist/compiler-ir/index.js +4 -0
- package/dist/compiler-ir/ir.js +67 -0
- package/dist/compiler-ir/json-schema.js +6 -0
- package/dist/compiler-ir/validate.js +116 -0
- package/dist/compiler-react/adapter.js +147 -0
- package/dist/compiler-react/analyze.js +199 -0
- package/dist/compiler-react/ast.js +105 -0
- package/dist/compiler-react/behavior.js +75 -0
- package/dist/compiler-react/detect.js +558 -0
- package/dist/compiler-react/emit.js +188 -0
- package/dist/compiler-react/index.js +2 -0
- package/dist/compiler-react/program.js +58 -0
- package/dist/compiler-react/props.js +157 -0
- package/dist/compiler-react/styling.js +138 -0
- package/dist/compiler-react/usage.js +116 -0
- package/dist/compiler-react/variants.js +111 -0
- package/dist/compiler-storybook/adapter.js +253 -0
- package/dist/compiler-storybook/csf.js +521 -0
- package/dist/compiler-storybook/emit.js +202 -0
- package/dist/compiler-storybook/index-json.js +41 -0
- package/dist/compiler-storybook/index.js +5 -0
- package/dist/compiler-storybook/mdx.js +120 -0
- package/dist/compiler-storybook/static-eval.js +145 -0
- package/dist/compiler-tokens/adapter.js +158 -0
- package/dist/compiler-tokens/css.js +59 -0
- package/dist/compiler-tokens/index.js +5 -0
- package/dist/compiler-tokens/json-lines.js +106 -0
- package/dist/compiler-tokens/json-tokens.js +52 -0
- package/dist/compiler-vue/adapter.js +107 -0
- package/dist/compiler-vue/analyze.js +344 -0
- package/dist/compiler-vue/declared.js +343 -0
- package/dist/compiler-vue/emit.js +129 -0
- package/dist/compiler-vue/index.js +5 -0
- package/dist/compiler-vue/script.js +472 -0
- package/dist/compiler-vue/sfc.js +44 -0
- package/dist/compiler-vue/template.js +73 -0
- package/dist/contract/archetype-checks.js +153 -0
- package/dist/contract/components.js +102 -0
- package/dist/contract/conflicts.js +39 -0
- package/dist/contract/contract.js +46 -0
- package/dist/contract/evidence.js +84 -0
- package/dist/contract/fact-path.js +39 -0
- package/dist/contract/facts.js +62 -0
- package/dist/contract/index.js +16 -0
- package/dist/contract/integrity.js +21 -0
- package/dist/contract/json-schema.js +11 -0
- package/dist/contract/knowledge.js +95 -0
- package/dist/contract/pattern-checks.js +254 -0
- package/dist/contract/patterns.js +225 -0
- package/dist/contract/primitives.js +81 -0
- package/dist/contract/sources.js +30 -0
- package/dist/contract/tokens.js +41 -0
- package/dist/contract/validate.js +253 -0
- package/dist/contract-query/archetype.js +188 -0
- package/dist/contract-query/index.js +6 -0
- package/dist/contract-query/patterns.js +298 -0
- package/dist/contract-query/scan.js +164 -0
- package/dist/contract-query/search.js +132 -0
- package/dist/contract-query/system.js +148 -0
- package/dist/contract-query/validate-code.js +239 -0
- package/dist/contract-query/validate-usage.js +150 -0
- package/dist/contract-query/views.js +288 -0
- package/dist/governance/decisions.js +229 -0
- package/dist/governance/index.js +5 -0
- package/dist/governance/patterns-file.js +156 -0
- package/dist/governance/patterns.js +510 -0
- package/dist/governance/policies.js +148 -0
- package/dist/mcp/index.js +7 -0
- package/dist/mcp/loader.js +70 -0
- package/dist/mcp/protocol.js +27 -0
- package/dist/mcp/resources.js +138 -0
- package/dist/mcp/server.js +177 -0
- package/dist/mcp/stdio.js +28 -0
- package/dist/mcp/tools.js +267 -0
- package/dist/reconciliation/code.js +62 -0
- package/dist/reconciliation/components.js +401 -0
- package/dist/reconciliation/conflicts.js +126 -0
- package/dist/reconciliation/facts.js +41 -0
- package/dist/reconciliation/index.js +7 -0
- package/dist/reconciliation/reconcile.js +134 -0
- package/dist/reconciliation/resolve.js +158 -0
- package/dist/reconciliation/review.js +81 -0
- package/dist/reconciliation/storybook.js +370 -0
- package/dist/reconciliation/tokens.js +179 -0
- package/dist/reconciliation/util.js +55 -0
- package/dist/semantic-engine/additive.js +51 -0
- package/dist/semantic-engine/compounds.js +91 -0
- package/dist/semantic-engine/documents.js +157 -0
- package/dist/semantic-engine/enrich.js +42 -0
- package/dist/semantic-engine/index.js +7 -0
- package/dist/semantic-engine/infer.js +38 -0
- package/dist/semantic-engine/tokens.js +120 -0
- package/dist/shared/canonical.js +65 -0
- package/dist/shared/diagnostic.js +78 -0
- package/dist/shared/glob.js +98 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/json.js +2 -0
- package/dist/validation/card.js +50 -0
- package/dist/validation/discovery/arrangements.js +162 -0
- package/dist/validation/discovery/discover.js +70 -0
- package/dist/validation/discovery/index.js +8 -0
- package/dist/validation/discovery/model.js +127 -0
- package/dist/validation/discovery/promote.js +24 -0
- package/dist/validation/discovery/reviews.js +63 -0
- package/dist/validation/discovery/shapes.js +47 -0
- package/dist/validation/discovery/similar-files.js +146 -0
- package/dist/validation/discovery/util.js +47 -0
- package/dist/validation/index.js +11 -0
- package/dist/validation/interaction-facts.js +341 -0
- package/dist/validation/interaction-workflows.js +633 -0
- package/dist/validation/literals.js +251 -0
- package/dist/validation/pattern-rules.js +608 -0
- package/dist/validation/policy.js +241 -0
- package/dist/validation/report.js +163 -0
- package/dist/validation/rules.js +269 -0
- package/dist/validation/scan.js +295 -0
- package/dist/validation/text.js +34 -0
- package/dist/validation/validate-code.js +513 -0
- package/dist/validation/validate-usage.js +196 -0
- package/package.json +38 -4
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
export function unwrap(node) {
|
|
3
|
+
let current = node;
|
|
4
|
+
while (ts.isParenthesizedExpression(current) ||
|
|
5
|
+
ts.isAsExpression(current) ||
|
|
6
|
+
ts.isSatisfiesExpression(current) ||
|
|
7
|
+
ts.isNonNullExpression(current) ||
|
|
8
|
+
ts.isTypeAssertionExpression(current)) {
|
|
9
|
+
current = current.expression;
|
|
10
|
+
}
|
|
11
|
+
return current;
|
|
12
|
+
}
|
|
13
|
+
export function collapse(text) {
|
|
14
|
+
return text.replace(/\s+/g, " ").trim();
|
|
15
|
+
}
|
|
16
|
+
/** JSON value of a static literal expression, or undefined when the expression is not a plain literal. */
|
|
17
|
+
export function literalValue(expression) {
|
|
18
|
+
const node = unwrap(expression);
|
|
19
|
+
if (ts.isStringLiteralLike(node))
|
|
20
|
+
return node.text;
|
|
21
|
+
if (ts.isNumericLiteral(node))
|
|
22
|
+
return Number(node.text);
|
|
23
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword)
|
|
24
|
+
return true;
|
|
25
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword)
|
|
26
|
+
return false;
|
|
27
|
+
if (node.kind === ts.SyntaxKind.NullKeyword)
|
|
28
|
+
return null;
|
|
29
|
+
if (ts.isPrefixUnaryExpression(node) &&
|
|
30
|
+
node.operator === ts.SyntaxKind.MinusToken &&
|
|
31
|
+
ts.isNumericLiteral(node.operand)) {
|
|
32
|
+
return -Number(node.operand.text);
|
|
33
|
+
}
|
|
34
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
35
|
+
const items = node.elements.map((e) => literalValue(e));
|
|
36
|
+
return items.every((i) => i !== undefined) ? items : undefined;
|
|
37
|
+
}
|
|
38
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
39
|
+
const out = {};
|
|
40
|
+
for (const p of node.properties) {
|
|
41
|
+
if (!ts.isPropertyAssignment(p) || !(ts.isIdentifier(p.name) || ts.isStringLiteralLike(p.name)))
|
|
42
|
+
return undefined;
|
|
43
|
+
const v = literalValue(p.initializer);
|
|
44
|
+
if (v === undefined)
|
|
45
|
+
return undefined;
|
|
46
|
+
out[p.name.text] = v;
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
export function lineOf(node) {
|
|
53
|
+
const sf = node.getSourceFile();
|
|
54
|
+
return sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1;
|
|
55
|
+
}
|
|
56
|
+
/** First source line of a node, trimmed and bounded, for use as an evidence excerpt. */
|
|
57
|
+
export function excerpt(node) {
|
|
58
|
+
const text = node.getText(node.getSourceFile());
|
|
59
|
+
return collapse(text.split("\n")[0] ?? "").slice(0, 200);
|
|
60
|
+
}
|
|
61
|
+
export function relativeFileOf(analysis, node) {
|
|
62
|
+
return analysis.relativePath(node.getSourceFile().fileName);
|
|
63
|
+
}
|
|
64
|
+
export function isProjectNode(analysis, node) {
|
|
65
|
+
return relativeFileOf(analysis, node) !== undefined;
|
|
66
|
+
}
|
|
67
|
+
export function hasModifier(node, kind) {
|
|
68
|
+
return ts.canHaveModifiers(node) && !!ts.getModifiers(node)?.some((m) => m.kind === kind);
|
|
69
|
+
}
|
|
70
|
+
/** Resolves aliases (imports and re-exports) to the symbol that declares the value. */
|
|
71
|
+
export function resolveSymbol(checker, symbol) {
|
|
72
|
+
if (!symbol)
|
|
73
|
+
return undefined;
|
|
74
|
+
return symbol.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
75
|
+
}
|
|
76
|
+
export function declarationOf(symbol) {
|
|
77
|
+
return symbol?.valueDeclaration ?? symbol?.declarations?.[0];
|
|
78
|
+
}
|
|
79
|
+
/** `Foo.bar = value` assignments at the top level of a file, keyed `Foo.bar`. */
|
|
80
|
+
export function topLevelAssignments(sf) {
|
|
81
|
+
const out = new Map();
|
|
82
|
+
for (const statement of sf.statements) {
|
|
83
|
+
if (!ts.isExpressionStatement(statement))
|
|
84
|
+
continue;
|
|
85
|
+
const e = statement.expression;
|
|
86
|
+
if (ts.isBinaryExpression(e) &&
|
|
87
|
+
e.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
88
|
+
ts.isPropertyAccessExpression(e.left) &&
|
|
89
|
+
ts.isIdentifier(e.left.expression)) {
|
|
90
|
+
out.set(`${e.left.expression.text}.${e.left.name.text}`, e.right);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
/** Walks `node` without descending into nested function-like bodies (other than `node` itself). */
|
|
96
|
+
export function walkSameFunction(node, visit) {
|
|
97
|
+
const go = (n) => {
|
|
98
|
+
if (n !== node && ts.isFunctionLike(n))
|
|
99
|
+
return;
|
|
100
|
+
visit(n);
|
|
101
|
+
ts.forEachChild(n, go);
|
|
102
|
+
};
|
|
103
|
+
ts.forEachChild(node, go);
|
|
104
|
+
}
|
|
105
|
+
export function subTarget(checker, node) {
|
|
106
|
+
if (ts.isShorthandPropertyAssignment(node))
|
|
107
|
+
return declarationOf(resolveSymbol(checker, checker.getShorthandAssignmentValueSymbol(node)));
|
|
108
|
+
const expression = ts.isPropertyAssignment(node)
|
|
109
|
+
? unwrap(node.initializer)
|
|
110
|
+
: ts.isExpression(node)
|
|
111
|
+
? unwrap(node)
|
|
112
|
+
: undefined;
|
|
113
|
+
if (expression && ts.isIdentifier(expression))
|
|
114
|
+
return declarationOf(resolveSymbol(checker, checker.getSymbolAtLocation(expression)));
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
/** Declaration a JSX tag refers to, following imports, `export default X`, and `Root.Child` properties. */
|
|
118
|
+
export function jsxTargetDeclaration(checker, tag) {
|
|
119
|
+
const symbol = ts.isPropertyAccessExpression(tag)
|
|
120
|
+
? checker.getSymbolAtLocation(tag.name)
|
|
121
|
+
: checker.getSymbolAtLocation(tag);
|
|
122
|
+
let decl = declarationOf(resolveSymbol(checker, symbol));
|
|
123
|
+
for (let hops = 0; decl && hops < 4; hops++) {
|
|
124
|
+
if (ts.isExportAssignment(decl)) {
|
|
125
|
+
const e = unwrap(decl.expression);
|
|
126
|
+
decl = ts.isIdentifier(e) ? declarationOf(resolveSymbol(checker, checker.getSymbolAtLocation(e))) : decl;
|
|
127
|
+
if (!ts.isExportAssignment(decl))
|
|
128
|
+
continue;
|
|
129
|
+
return decl;
|
|
130
|
+
}
|
|
131
|
+
if (ts.isPropertyAssignment(decl) || ts.isShorthandPropertyAssignment(decl)) {
|
|
132
|
+
decl = subTarget(checker, decl);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (ts.isPropertyAccessExpression(decl) &&
|
|
136
|
+
ts.isBinaryExpression(decl.parent) &&
|
|
137
|
+
decl.parent.left === decl) {
|
|
138
|
+
decl = subTarget(checker, decl.parent.right);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
return decl;
|
|
142
|
+
}
|
|
143
|
+
return decl;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Component name for a single-file component path: the PascalCase file name (`button-group.vue` is
|
|
147
|
+
* `ButtonGroup`). This is the convention both the Vue adapter and Storybook linking use.
|
|
148
|
+
*/
|
|
149
|
+
export function componentNameFromFile(path) {
|
|
150
|
+
const base = path.replace(/^.*\//, "").replace(/\.[^.]+$/, "");
|
|
151
|
+
return base
|
|
152
|
+
.split(/[-_.\s]+/)
|
|
153
|
+
.filter(Boolean)
|
|
154
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
155
|
+
.join("");
|
|
156
|
+
}
|
|
157
|
+
/** The name and type arguments of `Foo<P>`, `ns.Foo<P>` and `import("pkg").Foo<P>`: the written form, nothing resolved. */
|
|
158
|
+
export function typeReferenceInfo(type) {
|
|
159
|
+
const lastName = (n) => (ts.isQualifiedName(n) ? n.right.text : n.text);
|
|
160
|
+
if (ts.isTypeReferenceNode(type))
|
|
161
|
+
return { name: lastName(type.typeName), typeArguments: type.typeArguments ?? [] };
|
|
162
|
+
if (ts.isImportTypeNode(type) && type.qualifier)
|
|
163
|
+
return { name: lastName(type.qualifier), typeArguments: type.typeArguments ?? [] };
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=ast.js.map
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { collapse, declarationOf, isProjectNode, lineOf, resolveSymbol } from "./ast.js";
|
|
3
|
+
const UTILITY_TYPES = new Set(["Omit", "Pick", "Partial", "Required", "Readonly"]);
|
|
4
|
+
/**
|
|
5
|
+
* Properties of `type` declared inside the analyzed project. Members inherited from types outside the
|
|
6
|
+
* project (or unresolved) are not returned; use `externalBases` to report them.
|
|
7
|
+
*/
|
|
8
|
+
export function ownProperties(analysis, type) {
|
|
9
|
+
const out = [];
|
|
10
|
+
for (const symbol of analysis.checker.getPropertiesOfType(type)) {
|
|
11
|
+
const declaration = symbol.valueDeclaration ?? symbol.declarations?.[0];
|
|
12
|
+
if (declaration && isProjectNode(analysis, declaration))
|
|
13
|
+
out.push({ symbol, declaration });
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Describes one property: its declared type text, a framework-neutral kind, whether it is required,
|
|
19
|
+
* its literal domain in declaration order, and its JSDoc description and deprecation. `renderable`
|
|
20
|
+
* marks a framework's "renderable content" types (for example React's ReactNode) as kind `component`.
|
|
21
|
+
*/
|
|
22
|
+
export function describeMember(analysis, symbol, declaration, options = {}) {
|
|
23
|
+
const { checker } = analysis;
|
|
24
|
+
const typeNode = ts.isPropertySignature(declaration) || ts.isPropertyDeclaration(declaration)
|
|
25
|
+
? declaration.type
|
|
26
|
+
: undefined;
|
|
27
|
+
const type = checker.getTypeOfSymbolAtLocation(symbol, declaration);
|
|
28
|
+
const typeText = collapse(typeNode ? typeNode.getText() : checker.typeToString(type));
|
|
29
|
+
const kind = classifyKind(checker, type, typeText, options.renderable);
|
|
30
|
+
const allowedValues = allowedValuesOf(checker, typeNode, type, kind);
|
|
31
|
+
const doc = ts.displayPartsToString(symbol.getDocumentationComment(checker)).trim();
|
|
32
|
+
const deprecatedTag = symbol.getJsDocTags(checker).find((t) => t.name === "deprecated");
|
|
33
|
+
const deprecatedText = deprecatedTag ? ts.displayPartsToString(deprecatedTag.text).trim() : undefined;
|
|
34
|
+
const parentName = declarationParentName(declaration);
|
|
35
|
+
return {
|
|
36
|
+
name: symbol.name,
|
|
37
|
+
typeText,
|
|
38
|
+
kind,
|
|
39
|
+
required: (symbol.flags & ts.SymbolFlags.Optional) === 0,
|
|
40
|
+
...(allowedValues ? { allowedValues } : {}),
|
|
41
|
+
...(doc ? { description: doc } : {}),
|
|
42
|
+
...(deprecatedTag ? { deprecated: deprecatedText ? { reason: deprecatedText } : {} } : {}),
|
|
43
|
+
...(parentName ? { parentName } : {}),
|
|
44
|
+
node: declaration,
|
|
45
|
+
line: lineOf(declaration)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function classifyKind(checker, type, typeText, renderable) {
|
|
49
|
+
if (renderable?.test(typeText.replace(/\s*\|\s*(?:undefined|null)/g, "")))
|
|
50
|
+
return "component";
|
|
51
|
+
const nonNull = checker.getNonNullableType(type);
|
|
52
|
+
if (nonNull.getCallSignatures().length > 0)
|
|
53
|
+
return "function";
|
|
54
|
+
if (nonNull.flags & ts.TypeFlags.BooleanLike)
|
|
55
|
+
return "boolean";
|
|
56
|
+
if (nonNull.isUnion()) {
|
|
57
|
+
const parts = nonNull.types;
|
|
58
|
+
if (parts.every((t) => t.flags & ts.TypeFlags.BooleanLiteral))
|
|
59
|
+
return "boolean";
|
|
60
|
+
if (parts.every((t) => t.flags & (ts.TypeFlags.StringLiteral | ts.TypeFlags.NumberLiteral | ts.TypeFlags.BooleanLiteral)))
|
|
61
|
+
return "enum";
|
|
62
|
+
return "union";
|
|
63
|
+
}
|
|
64
|
+
if (nonNull.flags & ts.TypeFlags.StringLike)
|
|
65
|
+
return nonNull.flags & ts.TypeFlags.StringLiteral ? "enum" : "string";
|
|
66
|
+
if (nonNull.flags & ts.TypeFlags.NumberLike)
|
|
67
|
+
return nonNull.flags & ts.TypeFlags.NumberLiteral ? "enum" : "number";
|
|
68
|
+
if (checker.isArrayType(nonNull) || checker.isTupleType(nonNull))
|
|
69
|
+
return "array";
|
|
70
|
+
if (nonNull.flags & ts.TypeFlags.Object)
|
|
71
|
+
return "object";
|
|
72
|
+
return "unknown";
|
|
73
|
+
}
|
|
74
|
+
/** Finite literal domain in declaration order when the declared type is a union of literals (through aliases). */
|
|
75
|
+
export function allowedValuesOf(checker, typeNode, type, kind) {
|
|
76
|
+
if (kind !== "enum")
|
|
77
|
+
return undefined;
|
|
78
|
+
const ordered = typeNode ? literalDomain(checker, typeNode, 0) : undefined;
|
|
79
|
+
if (ordered && ordered.length > 0)
|
|
80
|
+
return ordered;
|
|
81
|
+
const nonNull = checker.getNonNullableType(type);
|
|
82
|
+
const parts = nonNull.isUnion() ? nonNull.types : [nonNull];
|
|
83
|
+
const values = parts.flatMap((t) => (t.isStringLiteral() || t.isNumberLiteral() ? [t.value] : []));
|
|
84
|
+
return values.length > 0 ? values.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)) : undefined;
|
|
85
|
+
}
|
|
86
|
+
/** Ordered literal values of a union-of-literals type node, or undefined when any member is not a literal. */
|
|
87
|
+
export function literalDomain(checker, node, depth = 0) {
|
|
88
|
+
if (depth > 5)
|
|
89
|
+
return undefined;
|
|
90
|
+
if (ts.isParenthesizedTypeNode(node))
|
|
91
|
+
return literalDomain(checker, node.type, depth + 1);
|
|
92
|
+
if (ts.isUnionTypeNode(node)) {
|
|
93
|
+
const parts = node.types.map((t) => literalDomain(checker, t, depth + 1));
|
|
94
|
+
return parts.every((p) => p !== undefined)
|
|
95
|
+
? parts.flat()
|
|
96
|
+
: undefined;
|
|
97
|
+
}
|
|
98
|
+
if (ts.isLiteralTypeNode(node)) {
|
|
99
|
+
const literal = node.literal;
|
|
100
|
+
if (ts.isStringLiteral(literal))
|
|
101
|
+
return [literal.text];
|
|
102
|
+
if (ts.isNumericLiteral(literal))
|
|
103
|
+
return [Number(literal.text)];
|
|
104
|
+
if (literal.kind === ts.SyntaxKind.NullKeyword)
|
|
105
|
+
return [];
|
|
106
|
+
if (literal.kind === ts.SyntaxKind.TrueKeyword)
|
|
107
|
+
return [true];
|
|
108
|
+
if (literal.kind === ts.SyntaxKind.FalseKeyword)
|
|
109
|
+
return [false];
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
if (node.kind === ts.SyntaxKind.UndefinedKeyword)
|
|
113
|
+
return [];
|
|
114
|
+
if (ts.isTypeReferenceNode(node)) {
|
|
115
|
+
const target = declarationOf(resolveSymbol(checker, checker.getSymbolAtLocation(node.typeName)));
|
|
116
|
+
if (target && ts.isTypeAliasDeclaration(target))
|
|
117
|
+
return literalDomain(checker, target.type, depth + 1);
|
|
118
|
+
}
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
export function declarationParentName(declaration) {
|
|
122
|
+
const parent = declaration.parent;
|
|
123
|
+
if (ts.isInterfaceDeclaration(parent) || ts.isClassDeclaration(parent))
|
|
124
|
+
return parent.name?.text;
|
|
125
|
+
if (ts.isTypeLiteralNode(parent) && ts.isTypeAliasDeclaration(parent.parent))
|
|
126
|
+
return parent.parent.name.text;
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
/** Types in the heritage of a props type that are external to the project or unresolved. */
|
|
130
|
+
export function externalBases(analysis, node, depth = 0) {
|
|
131
|
+
if (!node || depth > 6)
|
|
132
|
+
return [];
|
|
133
|
+
const { checker } = analysis;
|
|
134
|
+
if (ts.isIntersectionTypeNode(node) || ts.isUnionTypeNode(node))
|
|
135
|
+
return node.types.flatMap((t) => externalBases(analysis, t, depth + 1));
|
|
136
|
+
if (ts.isParenthesizedTypeNode(node))
|
|
137
|
+
return externalBases(analysis, node.type, depth + 1);
|
|
138
|
+
// `import("pkg").Type` always refers to something outside the analyzed project.
|
|
139
|
+
if (ts.isImportTypeNode(node))
|
|
140
|
+
return [collapse(node.getText())];
|
|
141
|
+
const reference = ts.isTypeReferenceNode(node)
|
|
142
|
+
? { name: node.typeName, args: node.typeArguments }
|
|
143
|
+
: ts.isExpressionWithTypeArguments(node)
|
|
144
|
+
? { name: node.expression, args: node.typeArguments }
|
|
145
|
+
: undefined;
|
|
146
|
+
if (!reference)
|
|
147
|
+
return [];
|
|
148
|
+
const text = collapse(node.getText());
|
|
149
|
+
if (UTILITY_TYPES.has(reference.name.getText()) && reference.args?.[0])
|
|
150
|
+
return externalBases(analysis, reference.args[0], depth + 1);
|
|
151
|
+
const symbol = resolveSymbol(checker, checker.getSymbolAtLocation(reference.name));
|
|
152
|
+
const local = (symbol?.declarations ?? []).filter((d) => isProjectNode(analysis, d));
|
|
153
|
+
if (local.length === 0)
|
|
154
|
+
return [text];
|
|
155
|
+
return local.flatMap((d) => {
|
|
156
|
+
if (ts.isInterfaceDeclaration(d))
|
|
157
|
+
return (d.heritageClauses ?? []).flatMap((h) => h.types.flatMap((t) => externalBases(analysis, t, depth + 1)));
|
|
158
|
+
if (ts.isTypeAliasDeclaration(d))
|
|
159
|
+
return externalBases(analysis, d.type, depth + 1);
|
|
160
|
+
return [];
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=members.js.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { posix } from "node:path";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
/**
|
|
5
|
+
* Builds a type-checking program over the supplied project files only. Nothing is read from
|
|
6
|
+
* `node_modules` and no customer code runs: third-party types (including `@types/react`) are not
|
|
7
|
+
* loaded, so references to them stay unresolved and are reported as such rather than guessed.
|
|
8
|
+
* TypeScript's own `lib.es2022.d.ts` is read so built-in utility types like `Omit` resolve.
|
|
9
|
+
*/
|
|
10
|
+
export function createAnalysis(files, extra = {}) {
|
|
11
|
+
const virtual = new Map([...files].map(([rel, text]) => [`/${rel}`, text]));
|
|
12
|
+
const external = new Map([...(extra.externalFiles ?? [])].map(([rel, text]) => [`/${rel}`, text]));
|
|
13
|
+
const options = {
|
|
14
|
+
target: ts.ScriptTarget.ES2022,
|
|
15
|
+
module: ts.ModuleKind.ESNext,
|
|
16
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
17
|
+
jsx: ts.JsxEmit.ReactJSX,
|
|
18
|
+
lib: ["lib.es2022.d.ts"],
|
|
19
|
+
types: [],
|
|
20
|
+
strict: true,
|
|
21
|
+
allowJs: true,
|
|
22
|
+
checkJs: false,
|
|
23
|
+
noEmit: true,
|
|
24
|
+
skipLibCheck: true,
|
|
25
|
+
resolveJsonModule: true,
|
|
26
|
+
allowArbitraryExtensions: true,
|
|
27
|
+
// Workspace package names resolved to project-relative entry files (supplied by the caller).
|
|
28
|
+
...(extra.paths
|
|
29
|
+
? {
|
|
30
|
+
baseUrl: "/",
|
|
31
|
+
paths: Object.fromEntries(Object.entries(extra.paths).map(([name, targets]) => [name, targets.map((t) => `/${t}`)]))
|
|
32
|
+
}
|
|
33
|
+
: {})
|
|
34
|
+
};
|
|
35
|
+
const libDir = ts.getDefaultLibFilePath(options).replace(/[^/\\]+$/, "");
|
|
36
|
+
const isLib = (file) => file.startsWith(libDir);
|
|
37
|
+
const read = (file) => {
|
|
38
|
+
const text = virtual.get(file) ?? external.get(file);
|
|
39
|
+
if (text !== undefined)
|
|
40
|
+
return text;
|
|
41
|
+
return isLib(file) && existsSync(file) ? readFileSync(file, "utf8") : undefined;
|
|
42
|
+
};
|
|
43
|
+
const host = {
|
|
44
|
+
getSourceFile: (file, languageVersion) => {
|
|
45
|
+
const text = read(file);
|
|
46
|
+
return text === undefined ? undefined : ts.createSourceFile(file, text, languageVersion, true);
|
|
47
|
+
},
|
|
48
|
+
getDefaultLibFileName: (o) => ts.getDefaultLibFilePath(o),
|
|
49
|
+
writeFile: () => { },
|
|
50
|
+
getCurrentDirectory: () => "/",
|
|
51
|
+
getDirectories: () => [],
|
|
52
|
+
fileExists: (file) => read(file) !== undefined,
|
|
53
|
+
readFile: read,
|
|
54
|
+
getCanonicalFileName: (file) => file,
|
|
55
|
+
useCaseSensitiveFileNames: () => true,
|
|
56
|
+
getNewLine: () => "\n",
|
|
57
|
+
...(extra.moduleAliases
|
|
58
|
+
? {
|
|
59
|
+
resolveModuleNames: (names, containingFile) => names.map((name) => {
|
|
60
|
+
const aliases = extra.moduleAliases;
|
|
61
|
+
if (name.startsWith(".")) {
|
|
62
|
+
const target = aliases[posix.normalize(posix.join(posix.dirname(containingFile.slice(1)), name))];
|
|
63
|
+
if (target)
|
|
64
|
+
return { resolvedFileName: `/${target}`, extension: ts.Extension.Ts };
|
|
65
|
+
}
|
|
66
|
+
return ts.resolveModuleName(name, containingFile, options, host).resolvedModule;
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
: {})
|
|
70
|
+
};
|
|
71
|
+
const roots = [...virtual.keys()].filter((f) => /\.(?:[cm]?[jt]sx?)$/.test(f));
|
|
72
|
+
const program = ts.createProgram({ rootNames: roots, options, host });
|
|
73
|
+
return {
|
|
74
|
+
program,
|
|
75
|
+
checker: program.getTypeChecker(),
|
|
76
|
+
relativePath: (fileName) => (virtual.has(fileName) ? fileName.slice(1) : undefined),
|
|
77
|
+
sourceFile: (rel) => program.getSourceFile(`/${rel}`),
|
|
78
|
+
hasFile: (rel) => virtual.has(`/${rel}`)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=program.js.map
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { declarationOf, resolveSymbol, unwrap } from "../index.js";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
const MAX_DEPTH = 8;
|
|
4
|
+
const SPY_CALLEES = new Set(["fn", "action"]);
|
|
5
|
+
export function evaluate(checker, expression, depth = 0) {
|
|
6
|
+
const node = unwrap(expression);
|
|
7
|
+
if (depth > MAX_DEPTH)
|
|
8
|
+
return dynamic();
|
|
9
|
+
if (ts.isStringLiteralLike(node))
|
|
10
|
+
return resolved(node.text);
|
|
11
|
+
if (ts.isNumericLiteral(node))
|
|
12
|
+
return resolved(Number(node.text));
|
|
13
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword)
|
|
14
|
+
return resolved(true);
|
|
15
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword)
|
|
16
|
+
return resolved(false);
|
|
17
|
+
if (node.kind === ts.SyntaxKind.NullKeyword)
|
|
18
|
+
return resolved(null);
|
|
19
|
+
if (ts.isIdentifier(node) && node.text === "undefined")
|
|
20
|
+
return { unresolved: [], spies: [] };
|
|
21
|
+
if (ts.isPrefixUnaryExpression(node) &&
|
|
22
|
+
node.operator === ts.SyntaxKind.MinusToken &&
|
|
23
|
+
ts.isNumericLiteral(node.operand)) {
|
|
24
|
+
return resolved(-Number(node.operand.text));
|
|
25
|
+
}
|
|
26
|
+
if (ts.isObjectLiteralExpression(node))
|
|
27
|
+
return evaluateObject(checker, node, depth);
|
|
28
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
29
|
+
const items = [];
|
|
30
|
+
const unresolved = [];
|
|
31
|
+
for (const element of node.elements) {
|
|
32
|
+
const inner = evaluate(checker, element, depth + 1);
|
|
33
|
+
if (inner.value === undefined || inner.unresolved.length > 0)
|
|
34
|
+
unresolved.push("[]");
|
|
35
|
+
else
|
|
36
|
+
items.push(inner.value);
|
|
37
|
+
}
|
|
38
|
+
// An array with any unresolvable element is not partially trusted.
|
|
39
|
+
return unresolved.length > 0 ? dynamic() : resolved(items);
|
|
40
|
+
}
|
|
41
|
+
if (ts.isIdentifier(node)) {
|
|
42
|
+
const decl = declarationOf(resolveSymbol(checker, checker.getSymbolAtLocation(node)));
|
|
43
|
+
if (decl && ts.isVariableDeclaration(decl) && decl.initializer && decl !== node.parent)
|
|
44
|
+
return evaluate(checker, decl.initializer, depth + 1);
|
|
45
|
+
return dynamic();
|
|
46
|
+
}
|
|
47
|
+
if (ts.isPropertyAccessExpression(node) ||
|
|
48
|
+
(ts.isElementAccessExpression(node) &&
|
|
49
|
+
node.argumentExpression &&
|
|
50
|
+
ts.isStringLiteralLike(node.argumentExpression))) {
|
|
51
|
+
const key = ts.isPropertyAccessExpression(node)
|
|
52
|
+
? node.name.text
|
|
53
|
+
: node.argumentExpression.text;
|
|
54
|
+
const base = evaluate(checker, node.expression, depth + 1);
|
|
55
|
+
if (base.value !== null &&
|
|
56
|
+
typeof base.value === "object" &&
|
|
57
|
+
!Array.isArray(base.value) &&
|
|
58
|
+
key in base.value) {
|
|
59
|
+
const picked = base.value[key];
|
|
60
|
+
return {
|
|
61
|
+
...(picked === undefined ? {} : { value: picked }),
|
|
62
|
+
unresolved: base.unresolved
|
|
63
|
+
.filter((p) => p === key || p.startsWith(`${key}.`))
|
|
64
|
+
.map((p) => (p === key ? "" : p.slice(key.length + 1))),
|
|
65
|
+
spies: base.spies
|
|
66
|
+
.filter((p) => p === key || p.startsWith(`${key}.`))
|
|
67
|
+
.map((p) => (p === key ? "" : p.slice(key.length + 1)))
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return dynamic();
|
|
71
|
+
}
|
|
72
|
+
if (ts.isCallExpression(node) && SPY_CALLEES.has(node.expression.getText().replace(/^.*\./, ""))) {
|
|
73
|
+
return { unresolved: [""], spies: [""] };
|
|
74
|
+
}
|
|
75
|
+
return dynamic();
|
|
76
|
+
}
|
|
77
|
+
function evaluateObject(checker, node, depth) {
|
|
78
|
+
const value = {};
|
|
79
|
+
const unresolved = [];
|
|
80
|
+
const spies = [];
|
|
81
|
+
const keys = new Set();
|
|
82
|
+
const mark = (key, inner) => {
|
|
83
|
+
for (const p of inner.unresolved)
|
|
84
|
+
unresolved.push(p === "" ? key : `${key}.${p}`);
|
|
85
|
+
for (const p of inner.spies)
|
|
86
|
+
spies.push(p === "" ? key : `${key}.${p}`);
|
|
87
|
+
};
|
|
88
|
+
for (const property of node.properties) {
|
|
89
|
+
if (ts.isSpreadAssignment(property)) {
|
|
90
|
+
const inner = evaluate(checker, property.expression, depth + 1);
|
|
91
|
+
if (inner.value !== null && typeof inner.value === "object" && !Array.isArray(inner.value)) {
|
|
92
|
+
for (const [k, v] of Object.entries(inner.value))
|
|
93
|
+
value[k] = v;
|
|
94
|
+
for (const k of inner.keys ?? Object.keys(inner.value))
|
|
95
|
+
keys.add(k);
|
|
96
|
+
unresolved.push(...inner.unresolved);
|
|
97
|
+
spies.push(...inner.spies);
|
|
98
|
+
}
|
|
99
|
+
else
|
|
100
|
+
unresolved.push("...");
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const name = propertyName(property);
|
|
104
|
+
if (name === undefined) {
|
|
105
|
+
unresolved.push("<computed>");
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
keys.add(name);
|
|
109
|
+
if (ts.isPropertyAssignment(property)) {
|
|
110
|
+
const inner = evaluate(checker, property.initializer, depth + 1);
|
|
111
|
+
if (inner.value !== undefined)
|
|
112
|
+
value[name] = inner.value;
|
|
113
|
+
mark(name, inner);
|
|
114
|
+
}
|
|
115
|
+
else if (ts.isShorthandPropertyAssignment(property)) {
|
|
116
|
+
const target = declarationOf(resolveSymbol(checker, checker.getShorthandAssignmentValueSymbol(property)));
|
|
117
|
+
const inner = target && ts.isVariableDeclaration(target) && target.initializer
|
|
118
|
+
? evaluate(checker, target.initializer, depth + 1)
|
|
119
|
+
: dynamic();
|
|
120
|
+
if (inner.value !== undefined)
|
|
121
|
+
value[name] = inner.value;
|
|
122
|
+
mark(name, inner);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
// Methods and accessors: present, but not statically evaluable.
|
|
126
|
+
unresolved.push(name);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { value, unresolved, spies, keys: [...keys].sort() };
|
|
130
|
+
}
|
|
131
|
+
function propertyName(property) {
|
|
132
|
+
const name = property.name;
|
|
133
|
+
if (!name)
|
|
134
|
+
return undefined;
|
|
135
|
+
if (ts.isIdentifier(name) || ts.isStringLiteralLike(name) || ts.isNumericLiteral(name))
|
|
136
|
+
return name.text;
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
function resolved(value) {
|
|
140
|
+
return { value, unresolved: [], spies: [] };
|
|
141
|
+
}
|
|
142
|
+
function dynamic() {
|
|
143
|
+
return { unresolved: [""], spies: [] };
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=static-eval.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
/** True for files that tsconfigPaths reads (`tsconfig.json`, `tsconfig.app.json`, ...). */
|
|
4
|
+
export const TSCONFIG_FILE = /(?:^|\/)tsconfig[^/]*\.json$/;
|
|
5
|
+
/**
|
|
6
|
+
* `compilerOptions.paths` for a package, as project-relative targets, so import aliases such as
|
|
7
|
+
* `@/Primitive` resolve in the analysis program. Follows relative `extends` and `references` (a common
|
|
8
|
+
* layout is a solution-style `tsconfig.json` whose real options live in `tsconfig.app.json`). Later
|
|
9
|
+
* configs override earlier ones; targets are resolved against `baseUrl` when set, else the config's
|
|
10
|
+
* directory. Nothing is executed and `node_modules` configs (`extends` from packages) are not read.
|
|
11
|
+
*/
|
|
12
|
+
export function tsconfigPaths(files, packageDir) {
|
|
13
|
+
const out = {};
|
|
14
|
+
const seen = new Set();
|
|
15
|
+
const visit = (file, depth) => {
|
|
16
|
+
if (depth > 6 || seen.has(file))
|
|
17
|
+
return;
|
|
18
|
+
seen.add(file);
|
|
19
|
+
const text = files.get(file);
|
|
20
|
+
if (text === undefined)
|
|
21
|
+
return;
|
|
22
|
+
const config = ts.parseConfigFileTextToJson(file, text).config;
|
|
23
|
+
if (!isRecord(config))
|
|
24
|
+
return;
|
|
25
|
+
const here = posix.dirname(file);
|
|
26
|
+
for (const parent of toArray(config.extends)) {
|
|
27
|
+
if (typeof parent === "string" && parent.startsWith("."))
|
|
28
|
+
visit(withJson(files, posix.normalize(posix.join(here, parent))), depth + 1);
|
|
29
|
+
}
|
|
30
|
+
const options = config.compilerOptions;
|
|
31
|
+
if (isRecord(options) && isRecord(options.paths)) {
|
|
32
|
+
const base = typeof options.baseUrl === "string" ? posix.normalize(posix.join(here, options.baseUrl)) : here;
|
|
33
|
+
for (const [pattern, targets] of Object.entries(options.paths)) {
|
|
34
|
+
const resolved = toArray(targets).flatMap((t) => typeof t === "string" ? [posix.normalize(posix.join(base, t))] : []);
|
|
35
|
+
if (resolved.length > 0)
|
|
36
|
+
out[pattern] = resolved;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
for (const reference of toArray(config.references)) {
|
|
40
|
+
if (isRecord(reference) && typeof reference.path === "string") {
|
|
41
|
+
visit(configFile(files, posix.normalize(posix.join(here, reference.path))), depth + 1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
visit(posix.join(packageDir, "tsconfig.json"), 0);
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
function withJson(files, path) {
|
|
49
|
+
return files.has(path) ? path : `${path}.json`;
|
|
50
|
+
}
|
|
51
|
+
function configFile(files, path) {
|
|
52
|
+
return files.has(path) ? path : posix.join(path, "tsconfig.json");
|
|
53
|
+
}
|
|
54
|
+
function toArray(value) {
|
|
55
|
+
return Array.isArray(value) ? value : value === undefined ? [] : [value];
|
|
56
|
+
}
|
|
57
|
+
function isRecord(value) {
|
|
58
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=tsconfig-paths.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const DEFAULT_IGNORED_DIRS = [
|
|
2
|
+
"node_modules",
|
|
3
|
+
".git",
|
|
4
|
+
"dist",
|
|
5
|
+
"build",
|
|
6
|
+
"out",
|
|
7
|
+
"coverage",
|
|
8
|
+
".next",
|
|
9
|
+
".nuxt",
|
|
10
|
+
".turbo",
|
|
11
|
+
".cache",
|
|
12
|
+
".angular",
|
|
13
|
+
".svelte-kit",
|
|
14
|
+
".output",
|
|
15
|
+
".pnpm-store",
|
|
16
|
+
"storybook-static"
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* Deterministic walk: sorted traversal, ignored directories skipped, symlinks never followed.
|
|
20
|
+
* Stops at `maxFiles` and reports truncation rather than silently returning a partial list.
|
|
21
|
+
*/
|
|
22
|
+
export async function walk(fs, options) {
|
|
23
|
+
const files = [];
|
|
24
|
+
let truncated = false;
|
|
25
|
+
const visit = async (dir) => {
|
|
26
|
+
for (const entry of await fs.readDir(dir)) {
|
|
27
|
+
if (truncated)
|
|
28
|
+
return;
|
|
29
|
+
const child = dir === "." ? entry.name : `${dir}/${entry.name}`;
|
|
30
|
+
if (entry.kind === "dir") {
|
|
31
|
+
if (!options.ignoreDirs.has(entry.name))
|
|
32
|
+
await visit(child);
|
|
33
|
+
}
|
|
34
|
+
else if (entry.kind === "file") {
|
|
35
|
+
if (files.length >= options.maxFiles) {
|
|
36
|
+
truncated = true;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
files.push(child);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
await visit(options.start ?? ".");
|
|
44
|
+
return { files: files.sort(), truncated };
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=walk.js.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { IR_VERSION, irDocumentSchema, irEntitySchema, irFactSchema } from "./ir.js";
|
|
2
|
+
export { irJsonSchemas } from "./json-schema.js";
|
|
3
|
+
export { canonicalizeIrDocument, computeIrContentHash, matchesCapability, parseIrDocument, serializeIrDocument, verifyIrDocument } from "./validate.js";
|
|
4
|
+
//# sourceMappingURL=index.js.map
|