@venizia/dev-configs 0.4.6 → 0.4.7-1
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/LICENSE.md +1 -3
- package/README.md +1 -1
- package/dist/checks/catalog.d.ts +4 -2
- package/dist/checks/catalog.d.ts.map +1 -1
- package/dist/checks/catalog.js +72 -68
- package/dist/checks/catalog.js.map +1 -1
- package/dist/checks/module-cycles.d.ts +11 -9
- package/dist/checks/module-cycles.d.ts.map +1 -1
- package/dist/checks/module-cycles.js +32 -30
- package/dist/checks/module-cycles.js.map +1 -1
- package/dist/checks/purity/manifest.d.ts +44 -38
- package/dist/checks/purity/manifest.d.ts.map +1 -1
- package/dist/checks/purity/manifest.js +121 -115
- package/dist/checks/purity/manifest.js.map +1 -1
- package/dist/checks/purity/probe.d.ts +22 -18
- package/dist/checks/purity/probe.d.ts.map +1 -1
- package/dist/checks/purity/probe.js +101 -99
- package/dist/checks/purity/probe.js.map +1 -1
- package/dist/checks/purity/run.d.ts +18 -16
- package/dist/checks/purity/run.d.ts.map +1 -1
- package/dist/checks/purity/run.js +90 -86
- package/dist/checks/purity/run.js.map +1 -1
- package/dist/checks/test-controls.d.ts +17 -15
- package/dist/checks/test-controls.d.ts.map +1 -1
- package/dist/checks/test-controls.js +71 -69
- package/dist/checks/test-controls.js.map +1 -1
- package/dist/checks/test-dead-code.d.ts +5 -3
- package/dist/checks/test-dead-code.d.ts.map +1 -1
- package/dist/checks/test-dead-code.js +23 -21
- package/dist/checks/test-dead-code.js.map +1 -1
- package/dist/checks/test-mutate.d.ts +12 -7
- package/dist/checks/test-mutate.d.ts.map +1 -1
- package/dist/checks/test-mutate.js +59 -56
- package/dist/checks/test-mutate.js.map +1 -1
- package/dist/checks/test-weight.d.ts +11 -8
- package/dist/checks/test-weight.d.ts.map +1 -1
- package/dist/checks/test-weight.js +98 -94
- package/dist/checks/test-weight.js.map +1 -1
- package/dist/cli/check.d.ts.map +1 -1
- package/dist/cli/check.js +11 -8
- package/dist/cli/check.js.map +1 -1
- package/dist/cli/codemod/async-style.d.ts +62 -0
- package/dist/cli/codemod/async-style.d.ts.map +1 -0
- package/dist/cli/codemod/async-style.js +248 -0
- package/dist/cli/codemod/async-style.js.map +1 -0
- package/dist/cli/codemod/const-classes.d.ts.map +1 -1
- package/dist/cli/codemod/const-classes.js +2 -1
- package/dist/cli/codemod/const-classes.js.map +1 -1
- package/dist/cli/codemod/drop-redundant-casts.d.ts.map +1 -1
- package/dist/cli/codemod/drop-redundant-casts.js +2 -1
- package/dist/cli/codemod/drop-redundant-casts.js.map +1 -1
- package/dist/cli/codemod/files.d.ts +7 -0
- package/dist/cli/codemod/files.d.ts.map +1 -1
- package/dist/cli/codemod/files.js +33 -0
- package/dist/cli/codemod/files.js.map +1 -1
- package/dist/cli/codemod/index.d.ts.map +1 -1
- package/dist/cli/codemod/index.js +12 -3
- package/dist/cli/codemod/index.js.map +1 -1
- package/dist/cli/codemod/model-settings.d.ts +7 -5
- package/dist/cli/codemod/model-settings.d.ts.map +1 -1
- package/dist/cli/codemod/model-settings.js +293 -291
- package/dist/cli/codemod/model-settings.js.map +1 -1
- package/dist/cli/codemod/namespace-functions/index.d.ts +20 -0
- package/dist/cli/codemod/namespace-functions/index.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/index.js +182 -0
- package/dist/cli/codemod/namespace-functions/index.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/logger-scope.d.ts +32 -0
- package/dist/cli/codemod/namespace-functions/logger-scope.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/logger-scope.js +128 -0
- package/dist/cli/codemod/namespace-functions/logger-scope.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mapping.d.ts +66 -0
- package/dist/cli/codemod/namespace-functions/mapping.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mapping.js +99 -0
- package/dist/cli/codemod/namespace-functions/mapping.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/boot.d.ts +7 -0
- package/dist/cli/codemod/namespace-functions/mappings/boot.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/boot.js +28 -0
- package/dist/cli/codemod/namespace-functions/mappings/boot.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/connectors.d.ts +4 -0
- package/dist/cli/codemod/namespace-functions/mappings/connectors.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/connectors.js +218 -0
- package/dist/cli/codemod/namespace-functions/mappings/connectors.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/core-server.d.ts +7 -0
- package/dist/cli/codemod/namespace-functions/mappings/core-server.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/core-server.js +162 -0
- package/dist/cli/codemod/namespace-functions/mappings/core-server.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/core-worker.d.ts +7 -0
- package/dist/cli/codemod/namespace-functions/mappings/core-worker.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/core-worker.js +18 -0
- package/dist/cli/codemod/namespace-functions/mappings/core-worker.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/dev-configs.d.ts +7 -0
- package/dist/cli/codemod/namespace-functions/mappings/dev-configs.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/dev-configs.js +192 -0
- package/dist/cli/codemod/namespace-functions/mappings/dev-configs.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/filter.d.ts +7 -0
- package/dist/cli/codemod/namespace-functions/mappings/filter.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/filter.js +30 -0
- package/dist/cli/codemod/namespace-functions/mappings/filter.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/helpers.d.ts +16 -0
- package/dist/cli/codemod/namespace-functions/mappings/helpers.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/helpers.js +535 -0
- package/dist/cli/codemod/namespace-functions/mappings/helpers.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/index.d.ts +4 -0
- package/dist/cli/codemod/namespace-functions/mappings/index.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/index.js +25 -0
- package/dist/cli/codemod/namespace-functions/mappings/index.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/inversion.d.ts +10 -0
- package/dist/cli/codemod/namespace-functions/mappings/inversion.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/inversion.js +81 -0
- package/dist/cli/codemod/namespace-functions/mappings/inversion.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/kernel.d.ts +17 -0
- package/dist/cli/codemod/namespace-functions/mappings/kernel.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/mappings/kernel.js +229 -0
- package/dist/cli/codemod/namespace-functions/mappings/kernel.js.map +1 -0
- package/dist/cli/codemod/namespace-functions/rewriter.d.ts +61 -0
- package/dist/cli/codemod/namespace-functions/rewriter.d.ts.map +1 -0
- package/dist/cli/codemod/namespace-functions/rewriter.js +564 -0
- package/dist/cli/codemod/namespace-functions/rewriter.js.map +1 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/compilers/bun.d.ts +1 -1
- package/dist/compilers/bun.js +1 -1
- package/dist/compilers/bun.js.map +1 -1
- package/dist/linters/house/await-support.d.ts +74 -0
- package/dist/linters/house/await-support.d.ts.map +1 -0
- package/dist/linters/house/await-support.js +238 -0
- package/dist/linters/house/await-support.js.map +1 -0
- package/dist/linters/house/common.d.ts +15 -9
- package/dist/linters/house/common.d.ts.map +1 -1
- package/dist/linters/house/common.js +20 -15
- package/dist/linters/house/common.js.map +1 -1
- package/dist/linters/house/configs.d.ts +26 -0
- package/dist/linters/house/configs.d.ts.map +1 -1
- package/dist/linters/house/configs.js +55 -1
- package/dist/linters/house/configs.js.map +1 -1
- package/dist/linters/house/const-class-values.rule.d.ts.map +1 -1
- package/dist/linters/house/const-class-values.rule.js +27 -19
- package/dist/linters/house/const-class-values.rule.js.map +1 -1
- package/dist/linters/house/effect-cleanup-consistency.rule.d.ts +17 -0
- package/dist/linters/house/effect-cleanup-consistency.rule.d.ts.map +1 -0
- package/dist/linters/house/effect-cleanup-consistency.rule.js +87 -0
- package/dist/linters/house/effect-cleanup-consistency.rule.js.map +1 -0
- package/dist/linters/house/hook-support.d.ts +29 -0
- package/dist/linters/house/hook-support.d.ts.map +1 -0
- package/dist/linters/house/hook-support.js +72 -0
- package/dist/linters/house/hook-support.js.map +1 -0
- package/dist/linters/house/index.d.ts +9 -0
- package/dist/linters/house/index.d.ts.map +1 -1
- package/dist/linters/house/index.js +9 -0
- package/dist/linters/house/index.js.map +1 -1
- package/dist/linters/house/max-params-own.rule.d.ts.map +1 -1
- package/dist/linters/house/max-params-own.rule.js +33 -24
- package/dist/linters/house/max-params-own.rule.js.map +1 -1
- package/dist/linters/house/no-async-hook-callback.rule.d.ts +18 -0
- package/dist/linters/house/no-async-hook-callback.rule.d.ts.map +1 -0
- package/dist/linters/house/no-async-hook-callback.rule.js +50 -0
- package/dist/linters/house/no-async-hook-callback.rule.js.map +1 -0
- package/dist/linters/house/no-await-promise-chain.rule.d.ts +24 -0
- package/dist/linters/house/no-await-promise-chain.rule.d.ts.map +1 -0
- package/dist/linters/house/no-await-promise-chain.rule.js +298 -0
- package/dist/linters/house/no-await-promise-chain.rule.js.map +1 -0
- package/dist/linters/house/no-inline-await.rule.d.ts +20 -0
- package/dist/linters/house/no-inline-await.rule.d.ts.map +1 -0
- package/dist/linters/house/no-inline-await.rule.js +70 -0
- package/dist/linters/house/no-inline-await.rule.js.map +1 -0
- package/dist/linters/house/no-new-error.rule.js +4 -4
- package/dist/linters/house/no-new-error.rule.js.map +1 -1
- package/dist/linters/house/no-return-await.rule.d.ts +15 -0
- package/dist/linters/house/no-return-await.rule.d.ts.map +1 -0
- package/dist/linters/house/no-return-await.rule.js +92 -0
- package/dist/linters/house/no-return-await.rule.js.map +1 -0
- package/dist/linters/house/no-silent-catch.rule.d.ts +22 -0
- package/dist/linters/house/no-silent-catch.rule.d.ts.map +1 -0
- package/dist/linters/house/no-silent-catch.rule.js +88 -0
- package/dist/linters/house/no-silent-catch.rule.js.map +1 -0
- package/dist/linters/house/plugin.d.ts.map +1 -1
- package/dist/linters/house/plugin.js +12 -0
- package/dist/linters/house/plugin.js.map +1 -1
- package/dist/linters/house/promise-chain-support.d.ts +49 -0
- package/dist/linters/house/promise-chain-support.d.ts.map +1 -0
- package/dist/linters/house/promise-chain-support.js +188 -0
- package/dist/linters/house/promise-chain-support.js.map +1 -0
- package/dist/linters/rules/no-restricted-properties.rule.js +1 -1
- package/dist/linters/rules/no-restricted-properties.rule.js.map +1 -1
- package/dist/testing/rejection.helper.d.ts +25 -20
- package/dist/testing/rejection.helper.d.ts.map +1 -1
- package/dist/testing/rejection.helper.js +33 -31
- package/dist/testing/rejection.helper.js.map +1 -1
- package/dist/testing/repo-tmp.d.ts +19 -9
- package/dist/testing/repo-tmp.d.ts.map +1 -1
- package/dist/testing/repo-tmp.js +50 -48
- package/dist/testing/repo-tmp.js.map +1 -1
- package/dist/testing/spawn.helper.d.ts +12 -10
- package/dist/testing/spawn.helper.d.ts.map +1 -1
- package/dist/testing/spawn.helper.js +22 -16
- package/dist/testing/spawn.helper.js.map +1 -1
- package/dist/testing/tmpdir-preload.js +1 -1
- package/dist/testing/tmpdir-preload.js.map +1 -1
- package/package.json +2 -3
package/LICENSE.md
CHANGED
|
@@ -37,7 +37,7 @@ This monorepo contains the following packages, all licensed under MIT:
|
|
|
37
37
|
| `@venizia/ignis-helpers` | Utility helpers - logging, cron, Redis, queues, storage |
|
|
38
38
|
| `@venizia/ignis-inversion` | Dependency Injection & IoC container |
|
|
39
39
|
| `@venizia/dev-configs` | Shared oxlint, ESLint, TypeScript configurations |
|
|
40
|
-
| `@venizia/ignis-docs` | Documentation
|
|
40
|
+
| `@venizia/ignis-docs` | Documentation site content |
|
|
41
41
|
|
|
42
42
|
---
|
|
43
43
|
|
|
@@ -79,8 +79,6 @@ Ignis uses the following open-source libraries. We are grateful to the authors a
|
|
|
79
79
|
| Library | License | Description |
|
|
80
80
|
|---------|---------|-------------|
|
|
81
81
|
| [VitePress](https://github.com/vuejs/vitepress) | MIT | Static site generator |
|
|
82
|
-
| [Fuse.js](https://github.com/krisk/fuse) | Apache-2.0 | Fuzzy search library |
|
|
83
|
-
| [gray-matter](https://github.com/jonschlinkert/gray-matter) | MIT | Front-matter parser |
|
|
84
82
|
|
|
85
83
|
---
|
|
86
84
|
|
package/README.md
CHANGED
|
@@ -104,7 +104,7 @@ Every IGNIS package and example does.
|
|
|
104
104
|
| :--- | :--- |
|
|
105
105
|
| `@venizia/dev-configs` | Everything below, re-exported |
|
|
106
106
|
| `@venizia/dev-configs/compilers` | `BunCompiler` |
|
|
107
|
-
| `@venizia/dev-configs/testing` | `rejectionOf`, `expectRejection`
|
|
107
|
+
| `@venizia/dev-configs/testing` | `RejectionHelper` (`rejectionOf`, `expectRejection`), `SpawnHelper` (`spawnSyncBounded`), `RepoTmp` (`findRoot`, `apply`) - test helpers (imports `bun:test`; tests only) |
|
|
108
108
|
| `@venizia/dev-configs/linters` | `oxlintConfigs`, `OxlintConfigs`, `BrowserOxlintConfigs`, `ReactOxlintConfigs`, `LintIgnore`, `namingConventionConfigs`, `reactNamingConventionConfigs`, `houseConfigs`, `reactHouseConfigs`, `eslintConfigs`, `ReactEslintConfigs`, the rule classes and their types |
|
|
109
109
|
| `@venizia/dev-configs/linters/oxlint` | `oxlintConfigs`, `OxlintConfigs`, `IOxlintPresetOptions`, `BrowserOxlintConfigs`, `ReactOxlintConfigs`, `LintIgnore`, the rule classes and their types: everything an oxlint config needs, and nothing that loads ESLint. Loads in milliseconds: `/linters` also loads ESLint and its plugins, which an oxlint config never uses |
|
|
110
110
|
| `@venizia/dev-configs/tsconfig.base.json` | Target and lib ES2025, `module` Node16, strict mode (`noImplicitAny` and `useUnknownInCatchVariables` on) with `strictPropertyInitialization` off (DI-injected properties have no initializer), `noEmitOnError`, tests excluded |
|
package/dist/checks/catalog.d.ts
CHANGED
|
@@ -34,6 +34,8 @@ export interface ICatalogReport {
|
|
|
34
34
|
/** Set when there is no `workspaces.catalog` to check against. */
|
|
35
35
|
noCatalog: boolean;
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
export declare class CatalogCheck {
|
|
38
|
+
/** Reads the root catalog and every manifest the options name, and reports everything wrong with their ranges. */
|
|
39
|
+
static find(opts?: ICatalogOptions): Promise<ICatalogReport>;
|
|
40
|
+
}
|
|
39
41
|
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/checks/catalog.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,6GAA6G;IAC7G,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAEjB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IAEnB,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;CACpB;AAcD,kHAAkH;
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/checks/catalog.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,6GAA6G;IAC7G,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAEjB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IAEnB,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;CACpB;AAcD,qBAAa,YAAY;IACvB,kHAAkH;WACrG,IAAI,CAAC,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;CAqGvE"}
|
package/dist/checks/catalog.js
CHANGED
|
@@ -1,94 +1,98 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.CatalogCheck = void 0;
|
|
4
4
|
const bun_1 = require("bun");
|
|
5
5
|
const node_fs_1 = require("node:fs");
|
|
6
6
|
const node_path_1 = require("node:path");
|
|
7
7
|
/** `peerDependencies` are compatibility statements for consumers and stay deliberately looser than the install range. */
|
|
8
8
|
const CATALOGUED_BLOCKS = ['dependencies', 'devDependencies'];
|
|
9
9
|
const DEFAULT_GLOB = 'packages/*/package.json';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const referenced = new Set();
|
|
20
|
-
const presentPinned = pinned.filter((file) => (0, node_fs_1.existsSync)((0, node_path_1.join)(root, file)));
|
|
21
|
-
const files = new Set();
|
|
22
|
-
for (const pattern of [DEFAULT_GLOB, ...globs]) {
|
|
23
|
-
for await (const file of new bun_1.Glob(pattern).scan(root)) {
|
|
24
|
-
files.add(file);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
for (const file of [...files, ...presentPinned]) {
|
|
28
|
-
let json;
|
|
29
|
-
try {
|
|
30
|
-
json = JSON.parse(await Bun.file((0, node_path_1.join)(root, file)).text());
|
|
10
|
+
class CatalogCheck {
|
|
11
|
+
/** Reads the root catalog and every manifest the options name, and reports everything wrong with their ranges. */
|
|
12
|
+
static async find(opts = {}) {
|
|
13
|
+
const { root = process.cwd(), globs = [], presetPrefix, pinned = [] } = opts;
|
|
14
|
+
const result = await Bun.file((0, node_path_1.join)(root, 'package.json')).text();
|
|
15
|
+
const rootJson = JSON.parse(result);
|
|
16
|
+
const catalog = rootJson.workspaces?.catalog ?? {};
|
|
17
|
+
if (Object.keys(catalog).length === 0) {
|
|
18
|
+
return { problems: [], entries: 0, referenced: 0, noCatalog: true };
|
|
31
19
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
20
|
+
const problems = [];
|
|
21
|
+
const referenced = new Set();
|
|
22
|
+
const presentPinned = pinned.filter((file) => (0, node_fs_1.existsSync)((0, node_path_1.join)(root, file)));
|
|
23
|
+
const files = new Set();
|
|
24
|
+
for (const pattern of [DEFAULT_GLOB, ...globs]) {
|
|
25
|
+
for await (const file of new bun_1.Glob(pattern).scan(root)) {
|
|
26
|
+
files.add(file);
|
|
27
|
+
}
|
|
38
28
|
}
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
29
|
+
for (const file of [...files, ...presentPinned]) {
|
|
30
|
+
let json;
|
|
31
|
+
try {
|
|
32
|
+
const result2 = await Bun.file((0, node_path_1.join)(root, file)).text();
|
|
33
|
+
json = JSON.parse(result2);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
problems.push({
|
|
37
|
+
file,
|
|
38
|
+
message: `invalid JSON - ${error instanceof Error ? error.message : error}`,
|
|
39
|
+
});
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const isPinned = presentPinned.includes(file);
|
|
43
|
+
for (const block of CATALOGUED_BLOCKS) {
|
|
44
|
+
const entriesList = Object.entries(json[block] ?? {});
|
|
45
|
+
for (const [dep, range] of entriesList) {
|
|
46
|
+
if (!(dep in catalog)) {
|
|
47
|
+
continue;
|
|
53
48
|
}
|
|
54
|
-
|
|
49
|
+
referenced.add(dep);
|
|
50
|
+
if (isPinned) {
|
|
51
|
+
if (range !== catalog[dep]) {
|
|
52
|
+
problems.push({
|
|
53
|
+
file,
|
|
54
|
+
message: `${block}.${dep} is "${range}" but the catalog pins "${catalog[dep]}" - this project is outside the workspace, so pin exactly that`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (range === 'catalog:') {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
problems.push({
|
|
63
|
+
file,
|
|
64
|
+
message: `${block}.${dep} is "${range}" but the catalog owns it - use "catalog:" (catalog pins ${catalog[dep]})`,
|
|
65
|
+
});
|
|
55
66
|
}
|
|
56
|
-
|
|
67
|
+
}
|
|
68
|
+
// A preset is not a published manifest: its markers are resolved by the release, and the library kind gives a
|
|
69
|
+
// name one catalog range, so a lib's peer takes the same marker as its dev dependency.
|
|
70
|
+
const isPreset = presetPrefix !== undefined && file.startsWith(presetPrefix);
|
|
71
|
+
// A peer resolved from the catalog would collapse to the exact install range, losing the looseness that makes it a peer.
|
|
72
|
+
const peerEntries = Object.entries(json.peerDependencies ?? {});
|
|
73
|
+
for (const [dep, range] of peerEntries) {
|
|
74
|
+
if (range !== 'catalog:' || isPreset) {
|
|
57
75
|
continue;
|
|
58
76
|
}
|
|
59
77
|
problems.push({
|
|
60
78
|
file,
|
|
61
|
-
message:
|
|
79
|
+
message: `peerDependencies.${dep} uses "catalog:" - a peer range must stay hand-authored and looser than the install range`,
|
|
62
80
|
});
|
|
63
81
|
}
|
|
64
82
|
}
|
|
65
|
-
// A
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
const peerEntries = Object.entries(json.peerDependencies ?? {});
|
|
70
|
-
for (const [dep, range] of peerEntries) {
|
|
71
|
-
if (range !== 'catalog:' || isPreset) {
|
|
83
|
+
// A catalog entry nobody references is dead weight that will drift out of date unnoticed.
|
|
84
|
+
const catalogKeys = Object.keys(catalog);
|
|
85
|
+
for (const dep of catalogKeys) {
|
|
86
|
+
if (referenced.has(dep)) {
|
|
72
87
|
continue;
|
|
73
88
|
}
|
|
74
89
|
problems.push({
|
|
75
|
-
file,
|
|
76
|
-
message: `
|
|
90
|
+
file: 'package.json',
|
|
91
|
+
message: `catalog entry "${dep}" is referenced by no workspace - drop it`,
|
|
77
92
|
});
|
|
78
93
|
}
|
|
94
|
+
return { problems, entries: catalogKeys.length, referenced: referenced.size, noCatalog: false };
|
|
79
95
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
for (const dep of catalogKeys) {
|
|
83
|
-
if (referenced.has(dep)) {
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
problems.push({
|
|
87
|
-
file: 'package.json',
|
|
88
|
-
message: `catalog entry "${dep}" is referenced by no workspace - drop it`,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
return { problems, entries: catalogKeys.length, referenced: referenced.size, noCatalog: false };
|
|
92
|
-
};
|
|
93
|
-
exports.findCatalogProblems = findCatalogProblems;
|
|
96
|
+
}
|
|
97
|
+
exports.CatalogCheck = CatalogCheck;
|
|
94
98
|
//# sourceMappingURL=catalog.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/checks/catalog.ts"],"names":[],"mappings":";;;AAAA,6BAA2B;AAC3B,qCAAqC;AACrC,yCAAiC;AA6CjC,yHAAyH;AACzH,MAAM,iBAAiB,GAAG,CAAC,cAAc,EAAE,iBAAiB,CAAU,CAAC;AAEvE,MAAM,YAAY,GAAG,yBAAyB,CAAC;AAS/C,kHAAkH;
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/checks/catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import { Glob } from 'bun';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/**\n * Guards dependency versions against the root `workspaces.catalog`.\n *\n * A catalogued dep is referenced as `catalog:` and resolved at publish time by `bun publish`, which\n * substitutes the real range while packing. `npm publish` does NOT - it ships `catalog:` verbatim\n * and the manifest is unresolvable for every consumer, which is how 0.1.1-9 / -6 / -4 broke.\n */\nexport interface ICatalogProblem {\n file: string;\n message: string;\n}\n\nexport interface ICatalogOptions {\n /** The repository root: where the root `package.json` and the globs resolve. Default: the current folder. */\n root?: string;\n\n /** Manifests to check, beside `packages/*\\/package.json`. A glob relative to the root. */\n globs?: string[];\n\n /**\n * Files that are not published manifests but carry `dependencies` and `devDependencies` the\n * release resolves (a VULCAN preset): `catalog:` is allowed in their `peerDependencies`, because a\n * library preset gives one name one catalog range. A file belongs here when its path starts with\n * this prefix, for example `presets/`.\n */\n presetPrefix?: string;\n\n /**\n * Manifests outside the workspace (a wiki with its own lockfile): `catalog:` does not resolve\n * there, so a catalogued dependency must be pinned to exactly the catalog's version instead.\n */\n pinned?: string[];\n}\n\nexport interface ICatalogReport {\n problems: ICatalogProblem[];\n entries: number;\n referenced: number;\n\n /** Set when there is no `workspaces.catalog` to check against. */\n noCatalog: boolean;\n}\n\n/** `peerDependencies` are compatibility statements for consumers and stay deliberately looser than the install range. */\nconst CATALOGUED_BLOCKS = ['dependencies', 'devDependencies'] as const;\n\nconst DEFAULT_GLOB = 'packages/*/package.json';\n\ninterface IManifest {\n workspaces?: { catalog?: Record<string, string> };\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\nexport class CatalogCheck {\n /** Reads the root catalog and every manifest the options name, and reports everything wrong with their ranges. */\n static async find(opts: ICatalogOptions = {}): Promise<ICatalogReport> {\n const { root = process.cwd(), globs = [], presetPrefix, pinned = [] } = opts;\n const result = await Bun.file(join(root, 'package.json')).text();\n const rootJson: IManifest = JSON.parse(result);\n const catalog: Record<string, string> = rootJson.workspaces?.catalog ?? {};\n\n if (Object.keys(catalog).length === 0) {\n return { problems: [], entries: 0, referenced: 0, noCatalog: true };\n }\n\n const problems: ICatalogProblem[] = [];\n const referenced = new Set<string>();\n const presentPinned = pinned.filter((file) => existsSync(join(root, file)));\n\n const files = new Set<string>();\n for (const pattern of [DEFAULT_GLOB, ...globs]) {\n for await (const file of new Glob(pattern).scan(root)) {\n files.add(file);\n }\n }\n\n for (const file of [...files, ...presentPinned]) {\n let json: IManifest;\n\n try {\n const result2 = await Bun.file(join(root, file)).text();\n json = JSON.parse(result2);\n } catch (error) {\n problems.push({\n file,\n message: `invalid JSON - ${error instanceof Error ? error.message : error}`,\n });\n continue;\n }\n\n const isPinned = presentPinned.includes(file);\n\n for (const block of CATALOGUED_BLOCKS) {\n const entriesList = Object.entries(json[block] ?? {});\n for (const [dep, range] of entriesList) {\n if (!(dep in catalog)) {\n continue;\n }\n\n referenced.add(dep);\n\n if (isPinned) {\n if (range !== catalog[dep]) {\n problems.push({\n file,\n message: `${block}.${dep} is \"${range}\" but the catalog pins \"${catalog[dep]}\" - this project is outside the workspace, so pin exactly that`,\n });\n }\n\n continue;\n }\n\n if (range === 'catalog:') {\n continue;\n }\n\n problems.push({\n file,\n message: `${block}.${dep} is \"${range}\" but the catalog owns it - use \"catalog:\" (catalog pins ${catalog[dep]})`,\n });\n }\n }\n\n // A preset is not a published manifest: its markers are resolved by the release, and the library kind gives a\n // name one catalog range, so a lib's peer takes the same marker as its dev dependency.\n const isPreset = presetPrefix !== undefined && file.startsWith(presetPrefix);\n\n // A peer resolved from the catalog would collapse to the exact install range, losing the looseness that makes it a peer.\n const peerEntries = Object.entries(json.peerDependencies ?? {});\n for (const [dep, range] of peerEntries) {\n if (range !== 'catalog:' || isPreset) {\n continue;\n }\n\n problems.push({\n file,\n message: `peerDependencies.${dep} uses \"catalog:\" - a peer range must stay hand-authored and looser than the install range`,\n });\n }\n }\n\n // A catalog entry nobody references is dead weight that will drift out of date unnoticed.\n const catalogKeys = Object.keys(catalog);\n for (const dep of catalogKeys) {\n if (referenced.has(dep)) {\n continue;\n }\n\n problems.push({\n file: 'package.json',\n message: `catalog entry \"${dep}\" is referenced by no workspace - drop it`,\n });\n }\n\n return { problems, entries: catalogKeys.length, referenced: referenced.size, noCatalog: false };\n }\n}\n"]}
|
|
@@ -10,13 +10,15 @@ export declare class ModuleGraph {
|
|
|
10
10
|
private static walk;
|
|
11
11
|
private static resolveRelative;
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
export declare class ModuleCyclesCheck {
|
|
14
|
+
/**
|
|
15
|
+
* `devz check module-cycles <dir> [--max <n>]`: prints the cycles of a built ESM directory and
|
|
16
|
+
* returns 1 when there are more than `max` (no bound by default), 2 on a usage error.
|
|
17
|
+
*/
|
|
18
|
+
static run(opts: {
|
|
19
|
+
args: string[];
|
|
20
|
+
print: (line: string) => void;
|
|
21
|
+
printError: (line: string) => void;
|
|
22
|
+
}): number;
|
|
23
|
+
}
|
|
22
24
|
//# sourceMappingURL=module-cycles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-cycles.d.ts","sourceRoot":"","sources":["../../src/checks/module-cycles.ts"],"names":[],"mappings":"AAaA,qBAAa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAFxB,OAAO;IAKP,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,WAAW;IAwBxD,uFAAuF;IACvF,MAAM,IAAI,MAAM,EAAE,EAAE;IAkDpB,OAAO,CAAC,MAAM,CAAC,IAAI;IAcnB,OAAO,CAAC,MAAM,CAAC,eAAe;CAa/B;AAED;;;
|
|
1
|
+
{"version":3,"file":"module-cycles.d.ts","sourceRoot":"","sources":["../../src/checks/module-cycles.ts"],"names":[],"mappings":"AAaA,qBAAa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAFxB,OAAO;IAKP,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,WAAW;IAwBxD,uFAAuF;IACvF,MAAM,IAAI,MAAM,EAAE,EAAE;IAkDpB,OAAO,CAAC,MAAM,CAAC,IAAI;IAcnB,OAAO,CAAC,MAAM,CAAC,eAAe;CAa/B;AAED,qBAAa,iBAAiB;IAC5B;;;OAGG;IACH,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE;QACf,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC9B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;KACpC,GAAG,MAAM;CA+BX"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.ModuleCyclesCheck = exports.ModuleGraph = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Lists import cycles in a built ESM directory. bun turns every member of a
|
|
6
6
|
* cycle into a lazy initializer, and a barrel `export *` over such a member
|
|
@@ -113,37 +113,39 @@ class ModuleGraph {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
exports.ModuleGraph = ModuleGraph;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return 2;
|
|
132
|
-
}
|
|
133
|
-
let max = Number.POSITIVE_INFINITY;
|
|
134
|
-
if (values.max !== undefined) {
|
|
135
|
-
if (!/^\d+$/.test(values.max)) {
|
|
116
|
+
class ModuleCyclesCheck {
|
|
117
|
+
/**
|
|
118
|
+
* `devz check module-cycles <dir> [--max <n>]`: prints the cycles of a built ESM directory and
|
|
119
|
+
* returns 1 when there are more than `max` (no bound by default), 2 on a usage error.
|
|
120
|
+
*/
|
|
121
|
+
static run(opts) {
|
|
122
|
+
const { args, print, printError } = opts;
|
|
123
|
+
const { positionals, values } = (0, node_util_1.parseArgs)({
|
|
124
|
+
args,
|
|
125
|
+
allowPositionals: true,
|
|
126
|
+
options: { max: { type: 'string' }, dist: { type: 'string' } },
|
|
127
|
+
});
|
|
128
|
+
const dir = values.dist ?? positionals[0];
|
|
129
|
+
const usage = 'usage: devz check module-cycles <built ESM dir> [--max <n>]';
|
|
130
|
+
if (!dir) {
|
|
136
131
|
printError(usage);
|
|
137
132
|
return 2;
|
|
138
133
|
}
|
|
139
|
-
max = Number
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
134
|
+
let max = Number.POSITIVE_INFINITY;
|
|
135
|
+
if (values.max !== undefined) {
|
|
136
|
+
if (!/^\d+$/.test(values.max)) {
|
|
137
|
+
printError(usage);
|
|
138
|
+
return 2;
|
|
139
|
+
}
|
|
140
|
+
max = Number(values.max);
|
|
141
|
+
}
|
|
142
|
+
const cycles = ModuleGraph.fromDirectory({ dir }).cycles();
|
|
143
|
+
print(`${dir}: ${cycles.length} cycle(s)`);
|
|
144
|
+
for (const cycle of cycles) {
|
|
145
|
+
print(` - ${cycle.join(' <-> ')}`);
|
|
146
|
+
}
|
|
147
|
+
return cycles.length > max ? 1 : 0;
|
|
145
148
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
exports.runModuleCycles = runModuleCycles;
|
|
149
|
+
}
|
|
150
|
+
exports.ModuleCyclesCheck = ModuleCyclesCheck;
|
|
149
151
|
//# sourceMappingURL=module-cycles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-cycles.js","sourceRoot":"","sources":["../../src/checks/module-cycles.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Lists import cycles in a built ESM directory. bun turns every member of a\n * cycle into a lazy initializer, and a barrel `export *` over such a member\n * can leave its exports undefined. Usage: devz check module-cycles packages/helpers/dist/esm [--max 0]\n */\nimport { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, join, relative, resolve } from 'node:path';\nimport { parseArgs } from 'node:util';\n\n// Only match import/export statements at the start of a line (after optional\n// whitespace), ignoring matches inside comments or string literals.\nconst IMPORT_PATTERN = /^\\s*(?:import|export)\\s[^;]*?from\\s+'([^']+)'|^\\s*import\\s+'([^']+)'/gm;\n\nexport class ModuleGraph {\n private constructor(\n private readonly root: string,\n private readonly edges: Map<string, string[]>,\n ) {}\n\n static fromDirectory(opts: { dir: string }): ModuleGraph {\n const root = resolve(opts.dir);\n const files = ModuleGraph.walk({ dir: root });\n const edges = new Map<string, string[]>();\n\n for (const file of files) {\n const text = readFileSync(file, 'utf8');\n const targets = new Set<string>();\n const matches = text.matchAll(IMPORT_PATTERN);\n for (const match of matches) {\n const target = ModuleGraph.resolveRelative({\n from: file,\n specifier: match[1] ?? match[2],\n });\n if (target) {\n targets.add(target);\n }\n }\n edges.set(file, [...targets]);\n }\n\n return new ModuleGraph(root, edges);\n }\n\n /** Strongly connected components with more than one member, as repo-relative paths. */\n cycles(): string[][] {\n let index = 0;\n const stack: string[] = [];\n const onStack = new Set<string>();\n const indices = new Map<string, number>();\n const lowLinks = new Map<string, number>();\n const found: string[][] = [];\n\n const visit = (node: string): void => {\n indices.set(node, index);\n lowLinks.set(node, index);\n index++;\n stack.push(node);\n onStack.add(node);\n\n const nexts = this.edges.get(node) ?? [];\n for (const next of nexts) {\n if (!indices.has(next)) {\n visit(next);\n lowLinks.set(node, Math.min(lowLinks.get(node)!, lowLinks.get(next)!));\n } else if (onStack.has(next)) {\n lowLinks.set(node, Math.min(lowLinks.get(node)!, indices.get(next)!));\n }\n }\n\n if (lowLinks.get(node) !== indices.get(node)) {\n return;\n }\n const component: string[] = [];\n let member: string;\n do {\n member = stack.pop()!;\n onStack.delete(member);\n component.push(relative(this.root, member));\n } while (member !== node);\n if (component.length > 1) {\n found.push(component.sort());\n }\n };\n\n const edgesKeys = this.edges.keys();\n for (const node of edgesKeys) {\n if (!indices.has(node)) {\n visit(node);\n }\n }\n\n return found;\n }\n\n private static walk(opts: { dir: string }): string[] {\n const out: string[] = [];\n const dirEntries = readdirSync(opts.dir);\n for (const name of dirEntries) {\n const full = join(opts.dir, name);\n if (statSync(full).isDirectory()) {\n out.push(...ModuleGraph.walk({ dir: full }));\n } else if (full.endsWith('.js')) {\n out.push(full);\n }\n }\n return out;\n }\n\n private static resolveRelative(opts: { from: string; specifier: string }): string | undefined {\n if (!opts.specifier.startsWith('.')) {\n return undefined;\n }\n const base = resolve(dirname(opts.from), opts.specifier);\n const candidates = [base, `${base}.js`, join(base, 'index.js')];\n for (const candidate of candidates) {\n if (existsSync(candidate) && statSync(candidate).isFile()) {\n return candidate;\n }\n }\n return undefined;\n }\n}\n\n/**\n * `devz check module-cycles <dir> [--max <n>]`: prints the cycles of a built ESM directory and\n * returns 1 when there are more than `max` (no bound by default), 2 on a usage error.\n */\nexport const runModuleCycles = (opts: {\n args: string[];\n print: (line: string) => void;\n printError: (line: string) => void;\n}): number => {\n const { args, print, printError } = opts;\n const { positionals, values } = parseArgs({\n args,\n allowPositionals: true,\n options: { max: { type: 'string' }, dist: { type: 'string' } },\n });\n const dir = values.dist ?? positionals[0];\n const usage = 'usage: devz check module-cycles <built ESM dir> [--max <n>]';\n if (!dir) {\n printError(usage);\n return 2;\n }\n\n let max = Number.POSITIVE_INFINITY;\n if (values.max !== undefined) {\n if (!/^\\d+$/.test(values.max)) {\n printError(usage);\n return 2;\n }\n max = Number(values.max);\n }\n\n const cycles = ModuleGraph.fromDirectory({ dir }).cycles();\n print(`${dir}: ${cycles.length} cycle(s)`);\n for (const cycle of cycles) {\n print(` - ${cycle.join(' <-> ')}`);\n }\n\n return cycles.length > max ? 1 : 0;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"module-cycles.js","sourceRoot":"","sources":["../../src/checks/module-cycles.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Lists import cycles in a built ESM directory. bun turns every member of a\n * cycle into a lazy initializer, and a barrel `export *` over such a member\n * can leave its exports undefined. Usage: devz check module-cycles packages/helpers/dist/esm [--max 0]\n */\nimport { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { dirname, join, relative, resolve } from 'node:path';\nimport { parseArgs } from 'node:util';\n\n// Only match import/export statements at the start of a line (after optional\n// whitespace), ignoring matches inside comments or string literals.\nconst IMPORT_PATTERN = /^\\s*(?:import|export)\\s[^;]*?from\\s+'([^']+)'|^\\s*import\\s+'([^']+)'/gm;\n\nexport class ModuleGraph {\n private constructor(\n private readonly root: string,\n private readonly edges: Map<string, string[]>,\n ) {}\n\n static fromDirectory(opts: { dir: string }): ModuleGraph {\n const root = resolve(opts.dir);\n const files = ModuleGraph.walk({ dir: root });\n const edges = new Map<string, string[]>();\n\n for (const file of files) {\n const text = readFileSync(file, 'utf8');\n const targets = new Set<string>();\n const matches = text.matchAll(IMPORT_PATTERN);\n for (const match of matches) {\n const target = ModuleGraph.resolveRelative({\n from: file,\n specifier: match[1] ?? match[2],\n });\n if (target) {\n targets.add(target);\n }\n }\n edges.set(file, [...targets]);\n }\n\n return new ModuleGraph(root, edges);\n }\n\n /** Strongly connected components with more than one member, as repo-relative paths. */\n cycles(): string[][] {\n let index = 0;\n const stack: string[] = [];\n const onStack = new Set<string>();\n const indices = new Map<string, number>();\n const lowLinks = new Map<string, number>();\n const found: string[][] = [];\n\n const visit = (node: string): void => {\n indices.set(node, index);\n lowLinks.set(node, index);\n index++;\n stack.push(node);\n onStack.add(node);\n\n const nexts = this.edges.get(node) ?? [];\n for (const next of nexts) {\n if (!indices.has(next)) {\n visit(next);\n lowLinks.set(node, Math.min(lowLinks.get(node)!, lowLinks.get(next)!));\n } else if (onStack.has(next)) {\n lowLinks.set(node, Math.min(lowLinks.get(node)!, indices.get(next)!));\n }\n }\n\n if (lowLinks.get(node) !== indices.get(node)) {\n return;\n }\n const component: string[] = [];\n let member: string;\n do {\n member = stack.pop()!;\n onStack.delete(member);\n component.push(relative(this.root, member));\n } while (member !== node);\n if (component.length > 1) {\n found.push(component.sort());\n }\n };\n\n const edgesKeys = this.edges.keys();\n for (const node of edgesKeys) {\n if (!indices.has(node)) {\n visit(node);\n }\n }\n\n return found;\n }\n\n private static walk(opts: { dir: string }): string[] {\n const out: string[] = [];\n const dirEntries = readdirSync(opts.dir);\n for (const name of dirEntries) {\n const full = join(opts.dir, name);\n if (statSync(full).isDirectory()) {\n out.push(...ModuleGraph.walk({ dir: full }));\n } else if (full.endsWith('.js')) {\n out.push(full);\n }\n }\n return out;\n }\n\n private static resolveRelative(opts: { from: string; specifier: string }): string | undefined {\n if (!opts.specifier.startsWith('.')) {\n return undefined;\n }\n const base = resolve(dirname(opts.from), opts.specifier);\n const candidates = [base, `${base}.js`, join(base, 'index.js')];\n for (const candidate of candidates) {\n if (existsSync(candidate) && statSync(candidate).isFile()) {\n return candidate;\n }\n }\n return undefined;\n }\n}\n\nexport class ModuleCyclesCheck {\n /**\n * `devz check module-cycles <dir> [--max <n>]`: prints the cycles of a built ESM directory and\n * returns 1 when there are more than `max` (no bound by default), 2 on a usage error.\n */\n static run(opts: {\n args: string[];\n print: (line: string) => void;\n printError: (line: string) => void;\n }): number {\n const { args, print, printError } = opts;\n const { positionals, values } = parseArgs({\n args,\n allowPositionals: true,\n options: { max: { type: 'string' }, dist: { type: 'string' } },\n });\n const dir = values.dist ?? positionals[0];\n const usage = 'usage: devz check module-cycles <built ESM dir> [--max <n>]';\n if (!dir) {\n printError(usage);\n return 2;\n }\n\n let max = Number.POSITIVE_INFINITY;\n if (values.max !== undefined) {\n if (!/^\\d+$/.test(values.max)) {\n printError(usage);\n return 2;\n }\n max = Number(values.max);\n }\n\n const cycles = ModuleGraph.fromDirectory({ dir }).cycles();\n print(`${dir}: ${cycles.length} cycle(s)`);\n for (const cycle of cycles) {\n print(` - ${cycle.join(' <-> ')}`);\n }\n\n return cycles.length > max ? 1 : 0;\n }\n}\n"]}
|
|
@@ -9,7 +9,7 @@ export interface IPurityEntry {
|
|
|
9
9
|
* field remap, which the downstream app's bundler (Vite, ...) honours and `bun build` does not.
|
|
10
10
|
* Never for the repository's own source: an external hides that file from the module graph
|
|
11
11
|
* entirely, so using it on our own code would let a real leak through unseen rather than prove
|
|
12
|
-
* anything pure. Enforced by {@link assertNoWorkspaceExternal}, not left to this comment alone.
|
|
12
|
+
* anything pure. Enforced by {@link PurityManifest.assertNoWorkspaceExternal}, not left to this comment alone.
|
|
13
13
|
*/
|
|
14
14
|
external?: string[];
|
|
15
15
|
/**
|
|
@@ -54,41 +54,47 @@ export interface IPurityOptions {
|
|
|
54
54
|
/** Package-name prefix of this repository's own packages; an `external` may never start with it. Default `@venizia/`. */
|
|
55
55
|
workspaceScope?: string;
|
|
56
56
|
}
|
|
57
|
-
/**
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
57
|
+
/** Derives the rows of the purity gate from the `exports` map of each claimed package, then runs the guards on them. */
|
|
58
|
+
export declare class PurityManifest {
|
|
59
|
+
/**
|
|
60
|
+
* A code-level guard, not just the JSDoc on `external`: it is an escape hatch from this gate, and a
|
|
61
|
+
* hatch with no lock is one bad edit away from hiding a real leak - `external: ['@venizia/ignis-helpers']`
|
|
62
|
+
* on a red entry would silently turn it green by removing the exact root-barrel import this gate
|
|
63
|
+
* exists to catch from the module graph, rather than proving it absent.
|
|
64
|
+
*
|
|
65
|
+
* A plain `Error`, not `getError`: the engine runs from the repository root through `devz`, outside
|
|
66
|
+
* every workspace package, and has no logger to resolve.
|
|
67
|
+
*/
|
|
68
|
+
static assertNoWorkspaceExternal(opts: {
|
|
69
|
+
manifest: IPurityEntry[];
|
|
70
|
+
workspaceScope?: string;
|
|
71
|
+
}): IPurityEntry[];
|
|
72
|
+
/**
|
|
73
|
+
* Public for the tests, which have to drive a claim that no longer matches its package's
|
|
74
|
+
* `exports` map - the staleness guard is the whole point of deriving, and it cannot be asserted
|
|
75
|
+
* through a built manifest, which by construction is never stale.
|
|
76
|
+
*/
|
|
77
|
+
static deriveEntries(opts: {
|
|
78
|
+
claim: IPurityClaim;
|
|
79
|
+
root: string;
|
|
80
|
+
}): IPurityEntry[];
|
|
81
|
+
/**
|
|
82
|
+
* A browser claim is only honest if a browser bundler can actually consume the entry. A CommonJS
|
|
83
|
+
* entry forces every consumer into a workaround, so the claim carries the obligation: every claimed
|
|
84
|
+
* sub-path must publish its runtime entries below `esmEntryPrefix`. Checked here rather than trusted
|
|
85
|
+
* to a comment, for the same reason as {@link PurityManifest.assertNoWorkspaceExternal} - the failure is otherwise
|
|
86
|
+
* invisible until someone tries to bundle the package downstream.
|
|
87
|
+
*/
|
|
88
|
+
static assertBrowserEsmEntry(opts: {
|
|
89
|
+
claims: IPurityClaim[];
|
|
90
|
+
root: string;
|
|
91
|
+
esmEntryPrefix: string;
|
|
92
|
+
}): IPurityClaim[];
|
|
93
|
+
/** The rows of a whole repository: every claim derived from its package's `exports`, then the guards. */
|
|
94
|
+
static build(opts: {
|
|
95
|
+
claims: IPurityClaim[];
|
|
96
|
+
root: string;
|
|
97
|
+
options?: IPurityOptions;
|
|
98
|
+
}): IPurityEntry[];
|
|
99
|
+
}
|
|
94
100
|
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/checks/purity/manifest.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,sGAAsG;IACtG,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACnC;AAED,6FAA6F;AAC7F,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,yHAAyH;IACzH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/checks/purity/manifest.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,sGAAsG;IACtG,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACnC;AAED,6FAA6F;AAC7F,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,yHAAyH;IACzH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AA2ED,wHAAwH;AACxH,qBAAa,cAAc;IACzB;;;;;;;;OAQG;IACH,MAAM,CAAC,yBAAyB,CAAC,IAAI,EAAE;QACrC,QAAQ,EAAE,YAAY,EAAE,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GAAG,YAAY,EAAE;IAqBlB;;;;OAIG;IACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,YAAY,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,YAAY,EAAE;IAgFjF;;;;;;OAMG;IACH,MAAM,CAAC,qBAAqB,CAAC,IAAI,EAAE;QACjC,MAAM,EAAE,YAAY,EAAE,CAAC;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,EAAE,MAAM,CAAC;KACxB,GAAG,YAAY,EAAE;IAoClB,yGAAyG;IACzG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE;QACjB,MAAM,EAAE,YAAY,EAAE,CAAC;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,cAAc,CAAC;KAC1B,GAAG,YAAY,EAAE;CAcnB"}
|