@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,295 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
const dyn = (text) => ({ expression: text.replace(/\s+/g, " ").trim().slice(0, 80) });
|
|
3
|
+
function jsxValue(init, sf) {
|
|
4
|
+
if (!init)
|
|
5
|
+
return true;
|
|
6
|
+
if (ts.isStringLiteral(init))
|
|
7
|
+
return init.text;
|
|
8
|
+
if (ts.isJsxExpression(init) && init.expression) {
|
|
9
|
+
const e = init.expression;
|
|
10
|
+
if (ts.isStringLiteralLike(e))
|
|
11
|
+
return e.text;
|
|
12
|
+
if (ts.isNumericLiteral(e))
|
|
13
|
+
return Number(e.text);
|
|
14
|
+
if (e.kind === ts.SyntaxKind.TrueKeyword)
|
|
15
|
+
return true;
|
|
16
|
+
if (e.kind === ts.SyntaxKind.FalseKeyword)
|
|
17
|
+
return false;
|
|
18
|
+
if (e.kind === ts.SyntaxKind.NullKeyword)
|
|
19
|
+
return null;
|
|
20
|
+
return dyn(e.getText(sf));
|
|
21
|
+
}
|
|
22
|
+
return dyn(init.getText(sf));
|
|
23
|
+
}
|
|
24
|
+
/** JSX elements and import bindings in a TypeScript/JavaScript snippet, by syntax only. Nothing is evaluated. */
|
|
25
|
+
export function scanJsx(code, filename = "snippet.tsx") {
|
|
26
|
+
const kind = /\.jsx?$/i.test(filename) ? ts.ScriptKind.JSX : ts.ScriptKind.TSX;
|
|
27
|
+
const sf = ts.createSourceFile(filename, code, ts.ScriptTarget.Latest, true, kind);
|
|
28
|
+
const uses = [];
|
|
29
|
+
const imports = new Map();
|
|
30
|
+
for (const stmt of sf.statements) {
|
|
31
|
+
if (!ts.isImportDeclaration(stmt) || !ts.isStringLiteral(stmt.moduleSpecifier))
|
|
32
|
+
continue;
|
|
33
|
+
const module = stmt.moduleSpecifier.text;
|
|
34
|
+
const clause = stmt.importClause;
|
|
35
|
+
if (!clause)
|
|
36
|
+
continue;
|
|
37
|
+
if (clause.name)
|
|
38
|
+
imports.set(clause.name.text, { module, imported: "default" });
|
|
39
|
+
const bindings = clause.namedBindings;
|
|
40
|
+
if (bindings && ts.isNamespaceImport(bindings))
|
|
41
|
+
imports.set(bindings.name.text, { module, imported: "*" });
|
|
42
|
+
else if (bindings)
|
|
43
|
+
for (const el of bindings.elements)
|
|
44
|
+
imports.set(el.name.text, { module, imported: (el.propertyName ?? el.name).text });
|
|
45
|
+
}
|
|
46
|
+
const unwrap = (node) => {
|
|
47
|
+
let n = node;
|
|
48
|
+
while (ts.isParenthesizedExpression(n) || ts.isAsExpression(n) || ts.isNonNullExpression(n))
|
|
49
|
+
n = n.expression;
|
|
50
|
+
return n;
|
|
51
|
+
};
|
|
52
|
+
const isJsx = (n) => ts.isJsxElement(n) || ts.isJsxSelfClosingElement(n) || ts.isJsxFragment(n);
|
|
53
|
+
const containsJsx = (n) => {
|
|
54
|
+
let found = false;
|
|
55
|
+
const look = (c) => {
|
|
56
|
+
if (found)
|
|
57
|
+
return;
|
|
58
|
+
if (isJsx(c))
|
|
59
|
+
found = true;
|
|
60
|
+
else
|
|
61
|
+
ts.forEachChild(c, look);
|
|
62
|
+
};
|
|
63
|
+
look(n);
|
|
64
|
+
return found;
|
|
65
|
+
};
|
|
66
|
+
/** True when this element is what a component returns (directly or through a conditional), not a value stored elsewhere. */
|
|
67
|
+
const isRendered = (node) => {
|
|
68
|
+
let child = node;
|
|
69
|
+
for (let p = node.parent; p; child = p, p = p.parent) {
|
|
70
|
+
if (ts.isParenthesizedExpression(p) || ts.isAsExpression(p) || ts.isNonNullExpression(p))
|
|
71
|
+
continue;
|
|
72
|
+
if (ts.isReturnStatement(p))
|
|
73
|
+
return true;
|
|
74
|
+
if (ts.isArrowFunction(p))
|
|
75
|
+
return p.body === child;
|
|
76
|
+
if (ts.isConditionalExpression(p)) {
|
|
77
|
+
if (p.condition === child)
|
|
78
|
+
return false;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (ts.isBinaryExpression(p) &&
|
|
82
|
+
[
|
|
83
|
+
ts.SyntaxKind.AmpersandAmpersandToken,
|
|
84
|
+
ts.SyntaxKind.BarBarToken,
|
|
85
|
+
ts.SyntaxKind.QuestionQuestionToken
|
|
86
|
+
].includes(p.operatorToken.kind))
|
|
87
|
+
continue;
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
};
|
|
92
|
+
const isOpaqueChild = (child) => {
|
|
93
|
+
if (!ts.isJsxExpression(child) || !child.expression)
|
|
94
|
+
return false;
|
|
95
|
+
const e = unwrap(child.expression);
|
|
96
|
+
if (ts.isStringLiteralLike(e) || ts.isNumericLiteral(e))
|
|
97
|
+
return false;
|
|
98
|
+
return !containsJsx(e);
|
|
99
|
+
};
|
|
100
|
+
const visit = (node, parent, depth, loop) => {
|
|
101
|
+
let next = parent;
|
|
102
|
+
let nextDepth = depth;
|
|
103
|
+
let nextLoop = loop;
|
|
104
|
+
if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
105
|
+
const opening = ts.isJsxElement(node) ? node.openingElement : node;
|
|
106
|
+
const attrs = {};
|
|
107
|
+
let spread = false;
|
|
108
|
+
for (const a of opening.attributes.properties) {
|
|
109
|
+
if (ts.isJsxSpreadAttribute(a))
|
|
110
|
+
spread = true;
|
|
111
|
+
else
|
|
112
|
+
attrs[a.name.getText(sf)] = jsxValue(a.initializer, sf);
|
|
113
|
+
}
|
|
114
|
+
const hasChildren = ts.isJsxElement(node)
|
|
115
|
+
? node.children.some((c) => !(ts.isJsxText(c) && c.containsOnlyTriviaWhiteSpaces))
|
|
116
|
+
: false;
|
|
117
|
+
const opaque = spread ||
|
|
118
|
+
"children" in attrs ||
|
|
119
|
+
"dangerouslySetInnerHTML" in attrs ||
|
|
120
|
+
(ts.isJsxElement(node) && node.children.some(isOpaqueChild));
|
|
121
|
+
const pos = sf.getLineAndCharacterOfPosition(node.getStart(sf));
|
|
122
|
+
// A root element that is not returned (a variable, an argument) is not placed in the tree here.
|
|
123
|
+
const level = parent === undefined && !isRendered(node) ? depth + 1 : depth;
|
|
124
|
+
uses.push({
|
|
125
|
+
tag: opening.tagName.getText(sf),
|
|
126
|
+
line: pos.line + 1,
|
|
127
|
+
column: pos.character + 1,
|
|
128
|
+
attrs,
|
|
129
|
+
hasChildren,
|
|
130
|
+
hasSpread: spread,
|
|
131
|
+
parent,
|
|
132
|
+
exprDepth: level,
|
|
133
|
+
loopDepth: loop,
|
|
134
|
+
opaque
|
|
135
|
+
});
|
|
136
|
+
next = uses.length - 1;
|
|
137
|
+
nextDepth = level;
|
|
138
|
+
}
|
|
139
|
+
else if (ts.isJsxExpression(node)) {
|
|
140
|
+
// `icon={<Icon />}` is an element handed to its parent as a prop, not a condition or a loop.
|
|
141
|
+
const direct = ts.isJsxAttribute(node.parent) && node.expression !== undefined && isJsx(unwrap(node.expression));
|
|
142
|
+
if (!direct)
|
|
143
|
+
nextDepth = depth + 1;
|
|
144
|
+
}
|
|
145
|
+
else if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && depth > 0) {
|
|
146
|
+
nextLoop = loop + 1;
|
|
147
|
+
}
|
|
148
|
+
ts.forEachChild(node, (child) => visit(child, next, nextDepth, nextLoop));
|
|
149
|
+
};
|
|
150
|
+
visit(sf, undefined, 0, 0);
|
|
151
|
+
return { uses, imports };
|
|
152
|
+
}
|
|
153
|
+
const RAW_TEXT = new Set(["script", "style"]);
|
|
154
|
+
const VOID = new Set([
|
|
155
|
+
"area",
|
|
156
|
+
"base",
|
|
157
|
+
"br",
|
|
158
|
+
"col",
|
|
159
|
+
"embed",
|
|
160
|
+
"hr",
|
|
161
|
+
"img",
|
|
162
|
+
"input",
|
|
163
|
+
"link",
|
|
164
|
+
"meta",
|
|
165
|
+
"source",
|
|
166
|
+
"track",
|
|
167
|
+
"wbr"
|
|
168
|
+
]);
|
|
169
|
+
const camel = (n) => /^(data|aria)-/.test(n) ? n : n.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
170
|
+
/**
|
|
171
|
+
* Element start tags in an HTML-like template (Vue, Angular, HTML), with their nesting. A single linear pass:
|
|
172
|
+
* no DOM, no expression evaluation. Event handlers, structural directives and references are skipped;
|
|
173
|
+
* bindings are kept as dynamic values.
|
|
174
|
+
*/
|
|
175
|
+
export function scanMarkup(code) {
|
|
176
|
+
const uses = [];
|
|
177
|
+
const stack = [];
|
|
178
|
+
let i = 0;
|
|
179
|
+
let line = 1;
|
|
180
|
+
let lineStart = 0;
|
|
181
|
+
const n = code.length;
|
|
182
|
+
const advance = (to) => {
|
|
183
|
+
for (; i < to && i < n; i++)
|
|
184
|
+
if (code[i] === "\n") {
|
|
185
|
+
line++;
|
|
186
|
+
lineStart = i + 1;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
while (i < n) {
|
|
190
|
+
const lt = code.indexOf("<", i);
|
|
191
|
+
if (lt < 0)
|
|
192
|
+
break;
|
|
193
|
+
advance(lt);
|
|
194
|
+
if (code.startsWith("<!--", i)) {
|
|
195
|
+
const end = code.indexOf("-->", i + 4);
|
|
196
|
+
advance(end < 0 ? n : end + 3);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (code.startsWith("</", i)) {
|
|
200
|
+
const close = /^<\/([A-Za-z][A-Za-z0-9_.:-]*)/.exec(code.slice(i, i + 130));
|
|
201
|
+
if (close) {
|
|
202
|
+
const at = stack.map((s) => s.tag).lastIndexOf(close[1]);
|
|
203
|
+
if (at >= 0)
|
|
204
|
+
stack.length = at;
|
|
205
|
+
}
|
|
206
|
+
advance(i + 2);
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const m = /^<([A-Za-z][A-Za-z0-9_.:-]*)/.exec(code.slice(i, i + 130));
|
|
210
|
+
if (!m) {
|
|
211
|
+
advance(i + 1);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const tag = m[1];
|
|
215
|
+
const startLine = line;
|
|
216
|
+
const startColumn = i - lineStart + 1;
|
|
217
|
+
let j = i + m[0].length;
|
|
218
|
+
const attrs = {};
|
|
219
|
+
let spread = false;
|
|
220
|
+
let selfClosing = false;
|
|
221
|
+
while (j < n) {
|
|
222
|
+
while (j < n && /\s/.test(code[j]))
|
|
223
|
+
j++;
|
|
224
|
+
const c = code[j];
|
|
225
|
+
if (c === undefined)
|
|
226
|
+
break;
|
|
227
|
+
if (c === ">") {
|
|
228
|
+
j++;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
if (c === "/" && code[j + 1] === ">") {
|
|
232
|
+
selfClosing = true;
|
|
233
|
+
j += 2;
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
const nm = /^[^\s=>/"']+/.exec(code.slice(j, j + 200));
|
|
237
|
+
if (!nm) {
|
|
238
|
+
j++;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const raw = nm[0];
|
|
242
|
+
j += raw.length;
|
|
243
|
+
let value;
|
|
244
|
+
let k = j;
|
|
245
|
+
while (k < n && /\s/.test(code[k]))
|
|
246
|
+
k++;
|
|
247
|
+
if (code[k] === "=") {
|
|
248
|
+
k++;
|
|
249
|
+
while (k < n && /\s/.test(code[k]))
|
|
250
|
+
k++;
|
|
251
|
+
const q = code[k];
|
|
252
|
+
if (q === '"' || q === "'") {
|
|
253
|
+
const end = code.indexOf(q, k + 1);
|
|
254
|
+
value = code.slice(k + 1, end < 0 ? n : end);
|
|
255
|
+
j = end < 0 ? n : end + 1;
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
const um = /^[^\s>]+/.exec(code.slice(k, k + 200));
|
|
259
|
+
value = um?.[0] ?? "";
|
|
260
|
+
j = k + value.length;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (/^(@|\(|v-on:|v-on$|#|\*|v-if|v-else|v-for|v-show|v-model|v-slot|ng)/.test(raw) &&
|
|
264
|
+
!/^\[/.test(raw)) {
|
|
265
|
+
if (raw === "v-bind" || raw.startsWith("v-bind="))
|
|
266
|
+
spread = true;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
const bound = /^(:|v-bind:|\[)/.test(raw);
|
|
270
|
+
const name = camel(raw
|
|
271
|
+
.replace(/^(:|v-bind:)/, "")
|
|
272
|
+
.replace(/^\[|\]$/g, "")
|
|
273
|
+
.replace(/^attr\./, ""));
|
|
274
|
+
attrs[name] = bound ? dyn(value ?? "") : value === undefined ? true : value;
|
|
275
|
+
}
|
|
276
|
+
uses.push({
|
|
277
|
+
tag,
|
|
278
|
+
line: startLine,
|
|
279
|
+
column: startColumn,
|
|
280
|
+
attrs,
|
|
281
|
+
hasChildren: selfClosing ? false : undefined,
|
|
282
|
+
hasSpread: spread,
|
|
283
|
+
parent: stack[stack.length - 1]?.index
|
|
284
|
+
});
|
|
285
|
+
if (!selfClosing && !VOID.has(tag.toLowerCase()) && !RAW_TEXT.has(tag.toLowerCase()))
|
|
286
|
+
stack.push({ tag, index: uses.length - 1 });
|
|
287
|
+
advance(j);
|
|
288
|
+
if (RAW_TEXT.has(tag.toLowerCase()) && !selfClosing) {
|
|
289
|
+
const close = code.toLowerCase().indexOf(`</${tag.toLowerCase()}`, i);
|
|
290
|
+
advance(close < 0 ? n : close);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return uses;
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Edit distance, capped: returns `limit + 1` as soon as the distance must exceed `limit`. */
|
|
2
|
+
export function distance(a, b, limit) {
|
|
3
|
+
if (Math.abs(a.length - b.length) > limit)
|
|
4
|
+
return limit + 1;
|
|
5
|
+
let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
6
|
+
for (let i = 1; i <= a.length; i++) {
|
|
7
|
+
const cur = [i];
|
|
8
|
+
let best = i;
|
|
9
|
+
for (let j = 1; j <= b.length; j++) {
|
|
10
|
+
const v = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
11
|
+
cur.push(v);
|
|
12
|
+
if (v < best)
|
|
13
|
+
best = v;
|
|
14
|
+
}
|
|
15
|
+
if (best > limit)
|
|
16
|
+
return limit + 1;
|
|
17
|
+
prev = cur;
|
|
18
|
+
}
|
|
19
|
+
return prev[b.length];
|
|
20
|
+
}
|
|
21
|
+
/** Up to `max` candidates close to `name`, nearest first. Case-insensitive; never suggests the name itself. */
|
|
22
|
+
export function nearest(name, candidates, max = 3) {
|
|
23
|
+
const n = name.toLowerCase();
|
|
24
|
+
const limit = Math.max(2, Math.floor(n.length / 3));
|
|
25
|
+
return [...new Set(candidates)]
|
|
26
|
+
.filter((c) => c.toLowerCase() !== n)
|
|
27
|
+
.map((c) => ({ c, d: distance(n, c.toLowerCase(), limit) }))
|
|
28
|
+
.filter((x) => x.d <= limit)
|
|
29
|
+
.sort((a, b) => a.d - b.d || (a.c < b.c ? -1 : 1))
|
|
30
|
+
.slice(0, max)
|
|
31
|
+
.map((x) => x.c);
|
|
32
|
+
}
|
|
33
|
+
export const quoteList = (values) => values.map((v) => JSON.stringify(v)).join(", ");
|
|
34
|
+
//# sourceMappingURL=text.js.map
|