ts-node-pack 0.1.3 → 0.2.0
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 +25 -9
- package/package.json +1 -1
- package/src/cli.js +12 -8
- package/src/index.d.ts +15 -3
- package/src/index.js +63 -17
package/README.md
CHANGED
|
@@ -25,18 +25,19 @@ Requires Node ≥ 20 and TypeScript ≥ 5.7 available in the package being packe
|
|
|
25
25
|
## Usage
|
|
26
26
|
|
|
27
27
|
```sh
|
|
28
|
-
ts-node-pack <packageDir> [--tsconfig <path>] [--
|
|
28
|
+
ts-node-pack <packageDir> [--tsconfig <path>] [--stage-to <dir>] [--skip-pack] [--force] [--verbose]
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
| Flag | Description |
|
|
32
32
|
| ------------------- | -------------------------------------------------------------------------------------------- |
|
|
33
33
|
| `--tsconfig <path>` | tsconfig to extend. Defaults to `tsconfig.build.json` if present, otherwise `tsconfig.json`. |
|
|
34
|
-
| `--
|
|
35
|
-
| `--
|
|
34
|
+
| `--stage-to <dir>` | Stage into `<dir>` instead of an auto-created temp dir. Caller owns its lifecycle. |
|
|
35
|
+
| `--skip-pack` | Skip the final `npm pack` step. Requires `--stage-to`. |
|
|
36
|
+
| `--force` | With `--stage-to`, clear `<dir>` if it already has contents. |
|
|
36
37
|
| `-v`, `--verbose` | Log each pipeline phase to stderr. |
|
|
37
38
|
| `-h`, `--help` | Show help. |
|
|
38
39
|
|
|
39
|
-
The resulting `<name>-<version>.tgz` is written to the current working directory.
|
|
40
|
+
The resulting `<name>-<version>.tgz` is written to the current working directory (unless `--skip-pack` is set).
|
|
40
41
|
|
|
41
42
|
### Example
|
|
42
43
|
|
|
@@ -46,20 +47,35 @@ ts-node-pack ./packages/core --verbose
|
|
|
46
47
|
npm install ./my-core-1.2.3.tgz
|
|
47
48
|
```
|
|
48
49
|
|
|
50
|
+
### `--stage-to` and `--skip-pack`
|
|
51
|
+
|
|
52
|
+
By default `ts-node-pack` stages into an auto-created `mkdtemp()` directory, runs `npm pack` against it, copies the resulting `.tgz` to the current working directory, and removes the temp dir.
|
|
53
|
+
|
|
54
|
+
Pass `--stage-to <dir>` when you want to keep the staged contents — for example, to let another tool pack from that directory instead (`lerna publish --contents <dir>`, an alternate tarball builder, etc.). `<dir>` must either not exist, be empty, or be opted-in for clearing via `--force`.
|
|
55
|
+
|
|
56
|
+
Combine with `--skip-pack` to stop after staging and never run `npm pack` at all. `--skip-pack` is only valid with `--stage-to` (otherwise the staged contents would have no accessible location).
|
|
57
|
+
|
|
58
|
+
| Invocation | Behavior |
|
|
59
|
+
| ------------------------------------------------- | ------------------------------------------------------------------- |
|
|
60
|
+
| `ts-node-pack <pkg>` | Stage to temp dir, pack, copy `.tgz` to CWD, delete temp dir. |
|
|
61
|
+
| `ts-node-pack <pkg> --stage-to <dir>` | Stage to `<dir>`, pack, copy `.tgz` to CWD, leave `<dir>` in place. |
|
|
62
|
+
| `ts-node-pack <pkg> --stage-to <dir> --skip-pack` | Stage to `<dir>`, skip pack, leave `<dir>` in place. |
|
|
63
|
+
| `ts-node-pack <pkg> --skip-pack` | Error: `skipPack requires stageTo`. |
|
|
64
|
+
|
|
49
65
|
## Pipeline
|
|
50
66
|
|
|
51
67
|
1. **Resolve package** — read `package.json`, pick tsconfig.
|
|
52
|
-
2. **Stage** — create `mkdtemp()/package/`.
|
|
53
|
-
3. **Derived tsconfig** — write `tsconfig.emit.json` _inside the
|
|
68
|
+
2. **Stage** — use `--stage-to <dir>` if given, otherwise create `mkdtemp()/package/`. A small separate `mkdtemp()` work dir always holds auxiliary files (e.g. the derived tsconfig) so they never land in the packed contents.
|
|
69
|
+
3. **Derived tsconfig** — write `tsconfig.emit.json` _inside the work dir_ that `extends` the chosen tsconfig (by absolute path) and forces `outDir`, `declaration`, `rewriteRelativeImportExtensions: true`, `noEmit: false`. If the base tsconfig enables `sourceMap`, `inlineSourceMap`, or `declarationMap`, `inlineSources: true` is also set so debuggers get full source-level fidelity without any `.ts` files in the tarball.
|
|
54
70
|
4. **Emit** — run `tsc -p` against the derived config.
|
|
55
71
|
5. **Rewrite `.d.ts`** — for each emitted `.d.ts`, rewrite `./foo.ts` → `./foo.js` in `import` / `export from` / dynamic `import()` specifiers. Non-relative specifiers are left alone.
|
|
56
72
|
6. **Rewrite `package.json`** — rewrite `.ts` → `.js` (and → `.d.ts` under `types` conditions) in `main`, `module`, `types`, `typings`, `bin`, `exports`, and the `files` array. Strip `devDependencies` and `scripts`.
|
|
57
73
|
7. **Copy assets** — `README*`, `LICENSE*`, `CHANGELOG*`, `NOTICE*`. Source `.ts` files are never copied.
|
|
58
74
|
8. **Validate** — fail if any `.ts` specifier remains in emitted `.js` / `.d.ts` / `package.json`, or if a referenced entry point does not exist.
|
|
59
|
-
9. **Pack** — `npm pack` in the staging directory
|
|
60
|
-
10. **Cleanup** — remove
|
|
75
|
+
9. **Pack** — unless `--skip-pack`: `npm pack` in the staging directory and move the tarball to the original CWD.
|
|
76
|
+
10. **Cleanup** — always remove the work dir. In default mode this also removes the staging dir (which is nested inside). In `--stage-to` mode the staging dir is the caller's, and survives.
|
|
61
77
|
|
|
62
|
-
The source tree is never mutated.
|
|
78
|
+
The source tree is never mutated.
|
|
63
79
|
|
|
64
80
|
### Sourcemaps
|
|
65
81
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -8,8 +8,9 @@ const { values, positionals } = parseArgs({
|
|
|
8
8
|
allowPositionals: true,
|
|
9
9
|
options: {
|
|
10
10
|
tsconfig: { type: "string" },
|
|
11
|
-
"
|
|
12
|
-
"
|
|
11
|
+
"skip-pack": { type: "boolean", default: false },
|
|
12
|
+
"stage-to": { type: "string" },
|
|
13
|
+
force: { type: "boolean", default: false },
|
|
13
14
|
verbose: { type: "boolean", short: "v", default: false },
|
|
14
15
|
help: { type: "boolean", short: "h", default: false },
|
|
15
16
|
},
|
|
@@ -20,10 +21,12 @@ if (values.help || positionals.length === 0) {
|
|
|
20
21
|
|
|
21
22
|
Options:
|
|
22
23
|
--tsconfig <path> Path to tsconfig (default: tsconfig.build.json or tsconfig.json)
|
|
23
|
-
--
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
24
|
+
--stage-to <dir> Stage into <dir> instead of an auto-created temp dir.
|
|
25
|
+
Caller owns cleanup. Errors if <dir> is non-empty unless --force.
|
|
26
|
+
--skip-pack Skip the final \`npm pack\` step. Requires --stage-to.
|
|
27
|
+
--force With --stage-to, clear <dir> if it already has contents.
|
|
28
|
+
-v, --verbose Log each pipeline phase to stderr.
|
|
29
|
+
-h, --help Show this help message.
|
|
27
30
|
`);
|
|
28
31
|
process.exit(values.help ? 0 : 1);
|
|
29
32
|
}
|
|
@@ -33,8 +36,9 @@ const packageDir = resolve(positionals[0]);
|
|
|
33
36
|
try {
|
|
34
37
|
const result = await tsNodePack(packageDir, {
|
|
35
38
|
tsconfig: values.tsconfig,
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
skipPack: values["skip-pack"],
|
|
40
|
+
stageTo: values["stage-to"],
|
|
41
|
+
force: values.force,
|
|
38
42
|
verbose: values.verbose,
|
|
39
43
|
});
|
|
40
44
|
console.log(result);
|
package/src/index.d.ts
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
export interface TsNodePackOptions {
|
|
2
2
|
tsconfig?: string;
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Skip the final `npm pack` step. Requires `stageTo` (otherwise there
|
|
5
|
+
* is no way for the caller to access the staged contents).
|
|
6
|
+
*/
|
|
7
|
+
skipPack?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Stage directly into this directory instead of an auto-created temp
|
|
10
|
+
* dir. Caller owns cleanup. Errors if the directory already has
|
|
11
|
+
* contents, unless `force` is set.
|
|
12
|
+
*/
|
|
13
|
+
stageTo?: string;
|
|
14
|
+
/** With `stageTo`, clear the target directory if it already has contents. */
|
|
15
|
+
force?: boolean;
|
|
5
16
|
verbose?: boolean;
|
|
6
17
|
}
|
|
7
18
|
/**
|
|
8
19
|
* Main pipeline: pack a TypeScript package into a Node-compatible tarball.
|
|
9
|
-
* Returns the path to the .tgz file
|
|
20
|
+
* Returns the path to the .tgz file, or the staging directory when
|
|
21
|
+
* `skipPack` is set.
|
|
10
22
|
*/
|
|
11
23
|
export declare function tsNodePack(packageDir: string, options?: TsNodePackOptions): Promise<string>;
|
|
12
24
|
/**
|
package/src/index.js
CHANGED
|
@@ -21,22 +21,40 @@ const execFileAsync = promisify(execFile);
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
26
37
|
|
|
27
38
|
|
|
28
39
|
|
|
29
40
|
/**
|
|
30
41
|
* Main pipeline: pack a TypeScript package into a Node-compatible tarball.
|
|
31
|
-
* Returns the path to the .tgz file
|
|
42
|
+
* Returns the path to the .tgz file, or the staging directory when
|
|
43
|
+
* `skipPack` is set.
|
|
32
44
|
*/
|
|
33
45
|
export async function tsNodePack(
|
|
34
46
|
packageDir ,
|
|
35
47
|
options = {},
|
|
36
48
|
) {
|
|
37
|
-
const { tsconfig,
|
|
49
|
+
const { tsconfig, skipPack, stageTo, force, verbose } = options;
|
|
38
50
|
const log = verbose ? (...args ) => console.error("[ts-node-pack]", ...args) : () => {};
|
|
39
51
|
|
|
52
|
+
if (skipPack && !stageTo) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
"skipPack requires stageTo: caller must specify where to put the staged contents",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
40
58
|
packageDir = resolve(packageDir);
|
|
41
59
|
|
|
42
60
|
// ── Phase 1: Resolve package ──────────────────────────────────────────
|
|
@@ -48,11 +66,34 @@ export async function tsNodePack(
|
|
|
48
66
|
const tsconfigPath = resolveTsconfig(packageDir, tsconfig);
|
|
49
67
|
if (tsconfigPath) log(`Found tsconfig: ${tsconfigPath}`);
|
|
50
68
|
|
|
51
|
-
// ── Phase 2: Create staging
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
69
|
+
// ── Phase 2: Create work and staging directories ─────────────────────
|
|
70
|
+
// We always need a private work dir for auxiliary files (e.g.
|
|
71
|
+
// tsconfig.emit.json) that MUST NOT land inside the packed contents.
|
|
72
|
+
// In default mode the staging dir is nested inside the work dir, so
|
|
73
|
+
// cleaning up the work dir cleans up everything. In stageTo mode the
|
|
74
|
+
// staging dir is the caller's directory — we still create a small
|
|
75
|
+
// separate work dir for auxiliary files and rm only that in Phase 10.
|
|
76
|
+
log("Phase 2: Creating work and staging directories...");
|
|
77
|
+
const workDir = await mkdtemp(join(tmpdir(), "ts-node-pack-"));
|
|
78
|
+
let stagingDir ;
|
|
79
|
+
if (stageTo) {
|
|
80
|
+
stagingDir = resolve(stageTo);
|
|
81
|
+
if (existsSync(stagingDir)) {
|
|
82
|
+
const entries = await readdir(stagingDir);
|
|
83
|
+
if (entries.length > 0) {
|
|
84
|
+
if (!force) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`stageTo directory is not empty: ${stagingDir}. Pass force: true to clear it.`,
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
await rm(stagingDir, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
await mkdir(stagingDir, { recursive: true });
|
|
93
|
+
} else {
|
|
94
|
+
stagingDir = join(workDir, "package");
|
|
95
|
+
await mkdir(stagingDir, { recursive: true });
|
|
96
|
+
}
|
|
56
97
|
log(`Staging: ${stagingDir}`);
|
|
57
98
|
|
|
58
99
|
try {
|
|
@@ -100,7 +141,7 @@ export async function tsNodePack(
|
|
|
100
141
|
|
|
101
142
|
if (shouldRunTsc) {
|
|
102
143
|
log("Phase 4: Generating derived tsconfig...");
|
|
103
|
-
const emitConfigPath = join(
|
|
144
|
+
const emitConfigPath = join(workDir, "tsconfig.emit.json");
|
|
104
145
|
// tsc's typeRoots walk-up starts at the config's directory, so it
|
|
105
146
|
// can't reach packageDir/node_modules/@types from our temp-dir
|
|
106
147
|
// location. Pin typeRoots when that directory exists. (TS 6.0
|
|
@@ -187,26 +228,31 @@ export async function tsNodePack(
|
|
|
187
228
|
await validate(stagingDir, rewrittenPkg, log);
|
|
188
229
|
|
|
189
230
|
// ── Phase 9: Pack ─────────────────────────────────────────────────────
|
|
190
|
-
if (!
|
|
231
|
+
if (!skipPack) {
|
|
191
232
|
log("Phase 9: Packing...");
|
|
192
233
|
const tgzPath = await pack(stagingDir);
|
|
193
234
|
const tgzName = basename(tgzPath);
|
|
194
235
|
const dest = join(process.cwd(), tgzName);
|
|
195
236
|
await copyFile(tgzPath, dest);
|
|
237
|
+
// In stageTo mode the whole staging dir survives into the caller's
|
|
238
|
+
// filesystem, so the intermediate .tgz that `npm pack` wrote in
|
|
239
|
+
// there would stick around as visible clutter. Remove it. (In
|
|
240
|
+
// default mode the entire workDir is rm'd in Phase 10, so this
|
|
241
|
+
// unlink is redundant but harmless.)
|
|
242
|
+
if (stageTo) await unlink(tgzPath);
|
|
196
243
|
log(`Created: ${dest}`);
|
|
197
244
|
return dest;
|
|
198
245
|
}
|
|
199
246
|
|
|
200
|
-
log(`
|
|
247
|
+
log(`Skip-pack mode. Staging directory: ${stagingDir}`);
|
|
201
248
|
return stagingDir;
|
|
202
249
|
} finally {
|
|
203
250
|
// ── Phase 10: Cleanup ───────────────────────────────────────────────
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
251
|
+
// Always rm the work dir. In default mode this also removes the
|
|
252
|
+
// staging dir (nested inside). In stageTo mode the staging dir is
|
|
253
|
+
// the caller's directory and survives.
|
|
254
|
+
log("Phase 10: Cleaning up work directory...");
|
|
255
|
+
await rm(workDir, { recursive: true, force: true });
|
|
210
256
|
}
|
|
211
257
|
}
|
|
212
258
|
|