@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.
Files changed (113) hide show
  1. package/README.md +54 -36
  2. package/dist/index.js +594 -165
  3. package/dist/lib.d.ts +1 -3
  4. package/dist/lib.decorators.d.ts +1 -3
  5. package/dist/lib.decorators.legacy.d.ts +1 -3
  6. package/dist/lib.dom.asynciterable.d.ts +3 -26
  7. package/dist/lib.dom.d.ts +12638 -6942
  8. package/dist/lib.dom.iterable.d.ts +3 -556
  9. package/dist/lib.es2015.collection.d.ts +7 -4
  10. package/dist/lib.es2015.core.d.ts +2 -4
  11. package/dist/lib.es2015.d.ts +1 -3
  12. package/dist/lib.es2015.generator.d.ts +1 -3
  13. package/dist/lib.es2015.iterable.d.ts +2 -4
  14. package/dist/lib.es2015.promise.d.ts +1 -3
  15. package/dist/lib.es2015.proxy.d.ts +1 -3
  16. package/dist/lib.es2015.reflect.d.ts +1 -3
  17. package/dist/lib.es2015.symbol.d.ts +1 -3
  18. package/dist/lib.es2015.symbol.wellknown.d.ts +1 -3
  19. package/dist/lib.es2016.array.include.d.ts +1 -3
  20. package/dist/lib.es2016.d.ts +1 -3
  21. package/dist/lib.es2016.full.d.ts +1 -3
  22. package/dist/lib.es2016.intl.d.ts +1 -3
  23. package/dist/lib.es2017.arraybuffer.d.ts +1 -3
  24. package/dist/lib.es2017.d.ts +1 -3
  25. package/dist/lib.es2017.date.d.ts +1 -3
  26. package/dist/lib.es2017.full.d.ts +1 -3
  27. package/dist/lib.es2017.intl.d.ts +1 -3
  28. package/dist/lib.es2017.object.d.ts +1 -3
  29. package/dist/lib.es2017.sharedmemory.d.ts +1 -3
  30. package/dist/lib.es2017.string.d.ts +1 -3
  31. package/dist/lib.es2017.typedarrays.d.ts +1 -3
  32. package/dist/lib.es2018.asyncgenerator.d.ts +1 -3
  33. package/dist/lib.es2018.asynciterable.d.ts +1 -3
  34. package/dist/lib.es2018.d.ts +1 -3
  35. package/dist/lib.es2018.full.d.ts +1 -3
  36. package/dist/lib.es2018.intl.d.ts +1 -3
  37. package/dist/lib.es2018.promise.d.ts +1 -3
  38. package/dist/lib.es2018.regexp.d.ts +1 -3
  39. package/dist/lib.es2019.array.d.ts +1 -3
  40. package/dist/lib.es2019.d.ts +1 -3
  41. package/dist/lib.es2019.full.d.ts +1 -3
  42. package/dist/lib.es2019.intl.d.ts +1 -3
  43. package/dist/lib.es2019.object.d.ts +1 -3
  44. package/dist/lib.es2019.string.d.ts +1 -3
  45. package/dist/lib.es2019.symbol.d.ts +1 -3
  46. package/dist/lib.es2020.bigint.d.ts +5 -7
  47. package/dist/lib.es2020.d.ts +1 -3
  48. package/dist/lib.es2020.date.d.ts +1 -3
  49. package/dist/lib.es2020.full.d.ts +1 -3
  50. package/dist/lib.es2020.intl.d.ts +1 -3
  51. package/dist/lib.es2020.number.d.ts +1 -3
  52. package/dist/lib.es2020.promise.d.ts +1 -3
  53. package/dist/lib.es2020.sharedmemory.d.ts +1 -3
  54. package/dist/lib.es2020.string.d.ts +2 -4
  55. package/dist/lib.es2020.symbol.wellknown.d.ts +2 -4
  56. package/dist/lib.es2021.d.ts +1 -3
  57. package/dist/lib.es2021.full.d.ts +1 -3
  58. package/dist/lib.es2021.intl.d.ts +1 -3
  59. package/dist/lib.es2021.promise.d.ts +1 -3
  60. package/dist/lib.es2021.string.d.ts +1 -3
  61. package/dist/lib.es2021.weakref.d.ts +1 -3
  62. package/dist/lib.es2022.array.d.ts +1 -3
  63. package/dist/lib.es2022.d.ts +1 -3
  64. package/dist/lib.es2022.error.d.ts +1 -3
  65. package/dist/lib.es2022.full.d.ts +1 -3
  66. package/dist/lib.es2022.intl.d.ts +1 -3
  67. package/dist/lib.es2022.object.d.ts +1 -3
  68. package/dist/lib.es2022.regexp.d.ts +2 -4
  69. package/dist/lib.es2022.string.d.ts +1 -3
  70. package/dist/lib.es2023.array.d.ts +1 -3
  71. package/dist/lib.es2023.collection.d.ts +1 -3
  72. package/dist/lib.es2023.d.ts +1 -3
  73. package/dist/lib.es2023.full.d.ts +1 -3
  74. package/dist/lib.es2023.intl.d.ts +10 -4
  75. package/dist/lib.es2024.arraybuffer.d.ts +1 -3
  76. package/dist/lib.es2024.collection.d.ts +1 -3
  77. package/dist/lib.es2024.d.ts +1 -3
  78. package/dist/lib.es2024.full.d.ts +1 -3
  79. package/dist/lib.es2024.object.d.ts +1 -3
  80. package/dist/lib.es2024.promise.d.ts +1 -3
  81. package/dist/lib.es2024.regexp.d.ts +1 -3
  82. package/dist/lib.es2024.sharedmemory.d.ts +1 -3
  83. package/dist/lib.es2024.string.d.ts +1 -3
  84. package/dist/lib.es2025.collection.d.ts +94 -0
  85. package/dist/lib.es2025.d.ts +23 -0
  86. package/dist/{lib.esnext.float16.d.ts → lib.es2025.float16.d.ts} +1 -3
  87. package/dist/lib.es2025.full.d.ts +22 -0
  88. package/dist/lib.es2025.intl.d.ts +200 -0
  89. package/dist/{lib.esnext.iterator.d.ts → lib.es2025.iterator.d.ts} +1 -3
  90. package/dist/{lib.esnext.promise.d.ts → lib.es2025.promise.d.ts} +1 -3
  91. package/dist/lib.es2025.regexp.d.ts +30 -0
  92. package/dist/lib.es5.d.ts +22 -24
  93. package/dist/lib.es6.d.ts +1 -3
  94. package/dist/lib.esnext.array.d.ts +1 -3
  95. package/dist/lib.esnext.collection.d.ts +20 -69
  96. package/dist/lib.esnext.d.ts +6 -8
  97. package/dist/lib.esnext.date.d.ts +21 -0
  98. package/dist/lib.esnext.decorators.d.ts +1 -3
  99. package/dist/lib.esnext.disposable.d.ts +1 -3
  100. package/dist/lib.esnext.error.d.ts +1 -3
  101. package/dist/lib.esnext.full.d.ts +1 -3
  102. package/dist/lib.esnext.intl.d.ts +89 -3
  103. package/dist/lib.esnext.sharedmemory.d.ts +1 -3
  104. package/dist/lib.esnext.temporal.d.ts +485 -0
  105. package/dist/lib.esnext.typedarrays.d.ts +90 -0
  106. package/dist/lib.scripthost.d.ts +1 -3
  107. package/dist/lib.webworker.asynciterable.d.ts +3 -26
  108. package/dist/lib.webworker.d.ts +3396 -940
  109. package/dist/lib.webworker.importscripts.d.ts +1 -3
  110. package/dist/lib.webworker.iterable.d.ts +3 -325
  111. package/dist/typescript.cjs +2589 -1826
  112. package/package.json +29 -2
  113. 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 = /\/\*[^]*?\*\//g;
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 looseEqual(a, b) {
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 ? looseCompareArrays(a, b) : false;
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
- aValidType = isMap(a);
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" && node.body.type !== "BlockStatement") {
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
- stack.push(node.body);
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/Groma.md/Groma.md/node_modules/@vue/language-core/lib";
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 { existsSync as existsSync2, readFileSync } from "fs";
39945
+ import { readFileSync } from "fs";
39898
39946
  import path2 from "path";
39899
39947
  import ts from "./typescript.cjs";
39900
39948
 
39901
- // plugins/scanners/projects.ts
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
- import { promisify } from "util";
39907
- var execute = promisify(execFile);
39908
- var excluded = new Set([
39909
- ".git",
39910
- "node_modules",
39911
- "vendor",
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
- async function frameworkProjects(root, dependency, extensions) {
39935
- const files = await projectFiles(root, () => true);
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 directories = new Set(manifests.map((file) => path.posix.dirname(file)));
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 !== "." && !directories.has(directory))
39987
+ while (directory !== "." && !candidates.has(directory))
39942
39988
  directory = path.posix.dirname(directory);
39943
- sources.add(directory);
39989
+ if (candidates.has(directory))
39990
+ sources.add(directory);
39944
39991
  }
39945
- const projects = [];
39946
- for (const file of manifests) {
39947
- const directory = path.posix.dirname(file);
39948
- if (!sources.has(directory) || !files.includes(path.posix.join(directory, "tsconfig.json")))
39949
- continue;
39950
- const manifest = JSON.parse(await readFile(path.join(root, file), "utf8"));
39951
- if (hasDependency(manifest, dependency))
39952
- projects.push(path.dirname(path.join(root, file)));
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 projects;
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
- constructor(root, repositoryRoot = root) {
40050
+ readable;
40051
+ constructor(root, repositoryRoot, sources, owners, files) {
39987
40052
  this.root = repositoryRoot;
39988
- const configFile = path2.join(root, "tsconfig.json");
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, root, {}, configFile, undefined, this.plugin.typescript.extraFileExtensions);
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
- }))({ rootNames: parsed.fileNames, options: parsed.options, host });
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 filename = path2.resolve(path2.dirname(file), src);
40028
- const member = relative(this.root, filename);
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 = root) {
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 (!existsSync2(manifestFile))
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 range = import_language_core2.parseScriptSetupRanges(vueTypeScript, setup.ast, this.project.options).defineEmits?.typeArg;
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 && ts2.isTypeLiteralNode(node)) {
40225
- 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));
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 (element.tagType !== import_compiler_dom.ElementTypes.COMPONENT || event.modifiers.length || event.arg?.type !== import_compiler_dom.NodeTypes.SIMPLE_EXPRESSION || !event.arg.isStatic || event.exp?.type !== import_compiler_dom.NodeTypes.SIMPLE_EXPRESSION)
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 calls = this.emissions(child, event.arg.content);
40257
- let bound = false;
40258
- for (const call of calls) {
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
- if (!caller || position === undefined)
40262
- continue;
40263
- const source = this.operationId(caller);
40264
- const targetId = this.operationId(target);
40265
- if (!source || !targetId)
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 bound;
40408
+ return script.length + template.length > 0;
40279
40409
  }
