@groma/scanner-vue 0.1.0 → 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/README.md +11 -1
- package/dist/index.js +105 -16
- package/package.json +2 -5
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The Vue scanner adds single-file component (SFC) event bindings to Groma's
|
|
4
4
|
TypeScript scanner evidence. Install the project's dependencies using its
|
|
5
|
-
package manager and lockfile. The scanner reads
|
|
5
|
+
package manager and lockfile. The scanner reads each selected project's `tsconfig.json`;
|
|
6
6
|
it does not install dependencies or execute application code.
|
|
7
7
|
|
|
8
8
|
```sh
|
|
@@ -65,3 +65,13 @@ owns that interpretation. No new architecture metadata is added.
|
|
|
65
65
|
|
|
66
66
|
See [validation](validation.md) for the pinned project and executed release
|
|
67
67
|
checks. This prototype package name does not imply public publication.
|
|
68
|
+
|
|
69
|
+
## Nested projects
|
|
70
|
+
|
|
71
|
+
Run Groma from the repository root. The scanner finds package declarations in
|
|
72
|
+
tracked and unignored files, including nested apps and libraries. Dependencies,
|
|
73
|
+
dev dependencies, peer dependencies and optional dependencies identify framework
|
|
74
|
+
projects. Each compiler uses that project's configuration and installed dependencies;
|
|
75
|
+
imported source in sibling repository libraries keeps its original source path.
|
|
76
|
+
Readiness checks all selected projects. A project error fails the complete scan.
|
|
77
|
+
Source and nested package/configuration changes use the shared scanner watch flow.
|
package/dist/index.js
CHANGED
|
@@ -208497,12 +208497,54 @@ var import_typescript3 = __toESM(require_typescript(), 1);
|
|
|
208497
208497
|
var import_typescript = __toESM(require_typescript2(), 1);
|
|
208498
208498
|
var import_language_core = __toESM(require_language_core2(), 1);
|
|
208499
208499
|
var import_typescript2 = __toESM(require_typescript(), 1);
|
|
208500
|
-
import { existsSync, readFileSync } from "fs";
|
|
208500
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
208501
208501
|
import { createRequire } from "module";
|
|
208502
|
+
import path2 from "path";
|
|
208503
|
+
|
|
208504
|
+
// plugins/scanners/projects.ts
|
|
208505
|
+
import { execFile } from "child_process";
|
|
208506
|
+
import { existsSync } from "fs";
|
|
208507
|
+
import { readFile } from "fs/promises";
|
|
208502
208508
|
import path from "path";
|
|
208509
|
+
import { promisify } from "util";
|
|
208510
|
+
var execute = promisify(execFile);
|
|
208511
|
+
var excluded = new Set([
|
|
208512
|
+
".git",
|
|
208513
|
+
"node_modules",
|
|
208514
|
+
"vendor",
|
|
208515
|
+
"target",
|
|
208516
|
+
"dist",
|
|
208517
|
+
"build",
|
|
208518
|
+
"bin",
|
|
208519
|
+
"obj",
|
|
208520
|
+
".gradle",
|
|
208521
|
+
".angular",
|
|
208522
|
+
"coverage",
|
|
208523
|
+
"generated",
|
|
208524
|
+
"groma",
|
|
208525
|
+
".groma"
|
|
208526
|
+
]);
|
|
208527
|
+
async function projectFiles(root, matches) {
|
|
208528
|
+
const { stdout } = await execute("git", ["-C", root, "ls-files", "-z", "--cached", "--others", "--exclude-standard"], { maxBuffer: 64 * 1024 * 1024 });
|
|
208529
|
+
return [...new Set(stdout.split("\x00").filter((file) => file && matches(file) && !file.split("/").some((part) => excluded.has(part)) && existsSync(path.join(root, file))))].sort();
|
|
208530
|
+
}
|
|
208531
|
+
function hasDependency(manifest, dependency) {
|
|
208532
|
+
return ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"].some((section) => typeof manifest[section]?.[dependency] === "string");
|
|
208533
|
+
}
|
|
208534
|
+
async function frameworkProjects(root, dependency) {
|
|
208535
|
+
const projects = [];
|
|
208536
|
+
for (const file of await projectFiles(root, (file) => path.posix.basename(file) === "package.json")) {
|
|
208537
|
+
const manifest = JSON.parse(await readFile(path.join(root, file), "utf8"));
|
|
208538
|
+
if (hasDependency(manifest, dependency))
|
|
208539
|
+
projects.push(path.dirname(path.join(root, file)));
|
|
208540
|
+
}
|
|
208541
|
+
return projects;
|
|
208542
|
+
}
|
|
208543
|
+
|
|
208544
|
+
// plugins/scanners/vue/src/project.ts
|
|
208503
208545
|
var vueTypeScript = import_typescript2.default;
|
|
208504
208546
|
function relative(root, file) {
|
|
208505
|
-
return
|
|
208547
|
+
return path2.relative(root, file).split(path2.sep).join("/");
|
|
208506
208548
|
}
|
|
208507
208549
|
function nodeAt(node, position) {
|
|
208508
208550
|
let result = node;
|
|
@@ -208528,9 +208570,9 @@ class VueProject {
|
|
|
208528
208570
|
options;
|
|
208529
208571
|
language;
|
|
208530
208572
|
plugin;
|
|
208531
|
-
constructor(root) {
|
|
208532
|
-
this.root =
|
|
208533
|
-
const configFile =
|
|
208573
|
+
constructor(root, repositoryRoot = root) {
|
|
208574
|
+
this.root = repositoryRoot;
|
|
208575
|
+
const configFile = path2.join(root, "tsconfig.json");
|
|
208534
208576
|
const config = import_typescript2.default.readJsonConfigFile(configFile, import_typescript2.default.sys.readFile);
|
|
208535
208577
|
const vue = import_language_core.createParsedCommandLine(vueTypeScript, import_typescript2.default.sys, configFile);
|
|
208536
208578
|
this.options = vue.vueOptions;
|
|
@@ -208597,18 +208639,18 @@ class VueProject {
|
|
|
208597
208639
|
`).length;
|
|
208598
208640
|
}
|
|
208599
208641
|
}
|
|
208600
|
-
function vueProject(root) {
|
|
208601
|
-
const manifestFile =
|
|
208602
|
-
if (!
|
|
208642
|
+
function vueProject(root, repositoryRoot = root) {
|
|
208643
|
+
const manifestFile = path2.join(root, "package.json");
|
|
208644
|
+
if (!existsSync2(manifestFile))
|
|
208603
208645
|
return;
|
|
208604
208646
|
const manifest = JSON.parse(readFileSync(manifestFile, "utf8"));
|
|
208605
|
-
if (!manifest
|
|
208647
|
+
if (!hasDependency(manifest, "vue"))
|
|
208606
208648
|
return;
|
|
208607
208649
|
try {
|
|
208608
208650
|
createRequire(manifestFile).resolve("vue/package.json");
|
|
208609
|
-
return { manifest, project: new VueProject(root) };
|
|
208651
|
+
return { manifest, project: new VueProject(root, repositoryRoot) };
|
|
208610
208652
|
} catch (error) {
|
|
208611
|
-
throw new Error(`VUE_PROJECT_PREPARATION: Install project dependencies with its declared package manager and lockfile; ensure
|
|
208653
|
+
throw new Error(`VUE_PROJECT_PREPARATION: Install project dependencies with its declared package manager and lockfile; ensure project tsconfig.json and Vue sources are valid. ${error}`);
|
|
208612
208654
|
}
|
|
208613
208655
|
}
|
|
208614
208656
|
|
|
@@ -208782,9 +208824,53 @@ class VueEvidence {
|
|
|
208782
208824
|
}
|
|
208783
208825
|
}
|
|
208784
208826
|
|
|
208827
|
+
// plugins/scanners/vue/src/index.ts
|
|
208828
|
+
import path3 from "path";
|
|
208829
|
+
|
|
208830
|
+
// plugins/scanners/observations.ts
|
|
208831
|
+
function combineObservations(parts) {
|
|
208832
|
+
if (!parts.length)
|
|
208833
|
+
return;
|
|
208834
|
+
const roots = [];
|
|
208835
|
+
const files = new Map;
|
|
208836
|
+
const operations = [];
|
|
208837
|
+
const invocations = [];
|
|
208838
|
+
const diagnostics = [];
|
|
208839
|
+
for (const { key, observation } of parts) {
|
|
208840
|
+
const id = (value) => JSON.stringify([key, value]);
|
|
208841
|
+
roots.push(...observation.roots.map((root) => ({ ...root, id: id(root.id), ...root.parent ? { parent: id(root.parent) } : {} })));
|
|
208842
|
+
for (const source of observation.files) {
|
|
208843
|
+
const combined = files.get(source.file) ?? { file: source.file, roots: [], symbols: [] };
|
|
208844
|
+
combined.roots.push(...source.roots.map(id));
|
|
208845
|
+
combined.symbols.push(...source.symbols.map((symbol) => ({ ...symbol, id: id(symbol.id) })));
|
|
208846
|
+
files.set(source.file, combined);
|
|
208847
|
+
}
|
|
208848
|
+
operations.push(...(observation.operations ?? []).map((operation) => ({ ...operation, id: id(operation.id) })));
|
|
208849
|
+
invocations.push(...(observation.invocations ?? []).map((call) => ({ ...call, source: id(call.source), targets: call.targets.map(id) })));
|
|
208850
|
+
diagnostics.push(...observation.diagnostics);
|
|
208851
|
+
}
|
|
208852
|
+
return createScanObservation({
|
|
208853
|
+
scanner: parts[0].observation.scanner,
|
|
208854
|
+
roots,
|
|
208855
|
+
files: [...files.values()],
|
|
208856
|
+
operations,
|
|
208857
|
+
invocations,
|
|
208858
|
+
diagnostics
|
|
208859
|
+
});
|
|
208860
|
+
}
|
|
208861
|
+
|
|
208785
208862
|
// plugins/scanners/vue/src/index.ts
|
|
208786
208863
|
async function scanVue(root) {
|
|
208787
|
-
const
|
|
208864
|
+
const parts = [];
|
|
208865
|
+
for (const project of await frameworkProjects(root, "vue")) {
|
|
208866
|
+
const observation = await scanVueProject(project, root);
|
|
208867
|
+
if (observation)
|
|
208868
|
+
parts.push({ key: relative(root, project), observation });
|
|
208869
|
+
}
|
|
208870
|
+
return combineObservations(parts);
|
|
208871
|
+
}
|
|
208872
|
+
async function scanVueProject(projectRoot, root) {
|
|
208873
|
+
const prepared = vueProject(projectRoot, root);
|
|
208788
208874
|
if (!prepared)
|
|
208789
208875
|
return;
|
|
208790
208876
|
const { manifest, project } = prepared;
|
|
@@ -208797,7 +208883,7 @@ async function scanVue(root) {
|
|
|
208797
208883
|
const files = project.files.map((source) => ({ file: relative(root, source.fileName), symbols: [] }));
|
|
208798
208884
|
return createScanObservation({
|
|
208799
208885
|
scanner: { id: "vue", technology: "typescript/vue", engine: "@vue/language-core", engineVersion: "3.3.11" },
|
|
208800
|
-
roots: [{ id: "vue-project", kind: "package", name: manifest.name, file: "package.json" }],
|
|
208886
|
+
roots: [{ id: "vue-project", kind: "package", name: manifest.name, file: relative(root, path3.join(projectRoot, "package.json")) }],
|
|
208801
208887
|
files: files.map((file) => ({ ...file, roots: ["vue-project"] })),
|
|
208802
208888
|
operations: [...evidence.operations.values()],
|
|
208803
208889
|
invocations: evidence.invocations,
|
|
@@ -208806,10 +208892,13 @@ async function scanVue(root) {
|
|
|
208806
208892
|
}
|
|
208807
208893
|
var src_default = {
|
|
208808
208894
|
id: "vue",
|
|
208809
|
-
watch: { include: ["**/*.vue", "**/*.ts", "tsconfig
|
|
208895
|
+
watch: { include: ["**/*.vue", "**/*.ts", "**/tsconfig*.json", "**/package.json"], exclude: [] },
|
|
208810
208896
|
checkReadiness: async (root) => {
|
|
208811
|
-
|
|
208812
|
-
|
|
208897
|
+
const projects = await frameworkProjects(root, "vue");
|
|
208898
|
+
if (!projects.length)
|
|
208899
|
+
throw new Error("VUE_PROJECT_REQUIRED: No Vue project declaration was found.");
|
|
208900
|
+
for (const project of projects)
|
|
208901
|
+
vueProject(project, root);
|
|
208813
208902
|
},
|
|
208814
208903
|
scan: scanVue
|
|
208815
208904
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@groma/scanner-vue",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Complementary Vue framework evidence; a dependency declaration does not verify runtime use.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -25,10 +25,7 @@
|
|
|
25
25
|
}
|
|
26
26
|
],
|
|
27
27
|
"compatibility": {
|
|
28
|
-
"groma": "^0.3.0"
|
|
29
|
-
"technologyVersions": {
|
|
30
|
-
"vue": "3.5.18 || 3.5.42"
|
|
31
|
-
}
|
|
28
|
+
"groma": "^0.3.0"
|
|
32
29
|
}
|
|
33
30
|
}
|
|
34
31
|
}
|