tsdown-stale-guard 0.0.0 → 0.1.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/README.md +76 -12
- package/dist/cli.mjs +9 -27
- package/dist/{check-YFLy7mcd.mjs → guard-CAD3_wn0.mjs} +41 -7
- package/dist/index.d.mts +51 -14
- package/dist/index.mjs +22 -29
- package/package.json +13 -8
package/README.md
CHANGED
|
@@ -8,13 +8,17 @@
|
|
|
8
8
|
|
|
9
9
|
Build freshness validation for [tsdown](https://github.com/rolldown/tsdown). Records hashes of all files involved in a build, enabling fast up-to-date checks without re-building.
|
|
10
10
|
|
|
11
|
+
> This plugin requires `tsdown@0.21.9` or later.
|
|
12
|
+
|
|
11
13
|
## Features
|
|
12
14
|
|
|
13
15
|
- **tsdown/Rolldown plugin** — automatically tracks source files, output files, config, and package lock file
|
|
14
16
|
- **Composite hash** — single hash for quick freshness checks
|
|
15
17
|
- **Find-up search** — detects lock files and configs in monorepo setups
|
|
16
|
-
- **CLI** — `tsdown-stale-guard
|
|
17
|
-
- **Programmatic API** — `
|
|
18
|
+
- **CLI** — `tsdown-stale-guard` for CI pipelines
|
|
19
|
+
- **Programmatic API** — `checkBuildState()` for tool integrations
|
|
20
|
+
- **Build guard** — `guardStaleBuild()` throws on stale builds, great for test setups
|
|
21
|
+
- **Structured diagnostics** — errors use [logs-sdk](https://github.com/vercel-labs/logs-sdk) with stable codes and actionable fixes
|
|
18
22
|
|
|
19
23
|
## Install
|
|
20
24
|
|
|
@@ -29,17 +33,17 @@ npm i tsdown-stale-guard
|
|
|
29
33
|
```ts
|
|
30
34
|
// tsdown.config.ts
|
|
31
35
|
import { defineConfig } from 'tsdown'
|
|
32
|
-
import {
|
|
36
|
+
import { StaleGuardRecorder } from 'tsdown-stale-guard'
|
|
33
37
|
|
|
34
38
|
export default defineConfig({
|
|
35
39
|
entry: ['src/index.ts'],
|
|
36
40
|
plugins: [
|
|
37
|
-
|
|
41
|
+
StaleGuardRecorder(),
|
|
38
42
|
],
|
|
39
43
|
})
|
|
40
44
|
```
|
|
41
45
|
|
|
42
|
-
After building, a hash file will be generated at `node_modules/.cache/tsdown-stale-guard/hash.yaml`.
|
|
46
|
+
After building, a hash file will be generated at `node_modules/.cache/tsdown-stale-guard/hash.yaml`.
|
|
43
47
|
|
|
44
48
|
Example of the generated hash file:
|
|
45
49
|
|
|
@@ -65,7 +69,7 @@ outputs:
|
|
|
65
69
|
### Plugin Options
|
|
66
70
|
|
|
67
71
|
```ts
|
|
68
|
-
|
|
72
|
+
StaleGuardRecorder({
|
|
69
73
|
hashFile: 'node_modules/.cache/tsdown-stale-guard/hash.yaml', // hash file path (default)
|
|
70
74
|
root: process.cwd(), // root directory (default)
|
|
71
75
|
hashOutputs: true, // hash output files (default)
|
|
@@ -76,10 +80,10 @@ TsdownStaleGuard({
|
|
|
76
80
|
|
|
77
81
|
```bash
|
|
78
82
|
# Check if the build is up to date
|
|
79
|
-
tsdown-stale-guard
|
|
83
|
+
tsdown-stale-guard
|
|
80
84
|
|
|
81
85
|
# Use a custom hash file path
|
|
82
|
-
tsdown-stale-guard
|
|
86
|
+
tsdown-stale-guard --hash-file custom.hash.yaml
|
|
83
87
|
```
|
|
84
88
|
|
|
85
89
|
Exit code `0` if fresh, `1` if stale.
|
|
@@ -87,9 +91,9 @@ Exit code `0` if fresh, `1` if stale.
|
|
|
87
91
|
### Programmatic API
|
|
88
92
|
|
|
89
93
|
```ts
|
|
90
|
-
import {
|
|
94
|
+
import { checkBuildState } from 'tsdown-stale-guard'
|
|
91
95
|
|
|
92
|
-
const result = await
|
|
96
|
+
const result = await checkBuildState()
|
|
93
97
|
|
|
94
98
|
if (result.fresh) {
|
|
95
99
|
console.log('Build is up to date')
|
|
@@ -101,6 +105,66 @@ else {
|
|
|
101
105
|
}
|
|
102
106
|
```
|
|
103
107
|
|
|
108
|
+
### Guard Stale Build
|
|
109
|
+
|
|
110
|
+
`guardStaleBuild()` checks the build state and throws a structured [`TSDSG0002`](./docs/errors/tsdsg0002.md) error if the build is stale. This is useful for CI pipelines or test setups where you want to fail early when the build output is outdated.
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { guardStaleBuild } from 'tsdown-stale-guard'
|
|
114
|
+
|
|
115
|
+
// Throws if the build is stale
|
|
116
|
+
await guardStaleBuild()
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### With Vitest
|
|
120
|
+
|
|
121
|
+
When writing tests against the built output (`dist/`), you can use `guardStaleBuild()` to ensure the build is fresh before tests run. Use `beforeAll` for a per-test-file check:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { guardStaleBuild } from 'tsdown-stale-guard'
|
|
125
|
+
import { beforeAll, describe, it } from 'vitest'
|
|
126
|
+
|
|
127
|
+
beforeAll(async () => {
|
|
128
|
+
await guardStaleBuild()
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('should work', async () => {
|
|
132
|
+
const { myFunction } = await import('../dist/index.mjs')
|
|
133
|
+
// test against the built output
|
|
134
|
+
})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Or use `globalSetup` for a one-time global check:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
// test/setup.ts
|
|
141
|
+
import { guardStaleBuild } from 'tsdown-stale-guard'
|
|
142
|
+
|
|
143
|
+
await guardStaleBuild()
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
// vitest.config.ts
|
|
148
|
+
import { defineConfig } from 'vitest/config'
|
|
149
|
+
|
|
150
|
+
export default defineConfig({
|
|
151
|
+
test: {
|
|
152
|
+
globalSetup: ['test/setup.ts'],
|
|
153
|
+
},
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Either way, tests fail immediately with a clear error message if the build is stale, instead of producing confusing failures from outdated output.
|
|
158
|
+
|
|
159
|
+
### Diagnostic Codes
|
|
160
|
+
|
|
161
|
+
All errors thrown by `tsdown-stale-guard` are structured [`CodedError`](https://github.com/vercel-labs/logs-sdk) objects with stable codes, actionable `fix` messages, and documentation links.
|
|
162
|
+
|
|
163
|
+
| Code | Level | Description |
|
|
164
|
+
|------|-------|-------------|
|
|
165
|
+
| [`TSDSG0001`](./docs/errors/tsdsg0001.md) | error | `tsdownConfigResolved` hook was not called (tsdown version too old) |
|
|
166
|
+
| [`TSDSG0002`](./docs/errors/tsdsg0002.md) | error | Build is stale — source files, config, or dependencies changed |
|
|
167
|
+
|
|
104
168
|
## How It Works
|
|
105
169
|
|
|
106
170
|
The plugin hooks into Rolldown's build pipeline:
|
|
@@ -133,7 +197,7 @@ Package lock files (`pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`, `bun.loc
|
|
|
133
197
|
[npm-downloads-href]: https://npmjs.com/package/tsdown-stale-guard
|
|
134
198
|
[bundle-src]: https://img.shields.io/bundlephobia/minzip/tsdown-stale-guard?style=flat&colorA=080f12&colorB=1fa669&label=minzip
|
|
135
199
|
[bundle-href]: https://bundlephobia.com/result?p=tsdown-stale-guard
|
|
136
|
-
[license-src]: https://img.shields.io/github/license/antfu/tsdown-stale-guard.svg?style=flat&colorA=080f12&colorB=1fa669
|
|
137
|
-
[license-href]: https://github.com/antfu/tsdown-stale-guard/blob/main/LICENSE
|
|
200
|
+
[license-src]: https://img.shields.io/github/license/antfu-collective/tsdown-stale-guard.svg?style=flat&colorA=080f12&colorB=1fa669
|
|
201
|
+
[license-href]: https://github.com/antfu-collective/tsdown-stale-guard/blob/main/LICENSE
|
|
138
202
|
[jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-080f12?style=flat&colorA=080f12&colorB=1fa669
|
|
139
203
|
[jsdocs-href]: https://www.jsdocs.io/package/tsdown-stale-guard
|
package/dist/cli.mjs
CHANGED
|
@@ -1,31 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as
|
|
3
|
-
import
|
|
2
|
+
import { t as guardStaleBuild } from "./guard-CAD3_wn0.mjs";
|
|
3
|
+
import cac from "cac";
|
|
4
4
|
//#region src/cli.ts
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
process.exit(0);
|
|
13
|
-
} else {
|
|
14
|
-
console.log("Build is stale. Changes detected:");
|
|
15
|
-
for (const change of result.changes) console.log(` ${change.type}: [${change.category}] ${change.file}`);
|
|
16
|
-
process.exit(1);
|
|
17
|
-
}
|
|
18
|
-
} else {
|
|
19
|
-
console.log(`tsdown-stale-guard - Build freshness validation for tsdown
|
|
20
|
-
|
|
21
|
-
Usage:
|
|
22
|
-
tsdown-stale-guard check Check if the build is up to date
|
|
23
|
-
tsdown-stale-guard check --hash-file <path> Use a custom hash file path
|
|
24
|
-
|
|
25
|
-
Options:
|
|
26
|
-
--hash-file <path> Path to the hash file (default: node_modules/.cache/tsdown-stale-guard/hash.yaml)
|
|
27
|
-
--help Show this help message`);
|
|
28
|
-
process.exit(command === "--help" || command === "-h" ? 0 : 1);
|
|
29
|
-
}
|
|
5
|
+
const cli = cac("tsdown-stale-guard");
|
|
6
|
+
cli.command("[...args]", "Check if the build is up to date").option("--hash-file <path>", "Path to the hash file").action(async (_args, options) => {
|
|
7
|
+
await guardStaleBuild({ hashFile: options.hashFile });
|
|
8
|
+
console.log("Build is up to date.");
|
|
9
|
+
});
|
|
10
|
+
cli.help();
|
|
11
|
+
cli.parse();
|
|
30
12
|
//#endregion
|
|
31
13
|
export {};
|
|
@@ -4,6 +4,7 @@ import process from "node:process";
|
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6
6
|
import { parse, stringify } from "yaml";
|
|
7
|
+
import { consoleReporter, createLogger, defineDiagnostics } from "logs-sdk";
|
|
7
8
|
//#region src/hash.ts
|
|
8
9
|
async function hashFile(path) {
|
|
9
10
|
const content = await readFile(path);
|
|
@@ -34,7 +35,7 @@ function serializeHashFile(data) {
|
|
|
34
35
|
version: data.version,
|
|
35
36
|
hash: data.hash
|
|
36
37
|
};
|
|
37
|
-
if (data.
|
|
38
|
+
if (data.configs) obj.configs = Object.fromEntries(data.configs.map((e) => [e.file, e.hash]));
|
|
38
39
|
if (data.lockfile) obj.lockfile = { [data.lockfile.file]: data.lockfile.hash };
|
|
39
40
|
if (data.sources.length > 0) obj.sources = Object.fromEntries(data.sources.map((e) => [e.file, e.hash]));
|
|
40
41
|
if (data.outputs.length > 0) obj.outputs = Object.fromEntries(data.outputs.map((e) => [e.file, e.hash]));
|
|
@@ -45,7 +46,7 @@ function parseHashFile(content) {
|
|
|
45
46
|
return {
|
|
46
47
|
version: obj.version,
|
|
47
48
|
hash: obj.hash,
|
|
48
|
-
|
|
49
|
+
configs: parseSectionList(obj.configs),
|
|
49
50
|
lockfile: parseSection(obj.lockfile),
|
|
50
51
|
sources: parseSectionList(obj.sources),
|
|
51
52
|
outputs: parseSectionList(obj.outputs)
|
|
@@ -78,22 +79,24 @@ async function writeHashFile(path, data) {
|
|
|
78
79
|
//#endregion
|
|
79
80
|
//#region src/check.ts
|
|
80
81
|
const DEFAULT_HASH_FILE = "node_modules/.cache/tsdown-stale-guard/hash.yaml";
|
|
81
|
-
async function
|
|
82
|
+
async function checkBuildState(options = {}) {
|
|
82
83
|
const root = options.root || process.cwd();
|
|
83
84
|
const data = await readHashFile(resolve(root, options.hashFile || DEFAULT_HASH_FILE));
|
|
84
85
|
const changes = [];
|
|
85
|
-
if (data.
|
|
86
|
+
if (data.configs) for (const entry of data.configs) await checkEntry(entry, "config", root, changes);
|
|
86
87
|
if (data.lockfile) await checkEntry(data.lockfile, "lockfile", root, changes);
|
|
87
88
|
for (const entry of data.sources) await checkEntry(entry, "source", root, changes);
|
|
88
89
|
for (const entry of data.outputs) await checkEntry(entry, "output", root, changes);
|
|
89
90
|
const currentHash = computeCompositeHash([
|
|
90
91
|
...data.sources,
|
|
91
92
|
...data.outputs,
|
|
92
|
-
...data.
|
|
93
|
+
...data.configs || [],
|
|
93
94
|
...data.lockfile ? [data.lockfile] : []
|
|
94
95
|
]);
|
|
96
|
+
const fresh = changes.length === 0 && currentHash === data.hash;
|
|
95
97
|
return {
|
|
96
|
-
fresh
|
|
98
|
+
fresh,
|
|
99
|
+
stale: !fresh,
|
|
97
100
|
changes
|
|
98
101
|
};
|
|
99
102
|
}
|
|
@@ -114,4 +117,35 @@ async function checkEntry(entry, category, root, changes) {
|
|
|
114
117
|
});
|
|
115
118
|
}
|
|
116
119
|
//#endregion
|
|
117
|
-
|
|
120
|
+
//#region src/diagnostics.ts
|
|
121
|
+
const diagnostics = defineDiagnostics({
|
|
122
|
+
docsBase: (code) => `https://github.com/antfu-collective/tsdown-stale-guard/blob/main/docs/errors/${code.toLowerCase()}.md`,
|
|
123
|
+
codes: {
|
|
124
|
+
TSDSG0001: {
|
|
125
|
+
message: "The `tsdownConfigResolved` hook was not called.",
|
|
126
|
+
why: "The `tsdownConfigResolved` hook is only available since `tsdown@0.21.9`. Your version of tsdown may not support it.",
|
|
127
|
+
fix: "Upgrade tsdown to `0.21.9` or later."
|
|
128
|
+
},
|
|
129
|
+
TSDSG0002: {
|
|
130
|
+
message: (p) => `Build is stale in \`${p.root}\`. ${p.changeCount} file${p.changeCount === 1 ? "" : "s"} changed since last build.`,
|
|
131
|
+
why: "Source files, config, or dependencies have changed since the last build.",
|
|
132
|
+
fix: "Run your build script (e.g. `npm run build`) or `tsdown` directly to rebuild the project."
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
const log = createLogger({
|
|
137
|
+
diagnostics: [diagnostics],
|
|
138
|
+
reporters: consoleReporter
|
|
139
|
+
});
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region src/guard.ts
|
|
142
|
+
async function guardStaleBuild(options = {}) {
|
|
143
|
+
const root = options.root || process.cwd();
|
|
144
|
+
const result = await checkBuildState(options);
|
|
145
|
+
if (result.stale) return log.TSDSG0002({
|
|
146
|
+
root,
|
|
147
|
+
changeCount: result.changes.length
|
|
148
|
+
}).throw();
|
|
149
|
+
}
|
|
150
|
+
//#endregion
|
|
151
|
+
export { parseHashFile as a, writeHashFile as c, hashFiles as d, checkBuildState as i, computeCompositeHash as l, diagnostics as n, readHashFile as o, log as r, serializeHashFile as s, guardStaleBuild as t, hashFile as u };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as _$logs_sdk0 from "logs-sdk";
|
|
2
|
+
import { TsdownPlugin } from "tsdown";
|
|
2
3
|
|
|
3
4
|
//#region src/types.d.ts
|
|
4
|
-
interface
|
|
5
|
+
interface StaleGuardEntry {
|
|
5
6
|
file: string;
|
|
6
7
|
hash: string;
|
|
7
8
|
}
|
|
8
|
-
interface
|
|
9
|
+
interface StaleGuardData {
|
|
9
10
|
version: 1;
|
|
10
11
|
hash: string;
|
|
11
|
-
|
|
12
|
-
lockfile?:
|
|
13
|
-
sources:
|
|
14
|
-
outputs:
|
|
12
|
+
configs?: StaleGuardEntry[];
|
|
13
|
+
lockfile?: StaleGuardEntry;
|
|
14
|
+
sources: StaleGuardEntry[];
|
|
15
|
+
outputs: StaleGuardEntry[];
|
|
15
16
|
}
|
|
16
17
|
interface CheckResult {
|
|
17
18
|
fresh: boolean;
|
|
19
|
+
stale: boolean;
|
|
18
20
|
changes: CheckChange[];
|
|
19
21
|
}
|
|
20
22
|
interface CheckChange {
|
|
@@ -22,7 +24,7 @@ interface CheckChange {
|
|
|
22
24
|
category: 'config' | 'lockfile' | 'source' | 'output';
|
|
23
25
|
file: string;
|
|
24
26
|
}
|
|
25
|
-
interface
|
|
27
|
+
interface StaleGuardRecorderOptions {
|
|
26
28
|
/**
|
|
27
29
|
* Path to the hash file.
|
|
28
30
|
* @default 'node_modules/.cache/tsdown-stale-guard/hash.yaml'
|
|
@@ -53,14 +55,49 @@ interface CheckOptions {
|
|
|
53
55
|
}
|
|
54
56
|
//#endregion
|
|
55
57
|
//#region src/check.d.ts
|
|
56
|
-
declare function
|
|
58
|
+
declare function checkBuildState(options?: CheckOptions): Promise<CheckResult>;
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/diagnostics.d.ts
|
|
61
|
+
declare const diagnostics: _$logs_sdk0.DiagnosticsResult<{
|
|
62
|
+
TSDSG0001: {
|
|
63
|
+
message: string;
|
|
64
|
+
why: string;
|
|
65
|
+
fix: string;
|
|
66
|
+
};
|
|
67
|
+
TSDSG0002: {
|
|
68
|
+
message: (p: {
|
|
69
|
+
root: string;
|
|
70
|
+
changeCount: number;
|
|
71
|
+
}) => string;
|
|
72
|
+
why: string;
|
|
73
|
+
fix: string;
|
|
74
|
+
};
|
|
75
|
+
}>;
|
|
76
|
+
declare const log: _$logs_sdk0.Logger<[_$logs_sdk0.DiagnosticsResult<{
|
|
77
|
+
TSDSG0001: {
|
|
78
|
+
message: string;
|
|
79
|
+
why: string;
|
|
80
|
+
fix: string;
|
|
81
|
+
};
|
|
82
|
+
TSDSG0002: {
|
|
83
|
+
message: (p: {
|
|
84
|
+
root: string;
|
|
85
|
+
changeCount: number;
|
|
86
|
+
}) => string;
|
|
87
|
+
why: string;
|
|
88
|
+
fix: string;
|
|
89
|
+
};
|
|
90
|
+
}>]>;
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/guard.d.ts
|
|
93
|
+
declare function guardStaleBuild(options?: CheckOptions): Promise<void>;
|
|
57
94
|
//#endregion
|
|
58
95
|
//#region src/lockfile.d.ts
|
|
59
|
-
declare function serializeHashFile(data:
|
|
60
|
-
declare function parseHashFile(content: string):
|
|
61
|
-
declare function readHashFile(path: string): Promise<
|
|
96
|
+
declare function serializeHashFile(data: StaleGuardData): string;
|
|
97
|
+
declare function parseHashFile(content: string): StaleGuardData;
|
|
98
|
+
declare function readHashFile(path: string): Promise<StaleGuardData>;
|
|
62
99
|
//#endregion
|
|
63
100
|
//#region src/plugin.d.ts
|
|
64
|
-
declare function
|
|
101
|
+
declare function StaleGuardRecorder(options?: StaleGuardRecorderOptions): TsdownPlugin;
|
|
65
102
|
//#endregion
|
|
66
|
-
export { type CheckChange, type CheckOptions, type CheckResult,
|
|
103
|
+
export { type CheckChange, type CheckOptions, type CheckResult, type StaleGuardData, type StaleGuardEntry, StaleGuardRecorder, type StaleGuardRecorderOptions, checkBuildState, diagnostics, guardStaleBuild, log, parseHashFile, readHashFile, serializeHashFile };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as parseHashFile, c as writeHashFile, d as hashFiles, i as checkBuildState, l as computeCompositeHash, n as diagnostics, o as readHashFile, r as log, s as serializeHashFile, t as guardStaleBuild, u as hashFile } from "./guard-CAD3_wn0.mjs";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { dirname, join, relative, resolve } from "node:path";
|
|
4
|
-
import process from "node:process";
|
|
5
4
|
import { readdir } from "node:fs/promises";
|
|
6
5
|
//#region src/detect.ts
|
|
7
6
|
const PACKAGE_LOCK_FILES = [
|
|
@@ -11,15 +10,6 @@ const PACKAGE_LOCK_FILES = [
|
|
|
11
10
|
"bun.lockb",
|
|
12
11
|
"bun.lock"
|
|
13
12
|
];
|
|
14
|
-
const TSDOWN_CONFIG_FILES = [
|
|
15
|
-
"tsdown.config.ts",
|
|
16
|
-
"tsdown.config.mts",
|
|
17
|
-
"tsdown.config.cts",
|
|
18
|
-
"tsdown.config.js",
|
|
19
|
-
"tsdown.config.mjs",
|
|
20
|
-
"tsdown.config.cjs",
|
|
21
|
-
"tsdown.config.json"
|
|
22
|
-
];
|
|
23
13
|
function findUp(names, cwd) {
|
|
24
14
|
let dir = resolve(cwd);
|
|
25
15
|
while (true) {
|
|
@@ -35,23 +25,26 @@ function findUp(names, cwd) {
|
|
|
35
25
|
function detectPackageLock(cwd) {
|
|
36
26
|
return findUp(PACKAGE_LOCK_FILES, cwd);
|
|
37
27
|
}
|
|
38
|
-
function detectTsdownConfig(cwd) {
|
|
39
|
-
return findUp(TSDOWN_CONFIG_FILES, cwd);
|
|
40
|
-
}
|
|
41
28
|
//#endregion
|
|
42
29
|
//#region src/plugin.ts
|
|
43
30
|
const RE_QUERY = /\?.*$/;
|
|
44
31
|
const RE_WINDOWS_DRIVE = /^[a-z]:\\/i;
|
|
45
32
|
const RE_NODE_MODULES = /node_modules/;
|
|
46
33
|
const DEFAULT_HASH_FILE = "node_modules/.cache/tsdown-stale-guard/hash.yaml";
|
|
47
|
-
function
|
|
34
|
+
function StaleGuardRecorder(options = {}) {
|
|
48
35
|
const { hashFile: hashFilePath = DEFAULT_HASH_FILE, hashOutputs = true } = options;
|
|
49
36
|
const sourceIds = /* @__PURE__ */ new Set();
|
|
50
37
|
let root;
|
|
38
|
+
let configDeps;
|
|
39
|
+
let outDir;
|
|
40
|
+
let isTsdownConfigResolvedCalled = false;
|
|
51
41
|
return {
|
|
52
42
|
name: "tsdown-stale-guard",
|
|
53
|
-
|
|
54
|
-
|
|
43
|
+
tsdownConfigResolved(config) {
|
|
44
|
+
isTsdownConfigResolvedCalled = true;
|
|
45
|
+
root = options.root || config.cwd;
|
|
46
|
+
configDeps = config.configDeps;
|
|
47
|
+
outDir = config.outDir;
|
|
55
48
|
},
|
|
56
49
|
transform: {
|
|
57
50
|
filter: { id: { exclude: [RE_NODE_MODULES] } },
|
|
@@ -60,8 +53,8 @@ function TsdownStaleGuard(options = {}) {
|
|
|
60
53
|
if (cleanId.startsWith("/") || RE_WINDOWS_DRIVE.test(cleanId)) sourceIds.add(cleanId);
|
|
61
54
|
}
|
|
62
55
|
},
|
|
63
|
-
async writeBundle(
|
|
64
|
-
|
|
56
|
+
async writeBundle() {
|
|
57
|
+
if (!isTsdownConfigResolvedCalled) return log.TSDSG0001().throw();
|
|
65
58
|
const resolvedHashFile = resolve(root, hashFilePath);
|
|
66
59
|
const sources = await hashFiles([...sourceIds].filter((f) => existsSync(f)), root);
|
|
67
60
|
let outputs = [];
|
|
@@ -74,14 +67,14 @@ function TsdownStaleGuard(options = {}) {
|
|
|
74
67
|
for (const file of files) if (file.isFile()) outputPaths.push(resolve(file.parentPath, file.name));
|
|
75
68
|
outputs = await hashFiles(outputPaths, root);
|
|
76
69
|
}
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
file
|
|
70
|
+
const configs = [];
|
|
71
|
+
if (configDeps) for (const dep of configDeps) {
|
|
72
|
+
const hash = await hashFile(dep);
|
|
73
|
+
const file = toForwardSlash(relative(root, dep));
|
|
74
|
+
configs.push({
|
|
75
|
+
file,
|
|
83
76
|
hash
|
|
84
|
-
};
|
|
77
|
+
});
|
|
85
78
|
}
|
|
86
79
|
let lockfileEntry;
|
|
87
80
|
const lockfilePath = detectPackageLock(root);
|
|
@@ -97,10 +90,10 @@ function TsdownStaleGuard(options = {}) {
|
|
|
97
90
|
hash: computeCompositeHash([
|
|
98
91
|
...sources,
|
|
99
92
|
...outputs,
|
|
100
|
-
...
|
|
93
|
+
...configs,
|
|
101
94
|
...lockfileEntry ? [lockfileEntry] : []
|
|
102
95
|
]),
|
|
103
|
-
|
|
96
|
+
configs,
|
|
104
97
|
lockfile: lockfileEntry,
|
|
105
98
|
sources,
|
|
106
99
|
outputs
|
|
@@ -112,4 +105,4 @@ function toForwardSlash(p) {
|
|
|
112
105
|
return p.replace(/\\/g, "/");
|
|
113
106
|
}
|
|
114
107
|
//#endregion
|
|
115
|
-
export {
|
|
108
|
+
export { StaleGuardRecorder, checkBuildState, diagnostics, guardStaleBuild, log, parseHashFile, readHashFile, serializeHashFile };
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsdown-stale-guard",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"description": "Build freshness validation for tsdown",
|
|
6
6
|
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://github.com/sponsors/antfu",
|
|
9
|
-
"homepage": "https://github.com/antfu/tsdown-stale-guard#readme",
|
|
9
|
+
"homepage": "https://github.com/antfu-collective/tsdown-stale-guard#readme",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/antfu/tsdown-stale-guard.git"
|
|
12
|
+
"url": "git+https://github.com/antfu-collective/tsdown-stale-guard.git"
|
|
13
13
|
},
|
|
14
|
-
"bugs": "https://github.com/antfu/tsdown-stale-guard/issues",
|
|
14
|
+
"bugs": "https://github.com/antfu-collective/tsdown-stale-guard/issues",
|
|
15
15
|
"keywords": [
|
|
16
16
|
"tsdown",
|
|
17
17
|
"build",
|
|
@@ -32,7 +32,12 @@
|
|
|
32
32
|
"files": [
|
|
33
33
|
"dist"
|
|
34
34
|
],
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"tsdown": "^0.21.9"
|
|
37
|
+
},
|
|
35
38
|
"dependencies": {
|
|
39
|
+
"cac": "^7.0.0",
|
|
40
|
+
"logs-sdk": "0.0.6",
|
|
36
41
|
"yaml": "^2.8.3"
|
|
37
42
|
},
|
|
38
43
|
"devDependencies": {
|
|
@@ -44,12 +49,12 @@
|
|
|
44
49
|
"eslint": "^10.2.0",
|
|
45
50
|
"lint-staged": "^16.4.0",
|
|
46
51
|
"publint": "^0.3.18",
|
|
47
|
-
"rolldown": "1.0.0-rc.15",
|
|
48
52
|
"simple-git-hooks": "^2.13.1",
|
|
49
|
-
"
|
|
50
|
-
"
|
|
53
|
+
"skills-npm": "^1.1.1",
|
|
54
|
+
"tsdown": "^0.21.9",
|
|
55
|
+
"tsnapi": "^0.3.2",
|
|
51
56
|
"tsx": "^4.21.0",
|
|
52
|
-
"typescript": "^6.0.
|
|
57
|
+
"typescript": "^6.0.3",
|
|
53
58
|
"vite": "^8.0.8",
|
|
54
59
|
"vitest": "^4.1.4"
|
|
55
60
|
},
|