@_linked/cli 1.46.2 → 1.47.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.
Files changed (167) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/README.md +48 -36
  3. package/hooks/drift.cjs +169 -0
  4. package/hooks/git-hook.cjs +170 -0
  5. package/hooks/hook-shim.cjs +63 -0
  6. package/hooks/lock-at-rest.cjs +268 -0
  7. package/hooks/manifests.cjs +216 -0
  8. package/hooks/platform.cjs +25 -0
  9. package/lib/esm/app-release/build-backend.d.ts.map +1 -1
  10. package/lib/esm/app-release/build-backend.js +2 -1
  11. package/lib/esm/app-release/build-backend.js.map +1 -1
  12. package/lib/esm/cli-methods.d.ts.map +1 -1
  13. package/lib/esm/cli-methods.js +166 -150
  14. package/lib/esm/cli-methods.js.map +1 -1
  15. package/lib/esm/cli.js +20 -22
  16. package/lib/esm/cli.js.map +1 -1
  17. package/lib/esm/commands/build-app.d.ts.map +1 -1
  18. package/lib/esm/commands/build-app.js +2 -1
  19. package/lib/esm/commands/build-app.js.map +1 -1
  20. package/lib/esm/commands/build-package.d.ts.map +1 -1
  21. package/lib/esm/commands/build-package.js +6 -2
  22. package/lib/esm/commands/build-package.js.map +1 -1
  23. package/lib/esm/commands/localize.d.ts +9 -15
  24. package/lib/esm/commands/localize.d.ts.map +1 -1
  25. package/lib/esm/commands/localize.js +43 -74
  26. package/lib/esm/commands/localize.js.map +1 -1
  27. package/lib/esm/commands/setup-publish.d.ts.map +1 -1
  28. package/lib/esm/commands/setup-publish.js +22 -15
  29. package/lib/esm/commands/setup-publish.js.map +1 -1
  30. package/lib/esm/commands/start.d.ts +8 -0
  31. package/lib/esm/commands/start.d.ts.map +1 -1
  32. package/lib/esm/commands/start.js +20 -8
  33. package/lib/esm/commands/start.js.map +1 -1
  34. package/lib/esm/installed-packages.d.ts +5 -13
  35. package/lib/esm/installed-packages.d.ts.map +1 -1
  36. package/lib/esm/installed-packages.js +5 -38
  37. package/lib/esm/installed-packages.js.map +1 -1
  38. package/lib/esm/lifecycle.d.ts +35 -22
  39. package/lib/esm/lifecycle.d.ts.map +1 -1
  40. package/lib/esm/lifecycle.js +62 -36
  41. package/lib/esm/lifecycle.js.map +1 -1
  42. package/lib/esm/localize/adopt.d.ts +5 -5
  43. package/lib/esm/localize/adopt.d.ts.map +1 -1
  44. package/lib/esm/localize/adopt.js +46 -55
  45. package/lib/esm/localize/adopt.js.map +1 -1
  46. package/lib/esm/localize/app-root.d.ts +16 -0
  47. package/lib/esm/localize/app-root.d.ts.map +1 -0
  48. package/lib/esm/localize/app-root.js +94 -0
  49. package/lib/esm/localize/app-root.js.map +1 -0
  50. package/lib/esm/localize/app-setup.d.ts +21 -0
  51. package/lib/esm/localize/app-setup.d.ts.map +1 -0
  52. package/lib/esm/localize/app-setup.js +178 -0
  53. package/lib/esm/localize/app-setup.js.map +1 -0
  54. package/lib/esm/localize/delocalize.d.ts.map +1 -1
  55. package/lib/esm/localize/delocalize.js +169 -104
  56. package/lib/esm/localize/delocalize.js.map +1 -1
  57. package/lib/esm/localize/drift-hook.d.ts +18 -0
  58. package/lib/esm/localize/drift-hook.d.ts.map +1 -0
  59. package/lib/esm/localize/drift-hook.js +37 -0
  60. package/lib/esm/localize/drift-hook.js.map +1 -0
  61. package/lib/esm/localize/drift.d.ts +36 -0
  62. package/lib/esm/localize/drift.d.ts.map +1 -0
  63. package/lib/esm/localize/drift.js +34 -0
  64. package/lib/esm/localize/drift.js.map +1 -0
  65. package/lib/esm/localize/errors.d.ts +14 -8
  66. package/lib/esm/localize/errors.d.ts.map +1 -1
  67. package/lib/esm/localize/errors.js +14 -8
  68. package/lib/esm/localize/errors.js.map +1 -1
  69. package/lib/esm/localize/fsops.d.ts +11 -27
  70. package/lib/esm/localize/fsops.d.ts.map +1 -1
  71. package/lib/esm/localize/fsops.js +40 -115
  72. package/lib/esm/localize/fsops.js.map +1 -1
  73. package/lib/esm/localize/git-hooks.d.ts +33 -0
  74. package/lib/esm/localize/git-hooks.d.ts.map +1 -0
  75. package/lib/esm/localize/git-hooks.js +146 -0
  76. package/lib/esm/localize/git-hooks.js.map +1 -0
  77. package/lib/esm/localize/hook-module.d.ts +6 -0
  78. package/lib/esm/localize/hook-module.d.ts.map +1 -0
  79. package/lib/esm/localize/hook-module.js +37 -0
  80. package/lib/esm/localize/hook-module.js.map +1 -0
  81. package/lib/esm/localize/index.d.ts +14 -15
  82. package/lib/esm/localize/index.d.ts.map +1 -1
  83. package/lib/esm/localize/index.js +8 -9
  84. package/lib/esm/localize/index.js.map +1 -1
  85. package/lib/esm/localize/list.d.ts +6 -10
  86. package/lib/esm/localize/list.d.ts.map +1 -1
  87. package/lib/esm/localize/list.js +49 -189
  88. package/lib/esm/localize/list.js.map +1 -1
  89. package/lib/esm/localize/localize.d.ts +46 -62
  90. package/lib/esm/localize/localize.d.ts.map +1 -1
  91. package/lib/esm/localize/localize.js +411 -285
  92. package/lib/esm/localize/localize.js.map +1 -1
  93. package/lib/esm/localize/members.d.ts +13 -0
  94. package/lib/esm/localize/members.d.ts.map +1 -0
  95. package/lib/esm/localize/members.js +46 -0
  96. package/lib/esm/localize/members.js.map +1 -0
  97. package/lib/esm/localize/resolve.d.ts +1 -2
  98. package/lib/esm/localize/resolve.d.ts.map +1 -1
  99. package/lib/esm/localize/resolve.js +3 -5
  100. package/lib/esm/localize/resolve.js.map +1 -1
  101. package/lib/esm/localize/run.d.ts +1 -0
  102. package/lib/esm/localize/run.d.ts.map +1 -1
  103. package/lib/esm/localize/run.js +11 -6
  104. package/lib/esm/localize/run.js.map +1 -1
  105. package/lib/esm/localize/setup-lockfile.d.ts +13 -0
  106. package/lib/esm/localize/setup-lockfile.d.ts.map +1 -0
  107. package/lib/esm/localize/setup-lockfile.js +80 -0
  108. package/lib/esm/localize/setup-lockfile.js.map +1 -0
  109. package/lib/esm/utils/createPackageLocation.d.ts +4 -13
  110. package/lib/esm/utils/createPackageLocation.d.ts.map +1 -1
  111. package/lib/esm/utils/createPackageLocation.js +12 -21
  112. package/lib/esm/utils/createPackageLocation.js.map +1 -1
  113. package/lib/esm/utils/packageSetup.d.ts +5 -2
  114. package/lib/esm/utils/packageSetup.d.ts.map +1 -1
  115. package/lib/esm/utils/packageSetup.js +9 -3
  116. package/lib/esm/utils/packageSetup.js.map +1 -1
  117. package/lib/esm/utils/platform.d.ts +24 -0
  118. package/lib/esm/utils/platform.d.ts.map +1 -0
  119. package/lib/esm/utils/platform.js +62 -0
  120. package/lib/esm/utils/platform.js.map +1 -0
  121. package/lib/esm/utils/shapeReferences.d.ts.map +1 -1
  122. package/lib/esm/utils/shapeReferences.js +3 -2
  123. package/lib/esm/utils/shapeReferences.js.map +1 -1
  124. package/lib/esm/utils/spawn.d.ts +65 -0
  125. package/lib/esm/utils/spawn.d.ts.map +1 -0
  126. package/lib/esm/utils/spawn.js +181 -0
  127. package/lib/esm/utils/spawn.js.map +1 -0
  128. package/lib/esm/utils.d.ts.map +1 -1
  129. package/lib/esm/utils.js +19 -5
  130. package/lib/esm/utils.js.map +1 -1
  131. package/lib/esm/vite-config.d.ts +5 -12
  132. package/lib/esm/vite-config.d.ts.map +1 -1
  133. package/lib/esm/vite-config.js +41 -33
  134. package/lib/esm/vite-config.js.map +1 -1
  135. package/package.json +4 -3
  136. package/lib/esm/localize/ensure.d.ts +0 -44
  137. package/lib/esm/localize/ensure.d.ts.map +0 -1
  138. package/lib/esm/localize/ensure.js +0 -151
  139. package/lib/esm/localize/ensure.js.map +0 -1
  140. package/lib/esm/localize/manifest.d.ts +0 -63
  141. package/lib/esm/localize/manifest.d.ts.map +0 -1
  142. package/lib/esm/localize/manifest.js +0 -133
  143. package/lib/esm/localize/manifest.js.map +0 -1
  144. package/lib/esm/localize/one-copy-hook.d.ts +0 -16
  145. package/lib/esm/localize/one-copy-hook.d.ts.map +0 -1
  146. package/lib/esm/localize/one-copy-hook.js +0 -20
  147. package/lib/esm/localize/one-copy-hook.js.map +0 -1
  148. package/lib/esm/localize/provided.d.ts +0 -28
  149. package/lib/esm/localize/provided.d.ts.map +0 -1
  150. package/lib/esm/localize/provided.js +0 -89
  151. package/lib/esm/localize/provided.js.map +0 -1
  152. package/lib/esm/localize/prune.d.ts +0 -182
  153. package/lib/esm/localize/prune.d.ts.map +0 -1
  154. package/lib/esm/localize/prune.js +0 -703
  155. package/lib/esm/localize/prune.js.map +0 -1
  156. package/lib/esm/localize/relink.d.ts +0 -13
  157. package/lib/esm/localize/relink.d.ts.map +0 -1
  158. package/lib/esm/localize/relink.js +0 -181
  159. package/lib/esm/localize/relink.js.map +0 -1
  160. package/lib/esm/localized-dedupe.d.ts +0 -26
  161. package/lib/esm/localized-dedupe.d.ts.map +0 -1
  162. package/lib/esm/localized-dedupe.js +0 -139
  163. package/lib/esm/localized-dedupe.js.map +0 -1
  164. package/lib/esm/utils/relinkHooks.d.ts +0 -19
  165. package/lib/esm/utils/relinkHooks.d.ts.map +0 -1
  166. package/lib/esm/utils/relinkHooks.js +0 -74
  167. package/lib/esm/utils/relinkHooks.js.map +0 -1
