@cubing/dev-config 0.6.6 → 0.7.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
@@ -50,6 +50,12 @@ bun add @biomejs/biome @cubing/dev-config
50
50
  bun x @biomejs/biome check
51
51
  ```
52
52
 
53
+ Add to a project using [`repo`](https://github.com/lgarron/repo):
54
+
55
+ ```shell
56
+ repo boilerplate biome add # Or invoke using `npx repo …` / `bun x repo …`
57
+ ```
58
+
53
59
  ### TypeScript
54
60
 
55
61
  #### Check types
@@ -72,6 +78,12 @@ bun add --dev typescript @cubing/dev-config
72
78
  bun x tsc --noEmit --project .
73
79
  ```
74
80
 
81
+ Add to a project using [`repo`](https://github.com/lgarron/repo):
82
+
83
+ ```shell
84
+ repo boilerplate tsconfig add # Or invoke using `npx repo …` / `bun x repo …`
85
+ ```
86
+
75
87
  #### Build types
76
88
 
77
89
  ```jsonc
@@ -95,6 +107,12 @@ bun add --dev typescript @cubing/dev-config
95
107
  bun x tsc --project .
96
108
  ```
97
109
 
110
+ Add to a project using [`repo`](https://github.com/lgarron/repo):
111
+
112
+ ```shell
113
+ repo boilerplate tsconfig add # Or invoke using `npx repo …` / `bun x repo …`
114
+ ```
115
+
98
116
  #### No DOM
99
117
 
100
118
  Use the `no-dom` variant instead:
@@ -106,6 +124,12 @@ Use the `no-dom` variant instead:
106
124
  }
107
125
  ```
108
126
 
127
+ Add to a project using [`repo`](https://github.com/lgarron/repo):
128
+
129
+ ```shell
130
+ repo boilerplate tsconfig add --no-dom # Or invoke using `npx repo …` / `bun x repo …`
131
+ ```
132
+
109
133
  ### `es2024`
110
134
 
111
135
  The following are also available:
@@ -115,6 +139,13 @@ The following are also available:
115
139
 
116
140
  This is useful for features like `Promise.withResolvers(…)`.
117
141
 
142
+ Add to a project using [`repo`](https://github.com/lgarron/repo):
143
+
144
+ ```shell
145
+ repo boilerplate tsconfig add --module es2022 # Or invoke using `npx repo …` / `bun x repo …`
146
+ repo boilerplate tsconfig add --no-dom --module es2022 # Or invoke using `npx repo …` / `bun x repo …`
147
+ ```
148
+
118
149
  ### Checking `package.json` for a project
119
150
 
120
151
  Run as follows:
@@ -0,0 +1,580 @@
1
+ #!/usr/bin/env -S bun run --
2
+ import {
3
+ __callDispose,
4
+ __using
5
+ } from "../../chunks/chunk-OZDRWEHO.js";
6
+
7
+ // src/bin/package.json/index.ts
8
+ import assert from "node:assert";
9
+ import { constants } from "node:fs/promises";
10
+ import { argv, exit } from "node:process";
11
+ import { semver } from "bun";
12
+ import { Path, ResolutionPrefix, stringifyIfPath } from "path-class";
13
+ import { PrintableShellCommand } from "printable-shell-command";
14
+ function categorize(v) {
15
+ if (Array.isArray(v)) {
16
+ return "array";
17
+ }
18
+ if (v === null) {
19
+ return "null";
20
+ }
21
+ return typeof v;
22
+ }
23
+ function* withOrderingMetadata(iter) {
24
+ let previous;
25
+ for (const value of iter) {
26
+ if (previous) {
27
+ yield previous[0];
28
+ previous = [
29
+ { value, previous: { value: previous[0].value }, isLast: false }
30
+ ];
31
+ } else {
32
+ previous = [{ value, previous: null, isLast: false }];
33
+ }
34
+ }
35
+ if (previous) {
36
+ yield { ...previous[0], isLast: true };
37
+ }
38
+ }
39
+ function traverse(breadcrumbs, options) {
40
+ assert(breadcrumbs.length > 0);
41
+ let maybeValue = [packageJSON];
42
+ let breadcrumbString = "";
43
+ for (let { value: breadcrumb, isLast } of withOrderingMetadata(breadcrumbs)) {
44
+ if (Array.isArray(breadcrumb)) {
45
+ assert(breadcrumb.length === 1);
46
+ assert(typeof breadcrumb[0] === "string");
47
+ breadcrumb = breadcrumb[0];
48
+ breadcrumbString += `[${JSON.stringify(breadcrumb)}]`;
49
+ } else if (typeof breadcrumb === "string") {
50
+ breadcrumbString += `.${breadcrumb}`;
51
+ } else {
52
+ breadcrumbString += `[${breadcrumb}]`;
53
+ }
54
+ if (options && "set" in options && isLast) {
55
+ if (!maybeValue || !["array", "object"].includes(categorize(maybeValue[0]))) {
56
+ throw new Error(
57
+ "Missing (but expected) traversal path while setting a value"
58
+ );
59
+ }
60
+ maybeValue[0][breadcrumb] = stringifyIfPath(options.set);
61
+ } else if (maybeValue && ["array", "object"].includes(categorize(maybeValue[0])) && breadcrumb in maybeValue[0]) {
62
+ maybeValue = [maybeValue[0][breadcrumb]];
63
+ } else {
64
+ maybeValue = null;
65
+ }
66
+ }
67
+ return { breadcrumbString, maybeValue };
68
+ }
69
+ function field(breadcrumbs, type, options) {
70
+ const mustBePopulatedMessage = () => options?.mustBePopulatedMessage ?? "Field must be populated.";
71
+ const { breadcrumbString, maybeValue } = traverse(breadcrumbs);
72
+ if (!maybeValue) {
73
+ if (options?.optional) {
74
+ if (!options.skipPrintingSuccess) {
75
+ console.log(`\u2611\uFE0F ${breadcrumbString}`);
76
+ }
77
+ return;
78
+ } else {
79
+ console.log(`\u274C ${breadcrumbString} \u2014 ${mustBePopulatedMessage()}`);
80
+ exitCode = 1;
81
+ return;
82
+ }
83
+ }
84
+ const [value] = maybeValue;
85
+ const typeArray = Array.isArray(type) ? type : [type];
86
+ const category = categorize(value);
87
+ if (typeArray.includes(category)) {
88
+ for (const [failureMessage, fn] of Object.entries(
89
+ options?.additionalChecks ?? {}
90
+ )) {
91
+ if (!fn) {
92
+ console.log(`\u274C ${breadcrumbString} | ${failureMessage}`);
93
+ exitCode = 1;
94
+ return;
95
+ }
96
+ }
97
+ if (!options?.skipPrintingSuccess) {
98
+ console.log(`\u2705 ${breadcrumbString}`);
99
+ }
100
+ } else {
101
+ if (category === "undefined") {
102
+ console.log(`\u274C ${breadcrumbString} \u2014 ${mustBePopulatedMessage()}.`);
103
+ } else if (type === "undefined") {
104
+ console.log(
105
+ `\u274C ${breadcrumbString} \u2014 Field is populated (but must not be).`
106
+ );
107
+ } else {
108
+ if (Array.isArray(type)) {
109
+ console.log(
110
+ `\u274C ${breadcrumbString} \u2014 Does not match an expected type: ${type.join(", ")}`
111
+ );
112
+ } else {
113
+ console.log(
114
+ `\u274C ${breadcrumbString} \u2014 Does not match expected type: ${type}`
115
+ );
116
+ }
117
+ }
118
+ exitCode = 1;
119
+ return;
120
+ }
121
+ }
122
+ function mustNotBePopulated(breadcrumbs) {
123
+ const { breadcrumbString, maybeValue } = traverse(breadcrumbs);
124
+ if (maybeValue) {
125
+ console.log(`\u274C ${breadcrumbString} \u2014 Must not be present.`);
126
+ exitCode = 1;
127
+ return;
128
+ }
129
+ }
130
+ function checkPath(breadcrumbs, options) {
131
+ const { breadcrumbString, maybeValue } = traverse(breadcrumbs);
132
+ if (!maybeValue) {
133
+ return;
134
+ }
135
+ const [value] = maybeValue;
136
+ checks.push(
137
+ (async () => {
138
+ if (typeof value !== "string") {
139
+ exitCode = 1;
140
+ return `\u274C ${breadcrumbString} \u2014 Non-string value`;
141
+ }
142
+ if (value.includes("*")) {
143
+ return `\u23ED\uFE0F ${breadcrumbString} \u2014 Skipping due to glob (*) \u2014 ${value}`;
144
+ }
145
+ const unresolvedPath = new Path(value);
146
+ if (unresolvedPath.resolutionPrefix !== options.expectPrefix) {
147
+ if (unresolvedPath.resolutionPrefix === ResolutionPrefix.Absolute) {
148
+ exitCode = 1;
149
+ return `\u274C ${breadcrumbString} \u2014 Incorrect resolution prefix (${unresolvedPath.resolutionPrefix}) \u2014 ${value}`;
150
+ } else {
151
+ switch (subcommand) {
152
+ case "check": {
153
+ exitCode = 1;
154
+ foundFixableErrors = true;
155
+ return `\u274C ${breadcrumbString} \u2014 Incorrect resolution prefix (${unresolvedPath.resolutionPrefix}) \u2014 \u{1F4DD} fixable! \u2014 ${value}`;
156
+ }
157
+ case "format": {
158
+ console.log(
159
+ `\u{1F4DD} \u2014 Incorrect resolution prefix (${unresolvedPath.resolutionPrefix}) \u2014 fixing! \u2014 ${value}`
160
+ );
161
+ const newPath = options.expectPrefix === ResolutionPrefix.Bare ? unresolvedPath.asBare() : unresolvedPath.asRelative();
162
+ traverse(breadcrumbs, { set: newPath });
163
+ break;
164
+ }
165
+ default:
166
+ throw new Error("Invalid subcommand.");
167
+ }
168
+ }
169
+ }
170
+ if (unresolvedPath.path.startsWith("../") || unresolvedPath.path === "..") {
171
+ exitCode = 1;
172
+ return `\u274C ${breadcrumbString} \u2014 Invalid traversal of parent path. \u2014 ${value}`;
173
+ }
174
+ const resolvedPath = Path.resolve(unresolvedPath, extractedRoot);
175
+ if (!await resolvedPath.existsAsFile()) {
176
+ exitCode = 1;
177
+ return `\u274C ${breadcrumbString} \u2014 Path must be present in the package. \u2014 ${value}`;
178
+ }
179
+ if (options.mustBeExecutable) {
180
+ if (!((await resolvedPath.stat()).mode ^ constants.X_OK)) {
181
+ return `\u274C ${breadcrumbString} \u2014 File at path must be executable. \u2014 ${value}`;
182
+ }
183
+ }
184
+ return `\u2705 ${breadcrumbString} \u2014 Path must be present in the package. \u2014 ${value}`;
185
+ })()
186
+ );
187
+ }
188
+ var _stack = [];
189
+ try {
190
+ var PERMITTED_LICENSES = /* @__PURE__ */ new Set([
191
+ "MPL-2.0",
192
+ "MIT",
193
+ "Unlicense",
194
+ "GPL-3.0-or-later"
195
+ ]);
196
+ var subcommand = (() => {
197
+ const subcommand2 = argv[2];
198
+ if (!["check", "format"].includes(subcommand2)) {
199
+ console.error("Must specify subcommand: `check` or `format`");
200
+ exit(1);
201
+ }
202
+ return subcommand2;
203
+ })();
204
+ var exitCode = 0;
205
+ var foundFixableErrors = false;
206
+ var PACKAGE_JSON_PATH = new Path("./package.json");
207
+ console.log("Parsing `package.json`:");
208
+ var packageJSONString = await PACKAGE_JSON_PATH.readText();
209
+ var packageJSON = (() => {
210
+ try {
211
+ const packageJSON2 = JSON.parse(packageJSONString);
212
+ console.log("\u2705 `package.json` is valid JSON.");
213
+ return packageJSON2;
214
+ } catch {
215
+ console.log(
216
+ "\u274C `package.json` must be valid JSON (not JSONC or JSON5 or anything else)."
217
+ );
218
+ exit(1);
219
+ }
220
+ })();
221
+ console.log("Checking field order:");
222
+ var opinionatedFieldOrder = [
223
+ "name",
224
+ "version",
225
+ "homepage",
226
+ "description",
227
+ "author",
228
+ "license",
229
+ "repository",
230
+ "engines",
231
+ "os",
232
+ "cpu",
233
+ "type",
234
+ "main",
235
+ "types",
236
+ "module",
237
+ "browser",
238
+ "exports",
239
+ "bin",
240
+ "dependencies",
241
+ "devDependencies",
242
+ "optionalDependencies",
243
+ "peerDependencies",
244
+ "bundleDependencies",
245
+ "devEngines",
246
+ "files",
247
+ "scripts",
248
+ "keywords",
249
+ "@cubing/deploy",
250
+ "$schema"
251
+ ];
252
+ var opinionatedFields = new Set(opinionatedFieldOrder);
253
+ var packageJSONOrder = [];
254
+ for (const key in packageJSON) {
255
+ if (opinionatedFields.has(key)) {
256
+ packageJSONOrder.push(key);
257
+ } else {
258
+ console.warn(`\u26A0\uFE0F [${JSON.stringify(key)}] Unexpected field.`);
259
+ }
260
+ }
261
+ var packageJSONByOpinionatedOrder = [];
262
+ for (const field2 of opinionatedFieldOrder) {
263
+ if (field2 in packageJSON) {
264
+ packageJSONByOpinionatedOrder.push(field2);
265
+ }
266
+ }
267
+ try {
268
+ assert.deepEqual(packageJSONOrder, packageJSONByOpinionatedOrder);
269
+ console.log(`\u2705 Field order is good.`);
270
+ } catch {
271
+ switch (subcommand) {
272
+ case "check": {
273
+ console.log(`\u274C Found opinionated fields out of order:`);
274
+ console.log(`\u21A4 ${packageJSONOrder.join(", ")}`);
275
+ console.log("Expected:");
276
+ console.log(`\u21A6 ${packageJSONByOpinionatedOrder.join(", ")}`);
277
+ console.log(
278
+ "\u{1F4DD} Run with the `sort` subcommand to sort. (Additional fields will kept after the field they previously followed.)"
279
+ );
280
+ foundFixableErrors = true;
281
+ exitCode = 1;
282
+ break;
283
+ }
284
+ case "format": {
285
+ console.log("\u{1F4DD} Invalid field order. Formatting\u2026");
286
+ exitCode = 1;
287
+ const newKeyOrder = [];
288
+ for (const key of packageJSONByOpinionatedOrder) {
289
+ newKeyOrder.push(key);
290
+ }
291
+ for (const { value: key, previous } of withOrderingMetadata(
292
+ Object.keys(packageJSON)
293
+ )) {
294
+ if (newKeyOrder.includes(key)) {
295
+ continue;
296
+ }
297
+ if (!previous) {
298
+ newKeyOrder.unshift(key);
299
+ } else {
300
+ const { value: previousKey } = previous;
301
+ const idx = newKeyOrder.indexOf(previousKey);
302
+ newKeyOrder.splice(idx + 1, 0, key);
303
+ }
304
+ }
305
+ const newPackageJSON = {};
306
+ for (const key of newKeyOrder) {
307
+ newPackageJSON[key] = packageJSON[key];
308
+ }
309
+ packageJSON = newPackageJSON;
310
+ break;
311
+ }
312
+ default:
313
+ throw new Error("Invalid subcommand.");
314
+ }
315
+ }
316
+ console.log("Checking presence and type of fields:");
317
+ field(["name"], "string");
318
+ field(["version"], "string", {
319
+ additionalChecks: {
320
+ "Version must parse successfully.": (version) => semver.order(version, version) === 0
321
+ }
322
+ });
323
+ field(["homepage"], "string", { optional: true });
324
+ field(["description"], "string");
325
+ field(["author"], ["string", "object"]);
326
+ if (categorize(packageJSON["author"]) === "object") {
327
+ field(["author", "name"], "string");
328
+ field(["author", "email"], "string");
329
+ field(["author", "url"], "string", {
330
+ additionalChecks: {
331
+ "URL must parse.": (url) => {
332
+ try {
333
+ new URL(url);
334
+ return true;
335
+ } catch {
336
+ return false;
337
+ }
338
+ }
339
+ }
340
+ });
341
+ }
342
+ field(["license"], "string", {
343
+ additionalChecks: {
344
+ "Must contain a non-permitted license.": (license) => {
345
+ for (const licenseEntry of license.split(" OR ")) {
346
+ if (!PERMITTED_LICENSES.has(licenseEntry)) {
347
+ return false;
348
+ }
349
+ }
350
+ return true;
351
+ }
352
+ }
353
+ });
354
+ field(["repository"], "object");
355
+ field(["repository", "type"], "string");
356
+ var GIT_URL_PREFIX = "git+";
357
+ var GIT_URL_SUFFIX = ".";
358
+ field(["repository", "url"], "string", {
359
+ additionalChecks: {
360
+ [`URL must be prefixed with \`${GIT_URL_PREFIX}\`.`]: (url) => url.startsWith(GIT_URL_PREFIX),
361
+ [`URL must end with with \`.${GIT_URL_SUFFIX}\`.`]: (url) => url.endsWith(GIT_URL_SUFFIX),
362
+ "URL must parse.": (url) => {
363
+ try {
364
+ new URL(url.slice());
365
+ return true;
366
+ } catch {
367
+ return false;
368
+ }
369
+ }
370
+ }
371
+ });
372
+ field(["engines"], "object", { optional: true });
373
+ field(["os"], "array", { optional: true });
374
+ field(["cpu"], "array", { optional: true });
375
+ field(["type"], "string", {
376
+ additionalChecks: {
377
+ 'Type must be `"module"`.': (type) => type === "module"
378
+ }
379
+ });
380
+ var mainOrTypesArePopoulated = (() => {
381
+ if ("main" in packageJSON || "types" in packageJSON) {
382
+ field(["main"], "string", {
383
+ mustBePopulatedMessage: 'Must be populated if "types" is populated.'
384
+ });
385
+ field(["types"], "string", {
386
+ mustBePopulatedMessage: 'Must be populated if "main" is populated.'
387
+ });
388
+ return true;
389
+ } else {
390
+ console.log("\u2611\uFE0F .main");
391
+ console.log("\u2611\uFE0F .types");
392
+ return false;
393
+ }
394
+ })();
395
+ mustNotBePopulated(["module"]);
396
+ mustNotBePopulated(["browser"]);
397
+ field(["exports"], "object", { optional: !mainOrTypesArePopoulated });
398
+ field(["bin"], "object", { optional: true });
399
+ field(["dependencies"], "object", { optional: true });
400
+ field(["devDependencies"], "object", { optional: true });
401
+ field(["optionalDependencies"], "object", { optional: true });
402
+ field(["peerDependencies"], "object", { optional: true });
403
+ field(["bundleDependencies"], "object", { optional: true });
404
+ field(["devEngines"], "object", { optional: true });
405
+ field(["files"], "array");
406
+ field(["scripts"], "object");
407
+ field(["scripts", "prepublishOnly"], "string");
408
+ console.log("Checking paths of binaries and exports:");
409
+ var tempDir = await Path.makeTempDir();
410
+ var tempDirDisposable = __using(_stack, {
411
+ [Symbol.asyncDispose]: async () => {
412
+ console.log("Disposing\u2026");
413
+ await tempDir.rm_rf();
414
+ }
415
+ }, true);
416
+ var extractionDir = await tempDir.join("extracted").mkdir();
417
+ var data = await new PrintableShellCommand("npm", [
418
+ "pack",
419
+ "--json",
420
+ "--ignore-scripts",
421
+ ["--pack-destination", tempDir]
422
+ ]).print().json();
423
+ var tgzPath = tempDir.join(data[0].filename);
424
+ await new PrintableShellCommand("tar", [
425
+ ["-C", extractionDir],
426
+ ["-xvzf", tgzPath]
427
+ ]).spawn().success;
428
+ var extractedRoot = extractionDir.join("package/");
429
+ assert(await extractedRoot.existsAsDir());
430
+ var checks = [];
431
+ checkPath(["main"], { expectPrefix: ResolutionPrefix.Relative });
432
+ checkPath(["types"], { expectPrefix: ResolutionPrefix.Relative });
433
+ checkPath(["module"], { expectPrefix: ResolutionPrefix.Relative });
434
+ checkPath(["browser"], { expectPrefix: ResolutionPrefix.Relative });
435
+ var { exports } = packageJSON;
436
+ if (exports) {
437
+ for (const [subpath, value] of Object.entries(exports)) {
438
+ if (!value) {
439
+ continue;
440
+ } else if (typeof value === "string") {
441
+ checkPath(["exports", [subpath]], {
442
+ expectPrefix: ResolutionPrefix.Relative
443
+ });
444
+ } else if (value === null) {
445
+ continue;
446
+ } else if (Array.isArray(value)) {
447
+ throw new Error(
448
+ "\u274C .exports \u2014 Must use an object (instead of an array)."
449
+ );
450
+ } else {
451
+ const keys = Object.keys(value);
452
+ checks.push(
453
+ (async () => {
454
+ const { breadcrumbString } = traverse(["exports", [subpath]]);
455
+ const fixingLines = [];
456
+ const orderingErrorLines = [];
457
+ let updateKeys = false;
458
+ if (keys.includes("types")) {
459
+ if (keys[0] !== "types") {
460
+ switch (subcommand) {
461
+ case "check": {
462
+ orderingErrorLines.push(
463
+ ` \u21AA "types" must be the first export if present \u2014 \u{1F4DD} fixable!`
464
+ );
465
+ break;
466
+ }
467
+ case "format": {
468
+ fixingLines.push(
469
+ ` \u21AA "types" must be the first export if present \u2014 \u{1F4DD} fixing!`
470
+ );
471
+ keys.splice(keys.indexOf("types"), 1);
472
+ keys.splice(0, 0, "types");
473
+ updateKeys = true;
474
+ break;
475
+ }
476
+ default:
477
+ throw new Error("Invalid subcommand.");
478
+ }
479
+ }
480
+ }
481
+ if (keys.includes("default")) {
482
+ if (keys.at(-1) !== "default") {
483
+ switch (subcommand) {
484
+ case "check": {
485
+ orderingErrorLines.push(
486
+ ` \u21AA "default" must be the last export if present \u2014 \u{1F4DD} fixable!`
487
+ );
488
+ break;
489
+ }
490
+ case "format": {
491
+ fixingLines.push(
492
+ ` \u21AA "default" must be the last export if present \u2014 \u{1F4DD} fixing!`
493
+ );
494
+ keys.splice(keys.indexOf("default"), 1);
495
+ keys.push("default");
496
+ updateKeys = true;
497
+ break;
498
+ }
499
+ default:
500
+ throw new Error("Invalid subcommand.");
501
+ }
502
+ }
503
+ }
504
+ if (updateKeys) {
505
+ const newConditionalExports = {};
506
+ for (const key of keys) {
507
+ newConditionalExports[key] = value[key];
508
+ }
509
+ exports[subpath] = newConditionalExports;
510
+ }
511
+ for (const key of keys) {
512
+ if (!["types", "import", "default"].includes(key)) {
513
+ orderingErrorLines.push(
514
+ ` \u21AA Key must not be present: ${JSON.stringify(key)}`
515
+ );
516
+ }
517
+ }
518
+ if (orderingErrorLines.length > 0) {
519
+ exitCode = 1;
520
+ return [
521
+ `\u274C ${breadcrumbString} \u2014 Invalid keys:`,
522
+ ...orderingErrorLines
523
+ ].join("\n");
524
+ } else {
525
+ if (fixingLines.length > 0) {
526
+ return [
527
+ `\u2705 ${breadcrumbString} \u2014 Fixing key ordering:`,
528
+ ...fixingLines
529
+ ].join("\n");
530
+ } else {
531
+ return `\u2705 ${breadcrumbString} \u2014 Key set and ordering is OK.`;
532
+ }
533
+ }
534
+ })()
535
+ );
536
+ for (const secondaryKey of keys) {
537
+ checkPath(["exports", [subpath], secondaryKey], {
538
+ expectPrefix: ResolutionPrefix.Relative
539
+ });
540
+ }
541
+ }
542
+ }
543
+ }
544
+ var { bin } = packageJSON;
545
+ if (bin) {
546
+ for (const binEntry of Object.keys(bin)) {
547
+ checkPath(["bin", [binEntry]], {
548
+ // `npm pkg fix` prefers bare paths for `bin` entries for some reason. 🤷
549
+ expectPrefix: ResolutionPrefix.Bare,
550
+ // `npm` will technically make binary entry points executable, but we want
551
+ // to enforce that the unpackaged path also is. This is particularly
552
+ // important when the package is linked.
553
+ mustBeExecutable: true
554
+ });
555
+ }
556
+ }
557
+ console.log((await Promise.all(checks)).join("\n"));
558
+ if (subcommand === "format") {
559
+ console.log("\u{1F4DD} Writing formatting fixes.");
560
+ await PACKAGE_JSON_PATH.write(`${JSON.stringify(packageJSON, null, " ")}
561
+ `);
562
+ console.log(PACKAGE_JSON_PATH.path);
563
+ console.log("\u{1F4DD} Running `npm pkg fix`.");
564
+ await new PrintableShellCommand("npm", ["pkg", "fix"]).print({ argumentLineWrapping: "inline" }).spawn().success;
565
+ } else if (foundFixableErrors) {
566
+ console.log();
567
+ console.log(
568
+ "\u{1F4DD} Found fixable errors. Run with the `format` subcommand to fix."
569
+ );
570
+ console.log();
571
+ }
572
+ await tempDirDisposable[Symbol.asyncDispose]();
573
+ exit(exitCode);
574
+ } catch (_) {
575
+ var _error = _, _hasError = true;
576
+ } finally {
577
+ var _promise = __callDispose(_stack, _error, _hasError);
578
+ _promise && await _promise;
579
+ }
580
+ //# sourceMappingURL=index.js.map