40280
40410
  }
40281
40411
 
40282
40412
  // plugins/scanners/vue/src/index.ts
40283
- import path5 from "path";
40413
+ import path7 from "path";
40284
40414
 
40285
- // plugins/scanners/typescript-project.ts
40286
- import path3 from "path";
40287
- async function frameworkSourceFiles(options) {
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
- return "unknown";
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) || callee.text !== "fetch")
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 = input === "unseen" || typeof input === "object" && urlText(context.ts, input.node) ? await declaredMethod(context, options, "GET") : undefined;
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, third] = call.arguments;
41294
+ const [first, second] = call.arguments;
41124
41295
  if (ts.isPropertyAccessExpression(callee) && ts.isIdentifier(callee.name)) {
41125
- const client = await axiosClient(context, callee.expression);
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 path4 from "path";
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([...source.statements.flatMap((statement) => listedExports(k, statement)), ...context.exported ?? []]);
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 = path4.join(repositoryRoot, reference.file);
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
- async function scanVue(root) {
42165
+ import ts6 from "./typescript.cjs";
42166
+ async function scanVue(root, _settings, files) {
41754
42167
  const parts = [];
41755
- for (const project of await frameworkProjects(root, "vue", [".vue"])) {
41756
- const observation = await scanVueProject(project, root);
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 scanVueProject(projectRoot, root) {
41763
- const prepared = vueProject(projectRoot, root);
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 files = project.files.map((source) => ({ file: relative(root, source.fileName), symbols: [] }));
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 (!files.some((source) => source.file === file))
41789
- files.push({ file, symbols: [] });
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, path5.join(projectRoot, "package.json")) }],
41794
- files: files.map((file) => ({ ...file, roots: ["vue-project"] })),
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 projects = await frameworkProjects(root, "vue", [".vue"]);
41815
- for (const project of projects)
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
  };