@@ -12,18 +12,22 @@ import { exec } from 'child_process';
12
12
  import depcheck from 'depcheck';
13
13
  import { getEnvFile } from 'env-cmd/dist/get-env-vars.js';
14
14
  import fs from 'fs-extra';
15
- import path, { dirname } from 'path';
15
+ import path from 'path';
16
+ import { fileURLToPath } from 'url';
16
17
  import { createInterface } from 'readline';
17
18
  import { debugInfo, execp, execPromise, getFileImports, getFiles, getLastCommitTime, getPackageJSON, isImportOutsideOfPackage, isInternalLinkedImport, needsRebuilding, } from './utils.js';
18
19
  import { renameShippedDotfiles } from './utils/shippedDotfiles.js';
20
+ import { findWorkspaceRoot } from './localize/app-root.js';
19
21
  import { planPackageSetup } from './utils/packageSetup.js';
20
- import { bareName, CreatePackageError, decideCreatePackageTarget, ensureRelinkPostinstall, ensureWorkspaceGlob, findLinkedAppRoot, RELINK_COMMAND, repositoryUrlFor, } from './utils/createPackageLocation.js';
22
+ import { bareName, CreatePackageError, decideCreatePackageTarget, ensureWorkspaceGlob, findLinkedAppRoot, repositoryUrlFor, } from './utils/createPackageLocation.js';
21
23
  import { detectPackageManager, execBinCommand, runScriptCommand, } from './utils/packageManager.js';
