nuxt-layerscope 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2
4
+
5
+ - A note appears when `nuxt.config` is newer than the registry, because changes to its
6
+ `layerscope` key only apply after `nuxi prepare`, `dev` or `build`.
7
+ - Layer errors caused by the `layerscope` key of `nuxt.config` name it as their source.
8
+
9
+ ## 0.1.1
10
+
11
+ - Names inside type syntax are no longer reported as unresolved references: labeled tuple members
12
+ (`defineEmits<{ close: [value: boolean] }>()`) and parameters of function types
13
+ (`(...next: T[]) => void`) and `typeof` queries in types.
14
+ - `$fetch` is a known global, so it is no longer reported in server code.
15
+ - The docs show `defineConfig` imported from `nuxt-layerscope` in every `layerscope.config.ts` sample.
16
+
3
17
  ## 0.1.0
4
18
 
5
19
  Initial release.
@@ -0,0 +1,2 @@
1
+ import { t as analyze } from "./analyze-QaYmBXyK.mjs";
2
+ export { analyze };
@@ -1,9 +1,9 @@
1
- import { c as realPath, d as effectiveConfig, g as LayerscopeError, h as ruleSeverity, m as isRuleName, s as readJson } from "./layer-factory-xZmIAPrA.mjs";
1
+ import { c as realPath, d as effectiveConfig, f as labelConfigError, g as ruleSeverity, h as isRuleName, s as readJson, v as LayerscopeError } from "./layer-factory-DFh7nkFH.mjs";
2
2
  import { r as pascalCase, t as compareStrings } from "./strings-CrOjNZmB.mjs";
3
3
  import { t as globComponents } from "./component-files-DgOXNE6l.mjs";
4
- import { c as createOwnerLookup, d as createAnalysisEnv, f as readRegistry, h as boundaryFindings, m as loadSymbolTable, n as analyzeFile, p as tableFromRegistry, r as collectFiles, u as resolveLayers, v as loadConfig } from "./file-analysis-Bkq_69x4.mjs";
4
+ import { c as createOwnerLookup, d as createAnalysisEnv, f as readRegistry, h as boundaryFindings, m as loadSymbolTable, n as analyzeFile, p as tableFromRegistry, r as collectFiles, u as resolveLayers, v as loadConfig } from "./file-analysis-Bh7qcWUK.mjs";
5
5
  import { basename, extname, join, relative, resolve } from "pathe";
6
- import { existsSync, writeFileSync } from "node:fs";
6
+ import { existsSync, statSync, writeFileSync } from "node:fs";
7
7
  import { escapePath, glob } from "tinyglobby";
8
8
  import { spawnSync } from "node:child_process";
9
9
  //#region src/baseline/index.ts
@@ -149,6 +149,24 @@ function runRules(input) {
149
149
  };
150
150
  }
151
151
  //#endregion
152
+ //#region src/analyze/config-freshness.ts
153
+ const NUXT_CONFIG_FILES = [
154
+ "nuxt.config.ts",
155
+ "nuxt.config.mts",
156
+ "nuxt.config.js",
157
+ "nuxt.config.mjs"
158
+ ];
159
+ /**
160
+ * The registry holds the `layerscope` key of `nuxt.config` as it was at the last `nuxi prepare`,
161
+ * `dev` or `build`, so an edit made since then does not apply yet.
162
+ */
163
+ function staleConfigNote(rootDir, registryFile) {
164
+ const config = NUXT_CONFIG_FILES.map((name) => join(rootDir, name)).find((file) => existsSync(file));
165
+ if (config === void 0 || !existsSync(registryFile)) return null;
166
+ if (statSync(config).mtimeMs <= statSync(registryFile).mtimeMs) return null;
167
+ return "nuxt.config is newer than the layerscope registry, so changes to its \"layerscope\" key do not apply yet. Run \"nuxi prepare\" again, or pass --prepare.";
168
+ }
169
+ //#endregion
152
170
  //#region src/analyze/freshness.ts
153
171
  const RERUN_HINT = "Run \"nuxi prepare\" again, or pass --prepare.";
154
172
  const COMPONENT_SUFFIX = /(?:\.(?:client|server))?(?:\.global|\.island)*$/u;
