@vltpkg/package-json 1.0.0-rc.22 → 1.0.0-rc.24

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.
@@ -0,0 +1,27 @@
1
+ import type { NormalizedManifest } from '@vltpkg/types';
2
+ export declare class PackageJson {
3
+ #private;
4
+ /**
5
+ * Reads and parses contents of a `package.json` file at a directory `dir`.
6
+ * `reload` will optionally skip reading from the cache when set to `true`.
7
+ */
8
+ read(dir: string, { reload }?: {
9
+ reload?: boolean;
10
+ }): NormalizedManifest;
11
+ /**
12
+ * Optionally reads and parses contents of a `package.json` file at a
13
+ * directory `dir`. Returns `undefined` if it could not be read.
14
+ */
15
+ maybeRead(dir: string, { reload }?: {
16
+ reload?: boolean;
17
+ }): NormalizedManifest | undefined;
18
+ write(dir: string, manifest: NormalizedManifest, indent?: number): void;
19
+ save(manifest: NormalizedManifest): void;
20
+ fix(manifest: NormalizedManifest): void;
21
+ /**
22
+ * Walks up the directory tree from the current working directory
23
+ * and returns the path to the first `package.json` file found.
24
+ * Returns undefined if no package.json is found.
25
+ */
26
+ find(cwd?: string, home?: string): string | undefined;
27
+ }
package/dist/index.js ADDED
@@ -0,0 +1,131 @@
1
+ import { error } from '@vltpkg/error-cause';
2
+ import { asManifest, longDependencyTypes, normalizeManifest, } from '@vltpkg/types';
3
+ import { readFileSync, writeFileSync, lstatSync } from 'node:fs';
4
+ import { resolve } from 'node:path';
5
+ import { homedir } from 'node:os';
6
+ import { parse, stringify } from 'polite-json';
7
+ import { walkUp } from 'walk-up-path';
8
+ const exists = (path) => {
9
+ try {
10
+ lstatSync(path);
11
+ return true;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ };
17
+ export class PackageJson {
18
+ /**
19
+ * cache of `package.json` loads
20
+ */
21
+ #cache = new Map();
22
+ /**
23
+ * cache of `package.json` paths by manifest
24
+ */
25
+ #pathCache = new Map();
26
+ /**
27
+ * cache of load errors
28
+ */
29
+ #errCache = new Map();
30
+ /**
31
+ * Reads and parses contents of a `package.json` file at a directory `dir`.
32
+ * `reload` will optionally skip reading from the cache when set to `true`.
33
+ */
34
+ read(dir, { reload } = {}) {
35
+ const cachedPackageJson = !reload && this.#cache.get(dir);
36
+ if (cachedPackageJson) {
37
+ return cachedPackageJson;
38
+ }
39
+ const filename = dir.endsWith('package.json') ?
40
+ resolve(dir)
41
+ : resolve(dir, 'package.json');
42
+ const fail = (err) => error('Could not read package.json file', err, this.read);
43
+ const cachedError = !reload && this.#errCache.get(dir);
44
+ if (cachedError) {
45
+ throw fail(cachedError);
46
+ }
47
+ try {
48
+ const res = normalizeManifest(asManifest(parse(readFileSync(filename, { encoding: 'utf8' }))));
49
+ this.#cache.set(dir, res);
50
+ this.#pathCache.set(res, dir);
51
+ return res;
52
+ }
53
+ catch (err) {
54
+ const ec = {
55
+ path: filename,
56
+ cause: err,
57
+ };
58
+ this.#errCache.set(dir, ec);
59
+ throw fail(ec);
60
+ }
61
+ }
62
+ /**
63
+ * Optionally reads and parses contents of a `package.json` file at a
64
+ * directory `dir`. Returns `undefined` if it could not be read.
65
+ */
66
+ maybeRead(dir, { reload } = {}) {
67
+ try {
68
+ return this.read(dir, { reload });
69
+ }
70
+ catch {
71
+ return undefined;
72
+ }
73
+ }
74
+ write(dir, manifest, indent) {
75
+ const filename = dir.endsWith('package.json') ?
76
+ resolve(dir)
77
+ : resolve(dir, 'package.json');
78
+ this.fix(manifest);
79
+ try {
80
+ // This assumes kIndent and kNewline are already present on the manifest because we would
81
+ // only write a package.json after reading it which will set those properties.
82
+ writeFileSync(filename, stringify(manifest, undefined, indent));
83
+ this.#cache.set(dir, manifest);
84
+ this.#pathCache.set(manifest, dir);
85
+ }
86
+ catch (err) {
87
+ // If there was an error writing to this package.json then also delete it from our cache
88
+ // just in case a future read would get stale data.
89
+ this.#cache.delete(dir);
90
+ this.#pathCache.delete(manifest);
91
+ throw error('Could not write package.json file', {
92
+ path: filename,
93
+ cause: err,
94
+ }, this.write);
95
+ }
96
+ }
97
+ save(manifest) {
98
+ const dir = this.#pathCache.get(manifest);
99
+ if (!dir) {
100
+ throw error('Could not save manifest', {
101
+ manifest,
102
+ }, this.save);
103
+ }
104
+ this.write(dir, manifest);
105
+ }
106
+ fix(manifest) {
107
+ for (const depType of longDependencyTypes) {
108
+ const deps = manifest[depType];
109
+ if (deps) {
110
+ // should sort dependencies by name
111
+ manifest[depType] = Object.fromEntries(Object.entries(deps).sort(([a], [b]) => a.localeCompare(b, 'en')));
112
+ }
113
+ }
114
+ }
115
+ /**
116
+ * Walks up the directory tree from the current working directory
117
+ * and returns the path to the first `package.json` file found.
118
+ * Returns undefined if no package.json is found.
119
+ */
120
+ find(cwd = process.cwd(), home = homedir()) {
121
+ for (const dir of walkUp(cwd)) {
122
+ // don't look in home directory
123
+ if (dir === home)
124
+ break;
125
+ const packageJsonPath = resolve(dir, 'package.json');
126
+ if (exists(packageJsonPath)) {
127
+ return packageJsonPath;
128
+ }
129
+ }
130
+ }
131
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vltpkg/package-json",
3
3
  "description": "Manage reading package.json files",
4
- "version": "1.0.0-rc.22",
4
+ "version": "1.0.0-rc.24",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/vltpkg/vltpkg.git",
@@ -12,8 +12,8 @@
12
12
  "email": "support@vlt.sh"
13
13
  },
14
14
  "dependencies": {
15
- "@vltpkg/error-cause": "1.0.0-rc.22",
16
- "@vltpkg/types": "1.0.0-rc.22",
15
+ "@vltpkg/error-cause": "1.0.0-rc.24",
16
+ "@vltpkg/types": "1.0.0-rc.24",
17
17
  "polite-json": "^5.0.0",
18
18
  "walk-up-path": "^4.0.0"
19
19
  },
@@ -46,13 +46,13 @@
46
46
  "extends": "../../tap-config.yaml"
47
47
  },
48
48
  "prettier": "../../.prettierrc.js",
49
- "module": "./src/index.ts",
49
+ "module": "./dist/index.js",
50
50
  "type": "module",
51
51
  "exports": {
52
52
  "./package.json": "./package.json",
53
53
  ".": {
54
54
  "import": {
55
- "default": "./src/index.ts"
55
+ "default": "./dist/index.js"
56
56
  }
57
57
  }
58
58
  },