pkg-preper 0.1.8 → 0.2.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 +63 -1
- package/dist/index.d.ts +30 -0
- package/dist/index.js +101 -0
- package/package.json +44 -14
- package/lib/pkg-preper.js +0 -122
package/README.md
CHANGED
|
@@ -1,2 +1,64 @@
|
|
|
1
|
+
[![NPM version][npm-image]][npm-url] [![Build Status][build-image]][build-url]
|
|
2
|
+
|
|
1
3
|
# pkg-preper
|
|
2
|
-
|
|
4
|
+
|
|
5
|
+
A [pacote] `dirPacker` that runs a package's `prepare` script before packing it.
|
|
6
|
+
|
|
7
|
+
When a dependency is installed from a git URL rather than the registry, what's in the repo is often source that has to be built first - that's what a `prepare` script is for. pacote will pack such a directory for you, but it won't build it. `pkg-preper` supplies the packer that does: it reads the directory's `package.json`, and if there's a `prepare` script it hands the directory to your `installDependencies` callback (which installs deps and runs the script) before packing the result into a tarball with [npm-packlist] and [tar].
|
|
8
|
+
|
|
9
|
+
Extracted from [fyn], which uses it for git dependencies.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install pkg-preper
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import PkgPreper from "pkg-preper";
|
|
21
|
+
import pacote from "pacote";
|
|
22
|
+
|
|
23
|
+
const preper = new PkgPreper({
|
|
24
|
+
tmpDir: "/path/to/tmp",
|
|
25
|
+
installDependencies: async (dir, message) => {
|
|
26
|
+
// install the package's dependencies in `dir` and run its prepare script
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await pacote.tarball(spec, { dirPacker: preper.getDirPackerCb() });
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
### `new PkgPreper({ tmpDir, installDependencies })`
|
|
36
|
+
|
|
37
|
+
- **`tmpDir`** - directory for [cacache]'s scratch space while packing
|
|
38
|
+
- **`installDependencies(dir, message)`** - called only when the package has a `prepare` script; return a promise
|
|
39
|
+
|
|
40
|
+
### `preper.getDirPackerCb()`
|
|
41
|
+
|
|
42
|
+
Returns the `(manifest, dir) => stream` callback to hand to pacote as its `dirPacker`.
|
|
43
|
+
|
|
44
|
+
### `preper.depDirPacker(manifest, dir)`
|
|
45
|
+
|
|
46
|
+
The packer itself, if you'd rather call it directly. Returns a stream of the packed tarball; emits `prepared` once the prepare step is done and `error` if anything fails.
|
|
47
|
+
|
|
48
|
+
### `preper.packDirectory(manifest, dir, target)`
|
|
49
|
+
|
|
50
|
+
Packs `dir` into a tarball at `target`, without the prepare step. Files are chosen by npm-packlist, so the package's `files` field and ignore rules are honored.
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
The packing code is adapted from the [npm CLI](https://github.com/npm/cli/blob/latest/lib/commands/pack.js), so this package is licensed under the [Artistic License 2.0](./LICENSE), same as the original.
|
|
55
|
+
|
|
56
|
+
[fyn]: https://github.com/jchip/fynjs/tree/main/packages/fyn
|
|
57
|
+
[pacote]: https://www.npmjs.com/package/pacote
|
|
58
|
+
[npm-packlist]: https://www.npmjs.com/package/npm-packlist
|
|
59
|
+
[tar]: https://www.npmjs.com/package/tar
|
|
60
|
+
[cacache]: https://www.npmjs.com/package/cacache
|
|
61
|
+
[npm-image]: https://badge.fury.io/js/pkg-preper.svg
|
|
62
|
+
[npm-url]: https://npmjs.org/package/pkg-preper
|
|
63
|
+
[build-image]: https://github.com/jchip/fynjs/actions/workflows/ci.yml/badge.svg
|
|
64
|
+
[build-url]: https://github.com/jchip/fynjs/actions/workflows/ci.yml
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { PassThrough } from "stream";
|
|
2
|
+
interface PackageJson {
|
|
3
|
+
name?: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
scripts?: {
|
|
6
|
+
prepare?: string;
|
|
7
|
+
[key: string]: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
}
|
|
11
|
+
interface Manifest {
|
|
12
|
+
_resolved?: string;
|
|
13
|
+
[key: string]: any;
|
|
14
|
+
}
|
|
15
|
+
type InstallDependenciesCallback = (dir: string, message: string) => Promise<any>;
|
|
16
|
+
interface PkgPreperOptions {
|
|
17
|
+
tmpDir: string;
|
|
18
|
+
installDependencies: InstallDependenciesCallback;
|
|
19
|
+
}
|
|
20
|
+
declare class PkgPreper {
|
|
21
|
+
private _tmpDir;
|
|
22
|
+
private _installDependencies;
|
|
23
|
+
constructor({ tmpDir, installDependencies }: PkgPreperOptions);
|
|
24
|
+
packDirectory(mani: Manifest, dir: string, target: string): Promise<void>;
|
|
25
|
+
depDirPacker(manifest: Manifest, dir: string): PassThrough;
|
|
26
|
+
getDirPackerCb(): (manifest: Manifest, dir: string) => PassThrough;
|
|
27
|
+
}
|
|
28
|
+
export default PkgPreper;
|
|
29
|
+
export { PkgPreper };
|
|
30
|
+
export type { PkgPreperOptions, Manifest, PackageJson, InstallDependenciesCallback };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
//
|
|
2
|
+
// With code copied from:
|
|
3
|
+
//
|
|
4
|
+
// https://github.com/npm/cli/blob/58ece8973f43c77b1f4f44ded0f49556ad30eb57/lib/pack.js
|
|
5
|
+
//
|
|
6
|
+
// Licensed under The Artistic License 2.0 as the original code.
|
|
7
|
+
//
|
|
8
|
+
// Heavily modified to allow custom callback hooks
|
|
9
|
+
//
|
|
10
|
+
// Prepare packages that did not come from npm registry, therefore may not
|
|
11
|
+
// have gone through the standard npm publish process, and npm scripts such
|
|
12
|
+
// as prepare may not have been executed.
|
|
13
|
+
//
|
|
14
|
+
// So if npm script prepare exist, then need to install dependencies (with dev)
|
|
15
|
+
// for the package, execute the prepare script, and finally pack files into
|
|
16
|
+
// tgz file for pacote.
|
|
17
|
+
//
|
|
18
|
+
import * as cacache from "cacache";
|
|
19
|
+
import * as Path from "path";
|
|
20
|
+
import { PassThrough } from "stream";
|
|
21
|
+
import { pipeline } from "node:stream/promises";
|
|
22
|
+
import * as tar from "tar";
|
|
23
|
+
import packlist from "npm-packlist";
|
|
24
|
+
import * as Fs from "node:fs";
|
|
25
|
+
import * as FsPromises from "node:fs/promises";
|
|
26
|
+
const readPkgJson = (dir) => {
|
|
27
|
+
return FsPromises.readFile(Path.join(dir, "package.json")).then((data) => JSON.parse(data.toString().trim()));
|
|
28
|
+
};
|
|
29
|
+
class PkgPreper {
|
|
30
|
+
constructor({ tmpDir, installDependencies }) {
|
|
31
|
+
this._tmpDir = tmpDir;
|
|
32
|
+
this._installDependencies = installDependencies;
|
|
33
|
+
}
|
|
34
|
+
packDirectory(mani, dir, target) {
|
|
35
|
+
return readPkgJson(dir).then((pkg) => {
|
|
36
|
+
return cacache.tmp.withTmp(this._tmpDir, { tmpPrefix: "packing" }, (tmp) => {
|
|
37
|
+
const tmpTarget = Path.join(tmp, Path.basename(target));
|
|
38
|
+
const tarOpt = {
|
|
39
|
+
file: tmpTarget,
|
|
40
|
+
cwd: dir,
|
|
41
|
+
prefix: "package/",
|
|
42
|
+
portable: true,
|
|
43
|
+
// Provide a specific date in the 1980s for the benefit of zip,
|
|
44
|
+
// which is confounded by files dated at the Unix epoch 0.
|
|
45
|
+
mtime: new Date("1985-10-26T08:15:00.000Z"),
|
|
46
|
+
gzip: true,
|
|
47
|
+
};
|
|
48
|
+
// npm-packlist 10+ expects an @npmcli/arborist tree node. Provide a
|
|
49
|
+
// minimal stand-in with the fields the walker actually reads (path,
|
|
50
|
+
// package, isProjectRoot, edgesOut) to avoid pulling in arborist.
|
|
51
|
+
const treeStub = {
|
|
52
|
+
path: dir,
|
|
53
|
+
package: pkg,
|
|
54
|
+
isProjectRoot: true,
|
|
55
|
+
edgesOut: new Map(),
|
|
56
|
+
};
|
|
57
|
+
return Promise.resolve(packlist(treeStub))
|
|
58
|
+
.then((files) => {
|
|
59
|
+
// NOTE: node-tar does some Magic Stuff depending on prefixes for files
|
|
60
|
+
// specifically with @ signs, so we just neutralize that one
|
|
61
|
+
// and any such future "features" by prepending `./`
|
|
62
|
+
return tar.create(tarOpt, files.map((f) => `./${f}`));
|
|
63
|
+
})
|
|
64
|
+
.then(() => FsPromises.rename(tmpTarget, target))
|
|
65
|
+
.then(() => undefined);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//
|
|
70
|
+
// dirPacker for pacote when retrieving packages from remote, particularly github
|
|
71
|
+
// reference: https://github.com/npm/cli/blob/58ece8973f43c77b1f4f44ded0f49556ad30eb57/lib/pack.js#L293
|
|
72
|
+
//
|
|
73
|
+
depDirPacker(manifest, dir) {
|
|
74
|
+
const stream = new PassThrough();
|
|
75
|
+
readPkgJson(dir)
|
|
76
|
+
.then((pkg) => {
|
|
77
|
+
if (pkg.scripts && pkg.scripts.prepare) {
|
|
78
|
+
return this._installDependencies(dir, `preparing gitdep package ${pkg.name} from ${manifest._resolved}`);
|
|
79
|
+
}
|
|
80
|
+
return Promise.resolve();
|
|
81
|
+
})
|
|
82
|
+
.then(() => stream.emit("prepared"))
|
|
83
|
+
.then(() => {
|
|
84
|
+
return cacache.tmp.withTmp(this._tmpDir, { tmpPrefix: "pacote-packing" }, (tmp) => {
|
|
85
|
+
const tmpTar = Path.join(tmp, "package.tgz");
|
|
86
|
+
return this.packDirectory(manifest, dir, tmpTar).then(() => {
|
|
87
|
+
return pipeline(Fs.createReadStream(tmpTar), stream);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
})
|
|
91
|
+
.catch((err) => {
|
|
92
|
+
stream.emit("error", err);
|
|
93
|
+
});
|
|
94
|
+
return stream;
|
|
95
|
+
}
|
|
96
|
+
getDirPackerCb() {
|
|
97
|
+
return (m, d) => this.depDirPacker(m, d);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export default PkgPreper;
|
|
101
|
+
export { PkgPreper };
|
package/package.json
CHANGED
|
@@ -1,26 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pkg-preper",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"homepage": "https://github.com/jchip/fynjs/tree/main/packages/pkg-preper",
|
|
4
5
|
"description": "Package Preparer",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
6
|
+
"type": "module",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22.12.0"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "rm -rf dist && tsc -p tsconfig.json",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"ci:check": "tsc --noEmit -p tsconfig.json && npm test",
|
|
23
|
+
"coverage": "vitest run --coverage",
|
|
24
|
+
"prepublishOnly": "xrun build",
|
|
25
|
+
"postpack": "publish-util-postpack"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"registry": "https://registry.npmjs.org/"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"npm",
|
|
32
|
+
"package",
|
|
33
|
+
"pack",
|
|
34
|
+
"tarball",
|
|
35
|
+
"prepare"
|
|
36
|
+
],
|
|
8
37
|
"files": [
|
|
9
|
-
"
|
|
38
|
+
"dist"
|
|
10
39
|
],
|
|
11
40
|
"author": "Joel Chen <joel123@gmail.com>",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/jchip/fynjs/issues"
|
|
43
|
+
},
|
|
12
44
|
"repository": {
|
|
13
45
|
"type": "git",
|
|
14
|
-
"url": "https://github.com/jchip/
|
|
46
|
+
"url": "git+https://github.com/jchip/fynjs.git",
|
|
47
|
+
"directory": "packages/pkg-preper"
|
|
15
48
|
},
|
|
16
49
|
"license": "Artistic-2.0",
|
|
17
50
|
"dependencies": {
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"tar": "^4.4.6",
|
|
24
|
-
"visual-exec": "^0.1.0"
|
|
25
|
-
}
|
|
51
|
+
"cacache": "^21.0.0",
|
|
52
|
+
"npm-packlist": "^11.3.0",
|
|
53
|
+
"tar": "^7.5.22"
|
|
54
|
+
},
|
|
55
|
+
"sideEffects": false
|
|
26
56
|
}
|
package/lib/pkg-preper.js
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
//
|
|
4
|
-
// With code copied from:
|
|
5
|
-
//
|
|
6
|
-
// https://github.com/npm/cli/blob/58ece8973f43c77b1f4f44ded0f49556ad30eb57/lib/pack.js
|
|
7
|
-
//
|
|
8
|
-
// Licensed under The Artistic License 2.0 as the original code.
|
|
9
|
-
//
|
|
10
|
-
// Heavily modified to allow custom callback hooks
|
|
11
|
-
//
|
|
12
|
-
// Prepare packages that did not come from npm registry, therefore may not
|
|
13
|
-
// have gone through the standard npm publish process, and npm scripts such
|
|
14
|
-
// as prepare may not have been executed.
|
|
15
|
-
//
|
|
16
|
-
// So if npm script prepare exist, then need to install dependencies (with dev)
|
|
17
|
-
// for the package, execute the prepare script, and finally pack files into
|
|
18
|
-
// tgz file for pacote.
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
const cacache = require("cacache");
|
|
22
|
-
const Path = require("path");
|
|
23
|
-
const Promise = require("aveazul");
|
|
24
|
-
const PassThrough = require("stream").PassThrough;
|
|
25
|
-
const mississippi = require("mississippi");
|
|
26
|
-
const pipe = Promise.promisify(mississippi.pipe, { context: mississippi });
|
|
27
|
-
const tar = require("tar");
|
|
28
|
-
const packlist = require("npm-packlist");
|
|
29
|
-
const Fs = require("opfs");
|
|
30
|
-
|
|
31
|
-
const readPkgJson = (dir) => {
|
|
32
|
-
return Fs.readFile(Path.join(dir, "package.json").toString().trim()).then(JSON.parse);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
class PkgPreper {
|
|
36
|
-
constructor({ tmpDir, installDependencies }) {
|
|
37
|
-
this._tmpDir = tmpDir;
|
|
38
|
-
this._installDependencies = installDependencies;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
packDirectory(mani, dir, target) {
|
|
42
|
-
return (
|
|
43
|
-
readPkgJson(dir)
|
|
44
|
-
// .then(pkg => {
|
|
45
|
-
// return lifecycle(pkg, "prepack", dir);
|
|
46
|
-
// })
|
|
47
|
-
// .then(() => {
|
|
48
|
-
// return readJson(path.join(dir, "package.json"));
|
|
49
|
-
// })
|
|
50
|
-
.then((pkg) => {
|
|
51
|
-
return cacache.tmp.withTmp(this._tmpDir, { tmpPrefix: "packing" }, (tmp) => {
|
|
52
|
-
const tmpTarget = Path.join(tmp, Path.basename(target));
|
|
53
|
-
|
|
54
|
-
const tarOpt = {
|
|
55
|
-
file: tmpTarget,
|
|
56
|
-
cwd: dir,
|
|
57
|
-
prefix: "package/",
|
|
58
|
-
portable: true,
|
|
59
|
-
// Provide a specific date in the 1980s for the benefit of zip,
|
|
60
|
-
// which is confounded by files dated at the Unix epoch 0.
|
|
61
|
-
mtime: new Date("1985-10-26T08:15:00.000Z"),
|
|
62
|
-
gzip: true,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
return Promise.resolve(packlist({ path: dir }))
|
|
66
|
-
.then((files) => {
|
|
67
|
-
// NOTE: node-tar does some Magic Stuff depending on prefixes for files
|
|
68
|
-
// specifically with @ signs, so we just neutralize that one
|
|
69
|
-
// and any such future "features" by prepending `./`
|
|
70
|
-
return tar.create(
|
|
71
|
-
tarOpt,
|
|
72
|
-
files.map((f) => `./${f}`)
|
|
73
|
-
);
|
|
74
|
-
})
|
|
75
|
-
.tap(() => Fs.rename(tmpTarget, target));
|
|
76
|
-
// .then(() => getContents(pkg, tmpTarget, filename, logIt))
|
|
77
|
-
// // thread the content info through
|
|
78
|
-
// .tap(() => move(tmpTarget, target, { Promise: BB, fs }))
|
|
79
|
-
// .tap(() => lifecycle(pkg, "postpack", dir))
|
|
80
|
-
});
|
|
81
|
-
})
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
// dirPacker for pacote when retrieving packages from remote, particularly github
|
|
87
|
-
// reference: https://github.com/npm/cli/blob/58ece8973f43c77b1f4f44ded0f49556ad30eb57/lib/pack.js#L293
|
|
88
|
-
//
|
|
89
|
-
depDirPacker(manifest, dir) {
|
|
90
|
-
const stream = new PassThrough();
|
|
91
|
-
|
|
92
|
-
readPkgJson(dir)
|
|
93
|
-
.then((pkg) => {
|
|
94
|
-
if (pkg.scripts && pkg.scripts.prepare) {
|
|
95
|
-
return this._installDependencies(
|
|
96
|
-
dir,
|
|
97
|
-
`preparing gitdep package ${pkg.name} from ${manifest._resolved}`
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
})
|
|
101
|
-
.tap(() => stream.emit("prepared"))
|
|
102
|
-
.then(() => {
|
|
103
|
-
return cacache.tmp.withTmp(this._tmpDir, { tmpPrefix: "pacote-packing" }, (tmp) => {
|
|
104
|
-
const tmpTar = Path.join(tmp, "package.tgz");
|
|
105
|
-
return this.packDirectory(manifest, dir, tmpTar).then(() => {
|
|
106
|
-
return pipe(Fs.createReadStream(tmpTar), stream);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
})
|
|
110
|
-
.catch((err) => {
|
|
111
|
-
stream.emit("error", err);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
return stream;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
getDirPackerCb() {
|
|
118
|
-
return (m, d) => this.depDirPacker(m, d);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
module.exports = PkgPreper;
|