znode-plugin 0.1.9 → 0.1.10
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/lib/znode-package.mjs +192 -42
- package/package.json +1 -1
package/lib/znode-package.mjs
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
import fs from "node:fs";
|
|
50
50
|
import path from "node:path";
|
|
51
51
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
52
|
-
import { createRequire } from "node:module";
|
|
52
|
+
import { builtinModules, createRequire } from "node:module";
|
|
53
53
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
54
54
|
import vm from "node:vm";
|
|
55
55
|
import { TEMPLATES } from "./templates.mjs";
|
|
@@ -235,6 +235,24 @@ function build(target) {
|
|
|
235
235
|
// the store modules its server part imports (the store's server registry, permission storeServer)
|
|
236
236
|
const serverStoreImports = [];
|
|
237
237
|
const store = linkedStore(dir);
|
|
238
|
+
// the npm packages its sources import: those the store does not share and the package does not have yet are installed
|
|
239
|
+
// at the store's version before anything compiles (--no-install: named instead); another version than the store's warns
|
|
240
|
+
if (store) {
|
|
241
|
+
const sources = [];
|
|
242
|
+
const walk = (folder) => {
|
|
243
|
+
if (!fs.existsSync(folder)) return;
|
|
244
|
+
for (const entry of fs.readdirSync(folder, { withFileTypes: true })) {
|
|
245
|
+
const file = path.join(folder, entry.name);
|
|
246
|
+
if (entry.isDirectory()) walk(file);
|
|
247
|
+
else if (/\.(tsx?|jsx?|mjs)$/.test(entry.name)) sources.push(file);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
walk(path.join(dir, "src"));
|
|
251
|
+
const specs = sources.flatMap((file) => npmImportsOf(fs.readFileSync(file, "utf8")));
|
|
252
|
+
ensureStorePackages(dir, store, specs, { install: !process.argv.includes("--no-install") });
|
|
253
|
+
const drift = versionDrift(dir, store, specs);
|
|
254
|
+
if (drift.length) console.log(`warning installed at another version than the store's: ${drift.join(", ")} (npm install --save-exact <pkg>@<store version>)`);
|
|
255
|
+
}
|
|
238
256
|
// A package with its own tsconfig.json (extending the store's tsconfig.base.json) is checked against the store's real
|
|
239
257
|
// types (every @znode alias, no declarations to write), then compiled file by file without type information, JSX as
|
|
240
258
|
// Next.js does (react/jsx-runtime: the store's). Without one, the package compiles as before (tsc, JSX factory h).
|
|
@@ -704,12 +722,134 @@ function linkStore(storeRepo, project = ".") {
|
|
|
704
722
|
const options = config.compilerOptions || {};
|
|
705
723
|
const toSlash = (value) => value.split(path.sep).join("/");
|
|
706
724
|
const file = path.resolve(project, "tsconfig.store.json");
|
|
725
|
+
// the npm packages the store shares at runtime (next-intl, lodash, ...): never installed in the package (the build uses
|
|
726
|
+
// the store's copy), so their types come from the store's own node_modules, at the store's version
|
|
727
|
+
const repo = path.dirname(base);
|
|
728
|
+
const sharedPaths = {};
|
|
729
|
+
for (const pkg of storeSharedPackages(repo)) {
|
|
730
|
+
const types = path.join(repo, "node_modules", "@types", pkg.replace(/^@/, "").replace("/", "__"));
|
|
731
|
+
const dir = path.join(repo, "node_modules", pkg);
|
|
732
|
+
if (fs.existsSync(path.join(types, "package.json"))) sharedPaths[pkg] = [toSlash(types)];
|
|
733
|
+
else if (fs.existsSync(path.join(dir, "package.json"))) {
|
|
734
|
+
sharedPaths[pkg] = [toSlash(dir)];
|
|
735
|
+
sharedPaths[`${pkg}/*`] = [`${toSlash(dir)}/*`];
|
|
736
|
+
}
|
|
737
|
+
}
|
|
707
738
|
const linked = {
|
|
708
739
|
extends: "znode-plugin/tsconfig.json",
|
|
709
|
-
compilerOptions: { baseUrl: toSlash(path.resolve(
|
|
740
|
+
compilerOptions: { baseUrl: toSlash(path.resolve(repo, options.baseUrl || ".")), paths: { ...sharedPaths, ...(options.paths || {}) } },
|
|
710
741
|
};
|
|
711
742
|
fs.writeFileSync(file, JSON.stringify(linked, null, 2) + "\n");
|
|
712
|
-
|
|
743
|
+
const shared = Object.keys(sharedPaths).filter((key) => !key.endsWith("/*"));
|
|
744
|
+
console.log(
|
|
745
|
+
`linked ${file} to ${base} (${Object.keys(options.paths || {}).length} store aliases${shared.length ? `; types of the packages the store shares: ${shared.join(", ")}` : ""})`
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// ---- the store's npm packages: shared at runtime, or installed in the package at the store's version -------------------
|
|
750
|
+
// react, react-dom, next and @znode/* are the store's at runtime (stand-ins, never bundled); so are the store's shared
|
|
751
|
+
// packages (its registry's sharedPackages: next-intl, lodash, ...). Any other npm package a package imports is bundled
|
|
752
|
+
// into it, so it must be installed in the package: at the version the store has installed, so a copied store component
|
|
753
|
+
// behaves as it does in the store. Installed exactly (no ^), from the npm registry, by eject and by build.
|
|
754
|
+
const RUNTIME_PROVIDED = /^(react|react-dom|next|@znode)(\/|$)/;
|
|
755
|
+
const DEFAULT_SHARED = ["lodash", "next-intl"];
|
|
756
|
+
const packageNameOf = (spec) => (spec.startsWith("@") ? spec.split("/").slice(0, 2).join("/") : spec.split("/")[0]);
|
|
757
|
+
|
|
758
|
+
function storeSharedPackages(root) {
|
|
759
|
+
for (const name of ["store-module-registry.json", "store-server-module-registry.json"]) {
|
|
760
|
+
const file = path.join(root, "packages/extensions", name);
|
|
761
|
+
try {
|
|
762
|
+
const list = readJson(file).sharedPackages;
|
|
763
|
+
if (Array.isArray(list) && list.length) return list.map(String);
|
|
764
|
+
} catch {
|
|
765
|
+
// no registry, or one from before sharedPackages: the default list
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return DEFAULT_SHARED;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// the version the store has installed (its node_modules), else its package.json range without ^ / ~
|
|
772
|
+
function storePackageVersion(root, pkg) {
|
|
773
|
+
try {
|
|
774
|
+
return readJson(path.join(root, "node_modules", pkg, "package.json")).version;
|
|
775
|
+
} catch {
|
|
776
|
+
try {
|
|
777
|
+
const manifest = readJson(path.join(root, "package.json"));
|
|
778
|
+
const range = { ...(manifest.devDependencies || {}), ...(manifest.dependencies || {}) }[pkg];
|
|
779
|
+
return range ? range.replace(/^[\^~]/, "") : null;
|
|
780
|
+
} catch {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const installedIn = (project, pkg) => fs.existsSync(path.join(project, "node_modules", pkg, "package.json"));
|
|
787
|
+
|
|
788
|
+
// the npm packages code imports (bare specifiers, type-only imports included: their types are needed too)
|
|
789
|
+
const npmImportsOf = (code) =>
|
|
790
|
+
[...code.matchAll(/(?:^|[^\w$.])(?:import|export)\s*(?:[^"';]*?\s+from\s*)?["']([^"'.][^"']*)["']|import\(\s*["']([^"'.][^"']*)["']\s*\)/g)]
|
|
791
|
+
.map((match) => match[1] || match[2])
|
|
792
|
+
.filter((spec) => !spec.startsWith("node:") && !builtinModules.includes(packageNameOf(spec)));
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* The npm packages `specs` need in the package at `project`: the store's runtime and shared packages are left out, the
|
|
796
|
+
* others not installed yet are installed at the store's version (with their @types package when the store has one), or
|
|
797
|
+
* only named when install is false. Returns what was done, for the caller's message.
|
|
798
|
+
*/
|
|
799
|
+
function ensureStorePackages(project, store, specs, { install = true } = {}) {
|
|
800
|
+
const root = store.root;
|
|
801
|
+
const shared = new Set(storeSharedPackages(root));
|
|
802
|
+
const wanted = new Map();
|
|
803
|
+
const typesWanted = new Map();
|
|
804
|
+
const notInStore = new Set();
|
|
805
|
+
const sharedUsed = new Set();
|
|
806
|
+
for (const pkg of new Set(specs.map(packageNameOf))) {
|
|
807
|
+
if (RUNTIME_PROVIDED.test(pkg)) continue;
|
|
808
|
+
if (shared.has(pkg)) {
|
|
809
|
+
sharedUsed.add(pkg);
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
if (installedIn(project, pkg)) continue;
|
|
813
|
+
const version = storePackageVersion(root, pkg);
|
|
814
|
+
if (!version) {
|
|
815
|
+
notInStore.add(pkg);
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
wanted.set(pkg, `${pkg}@${version}`);
|
|
819
|
+
const typesName = `@types/${pkg.replace(/^@/, "").replace("/", "__")}`;
|
|
820
|
+
const typesVersion = fs.existsSync(path.join(root, "node_modules", typesName, "package.json")) ? storePackageVersion(root, typesName) : null;
|
|
821
|
+
if (typesVersion && !installedIn(project, typesName)) typesWanted.set(typesName, `${typesName}@${typesVersion}`);
|
|
822
|
+
}
|
|
823
|
+
const run = (args) => spawnSync(process.platform === "win32" ? "npm.cmd" : "npm", args, { cwd: project, stdio: "inherit", shell: process.platform === "win32" });
|
|
824
|
+
let installed = [];
|
|
825
|
+
if (wanted.size) {
|
|
826
|
+
const list = [...wanted.values()];
|
|
827
|
+
if (install) {
|
|
828
|
+
console.log(`installing the store's versions: ${list.join(" ")}`);
|
|
829
|
+
const result = run(["install", "--save-exact", "--no-audit", "--no-fund", ...list]);
|
|
830
|
+
if (result.status !== 0) fail(`npm install failed: run it yourself in ${project}: npm install --save-exact ${list.join(" ")}`);
|
|
831
|
+
if (typesWanted.size) run(["install", "--save-dev", "--save-exact", "--no-audit", "--no-fund", ...typesWanted.values()]);
|
|
832
|
+
installed = [...list, ...typesWanted.values()];
|
|
833
|
+
} else {
|
|
834
|
+
console.log(`needs the store's versions (not installed: --no-install): npm install --save-exact ${list.join(" ")}`);
|
|
835
|
+
if (typesWanted.size) console.log(` and its types: npm install --save-dev --save-exact ${[...typesWanted.values()].join(" ")}`);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
for (const pkg of notInStore) console.log(`warning "${pkg}" is not a dependency of the store: install it yourself (npm install ${pkg})`);
|
|
839
|
+
return { installed, shared: [...sharedUsed], notInStore: [...notInStore] };
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// packages installed in the package at another version than the store's (after a store upgrade): a warning, the store's
|
|
843
|
+
// version is what its components were written against
|
|
844
|
+
function versionDrift(project, store, specs) {
|
|
845
|
+
const drift = [];
|
|
846
|
+
for (const pkg of new Set(specs.map(packageNameOf))) {
|
|
847
|
+
if (RUNTIME_PROVIDED.test(pkg) || !installedIn(project, pkg)) continue;
|
|
848
|
+
const mine = readJson(path.join(project, "node_modules", pkg, "package.json")).version;
|
|
849
|
+
const theirs = fs.existsSync(path.join(store.root, "node_modules", pkg, "package.json")) ? storePackageVersion(store.root, pkg) : null;
|
|
850
|
+
if (theirs && mine !== theirs) drift.push(`${pkg} ${mine} (store: ${theirs})`);
|
|
851
|
+
}
|
|
852
|
+
return drift;
|
|
713
853
|
}
|
|
714
854
|
|
|
715
855
|
// ---- eject: a store component copied into the package, in place of the store's, through its slot ----------------
|
|
@@ -779,8 +919,25 @@ function ejectableComponents(root) {
|
|
|
779
919
|
return found.sort((a, b) => a.name.localeCompare(b.name));
|
|
780
920
|
}
|
|
781
921
|
|
|
782
|
-
// a store file
|
|
783
|
-
function
|
|
922
|
+
// a store file that re-exports `target` (export * from / export { … } from), followed through nested barrels
|
|
923
|
+
function reExports(barrel, target, seen = new Set()) {
|
|
924
|
+
if (!barrel || seen.has(barrel) || !fs.existsSync(barrel)) return false;
|
|
925
|
+
seen.add(barrel);
|
|
926
|
+
const asFile = (base) =>
|
|
927
|
+
[base, `${base}.ts`, `${base}.tsx`, path.join(base, "index.ts"), path.join(base, "index.tsx")].find((file) => fs.existsSync(file) && fs.statSync(file).isFile());
|
|
928
|
+
for (const match of fs.readFileSync(barrel, "utf8").matchAll(/export\s*(?:\*|\{[^}]*\})\s*from\s*["'](\.{1,2}\/[^"']+)["']/g)) {
|
|
929
|
+
const file = asFile(path.resolve(path.dirname(barrel), match[1]));
|
|
930
|
+
if (!file) continue;
|
|
931
|
+
if (file.split(path.sep).join("/").replace(/\.(tsx?|jsx?)$/, "").replace(/\/index$/, "") === target) return true;
|
|
932
|
+
if (reExports(file, target, seen)) return true;
|
|
933
|
+
}
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// a store file's import path as the package can import it: the store alias that maps to that file, without extension;
|
|
938
|
+
// else, for named imports (statement: the import's text up to its path), an exact alias whose barrel re-exports the file
|
|
939
|
+
// (".../stores/modal" -> "@znode/base-components/stores"): export * does not carry a default, so a default import is not
|
|
940
|
+
function storeAlias(store, absolute, { statement = "" } = {}) {
|
|
784
941
|
const target = absolute.split(path.sep).join("/").replace(/\.(tsx?|jsx?)$/, "").replace(/\/index$/, "");
|
|
785
942
|
let best = null;
|
|
786
943
|
const norm = (value) => path.resolve(store.root, value).split(path.sep).join("/").replace(/\.(tsx?|jsx?)$/, "").replace(/\/index$/, "");
|
|
@@ -795,7 +952,14 @@ function storeAlias(store, absolute) {
|
|
|
795
952
|
if (target.startsWith(prefix) && (!best || prefix.length > best.prefix.length)) best = { prefix, alias: alias.slice(0, -1) };
|
|
796
953
|
}
|
|
797
954
|
}
|
|
798
|
-
|
|
955
|
+
if (best) return best.alias + target.slice(best.prefix.length);
|
|
956
|
+
const namedOnly = /^import\s*(?:type\s+)?\{/.test(statement.trim()) || /^export\s/.test(statement.trim());
|
|
957
|
+
if (!namedOnly) return null;
|
|
958
|
+
for (const [alias, targets] of Object.entries(store.paths)) {
|
|
959
|
+
if (alias.endsWith("/*") || !alias.startsWith("@znode/")) continue;
|
|
960
|
+
if (targets.some((pattern) => reExports(path.resolve(store.root, pattern), target))) return alias;
|
|
961
|
+
}
|
|
962
|
+
return null;
|
|
799
963
|
}
|
|
800
964
|
|
|
801
965
|
// a question on the terminal (only asked when stdin is a terminal); one line reader for the whole run, so answers
|
|
@@ -838,8 +1002,8 @@ function ejectRouteCopy(project, s, store) {
|
|
|
838
1002
|
text = text.replace(new RegExp(`^(async\\s+)?function\\s+${s.base}\\s*\\(`, "m"), (whole, isAsync) => `export ${isAsync || ""}function ${name}(`);
|
|
839
1003
|
// relative imports become the store's aliases (the package lives elsewhere)
|
|
840
1004
|
const warnings = [];
|
|
841
|
-
text = text.replace(/((?:from|import)\s*\(?\s*["'])(\.{1,2}\/[^"']+)(["'])/g, (whole, before, spec, after) => {
|
|
842
|
-
const alias = storeAlias(store, path.resolve(path.dirname(storeFile), spec));
|
|
1005
|
+
text = text.replace(/((?:from|import)\s*\(?\s*["'])(\.{1,2}\/[^"']+)(["'])/g, (whole, before, spec, after, offset, source) => {
|
|
1006
|
+
const alias = storeAlias(store, path.resolve(path.dirname(storeFile), spec), { statement: source.slice(source.lastIndexOf("import", offset), offset) });
|
|
843
1007
|
if (!alias) {
|
|
844
1008
|
warnings.push(`import ${spec}: no store alias for it; change it by hand`);
|
|
845
1009
|
return whole;
|
|
@@ -886,7 +1050,7 @@ function ejectRouteCopy(project, s, store) {
|
|
|
886
1050
|
return { text, warnings };
|
|
887
1051
|
}
|
|
888
1052
|
|
|
889
|
-
function ejectServerSlot(project, s, force, store) {
|
|
1053
|
+
function ejectServerSlot(project, s, force, store, noInstall = false) {
|
|
890
1054
|
const name = s.page;
|
|
891
1055
|
const out = path.join(project, "src", "server", "pages", `${name}.tsx`);
|
|
892
1056
|
if (fs.existsSync(out) && !force) fail(`${path.relative(project, out)} exists: delete it or run znode eject ${name} --force`);
|
|
@@ -896,6 +1060,9 @@ function ejectServerSlot(project, s, force, store) {
|
|
|
896
1060
|
fs.writeFileSync(out, text);
|
|
897
1061
|
console.log(`ejected ${name} (a copy of ${s.files[0]}, server slot "${s.name}") -> ${path.relative(project, out)}`);
|
|
898
1062
|
registerServerSlot(project, s, name);
|
|
1063
|
+
const deps = ensureStorePackages(project, store, npmImportsOf(text), { install: !noInstall });
|
|
1064
|
+
if (deps.installed.length) console.log(`installed (store versions): ${deps.installed.join(", ")}`);
|
|
1065
|
+
if (deps.shared.length) console.log(`shared by the store (not installed; types from the linked store): ${deps.shared.join(", ")}`);
|
|
899
1066
|
for (const warning of warnings) console.log(`warning ${warning}`);
|
|
900
1067
|
console.log(`\nNext: edit ${path.relative(project, out)}, then npm run build (it names any store import a server part cannot use) and npm run dev.`);
|
|
901
1068
|
return;
|
|
@@ -954,7 +1121,7 @@ function registerServerSlot(project, s, name) {
|
|
|
954
1121
|
console.log(`registered "${s.name}": ${local} in src/server.tsx (serverSlots)`);
|
|
955
1122
|
}
|
|
956
1123
|
|
|
957
|
-
async function eject(name, force, { slot: slotArg, yes } = {}) {
|
|
1124
|
+
async function eject(name, force, { slot: slotArg, yes, noInstall } = {}) {
|
|
958
1125
|
const project = path.resolve(".");
|
|
959
1126
|
if (!fs.existsSync(path.join(project, MANIFEST))) fail(`run znode eject in a package folder (the one with ${MANIFEST})`);
|
|
960
1127
|
const store = linkedStore(project);
|
|
@@ -980,7 +1147,7 @@ async function eject(name, force, { slot: slotArg, yes } = {}) {
|
|
|
980
1147
|
let c = find(components);
|
|
981
1148
|
if (!c) {
|
|
982
1149
|
const server = findServer();
|
|
983
|
-
if (server) return ejectServerSlot(project, server, force, store);
|
|
1150
|
+
if (server) return ejectServerSlot(project, server, force, store, noInstall);
|
|
984
1151
|
}
|
|
985
1152
|
if (!c) {
|
|
986
1153
|
// no slot hands this component over yet: offer to create one in the base store (what znode create-slot does), then eject
|
|
@@ -1012,7 +1179,7 @@ async function eject(name, force, { slot: slotArg, yes } = {}) {
|
|
|
1012
1179
|
const server = findServer();
|
|
1013
1180
|
if (server) {
|
|
1014
1181
|
console.log("");
|
|
1015
|
-
return ejectServerSlot(project, server, force, store);
|
|
1182
|
+
return ejectServerSlot(project, server, force, store, noInstall);
|
|
1016
1183
|
}
|
|
1017
1184
|
fail(`the slot "${slot}" was created, but ${name} is still not found as ejectable; check the store diff`);
|
|
1018
1185
|
}
|
|
@@ -1024,15 +1191,15 @@ async function eject(name, force, { slot: slotArg, yes } = {}) {
|
|
|
1024
1191
|
const warnings = [];
|
|
1025
1192
|
let text = fs.readFileSync(c.file, "utf8");
|
|
1026
1193
|
// relative imports become the store's aliases (the package lives elsewhere); a style file stays the store's
|
|
1027
|
-
text = text.replace(/((?:from|import)\s*\(?\s*["'])(\.{1,2}\/[^"']+)(["'])/g, (whole, before, spec, after) => {
|
|
1194
|
+
text = text.replace(/((?:from|import)\s*\(?\s*["'])(\.{1,2}\/[^"']+)(["'])/g, (whole, before, spec, after, offset, source) => {
|
|
1028
1195
|
const absolute = path.resolve(path.dirname(c.file), spec);
|
|
1029
1196
|
if (/\.(s?css)$/.test(spec)) {
|
|
1030
1197
|
warnings.push(`style import ${spec}: kept out of the copy; the store's own stylesheet is loaded where the store renders it, add your CSS to src/styles/`);
|
|
1031
1198
|
return `${before}${spec}${after}`;
|
|
1032
1199
|
}
|
|
1033
|
-
const alias = storeAlias(store,
|
|
1200
|
+
const alias = storeAlias(store, absolute, { statement: source.slice(source.lastIndexOf("import", offset), offset) });
|
|
1034
1201
|
if (!alias) {
|
|
1035
|
-
warnings.push(`import ${spec}: no store alias for it; change it by hand`);
|
|
1202
|
+
warnings.push(`import ${spec}: no store alias for it (nor a store barrel that re-exports its names); change it by hand`);
|
|
1036
1203
|
return whole;
|
|
1037
1204
|
}
|
|
1038
1205
|
return `${before}${alias}${after}`;
|
|
@@ -1051,32 +1218,11 @@ async function eject(name, force, { slot: slotArg, yes } = {}) {
|
|
|
1051
1218
|
fs.writeFileSync(out, text);
|
|
1052
1219
|
console.log(`ejected ${c.name} -> ${path.relative(project, out)}`);
|
|
1053
1220
|
|
|
1054
|
-
// npm packages the copy imports
|
|
1055
|
-
//
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
return readJson(path.join(store.root, "package.json"));
|
|
1060
|
-
} catch {
|
|
1061
|
-
return {};
|
|
1062
|
-
}
|
|
1063
|
-
})();
|
|
1064
|
-
const storeDeps = { ...(storePackage.devDependencies || {}), ...(storePackage.dependencies || {}) };
|
|
1065
|
-
const missing = new Map();
|
|
1066
|
-
for (const m of text.matchAll(/(?:from|import)\s*\(?\s*["']([^."'/][^"']*)["']/g)) {
|
|
1067
|
-
const spec = m[1];
|
|
1068
|
-
if (PROVIDED.test(spec)) continue;
|
|
1069
|
-
const pkg = spec.startsWith("@") ? spec.split("/").slice(0, 2).join("/") : spec.split("/")[0];
|
|
1070
|
-
try {
|
|
1071
|
-
createRequire(path.join(project, "package.json")).resolve(`${pkg}/package.json`);
|
|
1072
|
-
} catch {
|
|
1073
|
-
missing.set(pkg, storeDeps[pkg] ? `${pkg}@${storeDeps[pkg].replace(/^[\^~]/, "")}` : pkg);
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
if (missing.size) {
|
|
1077
|
-
console.log(`\nThe copy imports npm packages this package does not have (bundled into the package when it builds):`);
|
|
1078
|
-
console.log(` npm install ${[...missing.values()].join(" ")}`);
|
|
1079
|
-
}
|
|
1221
|
+
// npm packages the copy imports: the store's shared ones are used from the store (types through link-store), the others
|
|
1222
|
+
// are installed in this package at the store's version (bundled into the package when it builds)
|
|
1223
|
+
const deps = ensureStorePackages(project, store, npmImportsOf(text), { install: !noInstall });
|
|
1224
|
+
if (deps.installed.length) console.log(`installed (store versions): ${deps.installed.join(", ")}`);
|
|
1225
|
+
if (deps.shared.length) console.log(`shared by the store (not installed; types from the linked store): ${deps.shared.join(", ")}`);
|
|
1080
1226
|
|
|
1081
1227
|
// register the copy under the slot in src/browser.tsx
|
|
1082
1228
|
const browser = path.join(project, "src", "browser.tsx");
|
|
@@ -1518,7 +1664,11 @@ if (command === "eject") {
|
|
|
1518
1664
|
// eject <Name> [--force] [--slot <area.name>] [--yes]: --slot / --yes create a missing slot without asking
|
|
1519
1665
|
const slotAt = args.indexOf("--slot");
|
|
1520
1666
|
const name = args.find((arg, index) => index > 0 && !arg.startsWith("-") && !(slotAt >= 0 && index === slotAt + 1));
|
|
1521
|
-
await eject(name, args.includes("--force"), {
|
|
1667
|
+
await eject(name, args.includes("--force"), {
|
|
1668
|
+
slot: slotAt >= 0 ? args[slotAt + 1] : undefined,
|
|
1669
|
+
yes: args.includes("--yes") || args.includes("-y"),
|
|
1670
|
+
noInstall: args.includes("--no-install"),
|
|
1671
|
+
});
|
|
1522
1672
|
process.exit(0);
|
|
1523
1673
|
}
|
|
1524
1674
|
if (command === "link-store") {
|
package/package.json
CHANGED