plgg-bundle 0.0.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 +68 -0
- package/bin/appAliasHook.mjs +89 -0
- package/bin/hook.mjs +94 -0
- package/bin/plgg-bundle.mjs +16 -0
- package/dist/Dev/fixtures/devPoc.spec.d.ts +2 -0
- package/dist/Dev/fixtures/devPoc.spec.d.ts.map +1 -0
- package/dist/Dev/fixtures/devPoc.spec.js +145 -0
- package/dist/Dev/fixtures/devPoc.spec.js.map +1 -0
- package/dist/Dev/model/Fetch.d.ts +20 -0
- package/dist/Dev/model/Fetch.d.ts.map +1 -0
- package/dist/Dev/model/Fetch.js +8 -0
- package/dist/Dev/model/Fetch.js.map +1 -0
- package/dist/Dev/model/ModuleGraph.d.ts +27 -0
- package/dist/Dev/model/ModuleGraph.d.ts.map +1 -0
- package/dist/Dev/model/ModuleGraph.js +2 -0
- package/dist/Dev/model/ModuleGraph.js.map +1 -0
- package/dist/Dev/model/Protocol.d.ts +22 -0
- package/dist/Dev/model/Protocol.d.ts.map +1 -0
- package/dist/Dev/model/Protocol.js +31 -0
- package/dist/Dev/model/Protocol.js.map +1 -0
- package/dist/Dev/node/devServer.d.ts +21 -0
- package/dist/Dev/node/devServer.d.ts.map +1 -0
- package/dist/Dev/node/devServer.js +298 -0
- package/dist/Dev/node/devServer.js.map +1 -0
- package/dist/Dev/node/httpAdapter.d.ts +19 -0
- package/dist/Dev/node/httpAdapter.d.ts.map +1 -0
- package/dist/Dev/node/httpAdapter.js +76 -0
- package/dist/Dev/node/httpAdapter.js.map +1 -0
- package/dist/Dev/node/scanGraph.d.ts +21 -0
- package/dist/Dev/node/scanGraph.d.ts.map +1 -0
- package/dist/Dev/node/scanGraph.js +145 -0
- package/dist/Dev/node/scanGraph.js.map +1 -0
- package/dist/Dev/node/watch.d.ts +10 -0
- package/dist/Dev/node/watch.d.ts.map +1 -0
- package/dist/Dev/node/watch.js +44 -0
- package/dist/Dev/node/watch.js.map +1 -0
- package/dist/Dev/usecase/allowedHost.d.ts +16 -0
- package/dist/Dev/usecase/allowedHost.d.ts.map +1 -0
- package/dist/Dev/usecase/allowedHost.js +33 -0
- package/dist/Dev/usecase/allowedHost.js.map +1 -0
- package/dist/Dev/usecase/allowedHost.spec.d.ts +2 -0
- package/dist/Dev/usecase/allowedHost.spec.d.ts.map +1 -0
- package/dist/Dev/usecase/allowedHost.spec.js +13 -0
- package/dist/Dev/usecase/allowedHost.spec.js.map +1 -0
- package/dist/Dev/usecase/buildGraph.d.ts +12 -0
- package/dist/Dev/usecase/buildGraph.d.ts.map +1 -0
- package/dist/Dev/usecase/buildGraph.js +24 -0
- package/dist/Dev/usecase/buildGraph.js.map +1 -0
- package/dist/Dev/usecase/buildGraph.spec.d.ts +2 -0
- package/dist/Dev/usecase/buildGraph.spec.d.ts.map +1 -0
- package/dist/Dev/usecase/buildGraph.spec.js +16 -0
- package/dist/Dev/usecase/buildGraph.spec.js.map +1 -0
- package/dist/Dev/usecase/decorateDevHtml.d.ts +12 -0
- package/dist/Dev/usecase/decorateDevHtml.d.ts.map +1 -0
- package/dist/Dev/usecase/decorateDevHtml.js +15 -0
- package/dist/Dev/usecase/decorateDevHtml.js.map +1 -0
- package/dist/Dev/usecase/decorateDevHtml.spec.d.ts +2 -0
- package/dist/Dev/usecase/decorateDevHtml.spec.d.ts.map +1 -0
- package/dist/Dev/usecase/decorateDevHtml.spec.js +19 -0
- package/dist/Dev/usecase/decorateDevHtml.spec.js.map +1 -0
- package/dist/Dev/usecase/invalidate.d.ts +17 -0
- package/dist/Dev/usecase/invalidate.d.ts.map +1 -0
- package/dist/Dev/usecase/invalidate.js +57 -0
- package/dist/Dev/usecase/invalidate.js.map +1 -0
- package/dist/Dev/usecase/invalidate.spec.d.ts +2 -0
- package/dist/Dev/usecase/invalidate.spec.d.ts.map +1 -0
- package/dist/Dev/usecase/invalidate.spec.js +64 -0
- package/dist/Dev/usecase/invalidate.spec.js.map +1 -0
- package/dist/Dev/usecase/parseImports.d.ts +24 -0
- package/dist/Dev/usecase/parseImports.d.ts.map +1 -0
- package/dist/Dev/usecase/parseImports.js +40 -0
- package/dist/Dev/usecase/parseImports.js.map +1 -0
- package/dist/Dev/usecase/parseImports.spec.d.ts +2 -0
- package/dist/Dev/usecase/parseImports.spec.d.ts.map +1 -0
- package/dist/Dev/usecase/parseImports.spec.js +24 -0
- package/dist/Dev/usecase/parseImports.spec.js.map +1 -0
- package/dist/Dev/usecase/reloadDecision.d.ts +20 -0
- package/dist/Dev/usecase/reloadDecision.d.ts.map +1 -0
- package/dist/Dev/usecase/reloadDecision.js +52 -0
- package/dist/Dev/usecase/reloadDecision.js.map +1 -0
- package/dist/Dev/usecase/reloadDecision.spec.d.ts +2 -0
- package/dist/Dev/usecase/reloadDecision.spec.d.ts.map +1 -0
- package/dist/Dev/usecase/reloadDecision.spec.js +17 -0
- package/dist/Dev/usecase/reloadDecision.spec.js.map +1 -0
- package/dist/domain/model/BundleConfig.d.ts +136 -0
- package/dist/domain/model/BundleConfig.d.ts.map +1 -0
- package/dist/domain/model/BundleConfig.js +18 -0
- package/dist/domain/model/BundleConfig.js.map +1 -0
- package/dist/domain/model/BundleConfig.spec.d.ts +2 -0
- package/dist/domain/model/BundleConfig.spec.d.ts.map +1 -0
- package/dist/domain/model/BundleConfig.spec.js +8 -0
- package/dist/domain/model/BundleConfig.spec.js.map +1 -0
- package/dist/domain/usecase/asBundleConfig.d.ts +17 -0
- package/dist/domain/usecase/asBundleConfig.d.ts.map +1 -0
- package/dist/domain/usecase/asBundleConfig.js +179 -0
- package/dist/domain/usecase/asBundleConfig.js.map +1 -0
- package/dist/domain/usecase/asBundleConfig.spec.d.ts +2 -0
- package/dist/domain/usecase/asBundleConfig.spec.d.ts.map +1 -0
- package/dist/domain/usecase/asBundleConfig.spec.js +119 -0
- package/dist/domain/usecase/asBundleConfig.spec.js.map +1 -0
- package/dist/domain/usecase/build.d.ts +14 -0
- package/dist/domain/usecase/build.d.ts.map +1 -0
- package/dist/domain/usecase/build.js +177 -0
- package/dist/domain/usecase/build.js.map +1 -0
- package/dist/domain/usecase/collectModules.d.ts +53 -0
- package/dist/domain/usecase/collectModules.d.ts.map +1 -0
- package/dist/domain/usecase/collectModules.js +118 -0
- package/dist/domain/usecase/collectModules.js.map +1 -0
- package/dist/domain/usecase/deriveExternal.d.ts +25 -0
- package/dist/domain/usecase/deriveExternal.d.ts.map +1 -0
- package/dist/domain/usecase/deriveExternal.js +79 -0
- package/dist/domain/usecase/deriveExternal.js.map +1 -0
- package/dist/domain/usecase/deriveExternal.spec.d.ts +2 -0
- package/dist/domain/usecase/deriveExternal.spec.d.ts.map +1 -0
- package/dist/domain/usecase/deriveExternal.spec.js +56 -0
- package/dist/domain/usecase/deriveExternal.spec.js.map +1 -0
- package/dist/domain/usecase/discoverWorkspace.d.ts +27 -0
- package/dist/domain/usecase/discoverWorkspace.d.ts.map +1 -0
- package/dist/domain/usecase/discoverWorkspace.js +116 -0
- package/dist/domain/usecase/discoverWorkspace.js.map +1 -0
- package/dist/domain/usecase/discoverWorkspace.spec.d.ts +2 -0
- package/dist/domain/usecase/discoverWorkspace.spec.d.ts.map +1 -0
- package/dist/domain/usecase/discoverWorkspace.spec.js +23 -0
- package/dist/domain/usecase/discoverWorkspace.spec.js.map +1 -0
- package/dist/domain/usecase/emitBundle.d.ts +43 -0
- package/dist/domain/usecase/emitBundle.d.ts.map +1 -0
- package/dist/domain/usecase/emitBundle.js +157 -0
- package/dist/domain/usecase/emitBundle.js.map +1 -0
- package/dist/domain/usecase/emitBundle.spec.d.ts +2 -0
- package/dist/domain/usecase/emitBundle.spec.d.ts.map +1 -0
- package/dist/domain/usecase/emitBundle.spec.js +80 -0
- package/dist/domain/usecase/emitBundle.spec.js.map +1 -0
- package/dist/domain/usecase/emitDts.d.ts +32 -0
- package/dist/domain/usecase/emitDts.d.ts.map +1 -0
- package/dist/domain/usecase/emitDts.js +99 -0
- package/dist/domain/usecase/emitDts.js.map +1 -0
- package/dist/domain/usecase/isExternal.d.ts +12 -0
- package/dist/domain/usecase/isExternal.d.ts.map +1 -0
- package/dist/domain/usecase/isExternal.js +16 -0
- package/dist/domain/usecase/isExternal.js.map +1 -0
- package/dist/domain/usecase/isExternal.spec.d.ts +2 -0
- package/dist/domain/usecase/isExternal.spec.d.ts.map +1 -0
- package/dist/domain/usecase/isExternal.spec.js +16 -0
- package/dist/domain/usecase/isExternal.spec.js.map +1 -0
- package/dist/domain/usecase/resolveSpecifier.d.ts +35 -0
- package/dist/domain/usecase/resolveSpecifier.d.ts.map +1 -0
- package/dist/domain/usecase/resolveSpecifier.js +83 -0
- package/dist/domain/usecase/resolveSpecifier.js.map +1 -0
- package/dist/domain/usecase/resolveSpecifier.spec.d.ts +2 -0
- package/dist/domain/usecase/resolveSpecifier.spec.d.ts.map +1 -0
- package/dist/domain/usecase/resolveSpecifier.spec.js +44 -0
- package/dist/domain/usecase/resolveSpecifier.spec.js.map +1 -0
- package/dist/domain/usecase/resolveWorkspaceSpecifier.d.ts +29 -0
- package/dist/domain/usecase/resolveWorkspaceSpecifier.d.ts.map +1 -0
- package/dist/domain/usecase/resolveWorkspaceSpecifier.js +89 -0
- package/dist/domain/usecase/resolveWorkspaceSpecifier.js.map +1 -0
- package/dist/domain/usecase/resolveWorkspaceSpecifier.spec.d.ts +2 -0
- package/dist/domain/usecase/resolveWorkspaceSpecifier.spec.d.ts.map +1 -0
- package/dist/domain/usecase/resolveWorkspaceSpecifier.spec.js +27 -0
- package/dist/domain/usecase/resolveWorkspaceSpecifier.spec.js.map +1 -0
- package/dist/domain/usecase/rewriteDtsAliases.d.ts +25 -0
- package/dist/domain/usecase/rewriteDtsAliases.d.ts.map +1 -0
- package/dist/domain/usecase/rewriteDtsAliases.js +71 -0
- package/dist/domain/usecase/rewriteDtsAliases.js.map +1 -0
- package/dist/domain/usecase/rewriteDtsAliases.spec.d.ts +2 -0
- package/dist/domain/usecase/rewriteDtsAliases.spec.d.ts.map +1 -0
- package/dist/domain/usecase/rewriteDtsAliases.spec.js +35 -0
- package/dist/domain/usecase/rewriteDtsAliases.spec.js.map +1 -0
- package/dist/entrypoints/cli.d.ts +2 -0
- package/dist/entrypoints/cli.d.ts.map +1 -0
- package/dist/entrypoints/cli.js +79 -0
- package/dist/entrypoints/cli.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/vendors/runner.d.ts +20 -0
- package/dist/vendors/runner.d.ts.map +1 -0
- package/dist/vendors/runner.js +60 -0
- package/dist/vendors/runner.js.map +1 -0
- package/dist/vendors/runner.spec.d.ts +2 -0
- package/dist/vendors/runner.spec.d.ts.map +1 -0
- package/dist/vendors/runner.spec.js +20 -0
- package/dist/vendors/runner.spec.js.map +1 -0
- package/dist/vendors/transpiler.d.ts +19 -0
- package/dist/vendors/transpiler.d.ts.map +1 -0
- package/dist/vendors/transpiler.js +42 -0
- package/dist/vendors/transpiler.js.map +1 -0
- package/package.json +31 -0
- package/src/Dev/fixtures/devPoc.spec.ts +235 -0
- package/src/Dev/model/Fetch.ts +31 -0
- package/src/Dev/model/ModuleGraph.ts +30 -0
- package/src/Dev/model/Protocol.ts +35 -0
- package/src/Dev/node/devServer.ts +503 -0
- package/src/Dev/node/httpAdapter.ts +162 -0
- package/src/Dev/node/scanGraph.ts +203 -0
- package/src/Dev/node/watch.ts +54 -0
- package/src/Dev/usecase/allowedHost.spec.ts +50 -0
- package/src/Dev/usecase/allowedHost.ts +39 -0
- package/src/Dev/usecase/buildGraph.spec.ts +30 -0
- package/src/Dev/usecase/buildGraph.ts +31 -0
- package/src/Dev/usecase/decorateDevHtml.spec.ts +39 -0
- package/src/Dev/usecase/decorateDevHtml.ts +21 -0
- package/src/Dev/usecase/invalidate.spec.ts +88 -0
- package/src/Dev/usecase/invalidate.ts +67 -0
- package/src/Dev/usecase/parseImports.spec.ts +58 -0
- package/src/Dev/usecase/parseImports.ts +50 -0
- package/src/Dev/usecase/reloadDecision.spec.ts +50 -0
- package/src/Dev/usecase/reloadDecision.ts +65 -0
- package/src/domain/model/BundleConfig.spec.ts +35 -0
- package/src/domain/model/BundleConfig.ts +162 -0
- package/src/domain/usecase/asBundleConfig.spec.ts +230 -0
- package/src/domain/usecase/asBundleConfig.ts +257 -0
- package/src/domain/usecase/build.ts +259 -0
- package/src/domain/usecase/collectModules.ts +226 -0
- package/src/domain/usecase/deriveExternal.spec.ts +125 -0
- package/src/domain/usecase/deriveExternal.ts +108 -0
- package/src/domain/usecase/discoverWorkspace.spec.ts +63 -0
- package/src/domain/usecase/discoverWorkspace.ts +183 -0
- package/src/domain/usecase/emitBundle.spec.ts +162 -0
- package/src/domain/usecase/emitBundle.ts +215 -0
- package/src/domain/usecase/emitDts.ts +156 -0
- package/src/domain/usecase/isExternal.spec.ts +53 -0
- package/src/domain/usecase/isExternal.ts +20 -0
- package/src/domain/usecase/resolveSpecifier.spec.ts +112 -0
- package/src/domain/usecase/resolveSpecifier.ts +127 -0
- package/src/domain/usecase/resolveWorkspaceSpecifier.spec.ts +79 -0
- package/src/domain/usecase/resolveWorkspaceSpecifier.ts +120 -0
- package/src/domain/usecase/rewriteDtsAliases.spec.ts +123 -0
- package/src/domain/usecase/rewriteDtsAliases.ts +133 -0
- package/src/entrypoints/cli.ts +105 -0
- package/src/index.ts +28 -0
- package/src/vendors/runner.spec.ts +50 -0
- package/src/vendors/runner.ts +78 -0
- package/src/vendors/transpiler.ts +48 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type BundleConfig,
|
|
3
|
+
type DevConfig,
|
|
4
|
+
type SourceAlias,
|
|
5
|
+
type Entry,
|
|
6
|
+
type Format,
|
|
7
|
+
type Target,
|
|
8
|
+
} from "plgg-bundle/domain/model/BundleConfig";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Validate an `unknown` value (a dynamically-imported
|
|
12
|
+
* config module's default export) into a typed
|
|
13
|
+
* {@link BundleConfig}. The config is the bundler's
|
|
14
|
+
* `unknown` boundary, so every field is narrowed with a
|
|
15
|
+
* real guard (`typeof`, `Array.isArray`) — no `as`, no
|
|
16
|
+
* `any`. Throws a `ConfigError` on the first invalid
|
|
17
|
+
* field.
|
|
18
|
+
*
|
|
19
|
+
* Externals are NOT a config field: the bundler derives
|
|
20
|
+
* them from the package's `package.json` dependency
|
|
21
|
+
* graph (see `deriveExternal`), so they cannot drift
|
|
22
|
+
* from the manifest.
|
|
23
|
+
*/
|
|
24
|
+
export const asBundleConfig = (
|
|
25
|
+
value: unknown,
|
|
26
|
+
): BundleConfig => {
|
|
27
|
+
if (!isRecord(value)) {
|
|
28
|
+
return fail("config is not an object");
|
|
29
|
+
}
|
|
30
|
+
const devSection = dev(value);
|
|
31
|
+
return {
|
|
32
|
+
target: target(value),
|
|
33
|
+
root: str(value, "root"),
|
|
34
|
+
rootDir: str(value, "rootDir"),
|
|
35
|
+
outDir: str(value, "outDir"),
|
|
36
|
+
fileNamePattern: str(
|
|
37
|
+
value,
|
|
38
|
+
"fileNamePattern",
|
|
39
|
+
),
|
|
40
|
+
entries: entries(value),
|
|
41
|
+
formats: formats(value),
|
|
42
|
+
alias: alias(value),
|
|
43
|
+
// `exactOptionalPropertyTypes`: only attach `dev` when
|
|
44
|
+
// the config actually declared it (never `dev:
|
|
45
|
+
// undefined`).
|
|
46
|
+
...(devSection === undefined
|
|
47
|
+
? {}
|
|
48
|
+
: { dev: devSection }),
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The optional `dev` section (see {@link DevConfig}).
|
|
54
|
+
* Absent → `undefined` (a build-only library). Present →
|
|
55
|
+
* every field narrowed at the boundary.
|
|
56
|
+
*/
|
|
57
|
+
const dev = (
|
|
58
|
+
o: Record<string, unknown>,
|
|
59
|
+
): DevConfig | undefined => {
|
|
60
|
+
const raw = o["dev"];
|
|
61
|
+
if (raw === undefined) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
if (!isRecord(raw)) {
|
|
65
|
+
return fail(`"dev" must be an object`);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
entry: str(raw, "entry"),
|
|
69
|
+
port: num(raw, "port"),
|
|
70
|
+
watch: strArray(raw, "watch"),
|
|
71
|
+
allowedHosts: strArray(
|
|
72
|
+
raw,
|
|
73
|
+
"allowedHosts",
|
|
74
|
+
),
|
|
75
|
+
sourceAliases: sourceAliases(raw),
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The optional `sourceAliases` array (defaults to `[]`):
|
|
81
|
+
* each element `{ prefix, srcDir }` — both strings.
|
|
82
|
+
*/
|
|
83
|
+
const sourceAliases = (
|
|
84
|
+
o: Record<string, unknown>,
|
|
85
|
+
): ReadonlyArray<SourceAlias> => {
|
|
86
|
+
const raw = o["sourceAliases"];
|
|
87
|
+
return raw === undefined
|
|
88
|
+
? []
|
|
89
|
+
: Array.isArray(raw)
|
|
90
|
+
? raw.map(sourceAlias)
|
|
91
|
+
: fail(
|
|
92
|
+
`"sourceAliases" must be an array`,
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const sourceAlias = (
|
|
97
|
+
raw: unknown,
|
|
98
|
+
): SourceAlias =>
|
|
99
|
+
isRecord(raw) &&
|
|
100
|
+
typeof raw["prefix"] === "string" &&
|
|
101
|
+
typeof raw["srcDir"] === "string"
|
|
102
|
+
? {
|
|
103
|
+
prefix: raw["prefix"],
|
|
104
|
+
srcDir: raw["srcDir"],
|
|
105
|
+
}
|
|
106
|
+
: fail(
|
|
107
|
+
`each sourceAlias needs string "prefix" and "srcDir"`,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* A required finite-number field.
|
|
112
|
+
*/
|
|
113
|
+
const num = (
|
|
114
|
+
o: Record<string, unknown>,
|
|
115
|
+
key: string,
|
|
116
|
+
): number => {
|
|
117
|
+
const v = o[key];
|
|
118
|
+
return typeof v === "number" &&
|
|
119
|
+
Number.isFinite(v)
|
|
120
|
+
? v
|
|
121
|
+
: fail(`"${key}" must be a number`);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* A required array-of-strings field. Maps each element
|
|
126
|
+
* through a string guard (mirroring `entries`/`formats`)
|
|
127
|
+
* so the result is a real `string[]` — never a leaked
|
|
128
|
+
* `any[]` from `Array.isArray`.
|
|
129
|
+
*/
|
|
130
|
+
const strArray = (
|
|
131
|
+
o: Record<string, unknown>,
|
|
132
|
+
key: string,
|
|
133
|
+
): ReadonlyArray<string> => {
|
|
134
|
+
const v = o[key];
|
|
135
|
+
return Array.isArray(v)
|
|
136
|
+
? v.map((e) => strElem(e, key))
|
|
137
|
+
: fail(`"${key}" must be an array`);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const strElem = (
|
|
141
|
+
e: unknown,
|
|
142
|
+
key: string,
|
|
143
|
+
): string =>
|
|
144
|
+
typeof e === "string"
|
|
145
|
+
? e
|
|
146
|
+
: fail(
|
|
147
|
+
`each "${key}" entry must be a string`,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The optional `target` field — `"library"` (default) or
|
|
152
|
+
* `"app"`. Absent means a library, so the existing
|
|
153
|
+
* library configs need no change.
|
|
154
|
+
*/
|
|
155
|
+
const target = (
|
|
156
|
+
o: Record<string, unknown>,
|
|
157
|
+
): Target => {
|
|
158
|
+
const v = o["target"];
|
|
159
|
+
return v === undefined || v === "library"
|
|
160
|
+
? "library"
|
|
161
|
+
: v === "app"
|
|
162
|
+
? "app"
|
|
163
|
+
: fail(
|
|
164
|
+
`"target" must be "library" or "app"`,
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Throw a config validation error. Return type `never`
|
|
170
|
+
* so a failed check is a dead end at the call site.
|
|
171
|
+
*/
|
|
172
|
+
const fail = (message: string): never => {
|
|
173
|
+
throw new Error(`ConfigError: ${message}`);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Whether a value is a non-null object (records the
|
|
178
|
+
* narrowing for property reads).
|
|
179
|
+
*/
|
|
180
|
+
const isRecord = (
|
|
181
|
+
v: unknown,
|
|
182
|
+
): v is Record<string, unknown> =>
|
|
183
|
+
typeof v === "object" && v !== null;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* A required string field.
|
|
187
|
+
*/
|
|
188
|
+
const str = (
|
|
189
|
+
o: Record<string, unknown>,
|
|
190
|
+
key: string,
|
|
191
|
+
): string => {
|
|
192
|
+
const v = o[key];
|
|
193
|
+
return typeof v === "string"
|
|
194
|
+
? v
|
|
195
|
+
: fail(`"${key}" must be a string`);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* The `entries` array: each element an object with
|
|
200
|
+
* string `name` and `input`.
|
|
201
|
+
*/
|
|
202
|
+
const entries = (
|
|
203
|
+
o: Record<string, unknown>,
|
|
204
|
+
): ReadonlyArray<Entry> => {
|
|
205
|
+
const raw = o["entries"];
|
|
206
|
+
return Array.isArray(raw)
|
|
207
|
+
? raw.map(entry)
|
|
208
|
+
: fail(`"entries" must be an array`);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const entry = (raw: unknown): Entry =>
|
|
212
|
+
isRecord(raw) &&
|
|
213
|
+
typeof raw["name"] === "string" &&
|
|
214
|
+
typeof raw["input"] === "string"
|
|
215
|
+
? { name: raw["name"], input: raw["input"] }
|
|
216
|
+
: fail(
|
|
217
|
+
`each entry needs string "name" and "input"`,
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* The `formats` array: each `"es"` or `"cjs"`.
|
|
222
|
+
*/
|
|
223
|
+
const formats = (
|
|
224
|
+
o: Record<string, unknown>,
|
|
225
|
+
): ReadonlyArray<Format> => {
|
|
226
|
+
const raw = o["formats"];
|
|
227
|
+
return Array.isArray(raw)
|
|
228
|
+
? raw.map(format)
|
|
229
|
+
: fail(`"formats" must be an array`);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const format = (raw: unknown): Format =>
|
|
233
|
+
raw === "es" || raw === "cjs"
|
|
234
|
+
? raw
|
|
235
|
+
: fail(`each format must be "es" or "cjs"`);
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* The `alias` object: string `prefix` and `srcRoot`.
|
|
239
|
+
*/
|
|
240
|
+
const alias = (
|
|
241
|
+
o: Record<string, unknown>,
|
|
242
|
+
): Readonly<{
|
|
243
|
+
prefix: string;
|
|
244
|
+
srcRoot: string;
|
|
245
|
+
}> => {
|
|
246
|
+
const raw = o["alias"];
|
|
247
|
+
return isRecord(raw) &&
|
|
248
|
+
typeof raw["prefix"] === "string" &&
|
|
249
|
+
typeof raw["srcRoot"] === "string"
|
|
250
|
+
? {
|
|
251
|
+
prefix: raw["prefix"],
|
|
252
|
+
srcRoot: raw["srcRoot"],
|
|
253
|
+
}
|
|
254
|
+
: fail(
|
|
255
|
+
`"alias" needs string "prefix" and "srcRoot"`,
|
|
256
|
+
);
|
|
257
|
+
};
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import {
|
|
2
|
+
writeFileSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
rmSync,
|
|
5
|
+
renameSync,
|
|
6
|
+
existsSync,
|
|
7
|
+
} from "node:fs";
|
|
8
|
+
import { join, dirname } from "node:path";
|
|
9
|
+
import {
|
|
10
|
+
type BundleConfig,
|
|
11
|
+
type Entry,
|
|
12
|
+
applyFileName,
|
|
13
|
+
} from "plgg-bundle/domain/model/BundleConfig";
|
|
14
|
+
import {
|
|
15
|
+
collectModules,
|
|
16
|
+
type Graph,
|
|
17
|
+
} from "plgg-bundle/domain/usecase/collectModules";
|
|
18
|
+
import {
|
|
19
|
+
emitCjsBundle,
|
|
20
|
+
emitEsmBundle,
|
|
21
|
+
} from "plgg-bundle/domain/usecase/emitBundle";
|
|
22
|
+
import { emitDts } from "plgg-bundle/domain/usecase/emitDts";
|
|
23
|
+
import { deriveExternal } from "plgg-bundle/domain/usecase/deriveExternal";
|
|
24
|
+
import { readExportNames } from "plgg-bundle/vendors/runner";
|
|
25
|
+
import { discoverWorkspace } from "plgg-bundle/domain/usecase/discoverWorkspace";
|
|
26
|
+
import { resolveWorkspaceSpecifier } from "plgg-bundle/domain/usecase/resolveWorkspaceSpecifier";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Build one package's `dist` from its
|
|
30
|
+
* {@link BundleConfig}. Dispatches on the config
|
|
31
|
+
* `target`: a `"library"` (dual `es`/`cjs` per entry +
|
|
32
|
+
* per-file `.d.ts`, deps external) or the `"app"` leaf (a
|
|
33
|
+
* single self-contained `es` bundle, siblings inlined, no
|
|
34
|
+
* `.d.ts`). Both build into a private staging dir and
|
|
35
|
+
* publish with one atomic swap. Returns the relative
|
|
36
|
+
* paths written. Throws on the first failure (caught at
|
|
37
|
+
* the bin boundary). Fully synchronous.
|
|
38
|
+
*/
|
|
39
|
+
export const build = (
|
|
40
|
+
config: BundleConfig,
|
|
41
|
+
): ReadonlyArray<string> => {
|
|
42
|
+
const outDir = join(config.root, config.outDir);
|
|
43
|
+
// Build into a PRIVATE staging dir, then swap it into
|
|
44
|
+
// place as the final step (see swapIntoPlace). The live
|
|
45
|
+
// `dist` must never be observed half-built: it is read
|
|
46
|
+
// concurrently — by a downstream package's `tsc`/runner
|
|
47
|
+
// resolving this package as a dependency, and by any
|
|
48
|
+
// overlapping build invocation. The old emptyDir-on-live
|
|
49
|
+
// pattern left a multi-second window where `dist` was
|
|
50
|
+
// missing or partial; a reader hitting it resolved the
|
|
51
|
+
// dependency to its `.js` (TS7016 implicit-any), to a
|
|
52
|
+
// not-yet-complete barrel (TS2305 "no exported member"),
|
|
53
|
+
// or found no `index.cjs.js` at all — the
|
|
54
|
+
// non-deterministic dts-emit flake. Staging shrinks that
|
|
55
|
+
// window from the whole build to a single rename.
|
|
56
|
+
const stageDir = `${outDir}.stage`;
|
|
57
|
+
emptyDir(stageDir);
|
|
58
|
+
const written =
|
|
59
|
+
config.target === "app"
|
|
60
|
+
? buildApp(config, stageDir)
|
|
61
|
+
: buildLibrary(config, stageDir);
|
|
62
|
+
swapIntoPlace(stageDir, outDir);
|
|
63
|
+
return written;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Library build: per entry, emit the dual `es`/`cjs`
|
|
68
|
+
* bundle (CJS first so its runtime keys give ESM its
|
|
69
|
+
* export surface), then the per-file `.d.ts` tree once.
|
|
70
|
+
* Deps are external (ruling B), derived from the
|
|
71
|
+
* package's declared dependency graph (+ `node:*`) so a
|
|
72
|
+
* bundle stays faithful to its manifest and an undeclared
|
|
73
|
+
* import fails loudly.
|
|
74
|
+
*/
|
|
75
|
+
const buildLibrary = (
|
|
76
|
+
config: BundleConfig,
|
|
77
|
+
stageDir: string,
|
|
78
|
+
): ReadonlyArray<string> => {
|
|
79
|
+
const external = deriveExternal(config.root);
|
|
80
|
+
const written: string[] = [];
|
|
81
|
+
for (const entry of config.entries) {
|
|
82
|
+
const graph = collectModules({
|
|
83
|
+
entryFile: join(
|
|
84
|
+
config.root,
|
|
85
|
+
config.rootDir,
|
|
86
|
+
entry.input,
|
|
87
|
+
),
|
|
88
|
+
root: config.root,
|
|
89
|
+
aliasPrefix: config.alias.prefix,
|
|
90
|
+
aliasSrcRoot: join(
|
|
91
|
+
config.root,
|
|
92
|
+
config.alias.srcRoot,
|
|
93
|
+
),
|
|
94
|
+
external,
|
|
95
|
+
});
|
|
96
|
+
written.push(
|
|
97
|
+
...buildEntry(
|
|
98
|
+
config,
|
|
99
|
+
entry,
|
|
100
|
+
graph,
|
|
101
|
+
stageDir,
|
|
102
|
+
),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
emitDts({
|
|
106
|
+
root: config.root,
|
|
107
|
+
rootDir: config.rootDir,
|
|
108
|
+
outDir: stageDir,
|
|
109
|
+
aliasPrefix: config.alias.prefix,
|
|
110
|
+
});
|
|
111
|
+
return written;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* App build: a single self-contained `es` bundle per
|
|
116
|
+
* entry with every workspace sibling INLINED from source
|
|
117
|
+
* (the mirror of the library externalization — a browser
|
|
118
|
+
* cannot resolve a bare `import "plgg"`). Only `node:*`
|
|
119
|
+
* stays external. No CJS, no export-surface discovery
|
|
120
|
+
* (an app entry has side effects and no exports, and the
|
|
121
|
+
* vm sandbox has no DOM to run it), and no `.d.ts`
|
|
122
|
+
* (nothing consumes the app).
|
|
123
|
+
*/
|
|
124
|
+
const buildApp = (
|
|
125
|
+
config: BundleConfig,
|
|
126
|
+
stageDir: string,
|
|
127
|
+
): ReadonlyArray<string> => {
|
|
128
|
+
const packages = discoverWorkspace(config.root);
|
|
129
|
+
const written: string[] = [];
|
|
130
|
+
for (const entry of config.entries) {
|
|
131
|
+
const graph = collectModules({
|
|
132
|
+
entryFile: join(
|
|
133
|
+
config.root,
|
|
134
|
+
config.rootDir,
|
|
135
|
+
entry.input,
|
|
136
|
+
),
|
|
137
|
+
root: config.root,
|
|
138
|
+
aliasPrefix: config.alias.prefix,
|
|
139
|
+
aliasSrcRoot: join(
|
|
140
|
+
config.root,
|
|
141
|
+
config.alias.srcRoot,
|
|
142
|
+
),
|
|
143
|
+
external: NODE_EXTERNAL,
|
|
144
|
+
resolve: (specifier, fromFile) =>
|
|
145
|
+
resolveWorkspaceSpecifier({
|
|
146
|
+
specifier,
|
|
147
|
+
fromFile,
|
|
148
|
+
packages,
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
151
|
+
const rel = applyFileName(
|
|
152
|
+
config.fileNamePattern,
|
|
153
|
+
entry.name,
|
|
154
|
+
"es",
|
|
155
|
+
);
|
|
156
|
+
writeOut(
|
|
157
|
+
join(stageDir, rel),
|
|
158
|
+
emitEsmBundle(graph, []),
|
|
159
|
+
);
|
|
160
|
+
written.push(rel);
|
|
161
|
+
}
|
|
162
|
+
return written;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The app's only external: Node built-ins. Everything
|
|
167
|
+
* else (plgg + siblings) is inlined.
|
|
168
|
+
*/
|
|
169
|
+
const NODE_EXTERNAL = /^node:/;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Replace `outDir` with the freshly-built `stageDir` in a
|
|
173
|
+
* single rename, so a concurrent reader sees only a
|
|
174
|
+
* complete `dist` (old or new) — never a torn one. The
|
|
175
|
+
* destructive window is one `rename`, not the whole build.
|
|
176
|
+
*/
|
|
177
|
+
const swapIntoPlace = (
|
|
178
|
+
stageDir: string,
|
|
179
|
+
outDir: string,
|
|
180
|
+
): void => {
|
|
181
|
+
const backup = `${outDir}.old`;
|
|
182
|
+
rmSync(backup, {
|
|
183
|
+
recursive: true,
|
|
184
|
+
force: true,
|
|
185
|
+
});
|
|
186
|
+
if (existsSync(outDir)) {
|
|
187
|
+
renameSync(outDir, backup);
|
|
188
|
+
}
|
|
189
|
+
renameSync(stageDir, outDir);
|
|
190
|
+
rmSync(backup, {
|
|
191
|
+
recursive: true,
|
|
192
|
+
force: true,
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Build every configured format for one entry, returning
|
|
198
|
+
* the relative paths written.
|
|
199
|
+
*/
|
|
200
|
+
const buildEntry = (
|
|
201
|
+
config: BundleConfig,
|
|
202
|
+
entry: Entry,
|
|
203
|
+
graph: Graph,
|
|
204
|
+
destDir: string,
|
|
205
|
+
): ReadonlyArray<string> => {
|
|
206
|
+
const cjs = emitCjsBundle(graph);
|
|
207
|
+
// Discover the exact export surface by running the CJS
|
|
208
|
+
// bundle and reading its keys — ESM cannot declare
|
|
209
|
+
// exports dynamically. The bundle's external requires
|
|
210
|
+
// resolve against the target package's node_modules.
|
|
211
|
+
const esm = emitEsmBundle(
|
|
212
|
+
graph,
|
|
213
|
+
readExportNames(cjs, config.root),
|
|
214
|
+
);
|
|
215
|
+
const written: string[] = [];
|
|
216
|
+
for (const format of config.formats) {
|
|
217
|
+
const code = format === "es" ? esm : cjs;
|
|
218
|
+
const rel = applyFileName(
|
|
219
|
+
config.fileNamePattern,
|
|
220
|
+
entry.name,
|
|
221
|
+
format,
|
|
222
|
+
);
|
|
223
|
+
writeOut(join(destDir, rel), code);
|
|
224
|
+
written.push(rel);
|
|
225
|
+
}
|
|
226
|
+
return written;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Empty (and recreate) the output directory. The
|
|
231
|
+
* recursive remove is the bundler's own build output —
|
|
232
|
+
* `force` tolerates a not-yet-existing dir.
|
|
233
|
+
*/
|
|
234
|
+
const emptyDir = (dir: string): void => {
|
|
235
|
+
rmSync(dir, { recursive: true, force: true });
|
|
236
|
+
mkdirSync(dir, { recursive: true });
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Write a file, creating parent dirs; re-throws with
|
|
241
|
+
* context on failure.
|
|
242
|
+
*/
|
|
243
|
+
const writeOut = (
|
|
244
|
+
path: string,
|
|
245
|
+
code: string,
|
|
246
|
+
): void => {
|
|
247
|
+
try {
|
|
248
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
249
|
+
writeFileSync(path, code, "utf8");
|
|
250
|
+
} catch (cause) {
|
|
251
|
+
throw new Error(
|
|
252
|
+
`IoError: cannot write ${path}: ${
|
|
253
|
+
cause instanceof Error
|
|
254
|
+
? cause.message
|
|
255
|
+
: String(cause)
|
|
256
|
+
}`,
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
};
|