limina 0.0.2 → 0.0.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/README.md +17 -15
- package/chunks/{dep-jgc7X0zw.js → dep-DzYrmtQJ.js} +32 -49
- package/chunks/{dep-uPXyoC0V.js → dep-ZRIm_-Zk.js} +180 -253
- package/cli.js +732 -159
- package/config.d.ts +15 -23
- package/config.js +1 -1
- package/index.d.ts +7 -20
- package/index.js +3 -3
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ Limina makes these rules reviewable, runnable, and suitable for CI.
|
|
|
34
34
|
- **Compatibility path generation**: writes opt-in `tsconfig.dts.paths.generated.json` files for `workspace:*` dependencies whose package exports still point at build artifacts.
|
|
35
35
|
- **Checker target runner**: runs configured TypeScript and UI-framework checker entries in `typecheck` or `build` execution mode.
|
|
36
36
|
- **Published package checks**: validates built package outputs with `publint`, Are The Types Wrong, and a runtime import boundary audit.
|
|
37
|
+
- **Release checks**: verifies npm tarball hygiene, source/packed manifest consistency, and registry-backed workspace publish order.
|
|
37
38
|
- **Composable pipelines**: combines built-in checks and shell commands into named workflows such as `typecheck`, `package`, and `publish`.
|
|
38
39
|
- **Typed configuration**: ships `defineConfig(...)` for editor hints and typed user configs.
|
|
39
40
|
|
|
@@ -95,8 +96,8 @@ export default defineConfig({
|
|
|
95
96
|
],
|
|
96
97
|
},
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
package: {
|
|
100
|
+
entries: [
|
|
100
101
|
{
|
|
101
102
|
name: '@acme/core',
|
|
102
103
|
outDir: 'packages/core/dist',
|
|
@@ -106,7 +107,7 @@ export default defineConfig({
|
|
|
106
107
|
|
|
107
108
|
pipelines: {
|
|
108
109
|
package: ['package:check'],
|
|
109
|
-
publish: ['graph:check', 'proof:check', 'package:check'],
|
|
110
|
+
publish: ['graph:check', 'proof:check', 'package:check', 'release:check'],
|
|
110
111
|
},
|
|
111
112
|
});
|
|
112
113
|
```
|
|
@@ -135,7 +136,7 @@ pnpm exec limina package check --package @acme/core
|
|
|
135
136
|
|
|
136
137
|
### Checker entry
|
|
137
138
|
|
|
138
|
-
Each checker has one required `config.checkers.<name>.entry`, usually a `tsconfig*.build.json` graph aggregator.
|
|
139
|
+
Each checker has one required `config.checkers.<name>.entry`, usually a `tsconfig*.build.json` graph aggregator. Built-in first-class presets (`tsc` and `vue-tsc`) participate in graph, source, proof, and build checks. Source-only presets such as `svelte-check` prove source coverage and run direct checker execution through `limina checker typecheck`.
|
|
139
140
|
|
|
140
141
|
### Declaration leaf and local companion
|
|
141
142
|
|
|
@@ -151,7 +152,7 @@ A dependency declared as `link:`, `file:`, `catalog:`, or normal semver is treat
|
|
|
151
152
|
|
|
152
153
|
### Package checks
|
|
153
154
|
|
|
154
|
-
Source graph checks do not prove that an installed package works for consumers. `limina package check` inspects built package outputs under `
|
|
155
|
+
Source graph checks do not prove that an installed package works for consumers. `limina package check` inspects built package outputs under `package.entries[].outDir` and checks the actual package manifest, exports, type resolution, and runtime imports with `publint`, `attw`, and `boundary`. `limina release check` owns npm publish hygiene: private-output rejection, required README/license files, source map bans, source/packed manifest consistency, and registry-backed workspace publish order.
|
|
155
156
|
|
|
156
157
|
## CLI
|
|
157
158
|
|
|
@@ -168,13 +169,14 @@ limina [--config limina.config.mjs] [--mode mode] <command>
|
|
|
168
169
|
| `limina paths generate` | Generate compatibility source `paths` configs for artifact-facing workspace exports. |
|
|
169
170
|
| `limina paths apply` | Compatibility alias for `paths generate`. |
|
|
170
171
|
| `limina paths check` | Fail when generated path files are stale. |
|
|
171
|
-
| `limina checker typecheck` | Run typecheck targets derived from checker entries. |
|
|
172
172
|
| `limina checker build` | Run build execution for checker entries that support it. |
|
|
173
|
-
| `limina checker typecheck
|
|
173
|
+
| `limina checker typecheck` | Run source-only checker entries such as `svelte-check`. |
|
|
174
174
|
| `limina package check` | Run configured package output checks. |
|
|
175
|
-
| `limina package check --package <name>` | Check one configured package
|
|
175
|
+
| `limina package check --package <name>` | Check one configured package entry. |
|
|
176
176
|
| `limina package check --tool <tool>` | Run only `publint`, `attw`, or `boundary`. |
|
|
177
177
|
| `limina package check --attw-profile <profile>` | Override the ATTW profile: `strict`, `node16`, or `esm-only`. |
|
|
178
|
+
| `limina release check` | Check release hygiene and dependency consistency for the cwd package entry. |
|
|
179
|
+
| `limina release check --package <name>` | Check release hygiene and dependency consistency for one or more package entries. |
|
|
178
180
|
|
|
179
181
|
## Configuration reference
|
|
180
182
|
|
|
@@ -198,7 +200,7 @@ config: {
|
|
|
198
200
|
}
|
|
199
201
|
```
|
|
200
202
|
|
|
201
|
-
`config.checkers` defines checker entries. Every configured checker must declare a non-empty `entry
|
|
203
|
+
`config.checkers` defines checker entries. Every configured checker must declare a non-empty `entry` and use a built-in preset. Checker `extensions` are fixed by Limina and cannot be configured; if `source.include` is omitted, Limina derives the source boundary from configured checker extensions, then applies `source.exclude`.
|
|
202
204
|
|
|
203
205
|
### `graph`
|
|
204
206
|
|
|
@@ -270,11 +272,11 @@ proof: {
|
|
|
270
272
|
|
|
271
273
|
Checker entries cover files validated by TypeScript or framework-aware tools. Allowlist entries are the final fallback after all configured checker entries fail to cover a source file; they should be rare and must include a reason.
|
|
272
274
|
|
|
273
|
-
### `
|
|
275
|
+
### `package`
|
|
274
276
|
|
|
275
277
|
```js
|
|
276
|
-
|
|
277
|
-
|
|
278
|
+
package: {
|
|
279
|
+
entries: [
|
|
278
280
|
{
|
|
279
281
|
name: '@acme/core',
|
|
280
282
|
outDir: 'packages/core/dist',
|
|
@@ -290,7 +292,7 @@ packageChecks: {
|
|
|
290
292
|
}
|
|
291
293
|
```
|
|
292
294
|
|
|
293
|
-
`outDir` must point at the built package directory that contains the publish-ready `package.json`.
|
|
295
|
+
`outDir` must point at the built package directory that contains the publish-ready `package.json`. `package:check` uses this output for consumer-facing resolver and runtime checks; `release:check` packs the same output and verifies publish hygiene such as README/license files and source map bans.
|
|
294
296
|
|
|
295
297
|
### `pipelines`
|
|
296
298
|
|
|
@@ -303,7 +305,7 @@ pipelines: {
|
|
|
303
305
|
}
|
|
304
306
|
```
|
|
305
307
|
|
|
306
|
-
`limina check` runs the built-in default pipeline: `graph:check`, `source:check`, `proof:check`, and `checker:typecheck`. `limina check <pipeline>` only runs user pipelines from `limina.config.mjs#pipelines`; if the name is missing, Limina reports the missing pipeline and asks you to define it there.
|
|
308
|
+
`limina check` runs the built-in default pipeline: `graph:check`, `source:check`, `proof:check`, `checker:build`, and `checker:typecheck`. `limina check <pipeline>` only runs user pipelines from `limina.config.mjs#pipelines`; if the name is missing, Limina reports the missing pipeline and asks you to define it there.
|
|
307
309
|
|
|
308
310
|
String steps can be built-in task names or simple commands. Use object command steps when arguments, `cwd`, or `env` need to be explicit.
|
|
309
311
|
|
|
@@ -357,7 +359,7 @@ Run the command from inside the workspace, or pass `--config ./limina.config.mjs
|
|
|
357
359
|
|
|
358
360
|
Limina infers the workspace root from `pnpm-workspace.yaml`. Place the config inside the workspace or pass a config path located under the workspace root.
|
|
359
361
|
|
|
360
|
-
### `
|
|
362
|
+
### `package.entries[x].outDir` is invalid
|
|
361
363
|
|
|
362
364
|
Set `outDir` to the built package directory, not the source package directory, unless that directory is itself the publish-ready package output.
|
|
363
365
|
|
|
@@ -35,39 +35,30 @@ function isPathInsideDirectory(filePath, directoryPath) {
|
|
|
35
35
|
function createTscCommandTarget(options) {
|
|
36
36
|
const relativeConfigPath = toRelativePath(options.projectRootDir, options.configPath);
|
|
37
37
|
return {
|
|
38
|
-
args:
|
|
38
|
+
args: [
|
|
39
39
|
"-b",
|
|
40
40
|
relativeConfigPath,
|
|
41
41
|
"--pretty",
|
|
42
42
|
"false"
|
|
43
|
-
] : [
|
|
44
|
-
"-p",
|
|
45
|
-
relativeConfigPath,
|
|
46
|
-
"--noEmit"
|
|
47
43
|
],
|
|
48
44
|
command: options.commandOverride ?? "tsc",
|
|
49
|
-
label:
|
|
45
|
+
label: `tsc -b ${relativeConfigPath}`
|
|
50
46
|
};
|
|
51
47
|
}
|
|
52
48
|
function createVueTscCommandTarget(options) {
|
|
53
49
|
const relativeConfigPath = toRelativePath(options.projectRootDir, options.configPath);
|
|
54
50
|
return {
|
|
55
|
-
args:
|
|
51
|
+
args: [
|
|
56
52
|
"-b",
|
|
57
53
|
relativeConfigPath,
|
|
58
54
|
"--pretty",
|
|
59
55
|
"false"
|
|
60
|
-
] : [
|
|
61
|
-
"-p",
|
|
62
|
-
relativeConfigPath,
|
|
63
|
-
"--noEmit"
|
|
64
56
|
],
|
|
65
57
|
command: "vue-tsc",
|
|
66
|
-
label:
|
|
58
|
+
label: `${options.checker.name}: vue-tsc -b ${relativeConfigPath}`
|
|
67
59
|
};
|
|
68
60
|
}
|
|
69
61
|
function createSvelteCheckCommandTarget(options) {
|
|
70
|
-
if (options.executionKind === "build") throw new Error(`Checker "${options.checker.name}" uses svelte-check, which does not support checker:build.`);
|
|
71
62
|
const relativeConfigPath = toRelativePath(options.projectRootDir, options.configPath);
|
|
72
63
|
return {
|
|
73
64
|
args: ["--tsconfig", relativeConfigPath],
|
|
@@ -79,10 +70,11 @@ const builtinCheckerAdapters = {
|
|
|
79
70
|
"svelte-check": {
|
|
80
71
|
createCommandTarget: createSvelteCheckCommandTarget,
|
|
81
72
|
defaultExtensions: [".svelte"],
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
execution: "typecheck",
|
|
74
|
+
packageNames: ["svelte-check"],
|
|
84
75
|
preset: "svelte-check",
|
|
85
|
-
|
|
76
|
+
sourceGraph: false,
|
|
77
|
+
tier: "source-only"
|
|
86
78
|
},
|
|
87
79
|
tsc: {
|
|
88
80
|
createCommandTarget: createTscCommandTarget,
|
|
@@ -96,18 +88,20 @@ const builtinCheckerAdapters = {
|
|
|
96
88
|
".d.mts",
|
|
97
89
|
".json"
|
|
98
90
|
],
|
|
99
|
-
|
|
100
|
-
|
|
91
|
+
execution: "build",
|
|
92
|
+
packageNames: ["typescript"],
|
|
101
93
|
preset: "tsc",
|
|
102
|
-
|
|
94
|
+
sourceGraph: true,
|
|
95
|
+
tier: "first-class"
|
|
103
96
|
},
|
|
104
97
|
"vue-tsc": {
|
|
105
98
|
createCommandTarget: createVueTscCommandTarget,
|
|
106
99
|
defaultExtensions: [".vue"],
|
|
107
|
-
|
|
108
|
-
|
|
100
|
+
execution: "build",
|
|
101
|
+
packageNames: ["vue-tsc", "@vue/compiler-sfc"],
|
|
109
102
|
preset: "vue-tsc",
|
|
110
|
-
|
|
103
|
+
sourceGraph: true,
|
|
104
|
+
tier: "first-class"
|
|
111
105
|
}
|
|
112
106
|
};
|
|
113
107
|
function isBuiltinCheckerPreset(value) {
|
|
@@ -130,15 +124,16 @@ function collectMissingCheckerPeerDependencies(options) {
|
|
|
130
124
|
const resolvePackage = options.resolvePackage ?? resolveCheckerPackageFromRoot;
|
|
131
125
|
const missingCheckersByPackage = /* @__PURE__ */ new Map();
|
|
132
126
|
for (const checker of options.checkers) {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
127
|
+
const packageNames = getCheckerAdapter(checker.preset)?.packageNames ?? [];
|
|
128
|
+
for (const packageName of packageNames) {
|
|
129
|
+
if (resolvePackage({
|
|
130
|
+
packageName,
|
|
131
|
+
projectRootDir: options.projectRootDir
|
|
132
|
+
})) continue;
|
|
133
|
+
const checkerNames = missingCheckersByPackage.get(packageName) ?? /* @__PURE__ */ new Set();
|
|
134
|
+
checkerNames.add(checker.name);
|
|
135
|
+
missingCheckersByPackage.set(packageName, checkerNames);
|
|
136
|
+
}
|
|
142
137
|
}
|
|
143
138
|
return [...missingCheckersByPackage.entries()].map(([packageName, checkerNames]) => ({
|
|
144
139
|
checkerNames: [...checkerNames].sort((left, right) => left.localeCompare(right)),
|
|
@@ -157,10 +152,9 @@ function formatMissingCheckerPeerDependencies(missingDependencies) {
|
|
|
157
152
|
].join("\n");
|
|
158
153
|
}
|
|
159
154
|
function getCheckerExtensions(checker) {
|
|
160
|
-
if (checker.extensions) return normalizeExtensions(checker.extensions);
|
|
161
155
|
const adapter = getCheckerAdapter(checker.preset);
|
|
162
|
-
if (adapter
|
|
163
|
-
throw new Error(`Checker preset "${checker.preset}"
|
|
156
|
+
if (adapter) return normalizeExtensions(adapter.defaultExtensions);
|
|
157
|
+
throw new Error(`Checker preset "${checker.preset}" is not supported.`);
|
|
164
158
|
}
|
|
165
159
|
function getResolvedCheckers(config) {
|
|
166
160
|
const checkers = config.config?.checkers;
|
|
@@ -185,11 +179,9 @@ function defineConfig(config) {
|
|
|
185
179
|
return config;
|
|
186
180
|
}
|
|
187
181
|
const nonEmptyStringSchema = z.string().refine((value) => value.trim().length > 0);
|
|
188
|
-
const dotPrefixedStringSchema = nonEmptyStringSchema.refine((value) => value.startsWith("."));
|
|
189
182
|
const checkerObjectSchema = z.looseObject({});
|
|
190
183
|
const checkerConfigShapeSchema = z.looseObject({
|
|
191
184
|
entry: nonEmptyStringSchema,
|
|
192
|
-
extensions: z.array(dotPrefixedStringSchema).nonempty().optional(),
|
|
193
185
|
preset: nonEmptyStringSchema
|
|
194
186
|
});
|
|
195
187
|
const liminaConfigShapeSchema = z.looseObject({ config: z.looseObject({ checkers: z.record(z.string(), checkerConfigShapeSchema).optional() }).optional() });
|
|
@@ -245,15 +237,6 @@ function formatLiminaConfigShapeIssue(value, issue) {
|
|
|
245
237
|
` value: ${formatUnknownValue(getValueAtPath(value, pathSegments))}`,
|
|
246
238
|
" reason: checker entry must be a non-empty string path."
|
|
247
239
|
].join("\n");
|
|
248
|
-
if (pathSegments[3] === "extensions") {
|
|
249
|
-
const extensionsPath = pathSegments.slice(0, 4);
|
|
250
|
-
return [
|
|
251
|
-
"Invalid Limina checker config:",
|
|
252
|
-
` field: ${checkerField}.extensions`,
|
|
253
|
-
` value: ${formatUnknownValue(getValueAtPath(value, extensionsPath))}`,
|
|
254
|
-
" reason: checker extensions must be a non-empty array of dot-prefixed strings."
|
|
255
|
-
].join("\n");
|
|
256
|
-
}
|
|
257
240
|
}
|
|
258
241
|
return [
|
|
259
242
|
"Invalid Limina config:",
|
|
@@ -279,11 +262,11 @@ function collectCheckerConfigProblems(config) {
|
|
|
279
262
|
if (!checkerObjectResult.success) continue;
|
|
280
263
|
const checkerRecord = checkerObjectResult.data;
|
|
281
264
|
const preset = checkerRecord.preset;
|
|
282
|
-
if (checkerRecord
|
|
265
|
+
if (Object.hasOwn(checkerRecord, "extensions")) problems.push([
|
|
283
266
|
"Invalid Limina checker config:",
|
|
284
267
|
` field: ${field}.extensions`,
|
|
285
|
-
|
|
286
|
-
" reason: extensions
|
|
268
|
+
` value: ${formatUnknownValue(checkerRecord.extensions)}`,
|
|
269
|
+
" reason: checker extensions are fixed by built-in presets and cannot be configured."
|
|
287
270
|
].join("\n"));
|
|
288
271
|
if (Object.hasOwn(checkerRecord, "routes")) problems.push([
|
|
289
272
|
"Invalid Limina checker config:",
|
|
@@ -374,4 +357,4 @@ async function loadConfig(options = {}) {
|
|
|
374
357
|
}
|
|
375
358
|
|
|
376
359
|
//#endregion
|
|
377
|
-
export { validateLiminaConfig as a, getCheckerAdapter as c,
|
|
360
|
+
export { validateLiminaConfig as a, getCheckerAdapter as c, normalizeAbsolutePath as d, normalizeSlashes as f, toRelativePath as g, toPosixPath as h, loadConfig as i, normalizeExtensions as l, toAbsolutePath as m, getActiveCheckerExtensions as n, collectMissingCheckerPeerDependencies as o, normalizeWorkspacePath as p, getActiveCheckers as r, formatMissingCheckerPeerDependencies as s, defineConfig as t, isPathInsideDirectory as u };
|