@venizia/dev-configs 0.4.2 → 0.4.4
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 +2 -5
- package/README.md +20 -5
- package/dist/checks/catalog.d.ts +39 -0
- package/dist/checks/catalog.d.ts.map +1 -0
- package/dist/checks/catalog.js +94 -0
- package/dist/checks/catalog.js.map +1 -0
- package/dist/checks/index.d.ts +11 -0
- package/dist/checks/index.d.ts.map +1 -0
- package/dist/checks/index.js +27 -0
- package/dist/checks/index.js.map +1 -0
- package/dist/checks/module-cycles.d.ts +22 -0
- package/dist/checks/module-cycles.d.ts.map +1 -0
- package/dist/checks/module-cycles.js +149 -0
- package/dist/checks/module-cycles.js.map +1 -0
- package/dist/checks/purity/manifest.d.ts +94 -0
- package/dist/checks/purity/manifest.d.ts.map +1 -0
- package/dist/checks/purity/manifest.js +177 -0
- package/dist/checks/purity/manifest.js.map +1 -0
- package/dist/checks/purity/probe.d.ts +68 -0
- package/dist/checks/purity/probe.d.ts.map +1 -0
- package/dist/checks/purity/probe.js +295 -0
- package/dist/checks/purity/probe.js.map +1 -0
- package/dist/checks/purity/run.d.ts +47 -0
- package/dist/checks/purity/run.d.ts.map +1 -0
- package/dist/checks/purity/run.js +121 -0
- package/dist/checks/purity/run.js.map +1 -0
- package/dist/checks/split-report.d.ts +19 -0
- package/dist/checks/split-report.d.ts.map +1 -0
- package/dist/checks/split-report.js +123 -0
- package/dist/checks/split-report.js.map +1 -0
- package/dist/cli/check.d.ts +10 -0
- package/dist/cli/check.d.ts.map +1 -0
- package/dist/cli/check.js +206 -0
- package/dist/cli/check.js.map +1 -0
- package/dist/cli/clean.d.ts +2 -1
- package/dist/cli/clean.d.ts.map +1 -1
- package/dist/cli/clean.js +18 -1
- package/dist/cli/clean.js.map +1 -1
- package/dist/cli/codemod/const-classes.d.ts +80 -0
- package/dist/cli/codemod/const-classes.d.ts.map +1 -0
- package/dist/cli/codemod/const-classes.js +603 -0
- package/dist/cli/codemod/const-classes.js.map +1 -0
- package/dist/cli/codemod/drop-redundant-casts.d.ts +112 -0
- package/dist/cli/codemod/drop-redundant-casts.d.ts.map +1 -0
- package/dist/cli/codemod/drop-redundant-casts.js +780 -0
- package/dist/cli/codemod/drop-redundant-casts.js.map +1 -0
- package/dist/cli/codemod/files.d.ts +22 -0
- package/dist/cli/codemod/files.d.ts.map +1 -0
- package/dist/cli/codemod/files.js +68 -0
- package/dist/cli/codemod/files.js.map +1 -0
- package/dist/cli/codemod/index.d.ts +5 -4
- package/dist/cli/codemod/index.d.ts.map +1 -1
- package/dist/cli/codemod/index.js +77 -36
- package/dist/cli/codemod/index.js.map +1 -1
- package/dist/cli/codemod/model-settings.d.ts +2 -1
- package/dist/cli/codemod/model-settings.d.ts.map +1 -1
- package/dist/cli/codemod/model-settings.js +77 -3
- package/dist/cli/codemod/model-settings.js.map +1 -1
- package/dist/cli/index.js +21 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/linters/house/common.d.ts +1 -0
- package/dist/linters/house/common.d.ts.map +1 -1
- package/dist/linters/house/common.js +1 -0
- package/dist/linters/house/common.js.map +1 -1
- package/dist/linters/house/configs.d.ts.map +1 -1
- package/dist/linters/house/configs.js +20 -1
- package/dist/linters/house/configs.js.map +1 -1
- package/dist/linters/house/const-class-values.rule.d.ts +7 -4
- package/dist/linters/house/const-class-values.rule.d.ts.map +1 -1
- package/dist/linters/house/const-class-values.rule.js +73 -21
- package/dist/linters/house/const-class-values.rule.js.map +1 -1
- package/dist/linters/rules/common.d.ts +48 -1
- package/dist/linters/rules/common.d.ts.map +1 -1
- package/dist/linters/rules/common.js +53 -0
- package/dist/linters/rules/common.js.map +1 -1
- package/dist/linters/rules/eqeqeq.rule.d.ts +2 -2
- package/dist/linters/rules/eqeqeq.rule.d.ts.map +1 -1
- package/dist/linters/rules/eqeqeq.rule.js +2 -1
- package/dist/linters/rules/eqeqeq.rule.js.map +1 -1
- package/dist/linters/rules/no-unused-vars.rule.d.ts +3 -3
- package/dist/linters/rules/no-unused-vars.rule.d.ts.map +1 -1
- package/dist/linters/rules/no-unused-vars.rule.js +2 -1
- package/dist/linters/rules/no-unused-vars.rule.js.map +1 -1
- package/dist/linters/rules/switch-case-braces.rule.d.ts +2 -2
- package/dist/linters/rules/switch-case-braces.rule.d.ts.map +1 -1
- package/dist/linters/rules/switch-case-braces.rule.js +2 -1
- package/dist/linters/rules/switch-case-braces.rule.js.map +1 -1
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/repo-tmp.d.ts +12 -0
- package/dist/testing/repo-tmp.d.ts.map +1 -0
- package/dist/testing/repo-tmp.js +67 -0
- package/dist/testing/repo-tmp.js.map +1 -0
- package/dist/testing/spawn.helper.d.ts +13 -0
- package/dist/testing/spawn.helper.d.ts.map +1 -0
- package/dist/testing/spawn.helper.js +22 -0
- package/dist/testing/spawn.helper.js.map +1 -0
- package/dist/testing/tmpdir-preload.d.ts +2 -0
- package/dist/testing/tmpdir-preload.d.ts.map +1 -0
- package/dist/testing/tmpdir-preload.js +9 -0
- package/dist/testing/tmpdir-preload.js.map +1 -0
- package/package.json +9 -1
- package/src/tsconfig/tsconfig.base.json +5 -2
- package/src/tsconfig/tsconfig.common.json +2 -2
package/LICENSE.md
CHANGED
|
@@ -4,7 +4,7 @@ Ignis is a TypeScript Server Infrastructure framework built on [Hono](https://ho
|
|
|
4
4
|
|
|
5
5
|
## MIT License
|
|
6
6
|
|
|
7
|
-
Copyright (c) 2025
|
|
7
|
+
Copyright (c) 2025 Venizia Co., Ltd.
|
|
8
8
|
|
|
9
9
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
10
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -86,12 +86,9 @@ Ignis uses the following open-source libraries. We are grateful to the authors a
|
|
|
86
86
|
|
|
87
87
|
## Acknowledgments
|
|
88
88
|
|
|
89
|
-
Ignis Framework is
|
|
89
|
+
Ignis Framework is built on the work of open-source projects:
|
|
90
90
|
|
|
91
91
|
- **[Hono](https://hono.dev/)** by Yusuke Wada - The ultrafast web framework that powers Ignis
|
|
92
|
-
- **[LoopBack 4](https://loopback.io/)** by IBM/StrongLoop - Inspiration for the enterprise architecture patterns
|
|
93
|
-
- **[NestJS](https://nestjs.com/)** by Kamil Mysliwiec - Inspiration for decorator-based controllers
|
|
94
|
-
- **[InversifyJS](https://inversify.io/)** - Inspiration for the IoC container design
|
|
95
92
|
|
|
96
93
|
We thank all the maintainers and contributors of these projects for their excellent work.
|
|
97
94
|
|
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ The two options in `compilerOptions` repeat the base on purpose - see
|
|
|
61
61
|
|
|
62
62
|
### Browser and React projects
|
|
63
63
|
|
|
64
|
-
The presets above target a Bun
|
|
64
|
+
The presets above target a Bun backend. Code that runs in a browser swaps each one for its
|
|
65
65
|
browser version. A React project swaps it for the React version, which builds on the browser one.
|
|
66
66
|
|
|
67
67
|
| Tool | Backend | Browser | React |
|
|
@@ -169,15 +169,17 @@ booleans. `BrowserOxlintConfigs.create()` and `ReactOxlintConfigs.create()` take
|
|
|
169
169
|
| `MaxParamsOwnRule` | `venizia/max-params-own` | `build({ max: 5 })` | A function we write takes at most `max` positional parameters. Not counted: an inline callback passed to a call or a JSX prop, a signature a declared type fixes, a constructor whose parameters are all `@inject`. A hook callback counts. |
|
|
170
170
|
| `NoNewErrorRule` | `venizia/no-new-error` | `error` | Throw through `getError` (or an `ApplicationError`), never `new Error(...)` / `Error(...)`. Off in tests. |
|
|
171
171
|
| `NoLeakedRenderRule` | `venizia/no-leaked-render` | `error`, in `reactHouseConfigs` only | A JSX child is drawn with `cond ? <X /> : null`, never `cond && <X />`, which draws `0` when `cond` is `0`. `--fix` rewrites it. `disabled={a && b}` is a value, not a child, and passes. |
|
|
172
|
-
| `ConstClassValuesRule` | `venizia/const-class-values` |
|
|
172
|
+
| `ConstClassValuesRule` | `venizia/const-class-values` | `warn` in both presets; `build({ severity, namePattern })` | V-C-08. A union of string literals in an exported declaration (a type alias, an interface member, a generic constraint, a parameter or return type) is a const class plus `TConstValue<typeof X>`. Not counted: `Pick`, `Omit`, `Extract`, `Exclude`, `Record` arguments and mapped-type keys, and a union with a non-string member. `namePattern` narrows it to exported type aliases whose name matches. Off in tests. |
|
|
173
|
+
| `@typescript-eslint/consistent-type-assertions` | `assertionStyle: never` | `warn` in both presets | V-C-10. `as X`, `as any` and `as unknown as X` warn; `as const` and `satisfies` do not. Off in tests. |
|
|
173
174
|
|
|
174
|
-
`const-class-values`
|
|
175
|
-
|
|
175
|
+
`const-class-values` and the cast rule only warn, so adopting them never fails a lint. Raise one to an error
|
|
176
|
+
with `[ConstClassValuesRule.NAME]: ConstClassValuesRule.build({ severity: 'error' })`. The 5-parameter
|
|
177
|
+
limit (V-C-02) is `venizia/max-params-own`, an error.
|
|
176
178
|
|
|
177
179
|
### namingConventionConfigs
|
|
178
180
|
|
|
179
181
|
`namingConventionConfigs` (type `Linter.Config[]`) sets only `@typescript-eslint/naming-convention`, with
|
|
180
|
-
|
|
182
|
+
its 15 selectors. It targets `.ts`, `.tsx`, `.mts` and `.cts`, and ignores `dist`, `build`,
|
|
181
183
|
`coverage`, `*.d.ts` and plain JavaScript. ESLint does not report unused disable comments in this
|
|
182
184
|
config, because oxlint owns the other rules.
|
|
183
185
|
|
|
@@ -410,3 +412,16 @@ The root of the chain, with no IGNIS dependency: **dev-configs** -> inversion ->
|
|
|
410
412
|
- [Source](https://github.com/VENIZIA-AI/ignis/blob/main/packages/dev-configs)
|
|
411
413
|
|
|
412
414
|
MIT licensed - see [LICENSE.md](./LICENSE.md).
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
<p align="center">
|
|
419
|
+
<a href="https://venizia.ai">
|
|
420
|
+
<picture>
|
|
421
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://venizia.ai/assets/logo-white.svg">
|
|
422
|
+
<img src="https://venizia.ai/assets/logo.svg" alt="VENIZIA" height="28">
|
|
423
|
+
</picture>
|
|
424
|
+
</a>
|
|
425
|
+
<br>
|
|
426
|
+
<sub>@venizia/dev-configs is part of IGNIS, built and maintained by <a href="https://venizia.ai">VENIZIA</a>.</sub>
|
|
427
|
+
</p>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guards dependency versions against the root `workspaces.catalog`.
|
|
3
|
+
*
|
|
4
|
+
* A catalogued dep is referenced as `catalog:` and resolved at publish time by `bun publish`, which
|
|
5
|
+
* substitutes the real range while packing. `npm publish` does NOT - it ships `catalog:` verbatim
|
|
6
|
+
* and the manifest is unresolvable for every consumer, which is how 0.1.1-9 / -6 / -4 broke.
|
|
7
|
+
*/
|
|
8
|
+
export interface ICatalogProblem {
|
|
9
|
+
file: string;
|
|
10
|
+
message: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ICatalogOptions {
|
|
13
|
+
/** The repository root: where the root `package.json` and the globs resolve. Default: the current folder. */
|
|
14
|
+
root?: string;
|
|
15
|
+
/** Manifests to check, beside `packages/*\/package.json`. A glob relative to the root. */
|
|
16
|
+
globs?: string[];
|
|
17
|
+
/**
|
|
18
|
+
* Files that are not published manifests but carry `dependencies` and `devDependencies` the
|
|
19
|
+
* release resolves (a VULCAN preset): `catalog:` is allowed in their `peerDependencies`, because a
|
|
20
|
+
* library preset gives one name one catalog range. A file belongs here when its path starts with
|
|
21
|
+
* this prefix, for example `presets/`.
|
|
22
|
+
*/
|
|
23
|
+
presetPrefix?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Manifests outside the workspace (a wiki with its own lockfile): `catalog:` does not resolve
|
|
26
|
+
* there, so a catalogued dependency must be pinned to exactly the catalog's version instead.
|
|
27
|
+
*/
|
|
28
|
+
pinned?: string[];
|
|
29
|
+
}
|
|
30
|
+
export interface ICatalogReport {
|
|
31
|
+
problems: ICatalogProblem[];
|
|
32
|
+
entries: number;
|
|
33
|
+
referenced: number;
|
|
34
|
+
/** Set when there is no `workspaces.catalog` to check against. */
|
|
35
|
+
noCatalog: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** Reads the root catalog and every manifest the options name, and reports everything wrong with their ranges. */
|
|
38
|
+
export declare const findCatalogProblems: (opts?: ICatalogOptions) => Promise<ICatalogReport>;
|
|
39
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +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;AAClH,eAAO,MAAM,mBAAmB,GAAU,OAAM,eAAoB,KAAG,OAAO,CAAC,cAAc,CAkG5F,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findCatalogProblems = void 0;
|
|
4
|
+
const bun_1 = require("bun");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
/** `peerDependencies` are compatibility statements for consumers and stay deliberately looser than the install range. */
|
|
8
|
+
const CATALOGUED_BLOCKS = ['dependencies', 'devDependencies'];
|
|
9
|
+
const DEFAULT_GLOB = 'packages/*/package.json';
|
|
10
|
+
/** Reads the root catalog and every manifest the options name, and reports everything wrong with their ranges. */
|
|
11
|
+
const findCatalogProblems = async (opts = {}) => {
|
|
12
|
+
const { root = process.cwd(), globs = [], presetPrefix, pinned = [] } = opts;
|
|
13
|
+
const rootJson = JSON.parse(await Bun.file((0, node_path_1.join)(root, 'package.json')).text());
|
|
14
|
+
const catalog = rootJson.workspaces?.catalog ?? {};
|
|
15
|
+
if (Object.keys(catalog).length === 0) {
|
|
16
|
+
return { problems: [], entries: 0, referenced: 0, noCatalog: true };
|
|
17
|
+
}
|
|
18
|
+
const problems = [];
|
|
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());
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
problems.push({
|
|
34
|
+
file,
|
|
35
|
+
message: `invalid JSON - ${error instanceof Error ? error.message : error}`,
|
|
36
|
+
});
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const isPinned = presentPinned.includes(file);
|
|
40
|
+
for (const block of CATALOGUED_BLOCKS) {
|
|
41
|
+
const entriesList = Object.entries(json[block] ?? {});
|
|
42
|
+
for (const [dep, range] of entriesList) {
|
|
43
|
+
if (!(dep in catalog)) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
referenced.add(dep);
|
|
47
|
+
if (isPinned) {
|
|
48
|
+
if (range !== catalog[dep]) {
|
|
49
|
+
problems.push({
|
|
50
|
+
file,
|
|
51
|
+
message: `${block}.${dep} is "${range}" but the catalog pins "${catalog[dep]}" - this project is outside the workspace, so pin exactly that`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (range === 'catalog:') {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
problems.push({
|
|
60
|
+
file,
|
|
61
|
+
message: `${block}.${dep} is "${range}" but the catalog owns it - use "catalog:" (catalog pins ${catalog[dep]})`,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// A preset is not a published manifest: its markers are resolved by the release, and the library kind gives a
|
|
66
|
+
// name one catalog range, so a lib's peer takes the same marker as its dev dependency.
|
|
67
|
+
const isPreset = presetPrefix !== undefined && file.startsWith(presetPrefix);
|
|
68
|
+
// A peer resolved from the catalog would collapse to the exact install range, losing the looseness that makes it a peer.
|
|
69
|
+
const peerEntries = Object.entries(json.peerDependencies ?? {});
|
|
70
|
+
for (const [dep, range] of peerEntries) {
|
|
71
|
+
if (range !== 'catalog:' || isPreset) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
problems.push({
|
|
75
|
+
file,
|
|
76
|
+
message: `peerDependencies.${dep} uses "catalog:" - a peer range must stay hand-authored and looser than the install range`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// A catalog entry nobody references is dead weight that will drift out of date unnoticed.
|
|
81
|
+
const catalogKeys = Object.keys(catalog);
|
|
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;
|
|
94
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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\n/** Reads the root catalog and every manifest the options name, and reports everything wrong with their ranges. */\nexport const findCatalogProblems = async (opts: ICatalogOptions = {}): Promise<ICatalogReport> => {\n const { root = process.cwd(), globs = [], presetPrefix, pinned = [] } = opts;\n const rootJson: IManifest = JSON.parse(await Bun.file(join(root, 'package.json')).text());\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 json = JSON.parse(await Bun.file(join(root, file)).text());\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"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@venizia/dev-configs/checks`: the engines behind `devz check <name>`. Bun-only tooling - never
|
|
3
|
+
* import it from code a browser runs; the purity gate asserts that no browser-claimed entry reaches it.
|
|
4
|
+
*/
|
|
5
|
+
export * from './catalog';
|
|
6
|
+
export * from './module-cycles';
|
|
7
|
+
export * from './purity/manifest';
|
|
8
|
+
export * from './purity/probe';
|
|
9
|
+
export * from './purity/run';
|
|
10
|
+
export * from './split-report';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* `@venizia/dev-configs/checks`: the engines behind `devz check <name>`. Bun-only tooling - never
|
|
19
|
+
* import it from code a browser runs; the purity gate asserts that no browser-claimed entry reaches it.
|
|
20
|
+
*/
|
|
21
|
+
__exportStar(require("./catalog"), exports);
|
|
22
|
+
__exportStar(require("./module-cycles"), exports);
|
|
23
|
+
__exportStar(require("./purity/manifest"), exports);
|
|
24
|
+
__exportStar(require("./purity/probe"), exports);
|
|
25
|
+
__exportStar(require("./purity/run"), exports);
|
|
26
|
+
__exportStar(require("./split-report"), exports);
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/checks/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;GAGG;AACH,4CAA0B;AAC1B,kDAAgC;AAChC,oDAAkC;AAClC,iDAA+B;AAC/B,+CAA6B;AAC7B,iDAA+B","sourcesContent":["/**\n * `@venizia/dev-configs/checks`: the engines behind `devz check <name>`. Bun-only tooling - never\n * import it from code a browser runs; the purity gate asserts that no browser-claimed entry reaches it.\n */\nexport * from './catalog';\nexport * from './module-cycles';\nexport * from './purity/manifest';\nexport * from './purity/probe';\nexport * from './purity/run';\nexport * from './split-report';\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare class ModuleGraph {
|
|
2
|
+
private readonly root;
|
|
3
|
+
private readonly edges;
|
|
4
|
+
private constructor();
|
|
5
|
+
static fromDirectory(opts: {
|
|
6
|
+
dir: string;
|
|
7
|
+
}): ModuleGraph;
|
|
8
|
+
/** Strongly connected components with more than one member, as repo-relative paths. */
|
|
9
|
+
cycles(): string[][];
|
|
10
|
+
private static walk;
|
|
11
|
+
private static resolveRelative;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* `devz check module-cycles <dir> [--max <n>]`: prints the cycles of a built ESM directory and
|
|
15
|
+
* returns 1 when there are more than `max` (no bound by default), 2 on a usage error.
|
|
16
|
+
*/
|
|
17
|
+
export declare const runModuleCycles: (opts: {
|
|
18
|
+
args: string[];
|
|
19
|
+
print: (line: string) => void;
|
|
20
|
+
printError: (line: string) => void;
|
|
21
|
+
}) => number;
|
|
22
|
+
//# sourceMappingURL=module-cycles.d.ts.map
|
|
@@ -0,0 +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;;;GAGG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM;IACpC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,KAAG,MA8BH,CAAC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runModuleCycles = exports.ModuleGraph = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Lists import cycles in a built ESM directory. bun turns every member of a
|
|
6
|
+
* cycle into a lazy initializer, and a barrel `export *` over such a member
|
|
7
|
+
* can leave its exports undefined. Usage: devz check module-cycles packages/helpers/dist/esm [--max 0]
|
|
8
|
+
*/
|
|
9
|
+
const node_fs_1 = require("node:fs");
|
|
10
|
+
const node_path_1 = require("node:path");
|
|
11
|
+
const node_util_1 = require("node:util");
|
|
12
|
+
// Only match import/export statements at the start of a line (after optional
|
|
13
|
+
// whitespace), ignoring matches inside comments or string literals.
|
|
14
|
+
const IMPORT_PATTERN = /^\s*(?:import|export)\s[^;]*?from\s+'([^']+)'|^\s*import\s+'([^']+)'/gm;
|
|
15
|
+
class ModuleGraph {
|
|
16
|
+
constructor(root, edges) {
|
|
17
|
+
this.root = root;
|
|
18
|
+
this.edges = edges;
|
|
19
|
+
}
|
|
20
|
+
static fromDirectory(opts) {
|
|
21
|
+
const root = (0, node_path_1.resolve)(opts.dir);
|
|
22
|
+
const files = ModuleGraph.walk({ dir: root });
|
|
23
|
+
const edges = new Map();
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
const text = (0, node_fs_1.readFileSync)(file, 'utf8');
|
|
26
|
+
const targets = new Set();
|
|
27
|
+
const matches = text.matchAll(IMPORT_PATTERN);
|
|
28
|
+
for (const match of matches) {
|
|
29
|
+
const target = ModuleGraph.resolveRelative({
|
|
30
|
+
from: file,
|
|
31
|
+
specifier: match[1] ?? match[2],
|
|
32
|
+
});
|
|
33
|
+
if (target) {
|
|
34
|
+
targets.add(target);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
edges.set(file, [...targets]);
|
|
38
|
+
}
|
|
39
|
+
return new ModuleGraph(root, edges);
|
|
40
|
+
}
|
|
41
|
+
/** Strongly connected components with more than one member, as repo-relative paths. */
|
|
42
|
+
cycles() {
|
|
43
|
+
let index = 0;
|
|
44
|
+
const stack = [];
|
|
45
|
+
const onStack = new Set();
|
|
46
|
+
const indices = new Map();
|
|
47
|
+
const lowLinks = new Map();
|
|
48
|
+
const found = [];
|
|
49
|
+
const visit = (node) => {
|
|
50
|
+
indices.set(node, index);
|
|
51
|
+
lowLinks.set(node, index);
|
|
52
|
+
index++;
|
|
53
|
+
stack.push(node);
|
|
54
|
+
onStack.add(node);
|
|
55
|
+
const nexts = this.edges.get(node) ?? [];
|
|
56
|
+
for (const next of nexts) {
|
|
57
|
+
if (!indices.has(next)) {
|
|
58
|
+
visit(next);
|
|
59
|
+
lowLinks.set(node, Math.min(lowLinks.get(node), lowLinks.get(next)));
|
|
60
|
+
}
|
|
61
|
+
else if (onStack.has(next)) {
|
|
62
|
+
lowLinks.set(node, Math.min(lowLinks.get(node), indices.get(next)));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (lowLinks.get(node) !== indices.get(node)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const component = [];
|
|
69
|
+
let member;
|
|
70
|
+
do {
|
|
71
|
+
member = stack.pop();
|
|
72
|
+
onStack.delete(member);
|
|
73
|
+
component.push((0, node_path_1.relative)(this.root, member));
|
|
74
|
+
} while (member !== node);
|
|
75
|
+
if (component.length > 1) {
|
|
76
|
+
found.push(component.sort());
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const edgesKeys = this.edges.keys();
|
|
80
|
+
for (const node of edgesKeys) {
|
|
81
|
+
if (!indices.has(node)) {
|
|
82
|
+
visit(node);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return found;
|
|
86
|
+
}
|
|
87
|
+
static walk(opts) {
|
|
88
|
+
const out = [];
|
|
89
|
+
const dirEntries = (0, node_fs_1.readdirSync)(opts.dir);
|
|
90
|
+
for (const name of dirEntries) {
|
|
91
|
+
const full = (0, node_path_1.join)(opts.dir, name);
|
|
92
|
+
if ((0, node_fs_1.statSync)(full).isDirectory()) {
|
|
93
|
+
out.push(...ModuleGraph.walk({ dir: full }));
|
|
94
|
+
}
|
|
95
|
+
else if (full.endsWith('.js')) {
|
|
96
|
+
out.push(full);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
static resolveRelative(opts) {
|
|
102
|
+
if (!opts.specifier.startsWith('.')) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
const base = (0, node_path_1.resolve)((0, node_path_1.dirname)(opts.from), opts.specifier);
|
|
106
|
+
const candidates = [base, `${base}.js`, (0, node_path_1.join)(base, 'index.js')];
|
|
107
|
+
for (const candidate of candidates) {
|
|
108
|
+
if ((0, node_fs_1.existsSync)(candidate) && (0, node_fs_1.statSync)(candidate).isFile()) {
|
|
109
|
+
return candidate;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.ModuleGraph = ModuleGraph;
|
|
116
|
+
/**
|
|
117
|
+
* `devz check module-cycles <dir> [--max <n>]`: prints the cycles of a built ESM directory and
|
|
118
|
+
* returns 1 when there are more than `max` (no bound by default), 2 on a usage error.
|
|
119
|
+
*/
|
|
120
|
+
const runModuleCycles = (opts) => {
|
|
121
|
+
const { args, print, printError } = opts;
|
|
122
|
+
const { positionals, values } = (0, node_util_1.parseArgs)({
|
|
123
|
+
args,
|
|
124
|
+
allowPositionals: true,
|
|
125
|
+
options: { max: { type: 'string' }, dist: { type: 'string' } },
|
|
126
|
+
});
|
|
127
|
+
const dir = values.dist ?? positionals[0];
|
|
128
|
+
const usage = 'usage: devz check module-cycles <built ESM dir> [--max <n>]';
|
|
129
|
+
if (!dir) {
|
|
130
|
+
printError(usage);
|
|
131
|
+
return 2;
|
|
132
|
+
}
|
|
133
|
+
let max = Number.POSITIVE_INFINITY;
|
|
134
|
+
if (values.max !== undefined) {
|
|
135
|
+
if (!/^\d+$/.test(values.max)) {
|
|
136
|
+
printError(usage);
|
|
137
|
+
return 2;
|
|
138
|
+
}
|
|
139
|
+
max = Number(values.max);
|
|
140
|
+
}
|
|
141
|
+
const cycles = ModuleGraph.fromDirectory({ dir }).cycles();
|
|
142
|
+
print(`${dir}: ${cycles.length} cycle(s)`);
|
|
143
|
+
for (const cycle of cycles) {
|
|
144
|
+
print(` - ${cycle.join(' <-> ')}`);
|
|
145
|
+
}
|
|
146
|
+
return cycles.length > max ? 1 : 0;
|
|
147
|
+
};
|
|
148
|
+
exports.runModuleCycles = runModuleCycles;
|
|
149
|
+
//# sourceMappingURL=module-cycles.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
export interface IPurityEntry {
|
|
2
|
+
label: string;
|
|
3
|
+
package: string;
|
|
4
|
+
/** Repository-relative path to the built file the `exports` map points at. */
|
|
5
|
+
entry: string;
|
|
6
|
+
/**
|
|
7
|
+
* Specifiers to pass through as `bun build --external`. Only for a third-party dependency whose
|
|
8
|
+
* OWN packaging is out of this gate's remit - e.g. one that relies on its `package.json` `browser`
|
|
9
|
+
* field remap, which the downstream app's bundler (Vite, ...) honours and `bun build` does not.
|
|
10
|
+
* Never for the repository's own source: an external hides that file from the module graph
|
|
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.
|
|
13
|
+
*/
|
|
14
|
+
external?: string[];
|
|
15
|
+
/**
|
|
16
|
+
* This row is EXPECTED to be impure, so failing is its passing state. Derived from
|
|
17
|
+
* {@link IPurityClaim.impure} - never authored on a row directly.
|
|
18
|
+
*/
|
|
19
|
+
expectImpure?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A package whose published entry points carry a browser-purity claim.
|
|
23
|
+
*
|
|
24
|
+
* The ROW SET IS NEVER AUTHORED. It is read from the package's own `exports` map, so a sub-path
|
|
25
|
+
* added to a manifest is probed the moment it is published.
|
|
26
|
+
*/
|
|
27
|
+
export interface IPurityClaim {
|
|
28
|
+
/** Directory under `packages/`, and the token `devz check purity <token>` filters on. */
|
|
29
|
+
package: string;
|
|
30
|
+
/**
|
|
31
|
+
* Sub-paths (as spelled in `exports`) when the claim covers only PART of the published surface.
|
|
32
|
+
* Omit it and the whole surface is claimed. Every sub-path named here must still exist in
|
|
33
|
+
* `exports`; a rename fails the derivation loudly rather than quietly dropping a row.
|
|
34
|
+
*/
|
|
35
|
+
subpaths?: string[];
|
|
36
|
+
/** `external` for one sub-path - see {@link IPurityEntry.external}. Keyed as spelled in `exports`. */
|
|
37
|
+
external?: Record<string, string[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Entries that CANNOT be browser-pure, keyed as spelled in `exports`, valued by the conditions
|
|
40
|
+
* that are impure. The waiver is exact in BOTH directions: a listed entry that turns out to be
|
|
41
|
+
* pure fails as loudly as an unlisted one that is not. Deriving still owns the ROW SET, so a
|
|
42
|
+
* sub-path added later is claimed pure by default and has to earn its line here.
|
|
43
|
+
*/
|
|
44
|
+
impure?: Record<string, string[]>;
|
|
45
|
+
}
|
|
46
|
+
/** What a repository may tune about the engine; everything else is the engine's contract. */
|
|
47
|
+
export interface IPurityOptions {
|
|
48
|
+
/**
|
|
49
|
+
* When set, every claimed sub-path must publish its runtime entries below this prefix (for
|
|
50
|
+
* example `./dist/esm/`): a browser bundler needs an ES module, so a CommonJS-only entry makes
|
|
51
|
+
* the claim unconsumable. Omit it for a repository that publishes a single build.
|
|
52
|
+
*/
|
|
53
|
+
esmEntryPrefix?: string;
|
|
54
|
+
/** Package-name prefix of this repository's own packages; an `external` may never start with it. Default `@venizia/`. */
|
|
55
|
+
workspaceScope?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A code-level guard, not just the JSDoc on `external`: it is an escape hatch from this gate, and a
|
|
59
|
+
* hatch with no lock is one bad edit away from hiding a real leak - `external: ['@venizia/ignis-helpers']`
|
|
60
|
+
* on a red entry would silently turn it green by removing the exact root-barrel import this gate
|
|
61
|
+
* exists to catch from the module graph, rather than proving it absent.
|
|
62
|
+
*
|
|
63
|
+
* A plain `Error`, not `getError`: the engine runs from the repository root through `devz`, outside
|
|
64
|
+
* every workspace package, and has no logger to resolve.
|
|
65
|
+
*/
|
|
66
|
+
export declare const assertNoWorkspaceExternal: (manifest: IPurityEntry[], workspaceScope?: string) => IPurityEntry[];
|
|
67
|
+
/**
|
|
68
|
+
* Exported for the tests, which have to drive a claim that no longer matches its package's
|
|
69
|
+
* `exports` map - the staleness guard is the whole point of deriving, and it cannot be asserted
|
|
70
|
+
* through a built manifest, which by construction is never stale.
|
|
71
|
+
*/
|
|
72
|
+
export declare const deriveEntries: (opts: {
|
|
73
|
+
claim: IPurityClaim;
|
|
74
|
+
root: string;
|
|
75
|
+
}) => IPurityEntry[];
|
|
76
|
+
/**
|
|
77
|
+
* A browser claim is only honest if a browser bundler can actually consume the entry. A CommonJS
|
|
78
|
+
* entry forces every consumer into a workaround, so the claim carries the obligation: every claimed
|
|
79
|
+
* sub-path must publish its runtime entries below `esmEntryPrefix`. Checked here rather than trusted
|
|
80
|
+
* to a comment, for the same reason as {@link assertNoWorkspaceExternal} - the failure is otherwise
|
|
81
|
+
* invisible until someone tries to bundle the package downstream.
|
|
82
|
+
*/
|
|
83
|
+
export declare const assertBrowserEsmEntry: (opts: {
|
|
84
|
+
claims: IPurityClaim[];
|
|
85
|
+
root: string;
|
|
86
|
+
esmEntryPrefix: string;
|
|
87
|
+
}) => IPurityClaim[];
|
|
88
|
+
/** The rows of a whole repository: every claim derived from its package's `exports`, then the guards. */
|
|
89
|
+
export declare const buildManifest: (opts: {
|
|
90
|
+
claims: IPurityClaim[];
|
|
91
|
+
root: string;
|
|
92
|
+
options?: IPurityOptions;
|
|
93
|
+
}) => IPurityEntry[];
|
|
94
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +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;AAYD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,GACpC,UAAU,YAAY,EAAE,EACxB,iBAAgB,MAAgC,KAC/C,YAAY,EAiBd,CAAC;AAiEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,KAAG,YAAY,EA8EvF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,GAAI,MAAM;IAC1C,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;CACxB,KAAG,YAAY,EAiCf,CAAC;AAEF,yGAAyG;AACzG,eAAO,MAAM,aAAa,GAAI,MAAM;IAClC,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B,KAAG,YAAY,EAWf,CAAC"}
|