@groma/scanner-react 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +45 -27
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -15,7 +15,7 @@ bun plugins/scanners/react/build.ts
15
15
  From the project being scanned:
16
16
 
17
17
  ```sh
18
- groma scanner add /absolute/path/to/groma/plugins/scanners/react/dist/package
18
+ groma plugin add /absolute/path/to/groma/plugins/scanners/react/dist/package
19
19
  groma scanner check
20
20
  groma scan
21
21
  ```
package/dist/index.js CHANGED
@@ -252,13 +252,13 @@ function compare(...values) {
252
252
  }
253
253
  function uniqueBy(values, key, label) {
254
254
  const seen = new Set;
255
- for (const value of values) {
256
- const id = key(value);
255
+ const keyed = values.map((value) => ({ id: key(value), value }));
256
+ for (const { id } of keyed) {
257
257
  if (seen.has(id))
258
258
  throw new Error(`duplicate ${label}: ${id}`);
259
259
  seen.add(id);
260
260
  }
261
- return [...values].sort((left, right) => key(left).localeCompare(key(right)));
261
+ return keyed.sort((left, right) => left.id.localeCompare(right.id)).map((entry) => entry.value);
262
262
  }
263
263
  function createScanObservation(input) {
264
264
  const roots = validateRoots(input.roots);
@@ -269,9 +269,7 @@ function createScanObservation(input) {
269
269
  symbols: [...new Map(file.symbols.map((symbol) => [
270
270
  compare(symbol.id, symbol.kind),
271
271
  symbol
272
- ])).values()].sort((left, right) => {
273
- return compare(left.id, left.kind).localeCompare(compare(right.id, right.kind));
274
- })
272
+ ]))].sort(([left], [right]) => left.localeCompare(right)).map(([, symbol]) => symbol)
275
273
  })), (file) => file.file, "file path");
276
274
  const filePaths = new Set(files.map((file) => file.file));
277
275
  for (const file of files) {
@@ -282,8 +280,6 @@ function createScanObservation(input) {
282
280
  throw new Error(`file references unknown root: ${root}`);
283
281
  }
284
282
  }
285
- for (const diagnostic of input.diagnostics)
286
- diagnosticLocation(diagnostic);
287
283
  return {
288
284
  schemaVersion: 1,
289
285
  scanner: input.scanner,
@@ -293,14 +289,14 @@ function createScanObservation(input) {
293
289
  ...entryPoints(input.entryPoints, filePaths),
294
290
  ...operationEvidence(input, filePaths),
295
291
  ...httpEvidence(input.httpEndpoints, input.httpRequests, input.operations && new Set(input.operations.map((operation) => operation.id))),
296
- diagnostics: [...new Map(input.diagnostics.map((diagnostic) => [
297
- diagnosticKey(diagnostic),
298
- diagnostic
299
- ])).values()].sort((left, right) => {
300
- return diagnosticKey(left).localeCompare(diagnosticKey(right));
301
- })
292
+ diagnostics: normalizeScanDiagnostics(input.diagnostics)
302
293
  };
303
294
  }
