@groma/scanner-vue 0.1.5 → 0.2.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/README.md +54 -36
- package/dist/index.js +594 -165
- package/dist/lib.d.ts +1 -3
- package/dist/lib.decorators.d.ts +1 -3
- package/dist/lib.decorators.legacy.d.ts +1 -3
- package/dist/lib.dom.asynciterable.d.ts +3 -26
- package/dist/lib.dom.d.ts +12638 -6942
- package/dist/lib.dom.iterable.d.ts +3 -556
- package/dist/lib.es2015.collection.d.ts +7 -4
- package/dist/lib.es2015.core.d.ts +2 -4
- package/dist/lib.es2015.d.ts +1 -3
- package/dist/lib.es2015.generator.d.ts +1 -3
- package/dist/lib.es2015.iterable.d.ts +2 -4
- package/dist/lib.es2015.promise.d.ts +1 -3
- package/dist/lib.es2015.proxy.d.ts +1 -3
- package/dist/lib.es2015.reflect.d.ts +1 -3
- package/dist/lib.es2015.symbol.d.ts +1 -3
- package/dist/lib.es2015.symbol.wellknown.d.ts +1 -3
- package/dist/lib.es2016.array.include.d.ts +1 -3
- package/dist/lib.es2016.d.ts +1 -3
- package/dist/lib.es2016.full.d.ts +1 -3
- package/dist/lib.es2016.intl.d.ts +1 -3
- package/dist/lib.es2017.arraybuffer.d.ts +1 -3
- package/dist/lib.es2017.d.ts +1 -3
- package/dist/lib.es2017.date.d.ts +1 -3
- package/dist/lib.es2017.full.d.ts +1 -3
- package/dist/lib.es2017.intl.d.ts +1 -3
- package/dist/lib.es2017.object.d.ts +1 -3
- package/dist/lib.es2017.sharedmemory.d.ts +1 -3
- package/dist/lib.es2017.string.d.ts +1 -3
- package/dist/lib.es2017.typedarrays.d.ts +1 -3
- package/dist/lib.es2018.asyncgenerator.d.ts +1 -3
- package/dist/lib.es2018.asynciterable.d.ts +1 -3
- package/dist/lib.es2018.d.ts +1 -3
- package/dist/lib.es2018.full.d.ts +1 -3
- package/dist/lib.es2018.intl.d.ts +1 -3
- package/dist/lib.es2018.promise.d.ts +1 -3
- package/dist/lib.es2018.regexp.d.ts +1 -3
- package/dist/lib.es2019.array.d.ts +1 -3
- package/dist/lib.es2019.d.ts +1 -3
- package/dist/lib.es2019.full.d.ts +1 -3
- package/dist/lib.es2019.intl.d.ts +1 -3
- package/dist/lib.es2019.object.d.ts +1 -3
- package/dist/lib.es2019.string.d.ts +1 -3
- package/dist/lib.es2019.symbol.d.ts +1 -3
- package/dist/lib.es2020.bigint.d.ts +5 -7
- package/dist/lib.es2020.d.ts +1 -3
- package/dist/lib.es2020.date.d.ts +1 -3
- package/dist/lib.es2020.full.d.ts +1 -3
- package/dist/lib.es2020.intl.d.ts +1 -3
- package/dist/lib.es2020.number.d.ts +1 -3
- package/dist/lib.es2020.promise.d.ts +1 -3
- package/dist/lib.es2020.sharedmemory.d.ts +1 -3
- package/dist/lib.es2020.string.d.ts +2 -4
- package/dist/lib.es2020.symbol.wellknown.d.ts +2 -4
- package/dist/lib.es2021.d.ts +1 -3
- package/dist/lib.es2021.full.d.ts +1 -3
- package/dist/lib.es2021.intl.d.ts +1 -3
- package/dist/lib.es2021.promise.d.ts +1 -3
- package/dist/lib.es2021.string.d.ts +1 -3
- package/dist/lib.es2021.weakref.d.ts +1 -3
- package/dist/lib.es2022.array.d.ts +1 -3
- package/dist/lib.es2022.d.ts +1 -3
- package/dist/lib.es2022.error.d.ts +1 -3
- package/dist/lib.es2022.full.d.ts +1 -3
- package/dist/lib.es2022.intl.d.ts +1 -3
- package/dist/lib.es2022.object.d.ts +1 -3
- package/dist/lib.es2022.regexp.d.ts +2 -4
- package/dist/lib.es2022.string.d.ts +1 -3
- package/dist/lib.es2023.array.d.ts +1 -3
- package/dist/lib.es2023.collection.d.ts +1 -3
- package/dist/lib.es2023.d.ts +1 -3
- package/dist/lib.es2023.full.d.ts +1 -3
- package/dist/lib.es2023.intl.d.ts +10 -4
- package/dist/lib.es2024.arraybuffer.d.ts +1 -3
- package/dist/lib.es2024.collection.d.ts +1 -3
- package/dist/lib.es2024.d.ts +1 -3
- package/dist/lib.es2024.full.d.ts +1 -3
- package/dist/lib.es2024.object.d.ts +1 -3
- package/dist/lib.es2024.promise.d.ts +1 -3
- package/dist/lib.es2024.regexp.d.ts +1 -3
- package/dist/lib.es2024.sharedmemory.d.ts +1 -3
- package/dist/lib.es2024.string.d.ts +1 -3
- package/dist/lib.es2025.collection.d.ts +94 -0
- package/dist/lib.es2025.d.ts +23 -0
- package/dist/{lib.esnext.float16.d.ts → lib.es2025.float16.d.ts} +1 -3
- package/dist/lib.es2025.full.d.ts +22 -0
- package/dist/lib.es2025.intl.d.ts +200 -0
- package/dist/{lib.esnext.iterator.d.ts → lib.es2025.iterator.d.ts} +1 -3
- package/dist/{lib.esnext.promise.d.ts → lib.es2025.promise.d.ts} +1 -3
- package/dist/lib.es2025.regexp.d.ts +30 -0
- package/dist/lib.es5.d.ts +22 -24
- package/dist/lib.es6.d.ts +1 -3
- package/dist/lib.esnext.array.d.ts +1 -3
- package/dist/lib.esnext.collection.d.ts +20 -69
- package/dist/lib.esnext.d.ts +6 -8
- package/dist/lib.esnext.date.d.ts +21 -0
- package/dist/lib.esnext.decorators.d.ts +1 -3
- package/dist/lib.esnext.disposable.d.ts +1 -3
- package/dist/lib.esnext.error.d.ts +1 -3
- package/dist/lib.esnext.full.d.ts +1 -3
- package/dist/lib.esnext.intl.d.ts +89 -3
- package/dist/lib.esnext.sharedmemory.d.ts +1 -3
- package/dist/lib.esnext.temporal.d.ts +485 -0
- package/dist/lib.esnext.typedarrays.d.ts +90 -0
- package/dist/lib.scripthost.d.ts +1 -3
- package/dist/lib.webworker.asynciterable.d.ts +3 -26
- package/dist/lib.webworker.d.ts +3396 -940
- package/dist/lib.webworker.importscripts.d.ts +1 -3
- package/dist/lib.webworker.iterable.d.ts +3 -325
- package/dist/typescript.cjs +2589 -1826
- package/package.json +29 -2
- package/validation.md +2 -2
package/dist/index.js
CHANGED
|
@@ -276,10 +276,10 @@ var require_shared_cjs = __commonJS(function(exports) {
|
|
|
276
276
|
}
|
|
277
277
|
var listDelimiterRE = /;(?![^(]*\))/g;
|
|
278
278
|
var propertyDelimiterRE = /:([^]+)/;
|
|
279
|
-
var styleCommentRE =
|
|
279
|
+
var styleCommentRE = /"(?:[^"\\]|\\[^])*"|'(?:[^'\\]|\\[^])*'|\\[^]|\/\*[^]*?\*\//g;
|
|
280
280
|
function parseStringStyle(cssText) {
|
|
281
281
|
const ret = {};
|
|
282
|
-
cssText.replace(styleCommentRE, "").split(listDelimiterRE).forEach((item) => {
|
|
282
|
+
cssText.replace(styleCommentRE, (match) => match.startsWith("/*") ? "" : match).split(listDelimiterRE).forEach((item) => {
|
|
283
283
|
if (item) {
|
|
284
284
|
const tmp = item.split(propertyDelimiterRE);
|
|
285
285
|
tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim());
|
|
@@ -428,16 +428,16 @@ var require_shared_cjs = __commonJS(function(exports) {
|
|
|
428
428
|
function getEscapedCssVarName(key, doubleEscape) {
|
|
429
429
|
return key.replace(cssVarNameEscapeSymbolsRE, (s) => doubleEscape ? s === '"' ? "\\\\\\\"" : `\\\\${s}` : `\\${s}`);
|
|
430
430
|
}
|
|
431
|
-
function looseCompareArrays(a, b) {
|
|
431
|
+
function looseCompareArrays(a, b, seen) {
|
|
432
432
|
if (a.length !== b.length)
|
|
433
433
|
return false;
|
|
434
434
|
let equal = true;
|
|
435
435
|
for (let i = 0;equal && i < a.length; i++) {
|
|
436
|
-
equal = looseEqual(a[i], b[i]);
|
|
436
|
+
equal = looseEqual(a[i], b[i], seen);
|
|
437
437
|
}
|
|
438
438
|
return equal;
|
|
439
439
|
}
|
|
440
|
-
function looseCompareCollections(a, b) {
|
|
440
|
+
function looseCompareCollections(a, b, seen) {
|
|
441
441
|
if (a.size !== b.size)
|
|
442
442
|
return false;
|
|
443
443
|
const candidates = Array.from(b);
|
|
@@ -445,7 +445,7 @@ var require_shared_cjs = __commonJS(function(exports) {
|
|
|
445
445
|
for (const item of a) {
|
|
446
446
|
let index = -1;
|
|
447
447
|
for (let i = 0;i < candidates.length; i++) {
|
|
448
|
-
if (!matched[i] && looseEqual(item, candidates[i])) {
|
|
448
|
+
if (!matched[i] && looseEqual(item, candidates[i], seen)) {
|
|
449
449
|
index = i;
|
|
450
450
|
break;
|
|
451
451
|
}
|
|
@@ -456,7 +456,47 @@ var require_shared_cjs = __commonJS(function(exports) {
|
|
|
456
456
|
}
|
|
457
457
|
return true;
|
|
458
458
|
}
|
|
459
|
-
function
|
|
459
|
+
function looseCompareObjects(a, b, seen) {
|
|
460
|
+
let aValidType = isMap(a);
|
|
461
|
+
let bValidType = isMap(b);
|
|
462
|
+
if (aValidType || bValidType) {
|
|
463
|
+
return aValidType && bValidType ? looseCompareCollections(a, b, seen) : false;
|
|
464
|
+
}
|
|
465
|
+
aValidType = isSet(a);
|
|
466
|
+
bValidType = isSet(b);
|
|
467
|
+
if (aValidType || bValidType) {
|
|
468
|
+
return aValidType && bValidType ? looseCompareCollections(a, b, seen) : false;
|
|
469
|
+
}
|
|
470
|
+
const aKeysCount = Object.keys(a).length;
|
|
471
|
+
const bKeysCount = Object.keys(b).length;
|
|
472
|
+
if (aKeysCount !== bKeysCount) {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
for (const key in a) {
|
|
476
|
+
const aHasKey = a.hasOwnProperty(key);
|
|
477
|
+
const bHasKey = b.hasOwnProperty(key);
|
|
478
|
+
if (aHasKey && !bHasKey || !aHasKey && bHasKey || !looseEqual(a[key], b[key], seen)) {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return String(a) === String(b);
|
|
483
|
+
}
|
|
484
|
+
function looseCompareNested(a, b, seen, compare) {
|
|
485
|
+
if (!seen) {
|
|
486
|
+
seen = [/* @__PURE__ */ new Map, /* @__PURE__ */ new Map];
|
|
487
|
+
}
|
|
488
|
+
const [seenA, seenB] = seen;
|
|
489
|
+
if (seenA.has(a) || seenB.has(b)) {
|
|
490
|
+
return seenA.get(a) === b && seenB.get(b) === a;
|
|
491
|
+
}
|
|
492
|
+
seenA.set(a, b);
|
|
493
|
+
seenB.set(b, a);
|
|
494
|
+
const equal = compare(a, b, seen);
|
|
495
|
+
seenA.delete(a);
|
|
496
|
+
seenB.delete(b);
|
|
497
|
+
return equal;
|
|
498
|
+
}
|
|
499
|
+
function looseEqual(a, b, seen) {
|
|
460
500
|
if (a === b)
|
|
461
501
|
return true;
|
|
462
502
|
let aValidType = isDate(a);
|
|
@@ -472,7 +512,7 @@ var require_shared_cjs = __commonJS(function(exports) {
|
|
|
472
512
|
aValidType = isArray(a);
|
|
473
513
|
bValidType = isArray(b);
|
|
474
514
|
if (aValidType || bValidType) {
|
|
475
|
-
return aValidType && bValidType ?
|
|
515
|
+
return aValidType && bValidType ? looseCompareNested(a, b, seen, looseCompareArrays) : false;
|
|
476
516
|
}
|
|
477
517
|
aValidType = isObject(a);
|
|
478
518
|
bValidType = isObject(b);
|
|
@@ -480,28 +520,7 @@ var require_shared_cjs = __commonJS(function(exports) {
|
|
|
480
520
|
if (!aValidType || !bValidType) {
|
|
481
521
|
return false;
|
|
482
522
|
}
|
|
483
|
-
|
|
484
|
-
bValidType = isMap(b);
|
|
485
|
-
if (aValidType || bValidType) {
|
|
486
|
-
return aValidType && bValidType ? looseCompareCollections(a, b) : false;
|
|
487
|
-
}
|
|
488
|
-
aValidType = isSet(a);
|
|
489
|
-
bValidType = isSet(b);
|
|
490
|
-
if (aValidType || bValidType) {
|
|
491
|
-
return aValidType && bValidType ? looseCompareCollections(a, b) : false;
|
|
492
|
-
}
|
|
493
|
-
const aKeysCount = Object.keys(a).length;
|
|
494
|
-
const bKeysCount = Object.keys(b).length;
|
|
495
|
-
if (aKeysCount !== bKeysCount) {
|
|
496
|
-
return false;
|
|
497
|
-
}
|
|
498
|
-
for (const key in a) {
|
|
499
|
-
const aHasKey = a.hasOwnProperty(key);
|
|
500
|
-
const bHasKey = b.hasOwnProperty(key);
|
|
501
|
-
if (aHasKey && !bHasKey || !aHasKey && bHasKey || !looseEqual(a[key], b[key])) {
|
|
502
|
-
return false;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
523
|
+
return looseCompareNested(a, b, seen, looseCompareObjects);
|
|
505
524
|
}
|
|
506
525
|
return String(a) === String(b);
|
|
507
526
|
}
|
|
@@ -4166,13 +4185,15 @@ var require_lib = __commonJS(function(exports) {
|
|
|
4166
4185
|
const arrows = [];
|
|
4167
4186
|
while (stack.length !== 0) {
|
|
4168
4187
|
const node = stack.pop();
|
|
4169
|
-
if (node.type === "ArrowFunctionExpression"
|
|
4188
|
+
if (node.type === "ArrowFunctionExpression") {
|
|
4170
4189
|
if (node.typeParameters || !node.returnType) {
|
|
4171
4190
|
this.finishArrowValidation(node);
|
|
4172
4191
|
} else {
|
|
4173
4192
|
arrows.push(node);
|
|
4174
4193
|
}
|
|
4175
|
-
|
|
4194
|
+
if (node.body.type !== "BlockStatement") {
|
|
4195
|
+
stack.push(node.body);
|
|
4196
|
+
}
|
|
4176
4197
|
} else if (node.type === "ConditionalExpression") {
|
|
4177
4198
|
stack.push(node.consequent);
|
|
4178
4199
|
stack.push(node.alternate);
|
|
@@ -11486,8 +11507,11 @@ var require_lib = __commonJS(function(exports) {
|
|
|
11486
11507
|
}
|
|
11487
11508
|
}
|
|
11488
11509
|
fillOptionalPropertiesForTSESLint(node) {
|
|
11489
|
-
var _node$directive, _node$decorators, _node$optional, _node$typeAnnotation, _node$accessibility, _node$decorators2, _node$override, _node$readonly, _node$static, _node$declare, _node$returnType, _node$typeParameters, _node$optional2, _node$optional3, _node$accessibility2, _node$readonly2, _node$static2, _node$declare2, _node$definite, _node$readonly3, _node$typeAnnotation2, _node$accessibility3, _node$decorators3, _node$override2, _node$optional4, _node$id, _node$abstract, _node$declare3, _node$decorators4, _node$implements, _node$superTypeArgume, _node$typeParameters2, _node$declare4, _node$definite2, _node$const, _node$declare5, _node$computed, _node$qualifier, _node$options, _node$declare6, _node$extends, _node$optional5, _node$readonly4, _node$declare7, _node$global, _node$const2, _node$in, _node$out;
|
|
11510
|
+
var _node$phase, _node$directive, _node$decorators, _node$optional, _node$typeAnnotation, _node$accessibility, _node$decorators2, _node$override, _node$readonly, _node$static, _node$declare, _node$returnType, _node$typeParameters, _node$optional2, _node$optional3, _node$accessibility2, _node$readonly2, _node$static2, _node$declare2, _node$definite, _node$readonly3, _node$typeAnnotation2, _node$accessibility3, _node$decorators3, _node$override2, _node$optional4, _node$id, _node$abstract, _node$declare3, _node$decorators4, _node$implements, _node$superTypeArgume, _node$typeParameters2, _node$declare4, _node$definite2, _node$const, _node$declare5, _node$computed, _node$qualifier, _node$options, _node$declare6, _node$extends, _node$optional5, _node$readonly4, _node$declare7, _node$global, _node$const2, _node$in, _node$out;
|
|
11490
11511
|
switch (node.type) {
|
|
11512
|
+
case "ImportDeclaration":
|
|
11513
|
+
(_node$phase = node.phase) != null || (node.phase = null);
|
|
11514
|
+
return;
|
|
11491
11515
|
case "ExpressionStatement":
|
|
11492
11516
|
(_node$directive = node.directive) != null || (node.directive = undefined);
|
|
11493
11517
|
return;
|
|
@@ -30888,7 +30912,7 @@ var require_path_browserify = __commonJS(function(exports, module) {
|
|
|
30888
30912
|
|
|
30889
30913
|
// node_modules/@vue/language-core/lib/compilerOptions.js
|
|
30890
30914
|
var require_compilerOptions = __commonJS(function(exports) {
|
|
30891
|
-
var __dirname = "/Users/runner/work/
|
|
30915
|
+
var __dirname = "/Users/runner/work/groma.md/groma.md/node_modules/@vue/language-core/lib";
|
|
30892
30916
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30893
30917
|
exports.CompilerOptionsResolver = undefined;
|
|
30894
30918
|
exports.createParsedCommandLineByJson = createParsedCommandLineByJson;
|
|
@@ -39759,6 +39783,7 @@ function createScanObservation(input) {
|
|
|
39759
39783
|
roots,
|
|
39760
39784
|
files,
|
|
39761
39785
|
...sourceUnits(input.sourceUnits, filePaths),
|
|
39786
|
+
...entryPoints(input.entryPoints, filePaths),
|
|
39762
39787
|
...operationEvidence(input, filePaths),
|
|
39763
39788
|
...httpEvidence(input.httpEndpoints, input.httpRequests, input.operations && new Set(input.operations.map((operation) => operation.id))),
|
|
39764
39789
|
diagnostics: [...new Map(input.diagnostics.map((diagnostic) => [
|
|
@@ -39769,6 +39794,29 @@ function createScanObservation(input) {
|
|
|
39769
39794
|
})
|
|
39770
39795
|
};
|
|
39771
39796
|
}
|
|
39797
|
+
function entryPoints(input, paths) {
|
|
39798
|
+
if (input === undefined)
|
|
39799
|
+
return {};
|
|
39800
|
+
const entries = array(input, "entryPoints").map((value) => {
|
|
39801
|
+
const entry = object(value, "entry point");
|
|
39802
|
+
const files = [...new Set(array(entry.files, "entry point.files").map((file) => string(file, "entry point.file")))].sort();
|
|
39803
|
+
for (const file of files) {
|
|
39804
|
+
if (!paths.has(file))
|
|
39805
|
+
throw new Error(`entry point references unknown file: ${file}`);
|
|
39806
|
+
}
|
|
39807
|
+
const file = string(entry.file, "entry point.file");
|
|
39808
|
+
if (!files.includes(file))
|
|
39809
|
+
throw new Error(`entry point must include its own source file: ${file}`);
|
|
39810
|
+
return {
|
|
39811
|
+
file,
|
|
39812
|
+
declaration: string(entry.declaration, "entry point.declaration"),
|
|
39813
|
+
name: string(entry.name, "entry point.name"),
|
|
39814
|
+
files
|
|
39815
|
+
};
|
|
39816
|
+
});
|
|
39817
|
+
const key = (entry) => compare(entry.file, entry.declaration, entry.name, ...entry.files);
|
|
39818
|
+
return { entryPoints: [...new Map(entries.map((entry) => [key(entry), entry])).values()].sort((a, b) => key(a).localeCompare(key(b))) };
|
|
39819
|
+
}
|
|
39772
39820
|
function sourceUnits(input, paths) {
|
|
39773
39821
|
if (input === undefined)
|
|
39774
39822
|
return {};
|
|
@@ -39894,64 +39942,70 @@ import ts2 from "./typescript.cjs";
|
|
|
39894
39942
|
// plugins/scanners/vue/src/project.ts
|
|
39895
39943
|
var import_typescript = __toESM(require_typescript(), 1);
|
|
39896
39944
|
var import_language_core = __toESM(require_language_core2(), 1);
|
|
39897
|
-
import {
|
|
39945
|
+
import { readFileSync } from "fs";
|
|
39898
39946
|
import path2 from "path";
|
|
39899
39947
|
import ts from "./typescript.cjs";
|
|
39900
39948
|
|
|
39901
|
-
// plugins/scanners/
|
|
39902
|
-
import { execFile } from "child_process";
|
|
39903
|
-
import { existsSync } from "fs";
|
|
39949
|
+
// plugins/scanners/typescript-project.ts
|
|
39904
39950
|
import { readFile } from "fs/promises";
|
|
39905
39951
|
import path from "path";
|
|
39906
|
-
|
|
39907
|
-
|
|
39908
|
-
|
|
39909
|
-
|
|
39910
|
-
|
|
39911
|
-
|
|
39912
|
-
"target",
|
|
39913
|
-
"dist",
|
|
39914
|
-
"build",
|
|
39915
|
-
"bin",
|
|
39916
|
-
"obj",
|
|
39917
|
-
".gradle",
|
|
39918
|
-
".angular",
|
|
39919
|
-
"coverage",
|
|
39920
|
-
"generated",
|
|
39921
|
-
"groma",
|
|
39922
|
-
".groma"
|
|
39923
|
-
]);
|
|
39924
|
-
async function repositoryFiles(root, matches) {
|
|
39925
|
-
const { stdout } = await execute("git", ["-C", root, "ls-files", "-z", "--cached", "--others", "--exclude-standard"], { maxBuffer: 64 * 1024 * 1024 });
|
|
39926
|
-
return [...new Set(stdout.split("\x00").filter((file) => file && matches(file) && existsSync(path.join(root, file))))].sort();
|
|
39927
|
-
}
|
|
39928
|
-
function projectFiles(root, matches) {
|
|
39929
|
-
return repositoryFiles(root, (file) => matches(file) && !file.split("/").some((part) => excluded.has(part)));
|
|
39952
|
+
async function packageManifest(root, file) {
|
|
39953
|
+
try {
|
|
39954
|
+
return JSON.parse(await readFile(path.join(root, file), "utf8"));
|
|
39955
|
+
} catch {
|
|
39956
|
+
return;
|
|
39957
|
+
}
|
|
39930
39958
|
}
|
|
39931
39959
|
function hasDependency(manifest, dependency) {
|
|
39932
39960
|
return ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"].some((section) => typeof manifest[section]?.[dependency] === "string");
|
|
39933
39961
|
}
|
|
39934
|
-
|
|
39935
|
-
|
|
39962
|
+
function hasProjectConfig(directory, configs, options) {
|
|
39963
|
+
if (options.nestedConfig && [...configs].some((config) => directory === "." || config.startsWith(`${directory}/`)))
|
|
39964
|
+
return true;
|
|
39965
|
+
for (let current = directory;; current = path.posix.dirname(current)) {
|
|
39966
|
+
if (configs.has(current))
|
|
39967
|
+
return true;
|
|
39968
|
+
if (!options.inheritConfig || current === ".")
|
|
39969
|
+
return false;
|
|
39970
|
+
}
|
|
39971
|
+
}
|
|
39972
|
+
async function frameworkProjects(root, files, dependency, extensions, options = {}) {
|
|
39936
39973
|
const manifests = files.filter((file) => path.posix.basename(file) === "package.json");
|
|
39937
|
-
const
|
|
39974
|
+
const configs = new Set(files.filter((file) => path.posix.basename(file) === "tsconfig.json").map((file) => path.posix.dirname(file)));
|
|
39975
|
+
const candidates = new Set;
|
|
39976
|
+
for (const file of manifests) {
|
|
39977
|
+
const directory = path.posix.dirname(file);
|
|
39978
|
+
if (!hasProjectConfig(directory, configs, options))
|
|
39979
|
+
continue;
|
|
39980
|
+
const manifest = await packageManifest(root, file);
|
|
39981
|
+
if (manifest && hasDependency(manifest, dependency))
|
|
39982
|
+
candidates.add(directory);
|
|
39983
|
+
}
|
|
39938
39984
|
const sources = new Set;
|
|
39939
39985
|
for (const file of files.filter((file) => extensions.some((extension) => file.endsWith(extension)) && !file.endsWith(".d.ts"))) {
|
|
39940
39986
|
let directory = path.posix.dirname(file);
|
|
39941
|
-
while (directory !== "." && !
|
|
39987
|
+
while (directory !== "." && !candidates.has(directory))
|
|
39942
39988
|
directory = path.posix.dirname(directory);
|
|
39943
|
-
|
|
39989
|
+
if (candidates.has(directory))
|
|
39990
|
+
sources.add(directory);
|
|
39944
39991
|
}
|
|
39945
|
-
|
|
39946
|
-
|
|
39947
|
-
|
|
39948
|
-
|
|
39949
|
-
|
|
39950
|
-
|
|
39951
|
-
|
|
39952
|
-
|
|
39992
|
+
return [...candidates].filter((directory) => sources.has(directory)).map((directory) => path.resolve(root, directory));
|
|
39993
|
+
}
|
|
39994
|
+
async function frameworkProjectFiles(options) {
|
|
39995
|
+
const { root, files, dependency, projects, sources } = options;
|
|
39996
|
+
const directories = (await frameworkProjects(root, files, dependency, projects, options)).map((directory) => path.relative(root, directory).split(path.sep).join("/") || ".").sort((left, right) => right.length - left.length);
|
|
39997
|
+
const assigned = new Map(directories.map((directory) => [directory, []]));
|
|
39998
|
+
if (directories.length === 0)
|
|
39999
|
+
return assigned;
|
|
40000
|
+
for (const file of files.filter((candidate) => !candidate.endsWith(".d.ts"))) {
|
|
40001
|
+
const project = directories.find((directory) => directory === "." || file.startsWith(`${directory}/`));
|
|
40002
|
+
if (project !== undefined && sources.some((extension) => file.endsWith(extension)))
|
|
40003
|
+
assigned.get(project).push(file);
|
|
39953
40004
|
}
|
|
39954
|
-
return
|
|
40005
|
+
return assigned;
|
|
40006
|
+
}
|
|
40007
|
+
async function frameworkSourceFiles(options) {
|
|
40008
|
+
return [...(await frameworkProjectFiles(options)).values()].flat().sort();
|
|
39955
40009
|
}
|
|
39956
40010
|
|
|
39957
40011
|
// plugins/scanners/vue/src/project.ts
|
|
@@ -39974,6 +40028,15 @@ function failDiagnostics(diagnostics) {
|
|
|
39974
40028
|
`)}`).join(`
|
|
39975
40029
|
`));
|
|
39976
40030
|
}
|
|
40031
|
+
function projectConfig(root, repositoryRoot, files) {
|
|
40032
|
+
for (let directory = root;; directory = path2.dirname(directory)) {
|
|
40033
|
+
const file = path2.join(directory, "tsconfig.json");
|
|
40034
|
+
if (files.has(relative(repositoryRoot, file)))
|
|
40035
|
+
return file;
|
|
40036
|
+
if (directory === repositoryRoot)
|
|
40037
|
+
throw new Error(`${root}: no TypeScript config in the package or its repository ancestors`);
|
|
40038
|
+
}
|
|
40039
|
+
}
|
|
39977
40040
|
|
|
39978
40041
|
class VueProject {
|
|
39979
40042
|
program;
|
|
@@ -39981,17 +40044,32 @@ class VueProject {
|
|
|
39981
40044
|
files;
|
|
39982
40045
|
root;
|
|
39983
40046
|
options;
|
|
40047
|
+
diagnostics;
|
|
39984
40048
|
language;
|
|
39985
40049
|
plugin;
|
|
39986
|
-
|
|
40050
|
+
readable;
|
|
40051
|
+
constructor(root, repositoryRoot, sources, owners, files) {
|
|
39987
40052
|
this.root = repositoryRoot;
|
|
39988
|
-
|
|
40053
|
+
this.readable = files;
|
|
40054
|
+
const assigned = new Set(sources.map((file) => path2.resolve(repositoryRoot, file)));
|
|
40055
|
+
const selected = (file) => {
|
|
40056
|
+
const local = relative(repositoryRoot, file);
|
|
40057
|
+
return (owners.get(local) ?? root) === root && (local.startsWith("../") || files.has(local));
|
|
40058
|
+
};
|
|
40059
|
+
const configFile = projectConfig(root, repositoryRoot, files);
|
|
40060
|
+
const configRoot = path2.dirname(configFile);
|
|
39989
40061
|
const config = ts.readJsonConfigFile(configFile, ts.sys.readFile);
|
|
39990
40062
|
const vue = import_language_core.createParsedCommandLine(vueTypeScript, ts.sys, configFile);
|
|
39991
40063
|
this.options = vue.vueOptions;
|
|
39992
40064
|
this.plugin = import_language_core.createVueLanguagePlugin(vueTypeScript, vue.options, vue.vueOptions, (id) => id);
|
|
39993
|
-
const parsed = ts.parseJsonSourceFileConfigFileContent(config, ts.sys,
|
|
39994
|
-
failDiagnostics(parsed.errors);
|
|
40065
|
+
const parsed = ts.parseJsonSourceFileConfigFileContent(config, ts.sys, configRoot, {}, configFile, undefined, this.plugin.typescript.extraFileExtensions);
|
|
40066
|
+
failDiagnostics(parsed.errors.filter((item) => item.code !== 5083));
|
|
40067
|
+
this.diagnostics = parsed.errors.filter((item) => item.code === 5083).map((item) => ({
|
|
40068
|
+
severity: "warning",
|
|
40069
|
+
code: "vue-missing-config-base",
|
|
40070
|
+
file: relative(repositoryRoot, configFile),
|
|
40071
|
+
message: `The extended TypeScript config is absent; source uses the available settings. ${ts.flattenDiagnosticMessageText(item.messageText, " ")}`
|
|
40072
|
+
}));
|
|
39995
40073
|
parsed.options.allowNonTsExtensions = true;
|
|
39996
40074
|
const host = ts.createCompilerHost(parsed.options);
|
|
39997
40075
|
host.getCurrentDirectory = () => root;
|
|
@@ -40000,10 +40078,20 @@ class VueProject {
|
|
|
40000
40078
|
setup: (language) => {
|
|
40001
40079
|
this.language = language;
|
|
40002
40080
|
}
|
|
40003
|
-
}))({
|
|
40081
|
+
}))({
|
|
40082
|
+
rootNames: [...new Set([...assigned, ...parsed.fileNames.filter((file) => selected(file) || !ts.sys.fileExists(file))])],
|
|
40083
|
+
options: parsed.options,
|
|
40084
|
+
host
|
|
40085
|
+
});
|
|
40004
40086
|
failDiagnostics(this.program.getSyntacticDiagnostics());
|
|
40087
|
+
this.diagnostics.push(...this.program.getOptionsDiagnostics().filter((item) => item.code === 6053).map((item) => ({
|
|
40088
|
+
severity: "warning",
|
|
40089
|
+
code: "vue-missing-config-source",
|
|
40090
|
+
file: relative(repositoryRoot, configFile),
|
|
40091
|
+
message: `A declared TypeScript source is absent; available source was still scanned. ${ts.flattenDiagnosticMessageText(item.messageText, " ")}`
|
|
40092
|
+
})));
|
|
40005
40093
|
this.checker = this.program.getTypeChecker();
|
|
40006
|
-
this.files = this.program.getSourceFiles().filter((source) => this.owned(source));
|
|
40094
|
+
this.files = this.program.getSourceFiles().filter((source) => this.owned(source) && selected(source.fileName));
|
|
40007
40095
|
for (const source of this.files)
|
|
40008
40096
|
this.validateSfc(source.fileName);
|
|
40009
40097
|
}
|
|
@@ -40024,12 +40112,8 @@ class VueProject {
|
|
|
40024
40112
|
const src = block?.attrs.src;
|
|
40025
40113
|
if (typeof src !== "string" || !src.startsWith("."))
|
|
40026
40114
|
return [];
|
|
40027
|
-
const
|
|
40028
|
-
|
|
40029
|
-
if (member.startsWith("../"))
|
|
40030
|
-
return [];
|
|
40031
|
-
readFileSync(filename, "utf8");
|
|
40032
|
-
return [member];
|
|
40115
|
+
const member = relative(this.root, path2.resolve(path2.dirname(file), src));
|
|
40116
|
+
return this.readable.has(member) ? [member] : [];
|
|
40033
40117
|
});
|
|
40034
40118
|
return { primary, files: [primary, ...companions] };
|
|
40035
40119
|
}
|
|
@@ -40074,15 +40158,16 @@ class VueProject {
|
|
|
40074
40158
|
`).length;
|
|
40075
40159
|
}
|
|
40076
40160
|
}
|
|
40077
|
-
function vueProject(root, repositoryRoot =
|
|
40161
|
+
function vueProject(root, repositoryRoot, files, sources = [], owners = new Map) {
|
|
40162
|
+
const readable = new Set(files);
|
|
40078
40163
|
const manifestFile = path2.join(root, "package.json");
|
|
40079
|
-
if (!
|
|
40164
|
+
if (!readable.has(relative(repositoryRoot, manifestFile)))
|
|
40080
40165
|
return;
|
|
40081
40166
|
const manifest = JSON.parse(readFileSync(manifestFile, "utf8"));
|
|
40082
40167
|
if (!hasDependency(manifest, "vue"))
|
|
40083
40168
|
return;
|
|
40084
40169
|
try {
|
|
40085
|
-
return { manifest, project: new VueProject(root, repositoryRoot) };
|
|
40170
|
+
return { manifest, project: new VueProject(root, repositoryRoot, sources, owners, readable) };
|
|
40086
40171
|
} catch (error) {
|
|
40087
40172
|
throw new Error(`VUE_SOURCE_INVALID: Check the project tsconfig.json and Vue syntax. ${error}`);
|
|
40088
40173
|
}
|
|
@@ -40112,6 +40197,15 @@ function includesEvent(type, event) {
|
|
|
40112
40197
|
return type.literal.text === event;
|
|
40113
40198
|
return ts2.isUnionTypeNode(type) && type.types.some((item) => includesEvent(item, event));
|
|
40114
40199
|
}
|
|
40200
|
+
function directEmitOffset(expression, event) {
|
|
40201
|
+
const source = ts2.createSourceFile("event.ts", expression, ts2.ScriptTarget.Latest, true);
|
|
40202
|
+
const statement = source.statements[0];
|
|
40203
|
+
const call = statement && ts2.isExpressionStatement(statement) ? statement.expression : undefined;
|
|
40204
|
+
if (source.statements.length !== 1 || !call || !ts2.isCallExpression(call) || !ts2.isIdentifier(call.expression))
|
|
40205
|
+
return;
|
|
40206
|
+
const name = call.arguments[0];
|
|
40207
|
+
return name && ts2.isStringLiteral(name) && name.text === event ? call.expression.getStart(source) : undefined;
|
|
40208
|
+
}
|
|
40115
40209
|
|
|
40116
40210
|
class VueEvidence {
|
|
40117
40211
|
operations = new Map;
|
|
@@ -40126,6 +40220,8 @@ class VueEvidence {
|
|
|
40126
40220
|
if (!template?.ast)
|
|
40127
40221
|
return;
|
|
40128
40222
|
for (const element of import_language_core2.forEachElementNode(template.ast)) {
|
|
40223
|
+
if (element.tagType !== import_compiler_dom.ElementTypes.COMPONENT)
|
|
40224
|
+
continue;
|
|
40129
40225
|
for (const prop of element.props) {
|
|
40130
40226
|
if (prop.type !== import_compiler_dom.NodeTypes.DIRECTIVE || prop.name !== "on")
|
|
40131
40227
|
continue;
|
|
@@ -40178,7 +40274,7 @@ class VueEvidence {
|
|
|
40178
40274
|
if (!setup)
|
|
40179
40275
|
return;
|
|
40180
40276
|
const emits = import_language_core2.parseScriptSetupRanges(vueTypeScript, setup.ast, this.project.options).defineEmits;
|
|
40181
|
-
if (!emits?.typeArg)
|
|
40277
|
+
if (!emits?.typeArg && !emits?.arg)
|
|
40182
40278
|
return;
|
|
40183
40279
|
const symbols = new Set;
|
|
40184
40280
|
for (const node of this.project.nodes(sfc.fileName, setup.startTagEnd + emits.exp.start)) {
|
|
@@ -40212,17 +40308,52 @@ class VueEvidence {
|
|
|
40212
40308
|
visit(source);
|
|
40213
40309
|
return calls;
|
|
40214
40310
|
}
|
|
40311
|
+
templateEmissions(sfc, event) {
|
|
40312
|
+
const template = sfc.ir.template;
|
|
40313
|
+
const symbol = this.emitSymbol(sfc);
|
|
40314
|
+
if (!template?.ast || !symbol || !this.declaresEvent(sfc, event))
|
|
40315
|
+
return [];
|
|
40316
|
+
const positions = [];
|
|
40317
|
+
for (const element of import_language_core2.forEachElementNode(template.ast)) {
|
|
40318
|
+
for (const prop of element.props) {
|
|
40319
|
+
if (prop.type !== import_compiler_dom.NodeTypes.DIRECTIVE || prop.name !== "on" || prop.exp?.type !== import_compiler_dom.NodeTypes.SIMPLE_EXPRESSION)
|
|
40320
|
+
continue;
|
|
40321
|
+
const offset = directEmitOffset(prop.exp.content, event);
|
|
40322
|
+
if (offset === undefined)
|
|
40323
|
+
continue;
|
|
40324
|
+
const position = template.startTagEnd + prop.exp.loc.start.offset + offset;
|
|
40325
|
+
if (this.project.nodes(sfc.fileName, position).some((node) => ts2.isIdentifier(node) && this.project.checker.getSymbolAtLocation(node) === symbol))
|
|
40326
|
+
positions.push(position);
|
|
40327
|
+
}
|
|
40328
|
+
}
|
|
40329
|
+
return positions;
|
|
40330
|
+
}
|
|
40331
|
+
templateOperation(sfc) {
|
|
40332
|
+
const file = relative(this.project.root, sfc.fileName);
|
|
40333
|
+
const id = `${file}#template`;
|
|
40334
|
+
if (!this.operations.has(id))
|
|
40335
|
+
this.operations.set(id, { id, file, name: "(template)" });
|
|
40336
|
+
return id;
|
|
40337
|
+
}
|
|
40215
40338
|
declaresEvent(sfc, event) {
|
|
40216
40339
|
const setup = sfc.ir.scriptSetup;
|
|
40217
40340
|
if (!setup)
|
|
40218
40341
|
return false;
|
|
40219
|
-
const
|
|
40342
|
+
const emits = import_language_core2.parseScriptSetupRanges(vueTypeScript, setup.ast, this.project.options).defineEmits;
|
|
40343
|
+
const range = emits?.typeArg ?? emits?.arg;
|
|
40220
40344
|
if (!range)
|
|
40221
40345
|
return false;
|
|
40222
40346
|
let declared = false;
|
|
40223
40347
|
function visit(node) {
|
|
40224
|
-
if (node.getStart(setup.ast) === range.start
|
|
40225
|
-
|
|
40348
|
+
if (node.getStart(setup.ast) === range.start) {
|
|
40349
|
+
if (ts2.isArrayLiteralExpression(node)) {
|
|
40350
|
+
declared = node.elements.some((item) => ts2.isStringLiteral(item) && item.text === event);
|
|
40351
|
+
}
|
|
40352
|
+
if (ts2.isFunctionTypeNode(node))
|
|
40353
|
+
declared = includesEvent(node.parameters[0]?.type, event);
|
|
40354
|
+
if (ts2.isTypeLiteralNode(node)) {
|
|
40355
|
+
declared = node.members.some((member) => ts2.isPropertySignature(member) && (ts2.isIdentifier(member.name) || ts2.isStringLiteral(member.name)) ? member.name.text === event : ts2.isCallSignatureDeclaration(member) && includesEvent(member.parameters[0]?.type, event));
|
|
40356
|
+
}
|
|
40226
40357
|
}
|
|
40227
40358
|
ts2.forEachChild(node, visit);
|
|
40228
40359
|
}
|
|
@@ -40243,7 +40374,7 @@ class VueEvidence {
|
|
|
40243
40374
|
return id;
|
|
40244
40375
|
}
|
|
40245
40376
|
bind(file, element, event, binding, templateOffset) {
|
|
40246
|
-
if (
|
|
40377
|
+
if (event.modifiers.length || event.arg?.type !== import_compiler_dom.NodeTypes.SIMPLE_EXPRESSION || !event.arg.isStatic || event.exp?.type !== import_compiler_dom.NodeTypes.SIMPLE_EXPRESSION)
|
|
40247
40378
|
return false;
|
|
40248
40379
|
const expression = ts2.createSourceFile("handler.ts", event.exp.content, ts2.ScriptTarget.Latest, true);
|
|
40249
40380
|
const statement = expression.statements[0];
|
|
@@ -40253,17 +40384,17 @@ class VueEvidence {
|
|
|
40253
40384
|
const target = this.handler(file, templateOffset + event.exp.loc.start.offset);
|
|
40254
40385
|
if (!child || !target)
|
|
40255
40386
|
return false;
|
|
40256
|
-
const
|
|
40257
|
-
|
|
40258
|
-
|
|
40387
|
+
const targetId = this.operationId(target);
|
|
40388
|
+
if (!targetId)
|
|
40389
|
+
return false;
|
|
40390
|
+
const script = this.emissions(child, event.arg.content).flatMap((call) => {
|
|
40259
40391
|
const caller = enclosingOperation(call);
|
|
40260
40392
|
const position = this.project.position(call);
|
|
40261
|
-
|
|
40262
|
-
|
|
40263
|
-
|
|
40264
|
-
|
|
40265
|
-
|
|
40266
|
-
continue;
|
|
40393
|
+
const source = caller && this.operationId(caller);
|
|
40394
|
+
return source && position !== undefined ? [{ source, position }] : [];
|
|
40395
|
+
});
|
|
40396
|
+
const template = this.templateEmissions(child, event.arg.content).map((position) => ({ source: this.templateOperation(child), position }));
|
|
40397
|
+
for (const { source, position } of [...script, ...template]) {
|
|
40267
40398
|
this.invocations.push({
|
|
40268
40399
|
source,
|
|
40269
40400
|
targets: [targetId],
|
|
@@ -40273,32 +40404,17 @@ class VueEvidence {
|
|
|
40273
40404
|
line: this.project.line(child.fileName, position),
|
|
40274
40405
|
binding: { file: relative(this.project.root, file), position: binding, line: this.project.line(file, binding) }
|
|
40275
40406
|
});
|
|
40276
|
-
bound = true;
|
|
40277
40407
|
}
|
|
40278
|
-
return
|
|
40408
|
+
return script.length + template.length > 0;
|
|
40279
40409
|
}
|
|
40280
40410
|
}
|
|
40281
40411
|
|
|
40282
40412
|
// plugins/scanners/vue/src/index.ts
|
|
40283
|
-
import
|
|
40413
|
+
import path7 from "path";
|
|
40284
40414
|
|
|
40285
|
-
// plugins/scanners/
|
|
40286
|
-
|
|
40287
|
-
|
|
40288
|
-
const { root, dependency, projects, sources, also } = options;
|
|
40289
|
-
const directories = (await frameworkProjects(root, dependency, projects)).map((directory) => path3.relative(root, directory).split(path3.sep).join("/") || ".");
|
|
40290
|
-
if (directories.length === 0)
|
|
40291
|
-
return [];
|
|
40292
|
-
const listed = [];
|
|
40293
|
-
for (const file of await projectFiles(root, (candidate) => !candidate.endsWith(".d.ts"))) {
|
|
40294
|
-
const project = directories.find((directory) => directory === "." || file.startsWith(`${directory}/`));
|
|
40295
|
-
if (project === undefined)
|
|
40296
|
-
continue;
|
|
40297
|
-
const local = project === "." ? file : file.slice(project.length + 1);
|
|
40298
|
-
if (sources.some((extension) => file.endsWith(extension)) || (also?.(local) ?? false))
|
|
40299
|
-
listed.push(file);
|
|
40300
|
-
}
|
|
40301
|
-
return listed.sort();
|
|
40415
|
+
// plugins/scanners/projects.ts
|
|
40416
|
+
function isUnder(file, directory) {
|
|
40417
|
+
return directory === "" || file.startsWith(`${directory}/`);
|
|
40302
40418
|
}
|
|
40303
40419
|
|
|
40304
40420
|
// plugins/scanners/observations.ts
|
|
@@ -40311,6 +40427,7 @@ function combineObservations(parts) {
|
|
|
40311
40427
|
const invocations = [];
|
|
40312
40428
|
const diagnostics = [];
|
|
40313
40429
|
const sourceUnits = [];
|
|
40430
|
+
const entryPoints = [];
|
|
40314
40431
|
const httpEndpoints = [];
|
|
40315
40432
|
const httpRequests = [];
|
|
40316
40433
|
for (const { key, observation } of parts) {
|
|
@@ -40328,6 +40445,7 @@ function combineObservations(parts) {
|
|
|
40328
40445
|
httpRequests.push(...(observation.httpRequests ?? []).map((request) => ({ ...request, operation: id(request.operation) })));
|
|
40329
40446
|
diagnostics.push(...observation.diagnostics);
|
|
40330
40447
|
sourceUnits.push(...observation.sourceUnits ?? []);
|
|
40448
|
+
entryPoints.push(...observation.entryPoints ?? []);
|
|
40331
40449
|
}
|
|
40332
40450
|
return createScanObservation({
|
|
40333
40451
|
scanner: parts[0].observation.scanner,
|
|
@@ -40337,6 +40455,7 @@ function combineObservations(parts) {
|
|
|
40337
40455
|
invocations,
|
|
40338
40456
|
diagnostics,
|
|
40339
40457
|
...parts.some((part) => part.observation.sourceUnits !== undefined) ? { sourceUnits } : {},
|
|
40458
|
+
...parts.some((part) => part.observation.entryPoints !== undefined) ? { entryPoints } : {},
|
|
40340
40459
|
...parts.some((part) => part.observation.httpEndpoints !== undefined) ? { httpEndpoints } : {},
|
|
40341
40460
|
...parts.some((part) => part.observation.httpRequests !== undefined) ? { httpRequests } : {}
|
|
40342
40461
|
});
|
|
@@ -40365,8 +40484,10 @@ function ownProperty(ts, object, name) {
|
|
|
40365
40484
|
let found = "absent";
|
|
40366
40485
|
for (const property of object.properties) {
|
|
40367
40486
|
const key = propertyKey(ts, property);
|
|
40368
|
-
if (key === undefined || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property))
|
|
40369
|
-
|
|
40487
|
+
if (key === undefined || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property)) {
|
|
40488
|
+
found = "unknown";
|
|
40489
|
+
continue;
|
|
40490
|
+
}
|
|
40370
40491
|
if (key === name)
|
|
40371
40492
|
found = ts.isPropertyAssignment(property) ? { node: property.initializer } : "unknown";
|
|
40372
40493
|
}
|
|
@@ -40901,6 +41022,10 @@ async function variableHeld(context, name, path, depth) {
|
|
|
40901
41022
|
return "unseen";
|
|
40902
41023
|
if (path.length === 0 && ts.isFunctionDeclaration(declaration))
|
|
40903
41024
|
return { node: declaration };
|
|
41025
|
+
if (path.length === 1 && ts.isEnumDeclaration(declaration)) {
|
|
41026
|
+
const member = declaration.members.find((entry) => ts.isIdentifier(entry.name) && entry.name.text === path[0]);
|
|
41027
|
+
return member?.initializer === undefined ? "unknown" : held(context, member.initializer, [], depth + 1);
|
|
41028
|
+
}
|
|
40904
41029
|
if (!ts.isVariableDeclaration(declaration) || declaration.initializer === undefined)
|
|
40905
41030
|
return "unknown";
|
|
40906
41031
|
if (!ts.isIdentifier(declaration.name) || !await unassigned(context, declaration))
|
|
@@ -41021,6 +41146,23 @@ async function literalText(context, node) {
|
|
|
41021
41146
|
async function methodName(context, node) {
|
|
41022
41147
|
return methodText(await literalText(context, node));
|
|
41023
41148
|
}
|
|
41149
|
+
async function objectEntries(context, node) {
|
|
41150
|
+
const { ts } = context;
|
|
41151
|
+
const value = node === undefined ? undefined : await heldAt(context, node);
|
|
41152
|
+
if (typeof value !== "object" || !ts.isObjectLiteralExpression(value.node))
|
|
41153
|
+
return;
|
|
41154
|
+
const entries = new Map;
|
|
41155
|
+
for (const property of value.node.properties) {
|
|
41156
|
+
const key = propertyKey(ts, property);
|
|
41157
|
+
if (key === undefined || ts.isGetAccessorDeclaration(property) || ts.isSetAccessorDeclaration(property))
|
|
41158
|
+
return;
|
|
41159
|
+
if (ts.isPropertyAssignment(property))
|
|
41160
|
+
entries.set(key, property.initializer);
|
|
41161
|
+
else
|
|
41162
|
+
entries.delete(key);
|
|
41163
|
+
}
|
|
41164
|
+
return entries;
|
|
41165
|
+
}
|
|
41024
41166
|
|
|
41025
41167
|
// plugins/scanners/http-clients.ts
|
|
41026
41168
|
async function declaredMethod(context, options, fallback) {
|
|
@@ -41038,19 +41180,32 @@ async function optionsBase(context, config, fallback) {
|
|
|
41038
41180
|
return base === "absent" ? fallback : heldParts(context, base);
|
|
41039
41181
|
}
|
|
41040
41182
|
async function runtimeFetch(context, callee) {
|
|
41041
|
-
if (!context.ts.isIdentifier(callee)
|
|
41183
|
+
if (!context.ts.isIdentifier(callee))
|
|
41042
41184
|
return;
|
|
41043
41185
|
const origin = await importOrigin(context, callee);
|
|
41044
|
-
const fetch = origin === undefined ? await runtimeGlobal(context, callee) : origin.module === "node-fetch" && origin.name === "default";
|
|
41186
|
+
const fetch = origin === undefined ? callee.text === "fetch" && await runtimeGlobal(context, callee) : origin.module === "node-fetch" && origin.name === "default" || origin.module === "undici" && origin.name === "fetch";
|
|
41045
41187
|
return fetch ? "fetch" : undefined;
|
|
41046
41188
|
}
|
|
41189
|
+
async function urlWithoutMethod(context, url, input) {
|
|
41190
|
+
if (input === "unseen")
|
|
41191
|
+
return true;
|
|
41192
|
+
if (typeof input === "object") {
|
|
41193
|
+
const value = unwrapped(context.ts, input.node);
|
|
41194
|
+
if (urlText(context.ts, value))
|
|
41195
|
+
return true;
|
|
41196
|
+
const urlObject = context.ts.isNewExpression(value) && context.ts.isIdentifier(value.expression) && value.expression.text === "URL" && await runtimeGlobal(context, value.expression);
|
|
41197
|
+
if (urlObject)
|
|
41198
|
+
return true;
|
|
41199
|
+
}
|
|
41200
|
+
return context.checker.primitiveAt(url);
|
|
41201
|
+
}
|
|
41047
41202
|
async function fetchRequest(context, call, client) {
|
|
41048
41203
|
const [url, options] = call.arguments;
|
|
41049
41204
|
const kind = url === undefined ? undefined : await client(call.expression);
|
|
41050
41205
|
if (url === undefined || kind === undefined)
|
|
41051
41206
|
return;
|
|
41052
41207
|
const input = await heldAt(context, url);
|
|
41053
|
-
const method =
|
|
41208
|
+
const method = await urlWithoutMethod(context, url, input) ? await declaredMethod(context, options, "GET") : undefined;
|
|
41054
41209
|
const parts = await urlParts(context, url);
|
|
41055
41210
|
const target = kind === "ofetch" ? withBase(await optionsBase(context, options, []), parts) : parts;
|
|
41056
41211
|
return { ...method === undefined ? {} : { method }, ...requestUrl(target) };
|
|
@@ -41089,9 +41244,12 @@ var SHORTHAND = new Map([
|
|
|
41089
41244
|
["patch", "PATCH"],
|
|
41090
41245
|
["delete", "DELETE"],
|
|
41091
41246
|
["head", "HEAD"],
|
|
41092
|
-
["options", "OPTIONS"]
|
|
41247
|
+
["options", "OPTIONS"],
|
|
41248
|
+
["postForm", "POST"],
|
|
41249
|
+
["putForm", "PUT"],
|
|
41250
|
+
["patchForm", "PATCH"]
|
|
41093
41251
|
]);
|
|
41094
|
-
var WITH_BODY = new Set(["post", "put", "patch"]);
|
|
41252
|
+
var WITH_BODY = new Set(["post", "put", "patch", "postForm", "putForm", "patchForm"]);
|
|
41095
41253
|
async function isAxios(context, node) {
|
|
41096
41254
|
const origin = await importOrigin(context, node);
|
|
41097
41255
|
return origin?.module === "axios" && origin.name === "default";
|
|
@@ -41117,20 +41275,25 @@ async function axiosClient(context, node) {
|
|
|
41117
41275
|
return;
|
|
41118
41276
|
return await isAxios(context, node) ? defaultClient(context) : createdClient(context, node);
|
|
41119
41277
|
}
|
|
41278
|
+
async function memberRequest(context, receiver, member, call) {
|
|
41279
|
+
const method = SHORTHAND.get(member);
|
|
41280
|
+
if (method === undefined && member !== "request")
|
|
41281
|
+
return;
|
|
41282
|
+
const client = await axiosClient(context, receiver);
|
|
41283
|
+
if (client === undefined)
|
|
41284
|
+
return;
|
|
41285
|
+
const [first, second, third] = call.arguments;
|
|
41286
|
+
if (method !== undefined && first !== undefined) {
|
|
41287
|
+
return sent(context, client, await urlParts(context, first), method, WITH_BODY.has(member) ? third : second);
|
|
41288
|
+
}
|
|
41289
|
+
return member === "request" ? configRequest(context, client, first) : undefined;
|
|
41290
|
+
}
|
|
41120
41291
|
async function axiosRequest(context, call) {
|
|
41121
41292
|
const { ts } = context;
|
|
41122
41293
|
const callee = call.expression;
|
|
41123
|
-
const [first, second
|
|
41294
|
+
const [first, second] = call.arguments;
|
|
41124
41295
|
if (ts.isPropertyAccessExpression(callee) && ts.isIdentifier(callee.name)) {
|
|
41125
|
-
|
|
41126
|
-
if (client === undefined)
|
|
41127
|
-
return;
|
|
41128
|
-
const member = callee.name.text;
|
|
41129
|
-
const method = SHORTHAND.get(member);
|
|
41130
|
-
if (method !== undefined && first !== undefined) {
|
|
41131
|
-
return sent(context, client, await urlParts(context, first), method, WITH_BODY.has(member) ? third : second);
|
|
41132
|
-
}
|
|
41133
|
-
return member === "request" ? configRequest(context, client, first) : undefined;
|
|
41296
|
+
return memberRequest(context, callee.expression, callee.name.text, call);
|
|
41134
41297
|
}
|
|
41135
41298
|
const client = await axiosClient(context, callee);
|
|
41136
41299
|
if (client === undefined || first === undefined)
|
|
@@ -41618,7 +41781,7 @@ function addComparedOperations(project, operations) {
|
|
|
41618
41781
|
|
|
41619
41782
|
// plugins/scanners/vue/src/outline.ts
|
|
41620
41783
|
import { readFile as readFile2 } from "fs/promises";
|
|
41621
|
-
import
|
|
41784
|
+
import path3 from "path";
|
|
41622
41785
|
import ts5 from "./typescript.cjs";
|
|
41623
41786
|
|
|
41624
41787
|
// plugins/scanners/typescript-outline.ts
|
|
@@ -41688,7 +41851,7 @@ function typeMember(scope, member) {
|
|
|
41688
41851
|
return name === undefined ? [] : [symbolAt(scope, name.text, name, memberVisibility(scope, member))];
|
|
41689
41852
|
}
|
|
41690
41853
|
function typeMembers(k, statement) {
|
|
41691
|
-
if (is2(statement, k.ClassDeclaration) || is2(statement, k.InterfaceDeclaration))
|
|
41854
|
+
if (is2(statement, k.ClassDeclaration) || is2(statement, k.ClassExpression) || is2(statement, k.InterfaceDeclaration))
|
|
41692
41855
|
return statement.members;
|
|
41693
41856
|
return statement.kind === k.EnumDeclaration ? [] : undefined;
|
|
41694
41857
|
}
|
|
@@ -41717,9 +41880,12 @@ function declarationsIn(scope, statements) {
|
|
|
41717
41880
|
return [...functionDeclarations(scope, statement), ...typeDeclaration(scope, statement)];
|
|
41718
41881
|
});
|
|
41719
41882
|
}
|
|
41883
|
+
function listedExportNames(ts, source) {
|
|
41884
|
+
return new Set(source.statements.flatMap((statement) => listedExports(ts.SyntaxKind, statement)));
|
|
41885
|
+
}
|
|
41720
41886
|
function outlineSource(ts, source, context) {
|
|
41721
41887
|
const k = ts.SyntaxKind;
|
|
41722
|
-
const exported = new Set([...
|
|
41888
|
+
const exported = new Set([...listedExportNames(ts, source), ...context.exported ?? []]);
|
|
41723
41889
|
const scope = { k, source, symbols: context.symbols, exported, topLevelPrivate: context.topLevelPrivate ?? false };
|
|
41724
41890
|
return declarationsIn(scope, source.statements);
|
|
41725
41891
|
}
|
|
@@ -41740,7 +41906,7 @@ function componentDeclarations(fileName, text, symbols) {
|
|
|
41740
41906
|
async function readVueOutline(repositoryRoot, references) {
|
|
41741
41907
|
const files = [];
|
|
41742
41908
|
for (const reference of references.filter((reference) => SCRIPT.test(reference.file))) {
|
|
41743
|
-
const fileName =
|
|
41909
|
+
const fileName = path3.join(repositoryRoot, reference.file);
|
|
41744
41910
|
const text = await readFile2(fileName, "utf8");
|
|
41745
41911
|
const declarations = reference.file.endsWith(".vue") ? componentDeclarations(fileName, text, reference.symbols) : outlineDeclarations(ts5, { fileName, text, symbols: reference.symbols });
|
|
41746
41912
|
if (declarations.length > 0)
|
|
@@ -41749,18 +41915,280 @@ async function readVueOutline(repositoryRoot, references) {
|
|
|
41749
41915
|
return files;
|
|
41750
41916
|
}
|
|
41751
41917
|
|
|
41918
|
+
// plugins/scanners/entry-points/javascript.ts
|
|
41919
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
41920
|
+
import path5 from "path";
|
|
41921
|
+
|
|
41922
|
+
// plugins/scanners/workspace-packages.ts
|
|
41923
|
+
import path4 from "path";
|
|
41924
|
+
function inRootDir(file, outputs) {
|
|
41925
|
+
const output = outputs.find(({ outDir }) => file.startsWith(`${outDir}/`));
|
|
41926
|
+
return output === undefined ? undefined : path4.posix.join(output.rootDir, file.slice(output.outDir.length + 1));
|
|
41927
|
+
}
|
|
41928
|
+
function sourceOf(file, outputs, files) {
|
|
41929
|
+
const stem = inRootDir(file, outputs)?.replace(/\.(?:d\.[cm]?ts|[cm]?jsx?)$/, "");
|
|
41930
|
+
return stem === undefined ? undefined : [".ts", ".tsx"].map((extension) => `${stem}${extension}`).find((candidate) => files.has(candidate));
|
|
41931
|
+
}
|
|
41932
|
+
var conditions = new Set(["types", "import", "default", "require"]);
|
|
41933
|
+
|
|
41934
|
+
// plugins/scanners/entry-points/javascript.ts
|
|
41935
|
+
function packageFor(file, packages) {
|
|
41936
|
+
let directory = path5.posix.dirname(file);
|
|
41937
|
+
while (directory !== "." && !packages.has(directory))
|
|
41938
|
+
directory = path5.posix.dirname(directory);
|
|
41939
|
+
return directory;
|
|
41940
|
+
}
|
|
41941
|
+
function declaredBins(declaration, manifest) {
|
|
41942
|
+
const bins = typeof manifest.bin === "string" ? { [String(manifest.name ?? "main")]: manifest.bin } : manifest.bin;
|
|
41943
|
+
if (!bins || typeof bins !== "object")
|
|
41944
|
+
return [];
|
|
41945
|
+
return Object.entries(bins).flatMap(([name, target]) => typeof target === "string" ? [{ declaration, name, file: path5.posix.join(path5.posix.dirname(declaration), target) }] : []);
|
|
41946
|
+
}
|
|
41947
|
+
var RUNTIMES = new Set(["node", "bun", "tsx", "ts-node"]);
|
|
41948
|
+
var VALUE_OPTIONS = new Set(["-r", "--require", "--import", "--tsconfig"]);
|
|
41949
|
+
var SCRIPT2 = /^[\w./-]+\.[cm]?[jt]sx?$/;
|
|
41950
|
+
function runtimeAt(words) {
|
|
41951
|
+
let index = words[0] === "cross-env" ? 1 : 0;
|
|
41952
|
+
while (/^[A-Za-z_]\w*=/.test(words[index] ?? ""))
|
|
41953
|
+
index += 1;
|
|
41954
|
+
return index;
|
|
41955
|
+
}
|
|
41956
|
+
function commandScript(command) {
|
|
41957
|
+
const words = command.trim().split(/\s+/);
|
|
41958
|
+
let index = runtimeAt(words);
|
|
41959
|
+
if (!RUNTIMES.has(words[index] ?? ""))
|
|
41960
|
+
return;
|
|
41961
|
+
let subcommand = true;
|
|
41962
|
+
for (index += 1;index < words.length; index += 1) {
|
|
41963
|
+
const word = words[index];
|
|
41964
|
+
if (VALUE_OPTIONS.has(word))
|
|
41965
|
+
index += 1;
|
|
41966
|
+
else if (subcommand && (word === "run" || word === "watch"))
|
|
41967
|
+
subcommand = false;
|
|
41968
|
+
else if (!word.startsWith("-"))
|
|
41969
|
+
return SCRIPT2.test(word) ? word : undefined;
|
|
41970
|
+
}
|
|
41971
|
+
return;
|
|
41972
|
+
}
|
|
41973
|
+
function declaredScripts(declaration, scripts) {
|
|
41974
|
+
return Object.entries(scripts ?? {}).flatMap(([name, script]) => {
|
|
41975
|
+
if (typeof script !== "string")
|
|
41976
|
+
return [];
|
|
41977
|
+
const commands = /["'`]/.test(script) ? [script] : script.split(/\s+&&\s+/);
|
|
41978
|
+
return commands.flatMap((command) => {
|
|
41979
|
+
const file = commandScript(command);
|
|
41980
|
+
return file === undefined ? [] : [{ declaration, name, file: path5.posix.join(path5.posix.dirname(declaration), file) }];
|
|
41981
|
+
});
|
|
41982
|
+
});
|
|
41983
|
+
}
|
|
41984
|
+
var isString = (value) => typeof value === "string";
|
|
41985
|
+
function buildEntry(declaration, workspace, name, project) {
|
|
41986
|
+
const build = (project.architect ?? project.targets)?.build;
|
|
41987
|
+
const main = build?.options?.browser ?? build?.options?.main;
|
|
41988
|
+
if (!isString(main))
|
|
41989
|
+
return [];
|
|
41990
|
+
const replacements = Object.values(build?.configurations ?? {}).flatMap((configuration) => Array.isArray(configuration.fileReplacements) ? configuration.fileReplacements.map((replacement) => replacement?.with) : []);
|
|
41991
|
+
const at = (file) => path5.posix.join(workspace, file);
|
|
41992
|
+
return [{ declaration, name, file: at(main), compiled: [build?.options?.polyfills, ...replacements].flat().filter(isString).map(at) }];
|
|
41993
|
+
}
|
|
41994
|
+
function angularEntries(declaration, source) {
|
|
41995
|
+
const projects = JSON.parse(source).projects ?? {};
|
|
41996
|
+
return Object.entries(projects).flatMap(([name, project]) => buildEntry(declaration, path5.posix.dirname(declaration), name, project));
|
|
41997
|
+
}
|
|
41998
|
+
function nxEntries(declaration, source, workspaces) {
|
|
41999
|
+
const workspace = packageFor(declaration, workspaces);
|
|
42000
|
+
if (!workspaces.has(workspace))
|
|
42001
|
+
return [];
|
|
42002
|
+
const project = JSON.parse(source);
|
|
42003
|
+
return buildEntry(declaration, workspace, project.name ?? path5.posix.basename(path5.posix.dirname(declaration)), project);
|
|
42004
|
+
}
|
|
42005
|
+
function browserEntries(declaration, source, packages) {
|
|
42006
|
+
const scripts = [...source.matchAll(/<script\b[^>]*\bsrc\s*=\s*["']([^"']+)["'][^>]*>/gi)];
|
|
42007
|
+
const folder = path5.posix.dirname(declaration);
|
|
42008
|
+
const page = path5.posix.basename(declaration, ".html");
|
|
42009
|
+
const name = page === "index" && folder !== "." ? path5.posix.basename(folder) : page;
|
|
42010
|
+
return scripts.flatMap((match) => {
|
|
42011
|
+
const src = match[1];
|
|
42012
|
+
if (/^(?:[a-z]+:|\/\/)/i.test(src))
|
|
42013
|
+
return [];
|
|
42014
|
+
const base = src.startsWith("/") ? packageFor(declaration, packages) : folder;
|
|
42015
|
+
return [{ file: path5.posix.join(base, src.replace(/^\//, "")), declaration, name }];
|
|
42016
|
+
});
|
|
42017
|
+
}
|
|
42018
|
+
function reachedFiles(entry, compiled, imports, packages, units) {
|
|
42019
|
+
const owner = packageFor(entry, packages), found = new Set;
|
|
42020
|
+
const pending = [entry, ...compiled];
|
|
42021
|
+
while (pending.length) {
|
|
42022
|
+
const file = pending.pop();
|
|
42023
|
+
if (found.has(file) || packageFor(file, packages) !== owner)
|
|
42024
|
+
continue;
|
|
42025
|
+
found.add(file);
|
|
42026
|
+
pending.push(...imports.get(file) ?? []);
|
|
42027
|
+
}
|
|
42028
|
+
for (const unit of units)
|
|
42029
|
+
if (found.has(unit.primary))
|
|
42030
|
+
for (const file of unit.files)
|
|
42031
|
+
found.add(file);
|
|
42032
|
+
return found;
|
|
42033
|
+
}
|
|
42034
|
+
async function declaredEntries(root, declarations, packages, workspaces) {
|
|
42035
|
+
const entries = [];
|
|
42036
|
+
for (const file of declarations) {
|
|
42037
|
+
const text = await readFile3(path5.join(root, file), "utf8");
|
|
42038
|
+
const name = path5.posix.basename(file);
|
|
42039
|
+
if (name === "package.json") {
|
|
42040
|
+
const manifest = JSON.parse(text);
|
|
42041
|
+
entries.push(...declaredBins(file, manifest), ...declaredScripts(file, manifest.scripts));
|
|
42042
|
+
} else if (name === "angular.json")
|
|
42043
|
+
entries.push(...angularEntries(file, text));
|
|
42044
|
+
else if (name === "project.json")
|
|
42045
|
+
entries.push(...nxEntries(file, text, workspaces));
|
|
42046
|
+
else if (file.endsWith(".html"))
|
|
42047
|
+
entries.push(...browserEntries(file, text, packages));
|
|
42048
|
+
}
|
|
42049
|
+
return entries;
|
|
42050
|
+
}
|
|
42051
|
+
function sourced(entry, files, outputs = []) {
|
|
42052
|
+
const file = sourceOf(entry.file, outputs, files);
|
|
42053
|
+
return file === undefined ? entry : { ...entry, file };
|
|
42054
|
+
}
|
|
42055
|
+
async function withJavaScriptEntries(root, observation, inputs, files) {
|
|
42056
|
+
if (!observation)
|
|
42057
|
+
return;
|
|
42058
|
+
const inventory = files.filter((file) => ["package.json", "angular.json", "project.json", "nx.json"].includes(path5.posix.basename(file)) || file.endsWith(".html"));
|
|
42059
|
+
const workspaces = new Set(inventory.filter((file) => path5.posix.basename(file) === "nx.json").map((file) => path5.posix.dirname(file)));
|
|
42060
|
+
const packages = new Set(inventory.filter((file) => path5.posix.basename(file) === "package.json").map((file) => path5.posix.dirname(file)));
|
|
42061
|
+
const active = new Set(observation.files.map((file) => packageFor(file.file, packages)));
|
|
42062
|
+
const declarations = inventory.filter((file) => path5.posix.basename(file) !== "nx.json" && active.has(packageFor(file, packages)));
|
|
42063
|
+
const entries = [...inputs.entries, ...await declaredEntries(root, declarations, packages, workspaces)];
|
|
42064
|
+
const inventoryFiles = [...observation.files];
|
|
42065
|
+
const visible = new Set(inventoryFiles.map((file) => file.file));
|
|
42066
|
+
const readable = new Set(files);
|
|
42067
|
+
const entryPoints = entries.map((entry) => sourced(entry, readable, inputs.buildOutputs)).flatMap(({ compiled = [], ...entry }) => {
|
|
42068
|
+
if (!inputs.imports.has(entry.file))
|
|
42069
|
+
return [];
|
|
42070
|
+
const reached = reachedFiles(entry.file, compiled, inputs.imports, packages, observation.sourceUnits ?? []);
|
|
42071
|
+
const members = observation.files.filter((file) => reached.has(file.file));
|
|
42072
|
+
if (!members.length)
|
|
42073
|
+
return [];
|
|
42074
|
+
if (!visible.has(entry.file)) {
|
|
42075
|
+
inventoryFiles.push({ file: entry.file, symbols: [], roots: [...new Set(members.flatMap((file) => file.roots))] });
|
|
42076
|
+
visible.add(entry.file);
|
|
42077
|
+
}
|
|
42078
|
+
return [{ ...entry, files: [...new Set([entry.file, ...members.map((file) => file.file)])] }];
|
|
42079
|
+
});
|
|
42080
|
+
return createScanObservation({ ...observation, files: inventoryFiles, entryPoints });
|
|
42081
|
+
}
|
|
42082
|
+
|
|
42083
|
+
// plugins/scanners/entry-points/source.ts
|
|
42084
|
+
import path6 from "path";
|
|
42085
|
+
var relative2 = (root, file) => path6.relative(root, path6.resolve(root, file)).split(path6.sep).join("/");
|
|
42086
|
+
async function text2(context, node) {
|
|
42087
|
+
if (!node)
|
|
42088
|
+
return;
|
|
42089
|
+
const parts = await urlParts(context, node);
|
|
42090
|
+
return parts.every((part) => part.kind === "text") ? parts.map((part) => part.kind === "text" ? part.text : "").join("") : undefined;
|
|
42091
|
+
}
|
|
42092
|
+
async function entryPath(root, context, node) {
|
|
42093
|
+
const { ts } = context;
|
|
42094
|
+
const direct = await text2(context, node);
|
|
42095
|
+
if (direct !== undefined)
|
|
42096
|
+
return relative2(root, direct);
|
|
42097
|
+
if (!ts.isCallExpression(node))
|
|
42098
|
+
return;
|
|
42099
|
+
const origin = await importOrigin(context, node.expression);
|
|
42100
|
+
if (origin?.name !== "fileURLToPath" || !["node:url", "url"].includes(origin.module))
|
|
42101
|
+
return;
|
|
42102
|
+
const url = node.arguments[0];
|
|
42103
|
+
if (!url || !ts.isNewExpression(url) || !ts.isIdentifier(url.expression) || url.expression.text !== "URL" || !await runtimeGlobal(context, url.expression))
|
|
42104
|
+
return;
|
|
42105
|
+
const base = url.arguments?.[1];
|
|
42106
|
+
if (!base || !ts.isPropertyAccessExpression(base) || base.name.text !== "url" || !ts.isMetaProperty(base.expression))
|
|
42107
|
+
return;
|
|
42108
|
+
const value = await text2(context, url.arguments?.[0]);
|
|
42109
|
+
return value === undefined ? undefined : relative2(root, path6.resolve(root, path6.dirname(node.getSourceFile().fileName), value));
|
|
42110
|
+
}
|
|
42111
|
+
async function buildEntries(root, context, call) {
|
|
42112
|
+
const { ts } = context;
|
|
42113
|
+
const callee = call.expression;
|
|
42114
|
+
if (!ts.isPropertyAccessExpression(callee) || callee.name.text !== "build" || !ts.isIdentifier(callee.expression) || callee.expression.text !== "Bun" || !await runtimeGlobal(context, callee.expression))
|
|
42115
|
+
return [];
|
|
42116
|
+
const fields = await objectEntries(context, call.arguments[0]);
|
|
42117
|
+
if (!fields)
|
|
42118
|
+
return [];
|
|
42119
|
+
const compile = fields.get("compile"), entrypoints = fields.get("entrypoints");
|
|
42120
|
+
const executable = compile && await heldAt(context, compile);
|
|
42121
|
+
const native = typeof executable === "object" && (executable.node.kind === ts.SyntaxKind.TrueKeyword || ts.isObjectLiteralExpression(executable.node));
|
|
42122
|
+
if (!native && await literalText(context, fields.get("target")) !== "browser")
|
|
42123
|
+
return [];
|
|
42124
|
+
const array = entrypoints && await heldAt(context, entrypoints);
|
|
42125
|
+
if (typeof array !== "object" || !ts.isArrayLiteralExpression(array.node))
|
|
42126
|
+
return [];
|
|
42127
|
+
const declaration = relative2(root, call.getSourceFile().fileName);
|
|
42128
|
+
const files = await Promise.all(array.node.elements.map((node) => entryPath(root, context, node)));
|
|
42129
|
+
return files.flatMap((file) => file === undefined ? [] : [{ file, declaration, name: path6.posix.basename(file).replace(/\.[^.]+$/, "") }]);
|
|
42130
|
+
}
|
|
42131
|
+
async function sourceBuildEntries(root, ts, checker, sources) {
|
|
42132
|
+
const context = urlContext(ts, checker, sources);
|
|
42133
|
+
const calls = [];
|
|
42134
|
+
const visit = (node) => {
|
|
42135
|
+
if (ts.isCallExpression(node))
|
|
42136
|
+
calls.push(node);
|
|
42137
|
+
ts.forEachChild(node, visit);
|
|
42138
|
+
};
|
|
42139
|
+
for (const source of sources)
|
|
42140
|
+
visit(source);
|
|
42141
|
+
return (await Promise.all(calls.map((call) => buildEntries(root, context, call)))).flat();
|
|
42142
|
+
}
|
|
42143
|
+
async function entrySourceInputs(root, ts, checker, sources) {
|
|
42144
|
+
const selected = new Set(sources.map((source) => relative2(root, source.fileName)));
|
|
42145
|
+
const imports = new Map;
|
|
42146
|
+
for (const source of sources) {
|
|
42147
|
+
const literals = [];
|
|
42148
|
+
const visit = (node) => {
|
|
42149
|
+
if (ts.isStringLiteral(node))
|
|
42150
|
+
literals.push(node);
|
|
42151
|
+
ts.forEachChild(node, visit);
|
|
42152
|
+
};
|
|
42153
|
+
visit(source);
|
|
42154
|
+
const symbols = await checker.symbolsAt(literals);
|
|
42155
|
+
const declarations = await Promise.all(symbols.flatMap((symbol) => symbol && checker.module(symbol) ? [checker.declaration(symbol)] : []));
|
|
42156
|
+
imports.set(relative2(root, source.fileName), [...new Set(declarations.flatMap((declaration) => {
|
|
42157
|
+
const file = declaration && relative2(root, declaration.getSourceFile().fileName);
|
|
42158
|
+
return file && selected.has(file) ? [file] : [];
|
|
42159
|
+
}))]);
|
|
42160
|
+
}
|
|
42161
|
+
return { imports, entries: await sourceBuildEntries(root, ts, checker, sources) };
|
|
42162
|
+
}
|
|
42163
|
+
|
|
41752
42164
|
// plugins/scanners/vue/src/index.ts
|
|
41753
|
-
|
|
42165
|
+
import ts6 from "./typescript.cjs";
|
|
42166
|
+
async function scanVue(root, _settings, files) {
|
|
41754
42167
|
const parts = [];
|
|
41755
|
-
|
|
41756
|
-
|
|
42168
|
+
const { selected, owners } = await vueProjects(root, files);
|
|
42169
|
+
for (const [project, sources] of selected) {
|
|
42170
|
+
const observation = await scanVueProject(project, root, sources, owners, files);
|
|
41757
42171
|
if (observation)
|
|
41758
42172
|
parts.push({ key: relative(root, project), observation });
|
|
41759
42173
|
}
|
|
41760
42174
|
return combineObservations(parts);
|
|
41761
42175
|
}
|
|
41762
|
-
async function
|
|
41763
|
-
const
|
|
42176
|
+
async function vueProjects(root, files) {
|
|
42177
|
+
const projects = await frameworkProjects(root, files, "vue", [".vue"], { inheritConfig: true });
|
|
42178
|
+
const selected = new Map(projects.map((project) => [project, []]));
|
|
42179
|
+
const owners = new Map;
|
|
42180
|
+
const ordered = projects.map((project) => ({ project, directory: relative(root, project) })).sort((left, right) => right.directory.length - left.directory.length);
|
|
42181
|
+
for (const file of files.filter((file) => /\.(?:vue|[cm]?[jt]sx?)$/.test(file))) {
|
|
42182
|
+
const owner = ordered.find((item) => isUnder(file, item.directory));
|
|
42183
|
+
if (owner) {
|
|
42184
|
+
selected.get(owner.project).push(file);
|
|
42185
|
+
owners.set(file, owner.project);
|
|
42186
|
+
}
|
|
42187
|
+
}
|
|
42188
|
+
return { selected, owners };
|
|
42189
|
+
}
|
|
42190
|
+
async function scanVueProject(projectRoot, root, sources, owners, files) {
|
|
42191
|
+
const prepared = vueProject(projectRoot, root, files, sources, owners);
|
|
41764
42192
|
if (!prepared)
|
|
41765
42193
|
return;
|
|
41766
42194
|
const { manifest, project } = prepared;
|
|
@@ -41782,38 +42210,39 @@ async function scanVueProject(projectRoot, root) {
|
|
|
41782
42210
|
}
|
|
41783
42211
|
});
|
|
41784
42212
|
addComparedOperations(project, evidence.operations);
|
|
41785
|
-
const
|
|
42213
|
+
const reported = project.files.map((source) => ({ file: relative(root, source.fileName), symbols: [] }));
|
|
41786
42214
|
const sourceUnits = project.files.flatMap((source) => project.sourceUnit(source.fileName) ?? []);
|
|
41787
42215
|
for (const file of new Set(sourceUnits.flatMap((unit) => unit.files))) {
|
|
41788
|
-
if (!
|
|
41789
|
-
|
|
42216
|
+
if (!reported.some((source) => source.file === file))
|
|
42217
|
+
reported.push({ file, symbols: [] });
|
|
41790
42218
|
}
|
|
41791
|
-
return createScanObservation({
|
|
42219
|
+
return withJavaScriptEntries(root, createScanObservation({
|
|
41792
42220
|
scanner: { id: "vue", technology: "typescript/vue", engine: "@vue/language-core", engineVersion: "3.3.11" },
|
|
41793
|
-
roots: [{ id: "vue-project", kind: "package", name: manifest.name, file: relative(root,
|
|
41794
|
-
files:
|
|
42221
|
+
roots: [{ id: "vue-project", kind: "package", name: manifest.name, file: relative(root, path7.join(projectRoot, "package.json")) }],
|
|
42222
|
+
files: reported.map((file) => ({ ...file, roots: ["vue-project"] })),
|
|
41795
42223
|
sourceUnits,
|
|
41796
42224
|
operations: [...evidence.operations.values()],
|
|
41797
42225
|
invocations: evidence.invocations,
|
|
41798
|
-
diagnostics: evidence.diagnostics,
|
|
42226
|
+
diagnostics: [...project.diagnostics, ...evidence.diagnostics],
|
|
41799
42227
|
...httpEndpoints.length ? { httpEndpoints } : {},
|
|
41800
42228
|
...httpRequests.length ? { httpRequests } : {}
|
|
41801
|
-
});
|
|
42229
|
+
}), await entrySourceInputs(root, ts6, classicChecker(ts6, project.checker), project.files), files);
|
|
41802
42230
|
}
|
|
41803
42231
|
var src_default = {
|
|
41804
42232
|
id: "vue",
|
|
41805
|
-
watch: { include: ["**/*.vue", "**/*.ts", "**/*.js", "**/*.html", "**/*.css", "**/*.scss", "**/*.sass", "**/*.less", "**/*.styl", "**/tsconfig*.json", "**/package.json"], exclude: [] },
|
|
41806
42233
|
readCodeStructure: readVueOutline,
|
|
41807
|
-
listSourceFiles: (root) => frameworkSourceFiles({
|
|
42234
|
+
listSourceFiles: (root, _settings, candidates) => frameworkSourceFiles({
|
|
41808
42235
|
root,
|
|
42236
|
+
files: candidates,
|
|
41809
42237
|
dependency: "vue",
|
|
41810
42238
|
projects: [".vue"],
|
|
42239
|
+
inheritConfig: true,
|
|
41811
42240
|
sources: [".vue", ".ts", ".tsx", ".js", ".jsx", ".html", ".css", ".scss", ".sass", ".less", ".styl"]
|
|
41812
42241
|
}),
|
|
41813
|
-
checkReadiness: async (root) => {
|
|
41814
|
-
const
|
|
41815
|
-
for (const project of
|
|
41816
|
-
vueProject(project, root);
|
|
42242
|
+
checkReadiness: async (root, _settings, files) => {
|
|
42243
|
+
const { selected, owners } = await vueProjects(root, files);
|
|
42244
|
+
for (const [project, sources] of selected)
|
|
42245
|
+
vueProject(project, root, files, sources, owners);
|
|
41817
42246
|
},
|
|
41818
42247
|
scan: scanVue
|
|
41819
42248
|
};
|