22
24
  import { rewriteExtensionlessImports } from './utils/esmSpecifiers.js';
23
25
  import { checkShapeNames } from './utils/shapeNames.js';
24
26
  import { checkShapeReferences, inspectShapeReferences, } from './utils/shapeReferences.js';
25
27
  import { checkShapesIndex, checkShapesSideEffects } from './utils/shapesIndex.js';
26
- import { spawn as spawnChild, spawnSync } from 'child_process';
28
+ import { spawnSync } from 'child_process';
29
+ import { spawnCommand } from './utils/spawn.js';
30
+ import { importFile, withEolOf } from './utils/platform.js';
27
31
  import { findNearestPackageJson } from 'find-nearest-package-json';
28
32
  import { statSync } from 'fs';
29
33
  // import pkg from 'lincd/utils/LinkedFileStorage';
@@ -35,10 +39,9 @@ import { packagePublishesCjs } from './package-manifest.js';
35
39
  import { asNamespace, defaultOntologyNamespace } from './utils/ontologyNamespace.js';
36
40
  import { decidePackageKind, ontologySlugFor, packageNameFor, scaffoldKinds, PACKAGE_TEMPLATE_DIRS, SHARED_TEMPLATE_FILES, } from './utils/packageKind.js';
37
41
  import { resolvePackageBaseUri, withBaseUri } from './utils/packageBaseUri.js';