295
+ function normalizeScanDiagnostics(diagnostics) {
296
+ for (const diagnostic of diagnostics)
297
+ diagnosticLocation(diagnostic);
298
+ return [...new Map(diagnostics.map((diagnostic) => [diagnosticKey(diagnostic), diagnostic]))].sort(([left], [right]) => left.localeCompare(right)).map(([, diagnostic]) => diagnostic);
299
+ }
304
300
  function entryPoints(input, paths) {
305
301
  if (input === undefined)
306
302
  return {};
@@ -409,10 +405,14 @@ function operationTokens(operation) {
409
405
  const endLine = Number(operation.endLine);
410
406
  if (endLine < startLine)
411
407
  throw new Error("operation.endLine must be at or after startLine");
408
+ const tokens = array(operation.tokens, "operation.tokens");
409
+ tokens.forEach((token) => {
410
+ string(token, "operation.token");
411
+ });
412
412
  return {
413
413
  startLine,
414
414
  endLine,
415
- tokens: array(operation.tokens, "operation.tokens").map((token) => string(token, "operation.token"))
415
+ tokens
416
416
  };
417
417
  }
418
418
  function validateOperationTokens(operation) {
@@ -603,20 +603,32 @@ function reachedFiles(entry, compiled, imports, packages, units) {
603
603
  }
604
604
  async function declaredEntries(root, declarations, packages, workspaces) {
605
605
  const entries = [];
606
+ const diagnostics = [];
606
607
  for (const file of declarations) {
607
608
  const text = await readFile3(path4.join(root, file), "utf8");
608
609
  const name = path4.posix.basename(file);
609
- if (name === "package.json") {
610
- const manifest = JSON.parse(text);
611
- entries.push(...declaredBins(file, manifest), ...declaredScripts(file, manifest.scripts));
612
- } else if (name === "angular.json")
613
- entries.push(...angularEntries(file, text));
614
- else if (name === "project.json")
615
- entries.push(...nxEntries(file, text, workspaces));
616
- else if (file.endsWith(".html"))
617
- entries.push(...browserEntries(file, text, packages));
610
+ try {
611
+ if (name === "package.json") {
612
+ const manifest = JSON.parse(text);
613
+ entries.push(...declaredBins(file, manifest), ...declaredScripts(file, manifest.scripts));
614
+ } else if (name === "angular.json")
615
+ entries.push(...angularEntries(file, text));
616
+ else if (name === "project.json")
617
+ entries.push(...nxEntries(file, text, workspaces));
618
+ else if (file.endsWith(".html"))
619
+ entries.push(...browserEntries(file, text, packages));
620
+ } catch (error) {
621
+ if (!(error instanceof SyntaxError))
622
+ throw error;
623
+ diagnostics.push({
624
+ severity: "warning",
625
+ code: "JAVASCRIPT_MANIFEST_INVALID",
626
+ file,
627
+ message: `The file is not valid JSON; the entry points it declares are not read. ${error.message}`
628
+ });
629
+ }
618
630
  }
619
- return entries;
631
+ return { entries, diagnostics };
620
632
  }
621
633
  function sourced(entry, files, outputs = []) {
622
634
  const file = sourceOf(entry.file, outputs, files);
@@ -630,7 +642,8 @@ async function withJavaScriptEntries(root, observation, inputs, files) {
630
642
  const packages = new Set(inventory.filter((file) => path4.posix.basename(file) === "package.json").map((file) => path4.posix.dirname(file)));
631
643
  const active = new Set(observation.files.map((file) => packageFor(file.file, packages)));
632
644
  const declarations = inventory.filter((file) => path4.posix.basename(file) !== "nx.json" && active.has(packageFor(file, packages)));
633
- const entries = [...inputs.entries, ...await declaredEntries(root, declarations, packages, workspaces)];
645
+ const declared = await declaredEntries(root, declarations, packages, workspaces);
646
+ const entries = [...inputs.entries, ...declared.entries];
634
647
  const inventoryFiles = [...observation.files];
635
648
  const visible = new Set(inventoryFiles.map((file) => file.file));
636
649
  const readable = new Set(files);
@@ -647,7 +660,12 @@ async function withJavaScriptEntries(root, observation, inputs, files) {
647
660
  }
648
661
  return [{ ...entry, files: [...new Set([entry.file, ...members.map((file) => file.file)])] }];
649
662
  });
650
- return createScanObservation({ ...observation, files: inventoryFiles, entryPoints });
663
+ return createScanObservation({
664
+ ...observation,
665
+ files: inventoryFiles,
666
+ entryPoints,
667
+ diagnostics: [...observation.diagnostics, ...declared.diagnostics]
668
+ });
651
669
  }
652
670
 
653
671
  // plugins/scanners/entry-points/source.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groma/scanner-react",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Complementary React framework evidence; a dependency declaration does not verify runtime use.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "repository": {
54
54
  "type": "git",
55
- "url": "https://github.com/MrLesk/Groma.md.git"
55
+ "url": "https://github.com/MrLesk/groma.md.git"
56
56
  },
57
57
  "publishConfig": {
58
58
  "access": "public"