@component-compass/parser-vue 0.0.5 → 0.1.1
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/dist/emit-template.d.ts +41 -0
- package/dist/emit-template.js +178 -0
- package/dist/emit-template.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -160
- package/dist/index.js.map +1 -1
- package/dist/read-attrs.d.ts +8 -0
- package/dist/read-attrs.js +69 -0
- package/dist/read-attrs.js.map +1 -0
- package/package.json +12 -11
- package/dist/owner.d.ts +0 -14
- package/dist/owner.js +0 -22
- package/dist/owner.js.map +0 -1
- package/dist/walk-template.d.ts +0 -48
- package/dist/walk-template.js +0 -322
- package/dist/walk-template.js.map +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ResolveLazyManifest } from "@component-compass/plugin-core";
|
|
2
|
+
import type { FileBuilder } from "@component-compass/reference-graph";
|
|
3
|
+
import type { VueParseWrapper } from "./parse-sfc.js";
|
|
4
|
+
/**
|
|
5
|
+
* Options threaded into the parse5-based Vue SFC emitter. Mirrors the legacy
|
|
6
|
+
* `walkVueTemplate` surface but consumes the reference-graph FileBuilder
|
|
7
|
+
* instead of producing `Occurrence[]` directly. Tasks 2.4 → 2.12 progressively
|
|
8
|
+
* fill in script-import emission, template walking, owner attribution, and
|
|
9
|
+
* prop extraction.
|
|
10
|
+
*/
|
|
11
|
+
export type EmitVueTemplateOpts = {
|
|
12
|
+
file: string;
|
|
13
|
+
source: string;
|
|
14
|
+
wrapper: VueParseWrapper;
|
|
15
|
+
fileBuilder: FileBuilder;
|
|
16
|
+
captureValues: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Optional lazy-manifest priming hook. Vue SFCs commonly side-effect-import
|
|
19
|
+
* a WC's register entrypoint (`import "@pkg/components/button"`) so its
|
|
20
|
+
* template tag references (`<pie-button>`) can be resolved later. Calling
|
|
21
|
+
* `resolveLazyManifest` for each side-effect source primes the engine's
|
|
22
|
+
* tagIndex / CEM lookup pipeline. Optional — when undefined the priming
|
|
23
|
+
* loop is skipped (acceptable for synthetic test fixtures).
|
|
24
|
+
*/
|
|
25
|
+
resolveLazyManifest?: ResolveLazyManifest;
|
|
26
|
+
/**
|
|
27
|
+
* Optional pre-resolved SFC component symbol. When omitted, emit-template
|
|
28
|
+
* falls back to the filename stem (e.g. `button` for `button.vue`). The CLI
|
|
29
|
+
* passes the symbol resolved by `detectVueComponents` (which inspects
|
|
30
|
+
* `defineOptions` and falls back to a PascalCase filename) so the SFC's
|
|
31
|
+
* seed id and the engine's owner ComponentId hash to the same value. A
|
|
32
|
+
* mismatch here causes the SFC seed to be pruned as an unreachable local.
|
|
33
|
+
*/
|
|
34
|
+
sfcSymbol?: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* parse5-based emitter for Vue SFC templates. REPLACES the legacy
|
|
38
|
+
* `walkVueTemplate` pathway once Task 2.13 wires it into scan.ts. Until then
|
|
39
|
+
* the two coexist — the emitter is only driven by its unit tests.
|
|
40
|
+
*/
|
|
41
|
+
export declare function emitVueTemplate(opts: EmitVueTemplateOpts): void;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { basename, extname } from "node:path";
|
|
2
|
+
import { parseFragment } from "parse5";
|
|
3
|
+
import { isElement, hasChildren } from "@component-compass/ast-utils";
|
|
4
|
+
import { MODULE_SCOPE } from "@component-compass/reference-graph";
|
|
5
|
+
import { partsFromWrapper } from "./parse-sfc.js";
|
|
6
|
+
import { readAttrs } from "./read-attrs.js";
|
|
7
|
+
import { extractScriptImports } from "./script-imports.js";
|
|
8
|
+
/**
|
|
9
|
+
* Vue tag-form enumeration. A script-bound import resolves both via its
|
|
10
|
+
* lowercased exact form (`Card` → `card`) and its PascalCase→kebab form
|
|
11
|
+
* (`VBtn` → `v-btn`). Pre-computed once per import; ported from src/index.ts.
|
|
12
|
+
*/
|
|
13
|
+
function vueTagForms(importName) {
|
|
14
|
+
const lowercased = importName.toLowerCase();
|
|
15
|
+
const kebab = importName
|
|
16
|
+
.replace(/([A-Za-z0-9])([A-Z])/g, "$1-$2")
|
|
17
|
+
.toLowerCase();
|
|
18
|
+
return Array.from(new Set([lowercased, kebab]));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* parse5-based emitter for Vue SFC templates. REPLACES the legacy
|
|
22
|
+
* `walkVueTemplate` pathway once Task 2.13 wires it into scan.ts. Until then
|
|
23
|
+
* the two coexist — the emitter is only driven by its unit tests.
|
|
24
|
+
*/
|
|
25
|
+
export function emitVueTemplate(opts) {
|
|
26
|
+
const parts = partsFromWrapper(opts.wrapper);
|
|
27
|
+
// SFC's default export is the component itself. Stamp it as a JSX-returning
|
|
28
|
+
// BindingDecl + a default ExportRecord so the engine can resolve template
|
|
29
|
+
// usages back to this SFC as their owner (Task 2.9). Prefer the caller's
|
|
30
|
+
// pre-resolved symbol (which uses defineOptions / PascalCase filename for
|
|
31
|
+
// hash parity with `detectVueComponents`); fall back to the raw filename
|
|
32
|
+
// stem only when the caller didn't supply one (synthetic test fixtures).
|
|
33
|
+
const sfcSymbol = opts.sfcSymbol ?? basename(opts.file, extname(opts.file));
|
|
34
|
+
opts.fileBuilder.addDeclaration({
|
|
35
|
+
symbol: sfcSymbol,
|
|
36
|
+
value: { kind: "Function", returns: [{ kind: "JSX" }] },
|
|
37
|
+
loc: { line: 1, column: 1 },
|
|
38
|
+
isExported: true,
|
|
39
|
+
});
|
|
40
|
+
opts.fileBuilder.addExport({ kind: "default", local: sfcSymbol });
|
|
41
|
+
// Script imports flow through to `fileBuilder.addImport` regardless of
|
|
42
|
+
// whether the template emits anything — downstream engine passes look up
|
|
43
|
+
// imports by local name to resolve template tag references.
|
|
44
|
+
let importSpecs = [];
|
|
45
|
+
let sideEffectSources = [];
|
|
46
|
+
if (parts.scriptSource && opts.wrapper.scriptProgram) {
|
|
47
|
+
const scriptResult = extractScriptImports({
|
|
48
|
+
file: opts.file,
|
|
49
|
+
program: opts.wrapper.scriptProgram,
|
|
50
|
+
});
|
|
51
|
+
importSpecs = scriptResult.importSpecs;
|
|
52
|
+
sideEffectSources = scriptResult.sideEffectSources;
|
|
53
|
+
for (const spec of importSpecs) {
|
|
54
|
+
opts.fileBuilder.addImport({
|
|
55
|
+
specifier: spec.source,
|
|
56
|
+
imported: spec.imported,
|
|
57
|
+
local: spec.local,
|
|
58
|
+
// Per-import loc not tracked yet — script-imports.ts only records
|
|
59
|
+
// local + imported + source. Stamping a placeholder until either the
|
|
60
|
+
// extractor surfaces real positions or downstream consumers prove a
|
|
61
|
+
// need for them.
|
|
62
|
+
loc: { line: 1, column: 1 },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Side-effect imports (`import "pkg"`) carry no binding but signal that the
|
|
67
|
+
// SFC depends on the package's runtime; prime the lazy resolver so template
|
|
68
|
+
// tag references (`<pie-button>`) can find the leaf's CEM later. Mirrors
|
|
69
|
+
// the legacy walkVueTemplate priming step from src/index.ts.
|
|
70
|
+
if (opts.resolveLazyManifest) {
|
|
71
|
+
for (const source of sideEffectSources) {
|
|
72
|
+
opts.resolveLazyManifest(opts.file, source, "");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!parts.templateSource)
|
|
76
|
+
return;
|
|
77
|
+
// SFC owner Reference. Every template-emitted usage attributes back to the
|
|
78
|
+
// SFC's own BindingDecl (declared above). Module-scope, no member chain.
|
|
79
|
+
// `originFile` is required by `resolveOwnerChain` to look up the owner's
|
|
80
|
+
// declaration — without it the engine emits the occurrence with no
|
|
81
|
+
// ownerComponentId and the SFC seed gets filtered as an unreachable local.
|
|
82
|
+
const sfcOwnerRef = {
|
|
83
|
+
symbol: sfcSymbol,
|
|
84
|
+
scope: MODULE_SCOPE,
|
|
85
|
+
memberChain: [],
|
|
86
|
+
loc: { line: 1, column: 1 },
|
|
87
|
+
originFile: opts.file,
|
|
88
|
+
};
|
|
89
|
+
// parse5 line numbers are 1-based against the template content itself.
|
|
90
|
+
// SFC templates start mid-file, so add the line count of everything before
|
|
91
|
+
// `templateOffset` (minus the trailing 1 the count gives for the line the
|
|
92
|
+
// template opens on) so emitted locs read against the full SFC.
|
|
93
|
+
const lineOffset = opts.source.slice(0, parts.templateOffset ?? 0).split("\n").length - 1;
|
|
94
|
+
// Map of template tag form → ImportSpec. Vue addresses script-bound
|
|
95
|
+
// components either by the lowercased import name (`Card` → `card`) or by
|
|
96
|
+
// the PascalCase→kebab conversion (`VBtn` → `v-btn`). Pre-compute both forms
|
|
97
|
+
// here so the recursive walk can do a single Map lookup per element, and
|
|
98
|
+
// store the full spec so owner attribution can stamp specifier + import on
|
|
99
|
+
// the viaOverride.
|
|
100
|
+
const scriptBindings = new Map();
|
|
101
|
+
for (const spec of importSpecs) {
|
|
102
|
+
for (const form of vueTagForms(spec.local)) {
|
|
103
|
+
scriptBindings.set(form, spec);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const doc = parseFragment(parts.templateSource, { sourceCodeLocationInfo: true });
|
|
107
|
+
function visit(node) {
|
|
108
|
+
let pushed = false;
|
|
109
|
+
if (isElement(node)) {
|
|
110
|
+
const rawTag = node.tagName;
|
|
111
|
+
const scriptSpec = scriptBindings.get(rawTag);
|
|
112
|
+
if (scriptSpec) {
|
|
113
|
+
const loc = node.sourceCodeLocation;
|
|
114
|
+
const line = (loc?.startLine ?? 1) + lineOffset;
|
|
115
|
+
const column = loc?.startCol ?? 1;
|
|
116
|
+
// events not yet wired — see #57 (consumer-side event-listener tracking)
|
|
117
|
+
const { props } = readAttrs(node, opts.captureValues);
|
|
118
|
+
opts.fileBuilder.addJsxUsage({
|
|
119
|
+
ref: {
|
|
120
|
+
symbol: scriptSpec.local,
|
|
121
|
+
scope: MODULE_SCOPE,
|
|
122
|
+
memberChain: [],
|
|
123
|
+
loc: { line, column },
|
|
124
|
+
},
|
|
125
|
+
loc: { line, column },
|
|
126
|
+
props,
|
|
127
|
+
});
|
|
128
|
+
// Owner is always the enclosing SFC; viaOverride carries the
|
|
129
|
+
// script-import specifier + name so downstream consumers can present
|
|
130
|
+
// the usage as a vue-template occurrence with the import provenance
|
|
131
|
+
// intact.
|
|
132
|
+
opts.fileBuilder.setOwner(sfcOwnerRef, {
|
|
133
|
+
kind: "vue-template",
|
|
134
|
+
specifier: scriptSpec.source,
|
|
135
|
+
import: scriptSpec.imported,
|
|
136
|
+
});
|
|
137
|
+
pushed = true;
|
|
138
|
+
}
|
|
139
|
+
else if (rawTag.includes("-")) {
|
|
140
|
+
// Hyphenated tag with no script binding. Vue's auto-import / runtime
|
|
141
|
+
// global-component convention (e.g. `<pie-button>`, Vuetify's `<v-list>`
|
|
142
|
+
// when registered globally). Engine maps these to custom-element or
|
|
143
|
+
// vue-component identity by tag-name lookup in the tagIndex.
|
|
144
|
+
const loc = node.sourceCodeLocation;
|
|
145
|
+
const line = (loc?.startLine ?? 1) + lineOffset;
|
|
146
|
+
const column = loc?.startCol ?? 1;
|
|
147
|
+
// events not yet wired — see #57 (consumer-side event-listener tracking)
|
|
148
|
+
const { props } = readAttrs(node, opts.captureValues);
|
|
149
|
+
opts.fileBuilder.addTagUsage({
|
|
150
|
+
tagName: rawTag,
|
|
151
|
+
loc: { line, column },
|
|
152
|
+
props,
|
|
153
|
+
});
|
|
154
|
+
// Owner is the enclosing SFC; no viaOverride — engine defaults the
|
|
155
|
+
// occurrence's `via` to `{ kind: "html-tag" }` for TagUsage.
|
|
156
|
+
opts.fileBuilder.setTagOwner(sfcOwnerRef);
|
|
157
|
+
pushed = true;
|
|
158
|
+
}
|
|
159
|
+
// Plain HTML (`<div>`, `<span>`) and unknown PascalCase tags fall
|
|
160
|
+
// through without emission — they're neither tracked components nor
|
|
161
|
+
// hyphenated custom elements.
|
|
162
|
+
}
|
|
163
|
+
// Tracked elements push themselves as the lexical parent for their
|
|
164
|
+
// children; non-tracked elements (plain HTML, untracked tags) skip the
|
|
165
|
+
// push so descendants attribute to the next tracked ancestor
|
|
166
|
+
// (parent-transparency rule).
|
|
167
|
+
if (pushed)
|
|
168
|
+
opts.fileBuilder.pushUsageScope();
|
|
169
|
+
if (isElement(node) || hasChildren(node)) {
|
|
170
|
+
for (const child of node.childNodes)
|
|
171
|
+
visit(child);
|
|
172
|
+
}
|
|
173
|
+
if (pushed)
|
|
174
|
+
opts.fileBuilder.popUsageScope();
|
|
175
|
+
}
|
|
176
|
+
visit(doc);
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=emit-template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-template.js","sourceRoot":"","sources":["../src/emit-template.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
export { emitVueTemplate } from "./emit-template.js";
|
|
2
|
+
export type { EmitVueTemplateOpts } from "./emit-template.js";
|
package/dist/index.js
CHANGED
|
@@ -1,161 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import { serialiseComponentId } from "@component-compass/plugin-core";
|
|
3
|
-
import { asWrapperId } from "@component-compass/plugin-core";
|
|
4
|
-
import { posixPath } from "@component-compass/ast-utils";
|
|
5
|
-
import { partsFromWrapper } from "./parse-sfc.js";
|
|
6
|
-
import { walkVueTemplate } from "./walk-template.js";
|
|
7
|
-
import { resolveSfcOwner } from "./owner.js";
|
|
8
|
-
import { extractScriptImports } from "./script-imports.js";
|
|
9
|
-
function wrapperIdFromName(name) {
|
|
10
|
-
const kebab = name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
11
|
-
return asWrapperId(`wrap-${kebab.replaceAll(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "")}`);
|
|
12
|
-
}
|
|
13
|
-
function vueTagForms(importName) {
|
|
14
|
-
const lowercased = importName.toLowerCase();
|
|
15
|
-
// Vue convention: PascalCase like `VBtn` becomes kebab `v-btn`. Insert a hyphen
|
|
16
|
-
// before any uppercase letter that is preceded by a letter/digit (handles both
|
|
17
|
-
// `aB`→`a-b` and the leading-uppercase case `VB`→`v-b`).
|
|
18
|
-
const kebab = importName
|
|
19
|
-
.replace(/([A-Za-z0-9])([A-Z])/g, "$1-$2")
|
|
20
|
-
.toLowerCase();
|
|
21
|
-
return Array.from(new Set([lowercased, kebab]));
|
|
22
|
-
}
|
|
23
|
-
export const vuePlugin = {
|
|
24
|
-
name: "vue",
|
|
25
|
-
extensions: [".vue"],
|
|
26
|
-
parse(file, source, ctx) {
|
|
27
|
-
// Single-pass scan invariant (#48): scan.ts owns the SFC parse and threads
|
|
28
|
-
// the wrapper (descriptor + optional scriptAst) through ctx.ast. Defensive
|
|
29
|
-
// throw — should only fire under direct plugin invocation that bypasses
|
|
30
|
-
// scan.ts. Named `parsedWrapper` to disambiguate from the WrapperDef the
|
|
31
|
-
// SFC emits.
|
|
32
|
-
const parsedWrapper = ctx.ast;
|
|
33
|
-
if (parsedWrapper === undefined) {
|
|
34
|
-
throw new Error("parser-vue: ctx.ast must be provided (single-pass scan, #48)");
|
|
35
|
-
}
|
|
36
|
-
const parts = partsFromWrapper(parsedWrapper);
|
|
37
|
-
let imports = [];
|
|
38
|
-
let importSpecs = [];
|
|
39
|
-
let sideEffectSources = [];
|
|
40
|
-
const warnings = [];
|
|
41
|
-
if (parts.scriptSource) {
|
|
42
|
-
// scriptProgram is optional on the wrapper because an SFC with no script
|
|
43
|
-
// block has no script AST to thread. When `parts.scriptSource` is
|
|
44
|
-
// truthy, scan.ts must have produced a scriptProgram — anything else is
|
|
45
|
-
// direct plugin misuse.
|
|
46
|
-
if (parsedWrapper.scriptProgram === undefined) {
|
|
47
|
-
throw new Error("parser-vue: wrapper.scriptProgram must be provided when the SFC has a script block (single-pass scan, #48)");
|
|
48
|
-
}
|
|
49
|
-
const scriptResult = extractScriptImports({
|
|
50
|
-
file,
|
|
51
|
-
program: parsedWrapper.scriptProgram,
|
|
52
|
-
});
|
|
53
|
-
imports = scriptResult.imports;
|
|
54
|
-
importSpecs = scriptResult.importSpecs;
|
|
55
|
-
sideEffectSources = scriptResult.sideEffectSources;
|
|
56
|
-
warnings.push(...scriptResult.warnings);
|
|
57
|
-
}
|
|
58
|
-
// Side-effect imports (`import "pkg"`) carry no binding but signal that
|
|
59
|
-
// the SFC depends on the package's runtime; prime the lazy resolver so
|
|
60
|
-
// template tag references (`<x-button>`) find the leaf's CEM.
|
|
61
|
-
for (const source of sideEffectSources) {
|
|
62
|
-
ctx.resolveLazyManifest(file, source, "");
|
|
63
|
-
}
|
|
64
|
-
if (!parts.templateSource) {
|
|
65
|
-
return { occurrences: [], wrappers: [], imports, warnings };
|
|
66
|
-
}
|
|
67
|
-
// Build map of template tag (lowercased + kebab forms) → vue-direct binding,
|
|
68
|
-
// for direct Vue DS imports that resolve to a vue-component manifest entry.
|
|
69
|
-
const templateBindings = new Map();
|
|
70
|
-
// Track imports that did NOT match a manifest entry for opportunistic classification.
|
|
71
|
-
const unmappedBindings = new Map();
|
|
72
|
-
for (const spec of importSpecs) {
|
|
73
|
-
const hit = ctx.resolveLazyManifest(file, spec.source, spec.imported);
|
|
74
|
-
if (hit?.matched?.kind === "vue-component") {
|
|
75
|
-
const binding = {
|
|
76
|
-
kind: "vue-direct",
|
|
77
|
-
package: hit.leafPackage,
|
|
78
|
-
export: hit.matched.export,
|
|
79
|
-
specifier: spec.source,
|
|
80
|
-
importName: spec.imported,
|
|
81
|
-
modulePath: hit.modulePath,
|
|
82
|
-
};
|
|
83
|
-
for (const form of vueTagForms(spec.local)) {
|
|
84
|
-
templateBindings.set(form, binding);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
else if (hit) {
|
|
88
|
-
// Resolver landed on a leaf (could be CE / RC / no match) — track as
|
|
89
|
-
// opaque vue-unmapped with leafPackage so the template walker emits a
|
|
90
|
-
// vue-component occurrence attributed to that leaf.
|
|
91
|
-
const unmapped = {
|
|
92
|
-
kind: "vue-unmapped",
|
|
93
|
-
importedName: spec.imported,
|
|
94
|
-
specifier: spec.source,
|
|
95
|
-
leafPackage: hit.leafPackage,
|
|
96
|
-
modulePath: hit.modulePath,
|
|
97
|
-
};
|
|
98
|
-
for (const form of vueTagForms(spec.local)) {
|
|
99
|
-
unmappedBindings.set(form, unmapped);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
// Specifier did not resolve — fall back to local-component detection
|
|
104
|
-
// in walk-template via classifyImportOrigin.
|
|
105
|
-
const unmapped = {
|
|
106
|
-
kind: "vue-unmapped",
|
|
107
|
-
importedName: spec.imported,
|
|
108
|
-
specifier: spec.source,
|
|
109
|
-
leafPackage: null,
|
|
110
|
-
modulePath: null,
|
|
111
|
-
};
|
|
112
|
-
for (const form of vueTagForms(spec.local)) {
|
|
113
|
-
unmappedBindings.set(form, unmapped);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
const lineOffset = source.slice(0, parts.templateOffset ?? 0).split("\n").length - 1;
|
|
118
|
-
const ownerId = resolveSfcOwner(file, ctx.localIndex, ctx.repoRoot);
|
|
119
|
-
const occurrences = walkVueTemplate({
|
|
120
|
-
file,
|
|
121
|
-
template: parts.templateSource,
|
|
122
|
-
lineOffset,
|
|
123
|
-
lookupByTag: ctx.lookupByTag,
|
|
124
|
-
localIndex: ctx.localIndex,
|
|
125
|
-
templateBindings,
|
|
126
|
-
unmappedBindings,
|
|
127
|
-
...(ctx.cemIndex !== undefined ? { cemIndex: ctx.cemIndex } : {}),
|
|
128
|
-
captureValues: ctx.config.captureValues,
|
|
129
|
-
repoRoot: ctx.repoRoot,
|
|
130
|
-
...(ctx.collector !== undefined ? { collector: ctx.collector } : {}),
|
|
131
|
-
...(ownerId !== undefined ? { ownerId } : {}),
|
|
132
|
-
});
|
|
133
|
-
if (occurrences.length === 0) {
|
|
134
|
-
return { occurrences: [], wrappers: [], imports, warnings };
|
|
135
|
-
}
|
|
136
|
-
const componentName = basename(file, extname(file));
|
|
137
|
-
const seen = new Set();
|
|
138
|
-
const componentDeps = [];
|
|
139
|
-
for (const o of occurrences) {
|
|
140
|
-
const key = serialiseComponentId(o.componentId);
|
|
141
|
-
if (seen.has(key))
|
|
142
|
-
continue;
|
|
143
|
-
seen.add(key);
|
|
144
|
-
componentDeps.push(o.componentId);
|
|
145
|
-
}
|
|
146
|
-
const wrapper = {
|
|
147
|
-
id: wrapperIdFromName(componentName),
|
|
148
|
-
name: componentName,
|
|
149
|
-
file: posixPath(file),
|
|
150
|
-
exportName: "default",
|
|
151
|
-
componentDeps,
|
|
152
|
-
};
|
|
153
|
-
return {
|
|
154
|
-
occurrences,
|
|
155
|
-
wrappers: [wrapper],
|
|
156
|
-
imports,
|
|
157
|
-
warnings,
|
|
158
|
-
};
|
|
159
|
-
},
|
|
160
|
-
};
|
|
1
|
+
export { emitVueTemplate } from "./emit-template.js";
|
|
161
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DefaultTreeAdapterMap } from "parse5";
|
|
2
|
+
import type { PropUsage } from "@component-compass/plugin-core";
|
|
3
|
+
type Element = DefaultTreeAdapterMap["element"];
|
|
4
|
+
export declare function readAttrs(el: Element, captureValues: boolean): {
|
|
5
|
+
props: PropUsage[];
|
|
6
|
+
events: string[];
|
|
7
|
+
};
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const IDENT_RE = /^[A-Za-z_$][\w$]*$/;
|
|
2
|
+
const QUOTED_STRING_RE = /^(['"])(.*)\1$/s;
|
|
3
|
+
const NUMERIC_RE = /^-?\d+(\.\d+)?$/;
|
|
4
|
+
const BOOLEAN_RE = /^(true|false)$/;
|
|
5
|
+
export function readAttrs(el, captureValues) {
|
|
6
|
+
const props = [];
|
|
7
|
+
const events = [];
|
|
8
|
+
for (const attr of el.attrs) {
|
|
9
|
+
if (/^@|^v-on:/.test(attr.name)) {
|
|
10
|
+
events.push(attr.name.replace(/^@|^v-on:/, ""));
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
// Bare `v-bind="obj"` (no arg) → spread sentinel, deduped.
|
|
14
|
+
if (attr.name === "v-bind") {
|
|
15
|
+
if (props.some((p) => p.name === "...rest"))
|
|
16
|
+
continue;
|
|
17
|
+
props.push({ name: "...rest", isDynamic: true });
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
// Other Vue directives that aren't prop bindings → ignore.
|
|
21
|
+
if (/^v-/.test(attr.name) && !/^v-bind:/.test(attr.name))
|
|
22
|
+
continue;
|
|
23
|
+
if (/^[:.]|^v-bind:/.test(attr.name)) {
|
|
24
|
+
const name = attr.name.replace(/^[:.]|^v-bind:/, "");
|
|
25
|
+
const expr = attr.value.trim();
|
|
26
|
+
const usage = classifyBindExpr(name, expr, captureValues);
|
|
27
|
+
props.push(usage);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
// Static attribute. parse5 reports value `""` for boolean shorthand.
|
|
31
|
+
const usage = { name: attr.name, isDynamic: false };
|
|
32
|
+
if (captureValues) {
|
|
33
|
+
// Boolean shorthand: <X foo /> → literalValue: true.
|
|
34
|
+
// The HTML parser exposes both `<X foo>` and `<X foo="">` as value `""`.
|
|
35
|
+
// Treat empty value as boolean shorthand for consistency with the
|
|
36
|
+
// three-state model; explicit empty strings on Vue attributes are
|
|
37
|
+
// exceedingly rare in practice.
|
|
38
|
+
usage.literalValue = attr.value === "" ? true : attr.value;
|
|
39
|
+
}
|
|
40
|
+
props.push(usage);
|
|
41
|
+
}
|
|
42
|
+
return { props, events };
|
|
43
|
+
}
|
|
44
|
+
function classifyBindExpr(name, expr, captureValues) {
|
|
45
|
+
const quoted = expr.match(QUOTED_STRING_RE);
|
|
46
|
+
if (quoted) {
|
|
47
|
+
const usage = { name, isDynamic: false };
|
|
48
|
+
if (captureValues)
|
|
49
|
+
usage.literalValue = quoted[2] ?? "";
|
|
50
|
+
return usage;
|
|
51
|
+
}
|
|
52
|
+
if (NUMERIC_RE.test(expr)) {
|
|
53
|
+
const usage = { name, isDynamic: false };
|
|
54
|
+
if (captureValues)
|
|
55
|
+
usage.literalValue = Number(expr);
|
|
56
|
+
return usage;
|
|
57
|
+
}
|
|
58
|
+
if (BOOLEAN_RE.test(expr)) {
|
|
59
|
+
const usage = { name, isDynamic: false };
|
|
60
|
+
if (captureValues)
|
|
61
|
+
usage.literalValue = expr === "true";
|
|
62
|
+
return usage;
|
|
63
|
+
}
|
|
64
|
+
if (IDENT_RE.test(expr)) {
|
|
65
|
+
return { name, isDynamic: true };
|
|
66
|
+
}
|
|
67
|
+
return { name, isDynamic: true };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=read-attrs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-attrs.js","sourceRoot":"","sources":["../src/read-attrs.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@component-compass/parser-vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Consumer-scan parser for Vue Single-File Components. Detects component usages in .vue files.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -27,18 +27,19 @@
|
|
|
27
27
|
"clean": "rm -rf dist .turbo"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@component-compass/ast-utils": "
|
|
31
|
-
"@component-compass/plugin-core": "
|
|
32
|
-
"@
|
|
33
|
-
"@
|
|
34
|
-
"
|
|
35
|
-
"
|
|
30
|
+
"@component-compass/ast-utils": "0.1.1",
|
|
31
|
+
"@component-compass/plugin-core": "0.1.1",
|
|
32
|
+
"@component-compass/reference-graph": "0.1.1",
|
|
33
|
+
"@oxc-project/types": "0.130.0",
|
|
34
|
+
"@vue/compiler-sfc": "3.5.33",
|
|
35
|
+
"oxc-walker": "1.0.0",
|
|
36
|
+
"parse5": "8.0.1"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
|
-
"@types/node": "
|
|
39
|
-
"oxc-parser": "
|
|
40
|
-
"typescript": "
|
|
41
|
-
"vitest": "
|
|
39
|
+
"@types/node": "24.12.2",
|
|
40
|
+
"oxc-parser": "0.130.0",
|
|
41
|
+
"typescript": "5.9.3",
|
|
42
|
+
"vitest": "4.1.5"
|
|
42
43
|
},
|
|
43
44
|
"engines": {
|
|
44
45
|
"node": ">=24"
|
package/dist/owner.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { ComponentId, LocalDefinitionIndex } from "@component-compass/plugin-core";
|
|
2
|
-
/**
|
|
3
|
-
* Resolve the enclosing SFC's Component Identity for owner-stamping.
|
|
4
|
-
*
|
|
5
|
-
* Every template-emitted Occurrence in a `.vue` file is owned by that SFC's
|
|
6
|
-
* vue-component Identity. Looks up the file in the local-index — the single
|
|
7
|
-
* source of truth populated by `detect-vue.ts` — so the owner stamp aligns
|
|
8
|
-
* with the local-lane Component in `components[]`.
|
|
9
|
-
*
|
|
10
|
-
* Returns `undefined` if no Local definition exists for the file (e.g.
|
|
11
|
-
* `<script>`-only files that don't match `defineComponent` or SFC shape).
|
|
12
|
-
* Occurrences then surface as root in the composition rollup.
|
|
13
|
-
*/
|
|
14
|
-
export declare function resolveSfcOwner(file: string, localIndex: LocalDefinitionIndex, repoRoot?: string): ComponentId | undefined;
|
package/dist/owner.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { normalizeOwnerPath } from "@component-compass/plugin-core";
|
|
2
|
-
/**
|
|
3
|
-
* Resolve the enclosing SFC's Component Identity for owner-stamping.
|
|
4
|
-
*
|
|
5
|
-
* Every template-emitted Occurrence in a `.vue` file is owned by that SFC's
|
|
6
|
-
* vue-component Identity. Looks up the file in the local-index — the single
|
|
7
|
-
* source of truth populated by `detect-vue.ts` — so the owner stamp aligns
|
|
8
|
-
* with the local-lane Component in `components[]`.
|
|
9
|
-
*
|
|
10
|
-
* Returns `undefined` if no Local definition exists for the file (e.g.
|
|
11
|
-
* `<script>`-only files that don't match `defineComponent` or SFC shape).
|
|
12
|
-
* Occurrences then surface as root in the composition rollup.
|
|
13
|
-
*/
|
|
14
|
-
export function resolveSfcOwner(file, localIndex, repoRoot) {
|
|
15
|
-
const normalizedPath = normalizeOwnerPath(file, repoRoot);
|
|
16
|
-
const defs = localIndex.byPath.get(normalizedPath);
|
|
17
|
-
const first = defs?.[0];
|
|
18
|
-
if (!first)
|
|
19
|
-
return undefined;
|
|
20
|
-
return first.componentId;
|
|
21
|
-
}
|
|
22
|
-
//# sourceMappingURL=owner.js.map
|
package/dist/owner.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"owner.js","sourceRoot":"","sources":["../src/owner.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEpE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,UAAgC,EAChC,QAAiB;IAEjB,MAAM,cAAc,GAAG,kBAAkB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACxB,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,OAAO,KAAK,CAAC,WAAW,CAAC;AAC3B,CAAC"}
|
package/dist/walk-template.d.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { CemIndex, ComponentId, DiagnosticCollector, LocalDefinitionIndex, LookupByTag, Occurrence } from "@component-compass/plugin-core";
|
|
2
|
-
export type VueDirectBinding = {
|
|
3
|
-
kind: "vue-direct";
|
|
4
|
-
package: string;
|
|
5
|
-
export: string;
|
|
6
|
-
specifier: string;
|
|
7
|
-
importName: string;
|
|
8
|
-
modulePath: string;
|
|
9
|
-
};
|
|
10
|
-
export type VueUnmappedBinding = {
|
|
11
|
-
kind: "vue-unmapped";
|
|
12
|
-
/** The original imported export name (e.g. "Button" or "default"). */
|
|
13
|
-
importedName: string;
|
|
14
|
-
/** The import specifier (module path). */
|
|
15
|
-
specifier: string;
|
|
16
|
-
/**
|
|
17
|
-
* Non-null when the lazy resolver landed on a leaf package without a
|
|
18
|
-
* manifest entry for `importedName` — in that case the template walker
|
|
19
|
-
* attributes the opaque external occurrence to this leaf rather than
|
|
20
|
-
* re-running origin classification on the user-written aggregator
|
|
21
|
-
* specifier. Null when the specifier did not resolve via the lazy
|
|
22
|
-
* resolver (relative path, alias, or unresolvable bare import).
|
|
23
|
-
*/
|
|
24
|
-
leafPackage: string | null;
|
|
25
|
-
/**
|
|
26
|
-
* Package-relative resolved module path from the lazy resolver hit
|
|
27
|
-
* (paired with non-null `leafPackage`); null when the resolver returned
|
|
28
|
-
* no hit. Threaded onto the external identity by the template-emission
|
|
29
|
-
* pass so downstream consumers can disambiguate same-export entries
|
|
30
|
-
* served from different package subpaths (#63).
|
|
31
|
-
*/
|
|
32
|
-
modulePath: string | null;
|
|
33
|
-
};
|
|
34
|
-
export type WalkVueTemplateOpts = {
|
|
35
|
-
file: string;
|
|
36
|
-
template: string;
|
|
37
|
-
lineOffset: number;
|
|
38
|
-
lookupByTag: LookupByTag;
|
|
39
|
-
localIndex: LocalDefinitionIndex;
|
|
40
|
-
templateBindings: Map<string, VueDirectBinding>;
|
|
41
|
-
unmappedBindings?: Map<string, VueUnmappedBinding>;
|
|
42
|
-
cemIndex?: CemIndex;
|
|
43
|
-
captureValues: boolean;
|
|
44
|
-
repoRoot?: string;
|
|
45
|
-
collector?: DiagnosticCollector;
|
|
46
|
-
ownerId?: ComponentId;
|
|
47
|
-
};
|
|
48
|
-
export declare function walkVueTemplate(opts: WalkVueTemplateOpts): Occurrence[];
|
package/dist/walk-template.js
DELETED
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
import { parseFragment } from "parse5";
|
|
2
|
-
import { asTagName, externalPackageOf } from "@component-compass/plugin-core";
|
|
3
|
-
import { posixPath, isElement, hasChildren, classifyImportOrigin } from "@component-compass/ast-utils";
|
|
4
|
-
export function walkVueTemplate(opts) {
|
|
5
|
-
const { file, template, lineOffset, lookupByTag, localIndex, templateBindings, unmappedBindings, cemIndex, captureValues, repoRoot, collector, ownerId, } = opts;
|
|
6
|
-
const occurrences = [];
|
|
7
|
-
const doc = parseFragment(template, { sourceCodeLocationInfo: true });
|
|
8
|
-
// Phase 2: parent stack maintains the lexical chain of tracked elements.
|
|
9
|
-
// Vue scoped slots (`v-slot` on a host element) are deliberately treated as
|
|
10
|
-
// lexical — `<DataLoader v-slot="d"><Card/></DataLoader>` records `<Card>`'s
|
|
11
|
-
// parent as `<DataLoader>` because parse5 sees the slot content as a direct
|
|
12
|
-
// child of the host element. No render-prop guard is needed here (unlike the
|
|
13
|
-
// React walker), per the Phase 2 spec's parser-vue concerns.
|
|
14
|
-
const parentStack = [];
|
|
15
|
-
/** Push the occurrence onto the array, stamping parentRef + depth from the
|
|
16
|
-
* current parent stack. Returns the new index so the caller can later push
|
|
17
|
-
* this element onto the stack as a parent for its children. */
|
|
18
|
-
function emit(occurrence) {
|
|
19
|
-
const top = parentStack[parentStack.length - 1];
|
|
20
|
-
if (top)
|
|
21
|
-
occurrence.parentRef = top.idx;
|
|
22
|
-
occurrence.depth = parentStack.length;
|
|
23
|
-
if (ownerId !== undefined)
|
|
24
|
-
occurrence.ownerComponentId = ownerId;
|
|
25
|
-
const idx = occurrences.length;
|
|
26
|
-
occurrences.push(occurrence);
|
|
27
|
-
return idx;
|
|
28
|
-
}
|
|
29
|
-
function visit(node) {
|
|
30
|
-
if (isElement(node)) {
|
|
31
|
-
const rawTag = node.tagName;
|
|
32
|
-
const indexedWc = lookupByTag(rawTag);
|
|
33
|
-
let pushedIdx;
|
|
34
|
-
if (indexedWc) {
|
|
35
|
-
pushedIdx = emitWcOccurrence(node, indexedWc);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
const direct = templateBindings.get(rawTag);
|
|
39
|
-
if (direct) {
|
|
40
|
-
pushedIdx = emitVueDirectOccurrence(node, direct);
|
|
41
|
-
}
|
|
42
|
-
else if (unmappedBindings && repoRoot) {
|
|
43
|
-
const unmapped = unmappedBindings.get(rawTag);
|
|
44
|
-
if (unmapped) {
|
|
45
|
-
if (unmapped.leafPackage) {
|
|
46
|
-
// Resolver knew the leaf — emit external with that package.
|
|
47
|
-
pushedIdx = emitOpportunisticVueOccurrence(node, unmapped, unmapped.leafPackage);
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
// Specifier didn't resolve via the lazy resolver — fall back to
|
|
51
|
-
// local-component detection via classifyImportOrigin against the
|
|
52
|
-
// user-written specifier.
|
|
53
|
-
const origin = classifyImportOrigin(unmapped.specifier, {
|
|
54
|
-
repoRoot,
|
|
55
|
-
fromFile: file,
|
|
56
|
-
});
|
|
57
|
-
if (origin.type === "external") {
|
|
58
|
-
// Manifest enrichment is disabled but the specifier resolves to
|
|
59
|
-
// node_modules — emit an opaque external occurrence keyed by
|
|
60
|
-
// package name. Identity resolution and manifest enrichment are
|
|
61
|
-
// separate concerns; the component still appears in components[]
|
|
62
|
-
// with manifest: null.
|
|
63
|
-
pushedIdx = emitOpportunisticVueOccurrence(node, unmapped, origin.package);
|
|
64
|
-
}
|
|
65
|
-
else if (origin.type === "local") {
|
|
66
|
-
const localDefs = localIndex.byPath.get(origin.filePath);
|
|
67
|
-
const matched = localDefs?.find((d) => unmapped.importedName === "default"
|
|
68
|
-
? d.isDefault
|
|
69
|
-
: d.exportName === unmapped.importedName && !d.isDefault);
|
|
70
|
-
if (matched && matched.componentId.kind === "vue-component") {
|
|
71
|
-
pushedIdx = emitLocalVueOccurrence(node, unmapped, matched.componentId);
|
|
72
|
-
}
|
|
73
|
-
// Local miss → skip silently.
|
|
74
|
-
}
|
|
75
|
-
else if (origin.type === "unresolved" && isBarePackageSpecifier(unmapped.specifier)) {
|
|
76
|
-
// Bare-specifier fallback: workspace-symlinked packages resolve
|
|
77
|
-
// outside node_modules/ so classifyImportOrigin returns
|
|
78
|
-
// "unresolved". Use the specifier as the package name directly.
|
|
79
|
-
const pkgName = unmapped.specifier.startsWith("@")
|
|
80
|
-
? unmapped.specifier.split("/").slice(0, 2).join("/")
|
|
81
|
-
: (unmapped.specifier.split("/")[0] ?? unmapped.specifier);
|
|
82
|
-
pushedIdx = emitOpportunisticVueOccurrence(node, unmapped, pkgName);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
else if (rawTag.includes("-")) {
|
|
87
|
-
// Hyphenated tag not in index: Vue auto-import convention (e.g. Vuetify).
|
|
88
|
-
pushedIdx = emitOpportunisticVueAutoImport(node);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
else if (rawTag.includes("-")) {
|
|
92
|
-
// No unmapped bindings provided but tag is hyphenated and not in index.
|
|
93
|
-
pushedIdx = emitOpportunisticVueAutoImport(node);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
// Tracked elements push themselves as the lexical parent for their
|
|
97
|
-
// children; non-tracked elements (plain HTML, untracked components)
|
|
98
|
-
// skip the push so descendants attribute to the next tracked ancestor
|
|
99
|
-
// (parent-transparency rule).
|
|
100
|
-
if (pushedIdx !== undefined)
|
|
101
|
-
parentStack.push({ idx: pushedIdx, node });
|
|
102
|
-
for (const child of node.childNodes)
|
|
103
|
-
visit(child);
|
|
104
|
-
if (pushedIdx !== undefined)
|
|
105
|
-
parentStack.pop();
|
|
106
|
-
}
|
|
107
|
-
else if (hasChildren(node)) {
|
|
108
|
-
for (const child of node.childNodes)
|
|
109
|
-
visit(child);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
function emitWcOccurrence(node, indexed) {
|
|
113
|
-
const tag = asTagName(node.tagName);
|
|
114
|
-
const { props, events } = readAttrs(node, captureValues);
|
|
115
|
-
const loc = node.sourceCodeLocation;
|
|
116
|
-
return emit({
|
|
117
|
-
componentId: { kind: "custom-element", tagName: tag, source: { type: "external", package: externalPackageOf(indexed.source) } },
|
|
118
|
-
loc: {
|
|
119
|
-
file: posixPath(file),
|
|
120
|
-
line: (loc?.startLine ?? 1) + lineOffset,
|
|
121
|
-
column: loc?.startCol ?? 1,
|
|
122
|
-
},
|
|
123
|
-
via: { kind: "html-tag" },
|
|
124
|
-
props,
|
|
125
|
-
events,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
function emitOpportunisticVueOccurrence(node, binding, pkg) {
|
|
129
|
-
const { props, events } = readAttrs(node, captureValues);
|
|
130
|
-
const loc = node.sourceCodeLocation;
|
|
131
|
-
const via = {
|
|
132
|
-
kind: "vue-template",
|
|
133
|
-
specifier: binding.specifier,
|
|
134
|
-
import: binding.importedName,
|
|
135
|
-
};
|
|
136
|
-
return emit({
|
|
137
|
-
componentId: {
|
|
138
|
-
kind: "vue-component",
|
|
139
|
-
export: binding.importedName,
|
|
140
|
-
source: {
|
|
141
|
-
type: "external",
|
|
142
|
-
package: pkg,
|
|
143
|
-
...(binding.modulePath !== null ? { modulePath: binding.modulePath } : {}),
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
loc: {
|
|
147
|
-
file: posixPath(file),
|
|
148
|
-
line: (loc?.startLine ?? 1) + lineOffset,
|
|
149
|
-
column: loc?.startCol ?? 1,
|
|
150
|
-
},
|
|
151
|
-
via,
|
|
152
|
-
props,
|
|
153
|
-
events,
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
function emitLocalVueOccurrence(node, binding, componentId) {
|
|
157
|
-
const { props, events } = readAttrs(node, captureValues);
|
|
158
|
-
const loc = node.sourceCodeLocation;
|
|
159
|
-
const via = {
|
|
160
|
-
kind: "vue-template",
|
|
161
|
-
specifier: binding.specifier,
|
|
162
|
-
import: binding.importedName,
|
|
163
|
-
};
|
|
164
|
-
return emit({
|
|
165
|
-
componentId,
|
|
166
|
-
loc: {
|
|
167
|
-
file: posixPath(file),
|
|
168
|
-
line: (loc?.startLine ?? 1) + lineOffset,
|
|
169
|
-
column: loc?.startCol ?? 1,
|
|
170
|
-
},
|
|
171
|
-
via,
|
|
172
|
-
props,
|
|
173
|
-
events,
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
function emitOpportunisticVueAutoImport(node) {
|
|
177
|
-
const tag = asTagName(node.tagName);
|
|
178
|
-
const { props, events } = readAttrs(node, captureValues);
|
|
179
|
-
const loc = node.sourceCodeLocation;
|
|
180
|
-
// CEM index lookup: attribute to the package if known, otherwise emit
|
|
181
|
-
// unattributed but still tracked (packageName: null in the output).
|
|
182
|
-
const cemEntry = cemIndex?.byTag.get(tag);
|
|
183
|
-
if (!cemEntry) {
|
|
184
|
-
collector?.emit({
|
|
185
|
-
code: "vue-tag-low-confidence",
|
|
186
|
-
severity: "info",
|
|
187
|
-
filePath: posixPath(file),
|
|
188
|
-
...(loc?.startLine !== undefined && { line: loc.startLine + lineOffset }),
|
|
189
|
-
...(loc?.startCol !== undefined && { column: loc.startCol }),
|
|
190
|
-
tagName: tag,
|
|
191
|
-
emittedAs: "custom-element",
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
return emit({
|
|
195
|
-
componentId: {
|
|
196
|
-
kind: "custom-element",
|
|
197
|
-
tagName: tag,
|
|
198
|
-
source: cemEntry
|
|
199
|
-
? { type: "external", package: cemEntry.packageName }
|
|
200
|
-
: { type: "unknown" },
|
|
201
|
-
},
|
|
202
|
-
loc: {
|
|
203
|
-
file: posixPath(file),
|
|
204
|
-
line: (loc?.startLine ?? 1) + lineOffset,
|
|
205
|
-
column: loc?.startCol ?? 1,
|
|
206
|
-
},
|
|
207
|
-
via: { kind: "html-tag" },
|
|
208
|
-
props,
|
|
209
|
-
events,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
function emitVueDirectOccurrence(node, binding) {
|
|
213
|
-
const { props, events } = readAttrs(node, captureValues);
|
|
214
|
-
const loc = node.sourceCodeLocation;
|
|
215
|
-
const via = {
|
|
216
|
-
kind: "vue-template",
|
|
217
|
-
specifier: binding.specifier,
|
|
218
|
-
import: binding.importName,
|
|
219
|
-
};
|
|
220
|
-
return emit({
|
|
221
|
-
componentId: {
|
|
222
|
-
kind: "vue-component",
|
|
223
|
-
export: binding.export,
|
|
224
|
-
source: { type: "external", package: binding.package, modulePath: binding.modulePath },
|
|
225
|
-
},
|
|
226
|
-
loc: {
|
|
227
|
-
file: posixPath(file),
|
|
228
|
-
line: (loc?.startLine ?? 1) + lineOffset,
|
|
229
|
-
column: loc?.startCol ?? 1,
|
|
230
|
-
},
|
|
231
|
-
via,
|
|
232
|
-
props,
|
|
233
|
-
events,
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
visit(doc);
|
|
237
|
-
return occurrences;
|
|
238
|
-
}
|
|
239
|
-
const IDENT_RE = /^[A-Za-z_$][\w$]*$/;
|
|
240
|
-
const QUOTED_STRING_RE = /^(['"])(.*)\1$/s;
|
|
241
|
-
const NUMERIC_RE = /^-?\d+(\.\d+)?$/;
|
|
242
|
-
const BOOLEAN_RE = /^(true|false)$/;
|
|
243
|
-
function readAttrs(el, captureValues) {
|
|
244
|
-
const props = [];
|
|
245
|
-
const events = [];
|
|
246
|
-
for (const attr of el.attrs) {
|
|
247
|
-
if (/^@|^v-on:/.test(attr.name)) {
|
|
248
|
-
events.push(attr.name.replace(/^@|^v-on:/, ""));
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
// Bare `v-bind="obj"` (no arg) → spread sentinel, deduped.
|
|
252
|
-
if (attr.name === "v-bind") {
|
|
253
|
-
if (props.some((p) => p.name === "...rest"))
|
|
254
|
-
continue;
|
|
255
|
-
props.push({ name: "...rest", isDynamic: true, dynamicKind: "spread" });
|
|
256
|
-
continue;
|
|
257
|
-
}
|
|
258
|
-
// Other Vue directives that aren't prop bindings → ignore.
|
|
259
|
-
if (/^v-/.test(attr.name) && !/^v-bind:/.test(attr.name))
|
|
260
|
-
continue;
|
|
261
|
-
if (/^[:.]|^v-bind:/.test(attr.name)) {
|
|
262
|
-
const name = attr.name.replace(/^[:.]|^v-bind:/, "");
|
|
263
|
-
const expr = attr.value.trim();
|
|
264
|
-
const usage = classifyBindExpr(name, expr, captureValues);
|
|
265
|
-
props.push(usage);
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
// Static attribute. parse5 reports value `""` for boolean shorthand.
|
|
269
|
-
const usage = { name: attr.name, isDynamic: false };
|
|
270
|
-
if (captureValues) {
|
|
271
|
-
// Boolean shorthand: <X foo /> → literalValue: true.
|
|
272
|
-
// The HTML parser exposes both `<X foo>` and `<X foo="">` as value `""`.
|
|
273
|
-
// Treat empty value as boolean shorthand for consistency with the
|
|
274
|
-
// three-state model; explicit empty strings on Vue attributes are
|
|
275
|
-
// exceedingly rare in practice.
|
|
276
|
-
usage.literalValue = attr.value === "" ? true : attr.value;
|
|
277
|
-
}
|
|
278
|
-
props.push(usage);
|
|
279
|
-
}
|
|
280
|
-
return { props, events };
|
|
281
|
-
}
|
|
282
|
-
function classifyBindExpr(name, expr, captureValues) {
|
|
283
|
-
const quoted = expr.match(QUOTED_STRING_RE);
|
|
284
|
-
if (quoted) {
|
|
285
|
-
const usage = { name, isDynamic: false };
|
|
286
|
-
if (captureValues)
|
|
287
|
-
usage.literalValue = quoted[2] ?? "";
|
|
288
|
-
return usage;
|
|
289
|
-
}
|
|
290
|
-
if (NUMERIC_RE.test(expr)) {
|
|
291
|
-
const usage = { name, isDynamic: false };
|
|
292
|
-
if (captureValues)
|
|
293
|
-
usage.literalValue = Number(expr);
|
|
294
|
-
return usage;
|
|
295
|
-
}
|
|
296
|
-
if (BOOLEAN_RE.test(expr)) {
|
|
297
|
-
const usage = { name, isDynamic: false };
|
|
298
|
-
if (captureValues)
|
|
299
|
-
usage.literalValue = expr === "true";
|
|
300
|
-
return usage;
|
|
301
|
-
}
|
|
302
|
-
if (IDENT_RE.test(expr)) {
|
|
303
|
-
return { name, isDynamic: true, dynamicKind: "identifier" };
|
|
304
|
-
}
|
|
305
|
-
return { name, isDynamic: true, dynamicKind: "expr" };
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Returns true for specifiers that look like bare npm package names — neither
|
|
309
|
-
* relative paths (`.`, `..`) nor absolute paths (`/`). Scoped packages
|
|
310
|
-
* (`@scope/name`) are accepted only when the scope part is non-empty, to
|
|
311
|
-
* exclude alias conventions like `@/foo` where `@` is not a real npm scope.
|
|
312
|
-
*/
|
|
313
|
-
function isBarePackageSpecifier(specifier) {
|
|
314
|
-
if (specifier.startsWith(".") || specifier.startsWith("/"))
|
|
315
|
-
return false;
|
|
316
|
-
if (specifier.startsWith("@")) {
|
|
317
|
-
const slashIdx = specifier.indexOf("/");
|
|
318
|
-
return slashIdx > 1; // slashIdx 1 means "@/" — scope is empty
|
|
319
|
-
}
|
|
320
|
-
return true;
|
|
321
|
-
}
|
|
322
|
-
//# sourceMappingURL=walk-template.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"walk-template.js","sourceRoot":"","sources":["../src/walk-template.ts"],"names":[],"mappings":"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"}
|