@@ -266,13 +284,21 @@ function recordedConfig(buildDir, registry) {
266
284
  async function loadEnvironment(options) {
267
285
  const { rootDir, buildDir } = options;
268
286
  const { registry, table, ...symbols } = loadSymbols(buildDir, options.source);
269
- const config = effectiveConfig(options.config, recordedConfig(buildDir, registry));
270
- const { layers, ownerOf, notes } = await loadLayers(rootDir, config, registry?.layers);
287
+ const recorded = recordedConfig(buildDir, registry);
288
+ const config = effectiveConfig(options.config, recorded);
289
+ const { layers, ownerOf, notes } = await loadLayers(rootDir, config, registry?.layers).catch((error) => {
290
+ throw labelConfigError(error, recorded);
291
+ });
292
+ const stale = registry === null ? null : staleConfigNote(rootDir, symbols.sourceFile);
271
293
  await (registry === null ? assertFresh(table, layers) : assertRegistryFresh(table, registry));
272
294
  return {
273
295
  ...symbols,
274
296
  config,
275
- notes: [...symbols.notes, ...notes],
297
+ notes: [
298
+ ...symbols.notes,
299
+ ...notes,
300
+ ...stale === null ? [] : [stale]
301
+ ],
276
302
  registry,
277
303
  layers,
278
304
  env: createAnalysisEnv(table, ownerOf, buildDir, config)
package/dist/api.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { g as LayerscopeError, l as REGISTRY_FILE, u as REGISTRY_VERSION } from "./layer-factory-xZmIAPrA.mjs";
1
+ import { l as REGISTRY_FILE, u as REGISTRY_VERSION, v as LayerscopeError } from "./layer-factory-DFh7nkFH.mjs";
2
2
  import { t as defineConfig } from "./define-l62B9fVk.mjs";
3
- import { i as createBaseline, n as BASELINE_FILE, r as BASELINE_VERSION, t as analyze } from "./analyze-DS51xy6X.mjs";
3
+ import { i as createBaseline, n as BASELINE_FILE, r as BASELINE_VERSION, t as analyze } from "./analyze-QaYmBXyK.mjs";
4
4
  import { i as JSON_REPORT_VERSION, n as formatResult, t as OUTPUT_FORMATS } from "./report-BNW0GCl9.mjs";
5
- import { r as buildGraph, t as findUnused } from "./unused-Dxep1p6u.mjs";
5
+ import { r as buildGraph, t as findUnused } from "./unused-BtsPSfxb.mjs";
6
6
  export { BASELINE_FILE, BASELINE_VERSION, JSON_REPORT_VERSION, LayerscopeError, OUTPUT_FORMATS, REGISTRY_FILE, REGISTRY_VERSION, analyze, buildGraph, createBaseline, defineConfig, findUnused, formatResult };
package/dist/bin.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { g as LayerscopeError } from "./layer-factory-xZmIAPrA.mjs";
2
+ import { v as LayerscopeError } from "./layer-factory-DFh7nkFH.mjs";
3
3
  import { i as plural, r as pascalCase } from "./strings-CrOjNZmB.mjs";
4
- import { a as writeBaseline, i as createBaseline, n as BASELINE_FILE, t as analyze } from "./analyze-DS51xy6X.mjs";
4
+ import { a as writeBaseline, i as createBaseline, n as BASELINE_FILE, t as analyze } from "./analyze-QaYmBXyK.mjs";
5
5
  import { n as formatResult, r as isOutputFormat, t as OUTPUT_FORMATS } from "./report-BNW0GCl9.mjs";
6
- import { i as edgeStatus, n as GRAPH_LEVELS, r as buildGraph, t as findUnused } from "./unused-Dxep1p6u.mjs";
6
+ import { i as edgeStatus, n as GRAPH_LEVELS, r as buildGraph, t as findUnused } from "./unused-BtsPSfxb.mjs";
7
7
  import { relative, resolve } from "pathe";
8
8
  import { cac } from "cac";
9
9
  //#region src/commands/shared.ts
package/dist/eslint.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { d as effectiveConfig, l as REGISTRY_FILE } from "./layer-factory-xZmIAPrA.mjs";
2
- import { t as packageVersion } from "./version-D6whhsHH.mjs";
3
- import { _ as findConfigFile, a as lineColumn, c as createOwnerLookup, d as createAnalysisEnv, f as readRegistry, h as boundaryFindings, i as isCheckedFile, l as nameLayers, o as offsetAt, p as tableFromRegistry, s as scanFile, t as FileAnalysis, y as loadConfigSync } from "./file-analysis-Bkq_69x4.mjs";
1
+ import { d as effectiveConfig, l as REGISTRY_FILE } from "./layer-factory-DFh7nkFH.mjs";
2
+ import { t as packageVersion } from "./version-DFWOUgi5.mjs";
3
+ import { _ as findConfigFile, a as lineColumn, c as createOwnerLookup, d as createAnalysisEnv, f as readRegistry, h as boundaryFindings, i as isCheckedFile, l as nameLayers, o as offsetAt, p as tableFromRegistry, s as scanFile, t as FileAnalysis, y as loadConfigSync } from "./file-analysis-Bh7qcWUK.mjs";
4
4
  import { dirname, join, relative, resolve } from "pathe";
5
5
  import { existsSync, readFileSync, statSync } from "node:fs";
6
6
  //#region src/eslint/lint-file.ts
@@ -1,4 +1,4 @@
1
- import { a as isClonedFrom, c as realPath, g as LayerscopeError, h as ruleSeverity, i as layerFromPath, l as REGISTRY_FILE, n as deriveDirectories, o as isFile, p as validateConfig, r as layerFromNuxt, s as readJson, t as ROOT_LAYER_NAME } from "./layer-factory-xZmIAPrA.mjs";
1
+ import { _ as LayerConfigError, a as isClonedFrom, c as realPath, g as ruleSeverity, i as layerFromPath, l as REGISTRY_FILE, m as validateConfig, n as deriveDirectories, o as isFile, r as layerFromNuxt, s as readJson, t as ROOT_LAYER_NAME, v as LayerscopeError } from "./layer-factory-DFh7nkFH.mjs";
2
2
  import { n as escapeRegExp, r as pascalCase, t as compareStrings } from "./strings-CrOjNZmB.mjs";
3
3
  import { dirname, isAbsolute, join, relative, resolve } from "pathe";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -328,6 +328,8 @@ const SFC_MACROS = [
328
328
  "defineModel",
329
329
  "withDefaults"
330
330
  ];
331
+ /** Defined on `globalThis` by Nuxt (app) and Nitro (server), so absent from the registry there. */
332
+ const RUNTIME_GLOBALS = ["$fetch"];
331
333
  /** Registered globally by Vue and vue-router, so never listed in components.d.ts. */
332
334
  const GLOBAL_COMPONENTS = ["RouterLink", "RouterView"];
333
335
  function knownIdentifiers(extra) {
@@ -336,6 +338,7 @@ function knownIdentifiers(extra) {
336
338
  ...Object.keys(globals.browser),
337
339
  ...Object.keys(globals.node),
338
340
  ...SFC_MACROS,
341
+ ...RUNTIME_GLOBALS,
339
342
  "undefined",
340
343
  "arguments",
341
344
  ...extra
@@ -405,10 +408,10 @@ function validateLayers(layers, config) {
405
408
  for (const [name, rule] of Object.entries(config.layers ?? {})) {
406
409
  if (!names.has(name)) {
407
410
  const known = [...names].toSorted().join(", ");
408
- throw new LayerscopeError(`Unknown layer "${name}" in config. Known layers: ${known}`);
411
+ throw new LayerConfigError(`Unknown layer "${name}" in config. Known layers: ${known}`);
409
412
  }
410
413
  const unknown = rule.allow?.find((allowed) => !names.has(allowed));
411
- if (unknown !== void 0) throw new LayerscopeError(`layers.${name}.allow: unknown layer "${unknown}"`);
414
+ if (unknown !== void 0) throw new LayerConfigError(`layers.${name}.allow: unknown layer "${unknown}"`);
412
415
  }
413
416
  }
414
417
  //#endregion
@@ -540,6 +543,13 @@ const scriptVisitors = {
540
543
  },
541
544
  TSModuleDeclaration: skip,
542
545
  TSImportType: skip,
546
+ TSTypeQuery: skip,
547
+ TSNamedTupleMember: skip,
548
+ TSFunctionType: skip,
549
+ TSConstructorType: skip,
550
+ TSMethodSignature: skip,
551
+ TSCallSignatureDeclaration: skip,
552
+ TSConstructSignatureDeclaration: skip,
543
553
  CallExpression(node, _parent, { scan, mapOffset }) {
544
554
  if (node.type !== "CallExpression" || node.callee.type !== "Identifier") return;
545
555
  const [arg] = node.arguments;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { f as pickProjectConfig, l as REGISTRY_FILE, r as layerFromNuxt } from "./layer-factory-xZmIAPrA.mjs";
1
+ import { l as REGISTRY_FILE, p as pickProjectConfig, r as layerFromNuxt } from "./layer-factory-DFh7nkFH.mjs";
2
2
  import { t as summarize } from "./summary-DiUYKMPe.mjs";
3
3
  import { i as plural, t as compareStrings } from "./strings-CrOjNZmB.mjs";
4
- import { t as packageVersion } from "./version-D6whhsHH.mjs";
4
+ import { t as packageVersion } from "./version-DFWOUgi5.mjs";
5
5
  import { t as globComponents } from "./component-files-DgOXNE6l.mjs";
6
6
  import { t as defineConfig } from "./define-l62B9fVk.mjs";
7
7
  import { mkdir, writeFile } from "node:fs/promises";
@@ -106,7 +106,7 @@ function renderError(message) {
106
106
  //#region src/devtools/index.ts
107
107
  const DEVTOOLS_ROUTE = "/__layerscope";
108
108
  async function renderReport(nuxt, format) {
109
- const [{ analyze }, { formatResult }] = await Promise.all([import("./analyze-YePAJEVS.mjs"), import("./report-DtAi0vPb.mjs")]);
109
+ const [{ analyze }, { formatResult }] = await Promise.all([import("./analyze-DVzyPH7N.mjs"), import("./report-DtAi0vPb.mjs")]);
110
110
  const { rootDir, app } = nuxt.options;
111
111
  const result = await analyze({ rootDir });
112
112
  if (format === "json") return formatResult(result, "json", rootDir);
@@ -9,6 +9,15 @@ var LayerscopeError = class extends Error {
9
9
  }
10
10
  };
11
11
  //#endregion
12
+ //#region src/layer-config-error.ts
13
+ /** A layer name in the config that matches no layer. */
14
+ var LayerConfigError = class extends LayerscopeError {
15
+ constructor(..._args) {
16
+ super(..._args);
17
+ this.name = "LayerConfigError";
18
+ }
19
+ };
20
+ //#endregion
12
21
  //#region src/config/rules.ts
13
22
  const DEFAULT_SEVERITY = {
14
23
  "layer-boundary": "error",
@@ -70,6 +79,11 @@ function effectiveConfig(fileConfig, recorded) {
70
79
  ...recorded
71
80
  };
72
81
  }
82
+ /** Names the `nuxt.config` key in a layer error, when the settings that caused it came from there. */
83
+ function labelConfigError(error, recorded) {
84
+ if (error instanceof LayerConfigError && recorded !== void 0 && hasProjectConfig(recorded)) return new LayerscopeError(`${NUXT_CONFIG_LABEL}: ${error.message}`);
85
+ return error;
86
+ }
73
87
  //#endregion
74
88
  //#region src/registry/schema.ts
75
89
  /** Bumped on breaking changes to `registry.json`; readers fall back to the `.d.ts` files. */
@@ -165,4 +179,4 @@ function layerFromPath(name, root) {
165
179
  };
166
180
  }
167
181
  //#endregion
168
- export { isClonedFrom as a, realPath as c, effectiveConfig as d, pickProjectConfig as f, LayerscopeError as g, ruleSeverity as h, layerFromPath as i, REGISTRY_FILE as l, isRuleName as m, deriveDirectories as n, isFile as o, validateConfig as p, layerFromNuxt as r, readJson as s, ROOT_LAYER_NAME as t, REGISTRY_VERSION as u };
182
+ export { LayerConfigError as _, isClonedFrom as a, realPath as c, effectiveConfig as d, labelConfigError as f, ruleSeverity as g, isRuleName as h, layerFromPath as i, REGISTRY_FILE as l, validateConfig as m, deriveDirectories as n, isFile as o, pickProjectConfig as p, layerFromNuxt as r, readJson as s, ROOT_LAYER_NAME as t, REGISTRY_VERSION as u, LayerscopeError as v };
@@ -1,5 +1,5 @@
1
1
  import { t as compareStrings } from "./strings-CrOjNZmB.mjs";
2
- import { c as createOwnerLookup, g as isAllowed } from "./file-analysis-Bkq_69x4.mjs";
2
+ import { c as createOwnerLookup, g as isAllowed } from "./file-analysis-Bh7qcWUK.mjs";
3
3
  import { relative } from "pathe";
4
4
  //#region src/rules/edge-status.ts
5
5
  /** How the layer rules see one edge. */
@@ -1,4 +1,4 @@
1
- import { s as readJson } from "./layer-factory-xZmIAPrA.mjs";
1
+ import { s as readJson } from "./layer-factory-DFh7nkFH.mjs";
2
2
  import { fileURLToPath } from "node:url";
3
3
  //#region src/version.ts
4
4
  /** Both `src/` and the bundled `dist/` sit next to package.json. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-layerscope",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Layer boundary checks for Nuxt apps that see auto-imports",
5
5
  "keywords": [
6
6
  "architecture",
@@ -1,2 +0,0 @@
1
- import { t as analyze } from "./analyze-DS51xy6X.mjs";
2
- export { analyze };