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 CHANGED
@@ -1,2 +1,64 @@
1
+ [![NPM version][npm-image]][npm-url] [![Build Status][build-image]][build-url]
2
+
1
3
  # pkg-preper
2
- Package Preparer
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
@@ -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.8",
3
+ "version": "0.2.1",
4
+ "homepage": "https://github.com/jchip/fynjs/tree/main/packages/pkg-preper",
4
5
  "description": "Package Preparer",
5
- "main": "lib/pkg-preper.js",
6
- "scripts": {},
7
- "keywords": [],
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
- "lib"
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/pkg-preper.git"
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
- "aveazul": "^1.0.2",
19
- "cacache": "^20.0.1",
20
- "mississippi": "^3.0.0",
21
- "npm-packlist": "^10.0.3",
22
- "opfs": "^1.0.6",
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;