@groma/scanner-javascript 0.2.0 → 0.2.2
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 +5 -4
- package/dist/index.js +85 -68
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ bun plugins/scanners/javascript/build.ts
|
|
|
13
13
|
From the project being scanned:
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
|
-
groma
|
|
16
|
+
groma plugin add /absolute/path/to/groma/plugins/scanners/javascript/dist/package
|
|
17
17
|
groma scan
|
|
18
18
|
```
|
|
19
19
|
|
|
@@ -42,10 +42,10 @@ output, such as `jquery-ui.min.js`, and `node_modules`, `dist`, `build` and
|
|
|
42
42
|
lists select.
|
|
43
43
|
|
|
44
44
|
A bundle under an ordinary name, such as `vendor.js`, is read like any other
|
|
45
|
-
source; a project that keeps it out adds a pattern to `
|
|
45
|
+
source; a project that keeps it out adds a pattern to `config.json`.
|
|
46
46
|
|
|
47
47
|
Test sources are treated like any other JavaScript source: the defaults name
|
|
48
|
-
none, so a project that keeps them out adds a pattern to `
|
|
48
|
+
none, so a project that keeps them out adds a pattern to `config.json`.
|
|
49
49
|
|
|
50
50
|
TypeScript sources belong to the [TypeScript scanner](../typescript/index.md)
|
|
51
51
|
and single-file components to the [Vue scanner](../vue/index.md). This scanner
|
|
@@ -78,7 +78,8 @@ assignments or `cross-env` may come before the runtime, and runtime options and
|
|
|
78
78
|
a `run` or `watch` subcommand before the script; the first remaining word must
|
|
79
79
|
name the script, so a preloaded module or `bun build` supplies none. An HTML
|
|
80
80
|
page's script supplies one too, named after the page, or after its folder for
|
|
81
|
-
an `index.html`.
|
|
81
|
+
an `index.html`. A `package.json`, `angular.json` or `project.json` that is not
|
|
82
|
+
valid JSON supplies none: the scan continues and reports a warning for that file.
|
|
82
83
|
|
|
83
84
|
## Source outline
|
|
84
85
|
|
package/dist/index.js
CHANGED
|
@@ -118,13 +118,13 @@ function compare(...values) {
|
|
|
118
118
|
}
|
|
119
119
|
function uniqueBy(values, key, label) {
|
|
120
120
|
const seen = new Set;
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
const keyed = values.map((value) => ({ id: key(value), value }));
|
|
122
|
+
for (const { id } of keyed) {
|
|
123
123
|
if (seen.has(id))
|
|
124
124
|
throw new Error(`duplicate ${label}: ${id}`);
|
|
125
125
|
seen.add(id);
|
|
126
126
|
}
|
|
127
|
-
return
|
|
127
|
+
return keyed.sort((left, right) => left.id.localeCompare(right.id)).map((entry) => entry.value);
|
|
128
128
|
}
|
|
129
129
|
function createScanObservation(input) {
|
|
130
130
|
const roots = validateRoots(input.roots);
|
|
@@ -135,9 +135,7 @@ function createScanObservation(input) {
|
|
|
135
135
|
symbols: [...new Map(file.symbols.map((symbol) => [
|
|
136
136
|
compare(symbol.id, symbol.kind),
|
|
137
137
|
symbol
|
|
138
|
-
]))
|
|
139
|
-
return compare(left.id, left.kind).localeCompare(compare(right.id, right.kind));
|
|
140
|
-
})
|
|
138
|
+
]))].sort(([left], [right]) => left.localeCompare(right)).map(([, symbol]) => symbol)
|
|
141
139
|
})), (file) => file.file, "file path");
|
|
142
140
|
const filePaths = new Set(files.map((file) => file.file));
|
|
143
141
|
for (const file of files) {
|
|
@@ -148,8 +146,6 @@ function createScanObservation(input) {
|
|
|
148
146
|
throw new Error(`file references unknown root: ${root}`);
|
|
149
147
|
}
|
|
150
148
|
}
|
|
151
|
-
for (const diagnostic of input.diagnostics)
|
|
152
|
-
diagnosticLocation(diagnostic);
|
|
153
149
|
return {
|
|
154
150
|
schemaVersion: 1,
|
|
155
151
|
scanner: input.scanner,
|
|
@@ -159,14 +155,14 @@ function createScanObservation(input) {
|
|
|
159
155
|
...entryPoints(input.entryPoints, filePaths),
|
|
160
156
|
...operationEvidence(input, filePaths),
|
|
161
157
|
...httpEvidence(input.httpEndpoints, input.httpRequests, input.operations && new Set(input.operations.map((operation) => operation.id))),
|
|
162
|
-
diagnostics:
|
|
163
|
-
diagnosticKey(diagnostic),
|
|
164
|
-
diagnostic
|
|
165
|
-
])).values()].sort((left, right) => {
|
|
166
|
-
return diagnosticKey(left).localeCompare(diagnosticKey(right));
|
|
167
|
-
})
|
|
158
|
+
diagnostics: normalizeScanDiagnostics(input.diagnostics)
|
|
168
159
|
};
|
|
169
160
|
}
|
|
161
|
+
function normalizeScanDiagnostics(diagnostics) {
|
|
162
|
+
for (const diagnostic of diagnostics)
|
|
163
|
+
diagnosticLocation(diagnostic);
|
|
164
|
+
return [...new Map(diagnostics.map((diagnostic) => [diagnosticKey(diagnostic), diagnostic]))].sort(([left], [right]) => left.localeCompare(right)).map(([, diagnostic]) => diagnostic);
|
|
165
|
+
}
|
|
170
166
|
function entryPoints(input, paths) {
|
|
171
167
|
if (input === undefined)
|
|
172
168
|
return {};
|
|
@@ -275,10 +271,14 @@ function operationTokens(operation) {
|
|
|
275
271
|
const endLine = Number(operation.endLine);
|
|
276
272
|
if (endLine < startLine)
|
|
277
273
|
throw new Error("operation.endLine must be at or after startLine");
|
|
274
|
+
const tokens = array(operation.tokens, "operation.tokens");
|
|
275
|
+
tokens.forEach((token) => {
|
|
276
|
+
string(token, "operation.token");
|
|
277
|
+
});
|
|
278
278
|
return {
|
|
279
279
|
startLine,
|
|
280
280
|
endLine,
|
|
281
|
-
tokens
|
|
281
|
+
tokens
|
|
282
282
|
};
|
|
283
283
|
}
|
|
284
284
|
function validateOperationTokens(operation) {
|
|
@@ -308,7 +308,7 @@ function sourcePosition(position) {
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
// plugins/scanners/javascript/src/index.ts
|
|
311
|
-
import
|
|
311
|
+
import ts8 from "./typescript.cjs";
|
|
312
312
|
|
|
313
313
|
// plugins/scanners/javascript/src/evidence.ts
|
|
314
314
|
import ts2 from "./typescript.cjs";
|
|
@@ -643,15 +643,15 @@ function topLevelDeclarations(source) {
|
|
|
643
643
|
|
|
644
644
|
// plugins/scanners/javascript/src/evidence.ts
|
|
645
645
|
var { executable, operationFields } = typeScriptOperations(ts2);
|
|
646
|
-
function javaScriptEvidence(file,
|
|
646
|
+
function javaScriptEvidence(file, syntax) {
|
|
647
647
|
const operations = [];
|
|
648
648
|
const invocations = [];
|
|
649
649
|
const calls = [];
|
|
650
650
|
const owners = new Map;
|
|
651
|
-
const lineOf = (position) =>
|
|
651
|
+
const lineOf = (position) => syntax.getLineAndCharacterOfPosition(position).line + 1;
|
|
652
652
|
let moduleCode;
|
|
653
653
|
function operation(node) {
|
|
654
|
-
const position = node.getStart(
|
|
654
|
+
const position = node.getStart(syntax);
|
|
655
655
|
const recorded = { id: `${file}#${position}`, file, position, ...operationFields(node) };
|
|
656
656
|
operations.push(recorded);
|
|
657
657
|
owners.set(node, recorded.id);
|
|
@@ -659,13 +659,13 @@ function javaScriptEvidence(file, source) {
|
|
|
659
659
|
}
|
|
660
660
|
function moduleOperation() {
|
|
661
661
|
if (moduleCode === undefined) {
|
|
662
|
-
moduleCode = { id: `${file}#module`, file, name: "(anonymous)", position:
|
|
662
|
+
moduleCode = { id: `${file}#module`, file, name: "(anonymous)", position: syntax.getStart(syntax) };
|
|
663
663
|
operations.push(moduleCode);
|
|
664
664
|
}
|
|
665
665
|
return moduleCode;
|
|
666
666
|
}
|
|
667
667
|
function invocation(node, owner) {
|
|
668
|
-
const position = node.getStart(
|
|
668
|
+
const position = node.getStart(syntax);
|
|
669
669
|
invocations.push({
|
|
670
670
|
source: owner.id,
|
|
671
671
|
targets: [],
|
|
@@ -691,8 +691,8 @@ function javaScriptEvidence(file, source) {
|
|
|
691
691
|
}
|
|
692
692
|
return moduleOperation().id;
|
|
693
693
|
}
|
|
694
|
-
|
|
695
|
-
const symbols = new Map(topLevelDeclarations(
|
|
694
|
+
syntax.forEachChild((child) => visit(child, undefined));
|
|
695
|
+
const symbols = new Map(topLevelDeclarations(syntax).map((declaration) => [`${file}#${declaration.name}`, { id: `${file}#${declaration.name}`, ...declaration }]));
|
|
696
696
|
return { symbols: [...symbols.values()], operations, invocations, calls, operationAt };
|
|
697
697
|
}
|
|
698
698
|
|
|
@@ -2288,10 +2288,10 @@ async function httpRequest(context, call) {
|
|
|
2288
2288
|
}
|
|
2289
2289
|
|
|
2290
2290
|
// plugins/scanners/javascript/src/http.ts
|
|
2291
|
-
function fileChecker(
|
|
2291
|
+
function fileChecker(syntax) {
|
|
2292
2292
|
const options = { allowJs: true, noLib: true, noResolve: true, types: [], noEmit: true };
|
|
2293
2293
|
const host = {
|
|
2294
|
-
getSourceFile: (name) => name ===
|
|
2294
|
+
getSourceFile: (name) => name === syntax.fileName ? syntax : undefined,
|
|
2295
2295
|
getDefaultLibFileName: () => "lib.d.ts",
|
|
2296
2296
|
writeFile: () => {
|
|
2297
2297
|
return;
|
|
@@ -2301,18 +2301,18 @@ function fileChecker(source) {
|
|
|
2301
2301
|
useCaseSensitiveFileNames: () => true,
|
|
2302
2302
|
getNewLine: () => `
|
|
2303
2303
|
`,
|
|
2304
|
-
fileExists: (name) => name ===
|
|
2304
|
+
fileExists: (name) => name === syntax.fileName,
|
|
2305
2305
|
readFile: () => {
|
|
2306
2306
|
return;
|
|
2307
2307
|
}
|
|
2308
2308
|
};
|
|
2309
|
-
return ts4.createProgram([
|
|
2309
|
+
return ts4.createProgram([syntax.fileName], options, host).getTypeChecker();
|
|
2310
2310
|
}
|
|
2311
2311
|
function classic(node) {
|
|
2312
2312
|
return node;
|
|
2313
2313
|
}
|
|
2314
|
-
function fileContext(
|
|
2315
|
-
const context = urlContext(ts4, classicChecker(ts4, fileChecker(
|
|
2314
|
+
function fileContext({ file, syntax }, evidence) {
|
|
2315
|
+
const context = urlContext(ts4, classicChecker(ts4, fileChecker(syntax)), [syntax], true);
|
|
2316
2316
|
const operationAt = (node) => evidence.operationAt(classic(node));
|
|
2317
2317
|
return {
|
|
2318
2318
|
...context,
|
|
@@ -2323,7 +2323,7 @@ function fileContext(source, evidence) {
|
|
|
2323
2323
|
return typeof held === "object" && ts4.isFunctionLike(classic(held.node)) ? operationAt(held.node) : operationAt(registration);
|
|
2324
2324
|
},
|
|
2325
2325
|
callerOperation: operationAt,
|
|
2326
|
-
file: (
|
|
2326
|
+
file: () => file
|
|
2327
2327
|
};
|
|
2328
2328
|
}
|
|
2329
2329
|
async function javaScriptHttpFacts(source, evidence) {
|
|
@@ -2334,7 +2334,7 @@ async function javaScriptHttpFacts(source, evidence) {
|
|
|
2334
2334
|
if (request !== undefined)
|
|
2335
2335
|
httpRequests.push({ operation: evidence.operationAt(call), ...request });
|
|
2336
2336
|
}
|
|
2337
|
-
const placed = await routerEndpoints(context, [source], evidence.calls);
|
|
2337
|
+
const placed = await routerEndpoints(context, [source.syntax], evidence.calls);
|
|
2338
2338
|
return { httpEndpoints: [...withOrder(placed), ...await serveEndpoints(context, evidence.calls)], httpRequests };
|
|
2339
2339
|
}
|
|
2340
2340
|
|
|
@@ -2527,14 +2527,17 @@ async function readJavaScriptOutline(repositoryRoot, references) {
|
|
|
2527
2527
|
// plugins/scanners/javascript/src/sources.ts
|
|
2528
2528
|
import { readFile as readFile2 } from "fs/promises";
|
|
2529
2529
|
import path2 from "path";
|
|
2530
|
+
import ts6 from "./typescript.cjs";
|
|
2530
2531
|
var SOURCE = /\.(?:js|mjs|cjs|jsx)$/;
|
|
2531
2532
|
function javaScriptFiles(files) {
|
|
2532
2533
|
return files.filter((file) => SOURCE.test(file));
|
|
2533
2534
|
}
|
|
2534
2535
|
async function javaScriptSources(root, files) {
|
|
2535
2536
|
const sources = [];
|
|
2536
|
-
for (const file of javaScriptFiles(files))
|
|
2537
|
-
|
|
2537
|
+
for (const file of javaScriptFiles(files)) {
|
|
2538
|
+
const text = await readFile2(path2.join(root, file), "utf8");
|
|
2539
|
+
sources.push({ file, syntax: ts6.createSourceFile(file, text, ts6.ScriptTarget.Latest, true) });
|
|
2540
|
+
}
|
|
2538
2541
|
return sources;
|
|
2539
2542
|
}
|
|
2540
2543
|
|
|
@@ -2656,20 +2659,32 @@ function reachedFiles(entry, compiled, imports, packages, units) {
|
|
|
2656
2659
|
}
|
|
2657
2660
|
async function declaredEntries(root, declarations, packages, workspaces) {
|
|
2658
2661
|
const entries = [];
|
|
2662
|
+
const diagnostics = [];
|
|
2659
2663
|
for (const file of declarations) {
|
|
2660
2664
|
const text = await readFile3(path4.join(root, file), "utf8");
|
|
2661
2665
|
const name = path4.posix.basename(file);
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2666
|
+
try {
|
|
2667
|
+
if (name === "package.json") {
|
|
2668
|
+
const manifest = JSON.parse(text);
|
|
2669
|
+
entries.push(...declaredBins(file, manifest), ...declaredScripts(file, manifest.scripts));
|
|
2670
|
+
} else if (name === "angular.json")
|
|
2671
|
+
entries.push(...angularEntries(file, text));
|
|
2672
|
+
else if (name === "project.json")
|
|
2673
|
+
entries.push(...nxEntries(file, text, workspaces));
|
|
2674
|
+
else if (file.endsWith(".html"))
|
|
2675
|
+
entries.push(...browserEntries(file, text, packages));
|
|
2676
|
+
} catch (error) {
|
|
2677
|
+
if (!(error instanceof SyntaxError))
|
|
2678
|
+
throw error;
|
|
2679
|
+
diagnostics.push({
|
|
2680
|
+
severity: "warning",
|
|
2681
|
+
code: "JAVASCRIPT_MANIFEST_INVALID",
|
|
2682
|
+
file,
|
|
2683
|
+
message: `The file is not valid JSON; the entry points it declares are not read. ${error.message}`
|
|
2684
|
+
});
|
|
2685
|
+
}
|
|
2671
2686
|
}
|
|
2672
|
-
return entries;
|
|
2687
|
+
return { entries, diagnostics };
|
|
2673
2688
|
}
|
|
2674
2689
|
function sourced(entry, files, outputs = []) {
|
|
2675
2690
|
const file = sourceOf(entry.file, outputs, files);
|
|
@@ -2683,7 +2698,8 @@ async function withJavaScriptEntries(root, observation, inputs, files) {
|
|
|
2683
2698
|
const packages = new Set(inventory.filter((file) => path4.posix.basename(file) === "package.json").map((file) => path4.posix.dirname(file)));
|
|
2684
2699
|
const active = new Set(observation.files.map((file) => packageFor(file.file, packages)));
|
|
2685
2700
|
const declarations = inventory.filter((file) => path4.posix.basename(file) !== "nx.json" && active.has(packageFor(file, packages)));
|
|
2686
|
-
const
|
|
2701
|
+
const declared = await declaredEntries(root, declarations, packages, workspaces);
|
|
2702
|
+
const entries = [...inputs.entries, ...declared.entries];
|
|
2687
2703
|
const inventoryFiles = [...observation.files];
|
|
2688
2704
|
const visible = new Set(inventoryFiles.map((file) => file.file));
|
|
2689
2705
|
const readable = new Set(files);
|
|
@@ -2700,12 +2716,17 @@ async function withJavaScriptEntries(root, observation, inputs, files) {
|
|
|
2700
2716
|
}
|
|
2701
2717
|
return [{ ...entry, files: [...new Set([entry.file, ...members.map((file) => file.file)])] }];
|
|
2702
2718
|
});
|
|
2703
|
-
return createScanObservation({
|
|
2719
|
+
return createScanObservation({
|
|
2720
|
+
...observation,
|
|
2721
|
+
files: inventoryFiles,
|
|
2722
|
+
entryPoints,
|
|
2723
|
+
diagnostics: [...observation.diagnostics, ...declared.diagnostics]
|
|
2724
|
+
});
|
|
2704
2725
|
}
|
|
2705
2726
|
|
|
2706
2727
|
// plugins/scanners/javascript/src/entries.ts
|
|
2707
2728
|
import path6 from "path";
|
|
2708
|
-
import
|
|
2729
|
+
import ts7 from "./typescript.cjs";
|
|
2709
2730
|
|
|
2710
2731
|
// plugins/scanners/entry-points/source.ts
|
|
2711
2732
|
import path5 from "path";
|
|
@@ -2770,37 +2791,34 @@ async function sourceBuildEntries(root, ts, checker, sources) {
|
|
|
2770
2791
|
|
|
2771
2792
|
// plugins/scanners/javascript/src/entries.ts
|
|
2772
2793
|
async function javaScriptEntries(root, sources) {
|
|
2773
|
-
const files = new Set(sources.map((source) => source.
|
|
2774
|
-
const imports = new Map(sources.map((
|
|
2775
|
-
const targets =
|
|
2794
|
+
const files = new Set(sources.map((source) => source.file));
|
|
2795
|
+
const imports = new Map(sources.map(({ file, syntax }) => {
|
|
2796
|
+
const targets = ts7.preProcessFile(syntax.text, true, true).importedFiles.flatMap((imported) => {
|
|
2776
2797
|
if (!imported.fileName.startsWith("."))
|
|
2777
2798
|
return [];
|
|
2778
|
-
const base = path6.posix.normalize(path6.posix.join(path6.posix.dirname(
|
|
2799
|
+
const base = path6.posix.normalize(path6.posix.join(path6.posix.dirname(file), imported.fileName));
|
|
2779
2800
|
const candidates = [base, ...[".js", ".mjs", ".cjs", ".jsx"].flatMap((extension) => [base + extension, `${base}/index${extension}`])];
|
|
2780
|
-
return candidates.find((
|
|
2801
|
+
return candidates.find((candidate) => files.has(candidate)) ?? [];
|
|
2781
2802
|
});
|
|
2782
|
-
return [
|
|
2803
|
+
return [file, targets];
|
|
2783
2804
|
}));
|
|
2784
|
-
const entries = (await Promise.all(sources.map((
|
|
2805
|
+
const entries = (await Promise.all(sources.map(async ({ file, syntax }) => (await sourceBuildEntries(root, ts7, classicChecker(ts7, fileChecker(syntax)), [syntax])).map((entry) => ({ ...entry, declaration: file }))))).flat();
|
|
2785
2806
|
return { imports, entries };
|
|
2786
2807
|
}
|
|
2787
2808
|
|
|
2788
2809
|
// plugins/scanners/javascript/src/index.ts
|
|
2789
|
-
function parse(source) {
|
|
2790
|
-
return ts7.createSourceFile(source.file, source.text, ts7.ScriptTarget.Latest, true);
|
|
2791
|
-
}
|
|
2792
2810
|
var SLOPPY_MODE_ONLY = new Set([1121, 1487, 1488, 1489]);
|
|
2793
|
-
function parseWarning(
|
|
2794
|
-
const { parseDiagnostics } =
|
|
2811
|
+
function parseWarning({ file, syntax }) {
|
|
2812
|
+
const { parseDiagnostics } = syntax;
|
|
2795
2813
|
const first = parseDiagnostics.find((diagnostic) => !SLOPPY_MODE_ONLY.has(diagnostic.code));
|
|
2796
2814
|
if (first === undefined)
|
|
2797
2815
|
return;
|
|
2798
2816
|
return {
|
|
2799
2817
|
severity: "warning",
|
|
2800
2818
|
code: "JAVASCRIPT_SOURCE_INVALID",
|
|
2801
|
-
file
|
|
2802
|
-
line:
|
|
2803
|
-
message: `The file does not parse, so it contributes no evidence: ${
|
|
2819
|
+
file,
|
|
2820
|
+
line: syntax.getLineAndCharacterOfPosition(first.start).line + 1,
|
|
2821
|
+
message: `The file does not parse, so it contributes no evidence: ${ts8.flattenDiagnosticMessageText(first.messageText, " ")}`
|
|
2804
2822
|
};
|
|
2805
2823
|
}
|
|
2806
2824
|
var src_default = {
|
|
@@ -2815,18 +2833,17 @@ var src_default = {
|
|
|
2815
2833
|
const sources = await javaScriptSources(root, files);
|
|
2816
2834
|
if (!sources.length)
|
|
2817
2835
|
return;
|
|
2818
|
-
const
|
|
2819
|
-
const
|
|
2820
|
-
const readable = parsed.filter((_, index) => warnings[index] === undefined);
|
|
2836
|
+
const warnings = sources.map(parseWarning);
|
|
2837
|
+
const readable = sources.filter((_, index) => warnings[index] === undefined);
|
|
2821
2838
|
const scanned = await Promise.all(readable.map(async (source) => {
|
|
2822
|
-
const evidence = javaScriptEvidence(source.
|
|
2823
|
-
return { file: source.
|
|
2839
|
+
const evidence = javaScriptEvidence(source.file, source.syntax);
|
|
2840
|
+
return { file: source.file, evidence, facts: await javaScriptHttpFacts(source, evidence) };
|
|
2824
2841
|
}));
|
|
2825
2842
|
const symbols = new Map(scanned.map(({ file, evidence }) => [file, evidence.symbols]));
|
|
2826
2843
|
return withJavaScriptEntries(root, createScanObservation({
|
|
2827
|
-
scanner: { id: "javascript", technology: "javascript", engine: "typescript-sdk", engineVersion:
|
|
2844
|
+
scanner: { id: "javascript", technology: "javascript", engine: "typescript-sdk", engineVersion: ts8.version },
|
|
2828
2845
|
roots: [{ id: "javascript-source", kind: "source-group", name: path7.basename(root) }],
|
|
2829
|
-
files:
|
|
2846
|
+
files: sources.map(({ file }) => ({ file, symbols: symbols.get(file) ?? [], roots: ["javascript-source"] })),
|
|
2830
2847
|
operations: scanned.flatMap(({ evidence }) => evidence.operations),
|
|
2831
2848
|
invocations: scanned.flatMap(({ evidence }) => evidence.invocations),
|
|
2832
2849
|
httpEndpoints: scanned.flatMap(({ facts }) => facts.httpEndpoints),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@groma/scanner-javascript",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "JavaScript source declarations, outlines and operation bodies without project dependencies.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"repository": {
|
|
57
57
|
"type": "git",
|
|
58
|
-
"url": "https://github.com/MrLesk/
|
|
58
|
+
"url": "https://github.com/MrLesk/groma.md.git"
|
|
59
59
|
},
|
|
60
60
|
"publishConfig": {
|
|
61
61
|
"access": "public"
|