38
- let dirname__ = typeof __dirname !== 'undefined'
39
- ? __dirname
40
- : //@ts-ignore
41
- dirname(import.meta.url).replace('file:/', '');
42
+ // This module's directory. fileURLToPath, not the URL with `file:/` cut off,
43
+ // which on Windows leaves `//C:/...`.
44
+ let dirname__ = path.dirname(fileURLToPath(import.meta.url));
42
45
  /**
43
46
  * A folder under this package's `defaults/`. The built module sits in `lib/esm/`
44
47
  * and the source in `src/`, so the templates are two or one level up.
@@ -198,11 +201,11 @@ export const createApp = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...ar
198
201
  spinner: 'dots',
199
202
  }).start();
200
203
  const { stdout, stderr, failed } = yield new Promise((resolve) => {
201
- exec(`cd ${hyphenName} && ${installCommand}`, { maxBuffer: 50 * 1024 * 1024 }, (error, out, err) => {
202
- var _a, _b;
204
+ // The folder as cwd, not `cd <dir> &&`: cmd.exe's `cd` does not change drives.
205
+ exec(installCommand, { cwd: targetFolder, maxBuffer: 50 * 1024 * 1024 }, (error, out, err) => {
203
206
  resolve({
204
- stdout: typeof out === 'string' ? out : (_a = out === null || out === void 0 ? void 0 : out.toString()) !== null && _a !== void 0 ? _a : '',
205
- stderr: typeof err === 'string' ? err : (_b = err === null || err === void 0 ? void 0 : err.toString()) !== null && _b !== void 0 ? _b : '',
207
+ stdout: out !== null && out !== void 0 ? out : '',
208
+ stderr: err !== null && err !== void 0 ? err : '',
206
209
  failed: !!error,
207
210
  });
208
211
  });
@@ -703,52 +706,6 @@ function hasDependency(pkg, childPkg, dependencies, depth = 1) {
703
706
  console.log('going up');
704
707
  return false;
705
708
  }
706
- /**
707
- * Finds the topmost package.json that could be an APP_ROOT
708
- * Returns null if no app root is found (standalone repo case)
709
- */
710
- function findAppRoot(startPath = process.cwd()) {
711
- let currentPath = startPath;
712
- let candidateRoots = [];
713
- // Walk up the directory tree
714
- for (let i = 0; i < 10; i++) {
715
- const packageJsonPath = path.join(currentPath, 'package.json');
716
- if (fs.existsSync(packageJsonPath)) {
717
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
718
- candidateRoots.push({
719
- path: currentPath,
720
- hasWorkspaces: !!packageJson.workspaces,
721
- isLinked: packageJson.linkedPackage === true,
722
- });
723
- }
724
- const parentPath = path.join(currentPath, '..');
725
- // If we've reached the root or haven't moved up
726
- if (parentPath === currentPath) {
727
- break;
728
- }
729
- currentPath = parentPath;
730
- }
731
- // Find the topmost package.json that has workspaces
732
- // Prefer non-linked packages (app roots) over linked packages
733
- let appRoot = null;
734
- for (let i = candidateRoots.length - 1; i >= 0; i--) {
735
- const candidate = candidateRoots[i];
736
- if (candidate.hasWorkspaces && !candidate.isLinked) {
737
- appRoot = candidate.path;
738
- break;
739
- }
740
- }
741
- // If no non-linked workspace found, use the topmost workspace
742
- if (!appRoot) {
743
- for (let i = candidateRoots.length - 1; i >= 0; i--) {
744
- if (candidateRoots[i].hasWorkspaces) {
745
- appRoot = candidateRoots[i].path;
746
- break;
747
- }
748
- }
749
- }
750
- return appRoot;
751
- }
752
709
  /**
753
710
  * Print the discovery result in full: what will be built, and every package
754
711
  * that was found and will not be. Nothing is discovered silently.
@@ -799,51 +756,82 @@ function runBuildScript(pkg, failureOutput) {
799
756
  });
800
757
  }
801
758
  export function buildAll(options) {
802
- console.log('Building all linked packages of this repository in order of dependencies');
803
- const plan = planBuildAll('./', findAppRoot() || undefined);
804
- printBuildAllPlan(plan);
805
- if (plan.build.size === 0) {
806
- console.log(chalk.yellow('Nothing to build.'));
807
- return;
808
- }
809
- // The build tool goes first and alone: every other build runs it.
810
- const order = orderBuildToolFirst(plan.build, options === null || options === void 0 ? void 0 : options.from);
811
- const sync = (options === null || options === void 0 ? void 0 : options.sync) || false;
812
- // Successfully built (or deliberately passed over by --from).
813
- const done = new Set();
814
- if (!order.tool) {
815
- return buildInDependencyOrder(order.rest, order.from, sync, done);
816
- }
817
- const tool = order.tool;
818
- if (!order.buildToolFirst) {
819
- log(chalk.blue('skipping ' + tool.packageName));
820
- done.add(tool);
821
- return buildInDependencyOrder(order.rest, order.from, sync, done);
822
- }
823
- // This process has already loaded every module `build-all` uses (the
824
- // command's code is imported statically), so the tool's `rimraf ./lib`
825
- // cannot pull anything out from under it.
826
- console.log(chalk.blue(`Building ${tool.packageName} first: the other packages build with it.`));
827
- return runBuildScript(tool).then((res) => {
828
- if (typeof res === 'undefined') {
829
- const others = order.rest.size;
830
- console.error(chalk.red(`${tool.packageName} failed to build, so build-all stopped before ` +
831
- `the other ${others} package${others === 1 ? '' : 's'}: they build with it. ` +
832
- `Fix ${tool.packageName} and run build-all again.`));
833
- process.exit(1);
759
+ return __awaiter(this, void 0, void 0, function* () {
760
+ var _a;
761
+ console.log('Building all linked packages of this repository in order of dependencies');
762
+ const plan = planBuildAll('./', (_a = findWorkspaceRoot(process.cwd())) !== null && _a !== void 0 ? _a : undefined);
763
+ printBuildAllPlan(plan);
764
+ if (plan.build.size === 0) {
765
+ console.log(chalk.yellow('Nothing to build.'));
766
+ return;
767
+ }
768
+ // The build tool's own dependencies, then the tool alone (every other build
769
+ // runs it), then the rest. See `orderBuildToolFirst`.
770
+ const order = orderBuildToolFirst(plan.build, options === null || options === void 0 ? void 0 : options.from);
771
+ const sync = (options === null || options === void 0 ? void 0 : options.sync) || false;
772
+ // Successfully built (or deliberately passed over by --from).
773
+ const done = new Set();
774
+ const tool = order.tool;
775
+ if (!tool) {
776
+ yield buildInDependencyOrder(order.rest, order.from, sync, done);
834
777
  return;
835
778
  }
836
- log(chalk.green('Built ' + tool.packageName) +
837
- (res === false ? chalk.redBright(' (with warnings)') : ''));
838
- done.add(tool);
779
+ const passOver = (pkg) => {
780
+ log(chalk.blue('skipping ' + pkg.packageName));
781
+ done.add(pkg);
782
+ };
783
+ const plural = (n) => `${n} package${n === 1 ? '' : 's'}`;
784
+ if (order.start === 'pre' && order.pre.size > 0) {
785
+ const names = [...order.pre.keys()].join(', ');
786
+ const them = order.pre.size === 1 ? 'it' : 'them';
787
+ console.log(chalk.blue(`Building ${names} first: ${tool.packageName} depends on ${them}.`));
788
+ const built = yield buildInDependencyOrder(order.pre, order.from, sync, done, {
789
+ stopNote: `${tool.packageName} needs ${names}, so build-all stopped before it and ` +
790
+ `the other ${plural(order.rest.size)}, which build with it. ` +
791
+ `Fix the failure and run build-all again.`,
792
+ });
793
+ if (!built)
794
+ return;
795
+ }
796
+ else {
797
+ order.pre.forEach(passOver);
798
+ }
799
+ if (order.start === 'rest') {
800
+ passOver(tool);
801
+ }
802
+ else {
803
+ // This process has already loaded every module `build-all` uses (the
804
+ // command's code is imported statically), so the tool's `rimraf ./lib`
805
+ // cannot pull anything out from under it.
806
+ console.log(chalk.blue(`Building ${tool.packageName} alone: the other packages build with it.`));
807
+ const res = yield runBuildScript(tool);
808
+ if (typeof res === 'undefined') {
809
+ console.error(chalk.red(`${tool.packageName} failed to build, so build-all stopped before ` +
810
+ `the other ${plural(order.rest.size)}: they build with it. ` +
811
+ `Fix ${tool.packageName} and run build-all again.`));
812
+ process.exit(1);
813
+ return;
814
+ }
815
+ log(chalk.green('Built ' + tool.packageName) +
816
+ (res === false ? chalk.redBright(' (with warnings)') : ''));
817
+ done.add(tool);
818
+ }
839
819
  if (order.rest.size === 0) {
840
820
  printBuildAllSummary(done, new Set(), new Map(), [], new Map());
841
821
  return;
842
822
  }
843
- return buildInDependencyOrder(order.rest, order.from, sync, done);
823
+ yield buildInDependencyOrder(order.rest, order.start === 'rest' ? order.from : undefined, sync, done);
844
824
  });
845
825
  }
846
- function buildInDependencyOrder(lincdPackages, from, sync, done) {
826
+ /**
827
+ * Build `lincdPackages` in dependency order, in parallel where they allow it.
828
+ * Resolves to whether every package was built (or passed over by `from`).
829
+ *
830
+ * The last group of a run prints the end-of-run summary. A group with more to
831
+ * follow (`then`) prints it only when something failed, followed by
832
+ * `then.stopNote`, since nothing after it can be built.
833
+ */
834
+ function buildInDependencyOrder(lincdPackages, from, sync, done, then) {
847
835
  let startFrom;
848
836
  //by default start building
849
837
  let building = true;
@@ -863,7 +851,8 @@ function buildInDependencyOrder(lincdPackages, from, sync, done) {
863
851
  const failureOutput = new Map();
864
852
  progressUpdate(lincdPackages.size + ' packages left');
865
853
  let packagesLeft = lincdPackages.size;
866
- // `done` may already hold the build tool, built before this ran.
854
+ let allBuilt = false;
855
+ // `done` may already hold earlier groups (the build tool and what it needs).
867
856
  const doneBefore = done.size;
868
857
  const finished = runOnPackagesGroupedByDependencies(lincdPackages, (packageGroup, dependencies) => {
869
858
  if (done.size > doneBefore) {
@@ -956,12 +945,19 @@ function buildInDependencyOrder(lincdPackages, from, sync, done) {
956
945
  }
957
946
  }
958
947
  }
959
- printBuildAllSummary(done, failed, notBuilt, unscheduled, failureOutput);
960
- if (failed.size > 0 || notBuilt.size > 0 || unscheduled.length > 0) {
948
+ const problems = failed.size > 0 || notBuilt.size > 0 || unscheduled.length > 0;
949
+ if (problems || !then) {
950
+ printBuildAllSummary(done, failed, notBuilt, unscheduled, failureOutput);
951
+ }
952
+ if (problems) {
953
+ if (then)
954
+ console.error(chalk.red(then.stopNote));
961
955
  process.exit(1);
956
+ return;
962
957
  }
958
+ allBuilt = true;
963
959
  }, sync);
964
- return finished;
960
+ return finished.then(() => allBuilt);
965
961
  }
966
962
  /**
967
963
  * The end-of-run report of `build-all`: what was built, every package whose
@@ -1104,7 +1100,7 @@ const ensureBackendImportsShapes = function (root = process.cwd()) {
1104
1100
  let contents = fs.readFileSync(backendPath, 'utf-8');
1105
1101
  if (contents.includes('./shapes/index'))
1106
1102
  return;
1107
- fs.writeFileSync(backendPath, `import './shapes/index.js';\n` + contents);
1103
+ fs.writeFileSync(backendPath, withEolOf(`import './shapes/index.js';\n`, contents) + contents);
1108
1104
  };
1109
1105
  // Register a shape in the shapes barrel (src/shapes/index.ts), creating it if needed, and
1110
1106
  // make sure both the main index and backend.ts import the barrel. Idempotent.
@@ -1120,7 +1116,7 @@ export const addShapeToBarrel = function (shapeHyphenName, root = process.cwd())
1120
1116
  contents = contents.includes('//SHAPES')
1121
1117
  ? contents.replace('//SHAPES', `//SHAPES\n${line}`)
1122
1118
  : contents.replace(/\n*$/, '') + `\n${line}\n`;
1123
- fs.writeFileSync(barrelPath, contents);
1119
+ fs.writeFileSync(barrelPath, withEolOf(contents, contents));
1124
1120
  }
1125
1121
  // Both boot paths must load the barrel (idempotent).
1126
1122
  addLineToIndex(`import './shapes/index.js';`, 'shapes', root);
@@ -1164,7 +1160,7 @@ export const addLineToIndex = function (line, insertMatchString, root = process.
1164
1160
  }
1165
1161
  // log("Added at end",newContents);
1166
1162
  }
1167
- fs.writeFileSync(indexPath, newContents);
1163
+ fs.writeFileSync(indexPath, withEolOf(newContents, indexContents));
1168
1164
  }
1169
1165
  return indexPath;
1170
1166
  };
@@ -1177,7 +1173,12 @@ const replaceVariablesInFolder = function (folder) {
1177
1173
  return __awaiter(this, void 0, void 0, function* () {
1178
1174
  //get all files in folder, including files that start with a dot
1179
1175
  try {
1180
- const files = yield glob(folder + '/**/*', { dot: true, nodir: true });
1176
+ const files = yield glob('**/*', {
1177
+ cwd: folder,
1178
+ absolute: true,
1179
+ dot: true,
1180
+ nodir: true,
1181
+ });
1181
1182
  yield Promise.all(files.map((file) => {
1182
1183
  return replaceVariablesInFile(file);
1183
1184
  }));
@@ -1497,7 +1498,7 @@ export const runScript = (scriptName, options) => __awaiter(void 0, void 0, void
1497
1498
  }
1498
1499
  log('Running script ' + scriptName);
1499
1500
  const scriptPath = path.join(process.cwd(), 'scripts', scriptName);
1500
- const script = yield import(scriptPath);
1501
+ const script = yield importFile(scriptPath);
1501
1502
  yield script.default().catch((error) => {
1502
1503
  log('Script ' + scriptName + ' finished with errors');
1503
1504
  logError(error);
@@ -1509,17 +1510,17 @@ export const runScript = (scriptName, options) => __awaiter(void 0, void 0, void
1509
1510
  export const runMethod = (packageName, method, options) => __awaiter(void 0, void 0, void 0, function* () {
1510
1511
  yield ensureEnvironmentLoaded();
1511
1512
  if (options.spawn) {
1512
- let linkedConfig = (yield import(path.join(process.cwd(), 'linked.config.js'))).default;
1513
+ let linkedConfig = (yield importFile(path.join(process.cwd(), 'linked.config.js'))).default;
1513
1514
  // Set default loadAppComponent if not provided
1514
1515
  if (!linkedConfig.server) {
1515
1516
  linkedConfig.server = {};
1516
1517
  }
1517
1518
  if (!linkedConfig.server.loadAppComponent) {
1518
- linkedConfig.server.loadAppComponent = () => __awaiter(void 0, void 0, void 0, function* () { return (yield import(path.join(process.cwd(), 'src', 'App'))).default; });
1519
+ linkedConfig.server.loadAppComponent = () => __awaiter(void 0, void 0, void 0, function* () { return (yield importFile(path.join(process.cwd(), 'src', 'App'))).default; });
1519
1520
  }
1520
1521
  // Set default loadRoutes if not provided
1521
1522
  if (!linkedConfig.server.loadRoutes) {
1522
- linkedConfig.server.loadRoutes = () => __awaiter(void 0, void 0, void 0, function* () { return yield import(path.join(process.cwd(), 'src', 'routes.tsx')); });
1523
+ linkedConfig.server.loadRoutes = () => __awaiter(void 0, void 0, void 0, function* () { return yield importFile(path.join(process.cwd(), 'src', 'routes.tsx')); });
1523
1524
  }
1524
1525
  const ServerClass = yield loadServerClass();
1525
1526
  yield loadBackendStorageConfig();
@@ -1602,7 +1603,7 @@ export const runMethod = (packageName, method, options) => __awaiter(void 0, voi
1602
1603
  });
1603
1604
  export const startServer = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (initOnly = false, ServerClass = null) {
1604
1605
  yield ensureEnvironmentLoaded();
1605
- let linkedConfig = (yield import(path.join(process.cwd(), 'linked.config.js')))
1606
+ let linkedConfig = (yield importFile(path.join(process.cwd(), 'linked.config.js')))
1606
1607
  .default;
1607
1608
  // function scssLoadcall(source, filename) {
1608
1609
  // return 'console.log("SCSS CALL: ' + filename + '");\n' + source;
@@ -1625,11 +1626,11 @@ export const startServer = (...args_1) => __awaiter(void 0, [...args_1], void 0,
1625
1626
  if (!linkedConfig.server.loadAppComponent) {
1626
1627
  let appPromise;
1627
1628
  if (process.env.NODE_ENV !== 'development') {
1628
- appPromise = (yield import(path.join(process.cwd(), 'lib', 'App.js')))
1629
+ appPromise = (yield importFile(path.join(process.cwd(), 'lib', 'App.js')))
1629
1630
  .default;
1630
1631
  }
1631
1632
  else {
1632
- appPromise = (yield import(path.join(process.cwd(), 'src', 'App.tsx')))
1633
+ appPromise = (yield importFile(path.join(process.cwd(), 'src', 'App.tsx')))
1633
1634
  .default;
1634
1635
  }
1635
1636
  linkedConfig.server.loadAppComponent = () => __awaiter(void 0, void 0, void 0, function* () {
@@ -1640,10 +1641,10 @@ export const startServer = (...args_1) => __awaiter(void 0, [...args_1], void 0,
1640
1641
  if (!linkedConfig.server.loadRoutes) {
1641
1642
  linkedConfig.server.loadRoutes = () => __awaiter(void 0, void 0, void 0, function* () {
1642
1643
  if (process.env.NODE_ENV !== 'development') {
1643
- return yield import(path.join(process.cwd(), 'lib', 'routes.js'));
1644
+ return yield importFile(path.join(process.cwd(), 'lib', 'routes.js'));
1644
1645
  }
1645
1646
  else {
1646
- return yield import(path.join(process.cwd(), 'src', 'routes.tsx'));
1647
+ return yield importFile(path.join(process.cwd(), 'src', 'routes.tsx'));
1647
1648
  }
1648
1649
  });
1649
1650
  }
@@ -1920,6 +1921,8 @@ export const createPackage = (name_1, uriBase_1, ...args_1) => __awaiter(void 0,
1920
1921
  yield installWorkspacePackage(packageName, targetFolder, appRoot, options.skipInstall);
1921
1922
  }
1922
1923
  else if (options.skipInstall) {
1924
+ // Files, not install: the app is set up for checkouts either way.
1925
+ yield setUpAppForCheckouts(appRoot);
1923
1926
  skipped();
1924
1927
  }
1925
1928
  else {
@@ -1970,8 +1973,8 @@ function packageTargetFolder(name, basePath, appRoot, decision) {
1970
1973
  }
1971
1974
  // localize's own naming, so `linked localize` and this command can never
1972
1975
  // disagree about where a package lives.
1973
- const { checkoutNameFor, DEFAULT_DIR } = yield import('./localize/index.js');
1974
- return path.join(appRoot, DEFAULT_DIR, checkoutNameFor(name));
1976
+ const { checkoutNameFor, LOCAL_DIR } = yield import('./localize/index.js');
1977
+ return path.join(appRoot, LOCAL_DIR, checkoutNameFor(name));
1975
1978
  });
1976
1979
  }
1977
1980
  /**
@@ -2144,13 +2147,14 @@ function installStandalonePackage(targetFolder) {
2144
2147
  function installWorkspacePackage(name_1, targetFolder_1, appRoot_1) {
2145
2148
  return __awaiter(this, arguments, void 0, function* (name, targetFolder, appRoot, skipInstall = false) {
2146
2149
  const appPkgPath = path.join(appRoot, 'package.json');
2147
- const appPkg = fs.readJsonSync(appPkgPath);
2150
+ const appPkgText = fs.readFileSync(appPkgPath, 'utf8');
2151
+ const appPkg = JSON.parse(appPkgText);
2148
2152
  const workspaces = ensureWorkspaceGlob(appPkg);
2149
2153
  if (workspaces.warning)
2150
2154
  console.warn(chalk.yellow(workspaces.warning));
2151
2155
  const version = fs.readJsonSync(path.join(targetFolder, 'package.json')).version;
2152
2156
  appPkg.dependencies = Object.assign(Object.assign({}, appPkg.dependencies), { [name]: `^${version}` });
2153
- fs.writeJsonSync(appPkgPath, appPkg, { spaces: 2 });
2157
+ fs.writeFileSync(appPkgPath, withEolOf(JSON.stringify(appPkg, null, 2) + '\n', appPkgText));
2154
2158
  log(`Added ${name}@^${version} to ${path.relative(process.cwd(), appPkgPath) || 'package.json'}` +
2155
2159
  (workspaces.changed ? ' and packages/* to its workspaces' : ''));
2156
2160
  if (skipInstall) {
@@ -2164,7 +2168,8 @@ function installWorkspacePackage(name_1, targetFolder_1, appRoot_1) {
2164
2168
  }
2165
2169
  /**
2166
2170
  * packages-local/: a repository of its own. Its git history starts here, and
2167
- * localize's `adopt` installs, builds, links and records it. The app's
2171
+ * localize's `adopt` sets the app up for checkouts, installs at the app root
2172
+ * (npm links it as a workspace member) and builds it. The app's
2168
2173
  * dependencies are NOT touched: until the package is published a version range
2169
2174
  * fails `npm install` (E404 once a lockfile exists), and a `file:` path would
2170
2175
  * install cleanly for a teammate without the checkout and fail at runtime.
@@ -2189,14 +2194,8 @@ function installOwnRepoPackage(name, targetFolder, appRoot, decision) {
2189
2194
  pkg.repository = { type: 'git', url: repositoryUrlFor(remote) };
2190
2195
  fs.writeJsonSync(pkgPath, pkg, { spaces: 2 });
2191
2196
  }
2192
- // Before adopt, never during it: adopt asserts the app's package.json did not
2193
- // change while it ran.
2194
- const appPkgPath = path.join(appRoot, 'package.json');
2195
- const appPkg = fs.readJsonSync(appPkgPath);
2196
- if (ensureRelinkPostinstall(appPkg)) {
2197
- fs.writeJsonSync(appPkgPath, appPkg, { spaces: 2 });
2198
- log(`Added \`${RELINK_COMMAND}\` to the app's postinstall, so npm install keeps the link`);
2199
- }
2197
+ // adopt sets the app up for checkouts (workspaces glob, lock-at-rest hook,
2198
+ // .gitignore) and says what it changed, then installs at the app root.
2200
2199
  const { adoptPackage } = yield import('./commands/localize.js');
2201
2200
  const { EXIT_WARNED } = yield import('./localize/index.js');
2202
2201
  // Only the build command matters here: adopt always installs with npm, so
@@ -2204,12 +2203,11 @@ function installOwnRepoPackage(name, targetFolder, appRoot, decision) {
2204
2203
  const { buildCommand } = planPackageSetup('', path.join(getScriptDir(), 'launch.js'), process.execPath);
2205
2204
  const code = yield adoptPackage(name, { appRoot, build: buildCommand });
2206
2205
  if (code === EXIT_WARNED) {
2207
- fail('The package is linked, but its initial build failed');
2206
+ fail('The package is installed, but its initial build failed');
2208
2207
  }
2209
2208
  else if (code !== 0) {
2210
- return fail(`Linking ${name} failed (localize exit ${code}). ${rel} is scaffolded with an uncommitted ` +
2211
- `git init, and the app's postinstall relinks localized packages. Fix the cause and retry ` +
2212
- `with: linked localize ${name} --adopt`);
2209
+ return fail(`Installing ${name} failed (localize exit ${code}). ${rel} is scaffolded with an uncommitted ` +
2210
+ `git init. Fix the cause and retry with: linked localize ${name} --adopt`);
2213
2211
  }
2214
2212
  const committed = git(['add', '-A'], targetFolder) &&
2215
2213
  git(['commit', '--quiet', '-m', `feat: scaffold ${name}`], targetFolder);
@@ -2225,10 +2223,27 @@ function installOwnRepoPackage(name, targetFolder, appRoot, decision) {
2225
2223
  }
2226
2224
  const version = fs.readJsonSync(pkgPath).version;
2227
2225
  log(`Prepared ${name} in ${chalk.magenta(rel)}, in its own git repository` +
2228
- (remote ? ` (origin ${remote}${pushed ? ', pushed' : ''})` : ' (no remote yet)'), `It is linked into node_modules and recorded in local-packages.json.`, `It is not in the app's dependencies: until it is published a version range would fail npm install.`, ` After publishing: ${chalk.blueBright(`npm install ${name}@^${version}`)}`);
2226
+ (remote ? ` (origin ${remote}${pushed ? ', pushed' : ''})` : ' (no remote yet)'), `It is a workspace member through the app's packages-local/* glob, so npm links it.`, `It is not in the app's dependencies: until it is published a version range would fail npm install.`, ` After publishing: ${chalk.blueBright(`npm install ${name}@^${version}`)}`);
2229
2227
  if (!remote) {
2230
- log(`To add a remote later: ${chalk.blueBright('git remote add origin <url>')} in ${rel}, ` +
2231
- `then ${chalk.blueBright(`linked localize ${name} --adopt`)} to record it.`);
2228
+ log(`To add a remote later: ${chalk.blueBright('git remote add origin <url>')} in ${rel}.`);
2229
+ }
2230
+ });
2231
+ }
2232
+ /** localize's one-time app setup, reported the way localize reports it. */
2233
+ function setUpAppForCheckouts(appRoot) {
2234
+ return __awaiter(this, void 0, void 0, function* () {
2235
+ const { ensureAppSetup, LocalizeError } = yield import('./localize/index.js');
2236
+ try {
2237
+ const changes = ensureAppSetup(appRoot);
2238
+ if (changes.length) {
2239
+ log(`Set up this app for checkouts in packages-local/ (commit these):`, ...changes.map((c) => ` ${c.file}: ${c.what}`));
2240
+ }
2241
+ }
2242
+ catch (e) {
2243
+ if (!(e instanceof LocalizeError))
2244
+ throw e;
2245
+ console.warn(chalk.yellow(e.message));
2246
+ process.exitCode = 1;
2232
2247
  }
2233
2248
  });
2234
2249
  }
@@ -2514,22 +2529,23 @@ export const planBuildSteps = (pkgJson, packagePath) => {
2514
2529
  {
2515
2530
  name: 'Copying files to lib folder',
2516
2531
  apply: () => __awaiter(void 0, void 0, void 0, function* () {
2517
- const files = yield glob(packagePath + '/src/**/*.{json,d.ts,css,scss}');
2532
+ // Relative to src/ (glob's cwd), so the destination is a plain join: a pattern or a
2533
+ // prefix built from an absolute Windows path would not match.
2534
+ const files = yield glob('**/*.{json,d.ts,css,scss}', {
2535
+ cwd: path.join(packagePath, 'src'),
2536
+ });
2518
2537
  let cjsPublished = false;
2519
2538
  try {
2520
2539
  cjsPublished = packagePublishesCjs(JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json'), 'utf8')));
2521
2540
  }
2522
2541
  catch (_a) { }
2523
2542
  return Promise.all(files.map((file) => __awaiter(void 0, void 0, void 0, function* () {
2543
+ const source = path.join(packagePath, 'src', file);
2524
2544
  try {
2525
- yield fs.copy(file, packagePath +
2526
- '/lib/esm/' +
2527
- file.replace(packagePath + '/src/', ''));
2545
+ yield fs.copy(source, path.join(packagePath, 'lib', 'esm', file));
2528
2546
  // Only mirror into lib/cjs when there is a CJS build to mirror.
2529
2547
  if (cjsPublished) {
2530
- yield fs.copy(file, packagePath +
2531
- '/lib/cjs/' +
2532
- file.replace(packagePath + '/src/', ''));
2548
+ yield fs.copy(source, path.join(packagePath, 'lib', 'cjs', file));
2533
2549
  }
2534
2550
  return true;
2535
2551
  }
@@ -2884,7 +2900,8 @@ export var publishPackage = function (pkg, test, info, publishVersion) {
2884
2900
  const versionAndPublish = publishPm === 'yarn'
2885
2901
  ? `yarn version ${publishVersion} && yarn npm publish`
2886
2902
  : `npm version ${publishVersion} --no-git-tag-version && npm publish`;
2887
- return execPromise(`cd ${pkg.path} && ${envJsonPath ? `env-cmd -f ${envJsonPath} --use-shell "` : ''}${versionAndPublish}${envJsonPath ? `"` : ''}`, true, false, {}, true)
2903
+ // The package as cwd, not `cd <dir> &&`: cmd.exe's `cd` does not change drives.
2904
+ return execPromise(`${envJsonPath ? `env-cmd -f "${envJsonPath}" --use-shell "` : ''}${versionAndPublish}${envJsonPath ? `"` : ''}`, true, false, { cwd: pkg.path }, true)
2888
2905
  .then((res) => {
2889
2906
  if (res.indexOf('Aborted due to warnings') !== -1 ||
2890
2907
  res.indexOf('Could not publish') !== -1 ||
@@ -3044,7 +3061,7 @@ export var executeCommandForEachPackage = function (packages, command, filterMet
3044
3061
  packages.forEach((pkg) => {
3045
3062
  p = p.then(() => {
3046
3063
  log('# Package ' + chalk.magenta(pkg.packageName));
3047
- return execp('cd ' + pkg.path + ' && ' + command);
3064
+ return execp(command, false, false, { cwd: pkg.path });
3048
3065
  });
3049
3066
  });
3050
3067
  return p;
@@ -3124,16 +3141,15 @@ export var executeCommandForPackage = function (packageName, command) {
3124
3141
  // npm is the default; only a package inside a yarn project is driven with
3125
3142
  // yarn (`yarn linked <cmd>` resolves the bin from the yarn workspace).
3126
3143
  const pm = detectPackageManager(packageDetails.path);
3127
- // Windows quirk: the shim is `yarn.cmd` / `npx.cmd`.
3128
- const isWin = process.platform === 'win32';
3129
- const runner = pm === 'yarn' ? (isWin ? 'yarn.cmd' : 'yarn') : isWin ? 'npx.cmd' : 'npx';
3144
+ const runner = pm === 'yarn' ? 'yarn' : 'npx';
3130
3145
  const runnerArgs = pm === 'yarn' ? ['linked'] : ['--no-install', 'linked'];
3131
- log("Executing 'cd " +
3132
- packageDetails.path +
3133
- ` && ${runner} linked` +
3134
- (command ? ' ' + command : '') +
3135
- "'");
3136
- spawnChild(runner, [...runnerArgs, command || null], {
3146
+ const commandArgs = command ? String(command).split(/\s+/).filter(Boolean) : [];
3147
+ log("Executing '" +
3148
+ [runner, ...runnerArgs, ...commandArgs].join(' ') +
3149
+ "' in " +
3150
+ packageDetails.path);
3151
+ // spawnCommand starts the `.cmd` shim on Windows.
3152
+ spawnCommand(runner, [...runnerArgs, ...commandArgs], {
3137
3153
  cwd: packageDetails.path,
3138
3154
  stdio: 'inherit',
3139
3155
  });
@@ -3151,7 +3167,7 @@ export const removeOldFiles = (packagePath) => __awaiter(void 0, void 0, void 0,
3151
3167
  const libPath = path.join(packagePath, 'lib');
3152
3168
  try {
3153
3169
  // Read all files in the 'lib' folder asynchronously
3154
- const files = yield glob(packagePath + '/lib/**/*.*');
3170
+ const files = yield glob('**/*.*', { cwd: libPath, absolute: true });
3155
3171
  // Iterate through each file
3156
3172
  for (const file of files) {
3157
3173
  // const filePath = path.join(libPath, file);