pkgbld 1.36.0 → 2.1.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.
- package/README.md +71 -89
- package/index.js +2 -2
- package/package.json +31 -27
- package/src/build-configuration.js +406 -0
- package/src/build-entries.js +271 -0
- package/src/build-plugin-lifecycle.js +100 -0
- package/src/builtin-plugins/binify.js +31 -0
- package/src/builtin-plugins/clean.js +30 -0
- package/src/builtin-plugins/commonjs.js +14 -0
- package/src/builtin-plugins/externals.js +108 -0
- package/src/builtin-plugins/json.js +14 -0
- package/src/builtin-plugins/package-imports.js +79 -0
- package/src/builtin-plugins/preprocess.js +37 -0
- package/src/builtin-plugins/resolve.js +22 -0
- package/src/builtin-plugins/terser.js +50 -0
- package/src/eject.js +151 -0
- package/src/get-json.js +16 -0
- package/src/get-plugins.js +44 -0
- package/src/get-rollup-configs.js +261 -0
- package/src/helpers.js +229 -0
- package/src/index.js +133 -0
- package/src/load-plugins.js +37 -0
- package/src/messages.js +13 -0
- package/src/options/index.js +277 -0
- package/src/options/types.js +24 -0
- package/src/package-imports.js +240 -0
- package/src/plugin-name.js +6 -0
- package/src/priorities.js +11 -0
- package/src/process-pkg.js +244 -0
- package/src/process-ts-config.js +80 -0
- package/src/rollup-plugin-preprocess.d.ts +1 -0
- package/src/types.js +175 -0
- package/src/write-json.js +21 -0
- package/types/index.d.ts +310 -0
- package/dist/index.d.ts +0 -79
- package/dist/index.mjs +0 -1626
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import binify from './builtin-plugins/binify.js';
|
|
2
|
+
import clean from './builtin-plugins/clean.js';
|
|
3
|
+
import commonjs from './builtin-plugins/commonjs.js';
|
|
4
|
+
import externals from './builtin-plugins/externals.js';
|
|
5
|
+
import json from './builtin-plugins/json.js';
|
|
6
|
+
import packageImports from './builtin-plugins/package-imports.js';
|
|
7
|
+
import preprocess from './builtin-plugins/preprocess.js';
|
|
8
|
+
import resolve from './builtin-plugins/resolve.js';
|
|
9
|
+
import terser from './builtin-plugins/terser.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {import('./types.js').PkgbldRollupPlugin} PkgbldRollupPlugin
|
|
13
|
+
* @typedef {import('./types.js').Provider} Provider
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const plugins = [clean, commonjs, externals, preprocess, packageImports, resolve, terser, binify, json];
|
|
17
|
+
|
|
18
|
+
const noop = () => undefined;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @returns {[Provider, PkgbldRollupPlugin[]]}
|
|
22
|
+
*/
|
|
23
|
+
export function createProvider() {
|
|
24
|
+
/** @type {PkgbldRollupPlugin[]} */
|
|
25
|
+
const plugins = [];
|
|
26
|
+
return [
|
|
27
|
+
{
|
|
28
|
+
provide: (
|
|
29
|
+
/** @type {PkgbldRollupPlugin['plugin']} */ plugin,
|
|
30
|
+
/** @type {PkgbldRollupPlugin['priority']} */ priority,
|
|
31
|
+
/** @type {Omit<PkgbldRollupPlugin, 'plugin' | 'priority'>=} */ options
|
|
32
|
+
) => {
|
|
33
|
+
plugins.push({ priority, plugin, format: options?.format, inputs: options?.inputs, outputPlugin: options?.outputPlugin });
|
|
34
|
+
},
|
|
35
|
+
import: async (/** @type {string} */ name, /** @type {string=} */ exportName) => {
|
|
36
|
+
const result = await import(name);
|
|
37
|
+
return result[exportName ?? 'default'];
|
|
38
|
+
},
|
|
39
|
+
globalImport: noop,
|
|
40
|
+
globalSetup: code => (typeof code === 'function' ? code : undefined),
|
|
41
|
+
},
|
|
42
|
+
plugins,
|
|
43
|
+
];
|
|
44
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
import refiner from '@slimlib/refine-partition';
|
|
4
|
+
|
|
5
|
+
import { plugins as pluginFactories } from './get-plugins.js';
|
|
6
|
+
import { areSetsEqual, toArray } from './helpers.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {import('rollup').InternalModuleFormat} InternalModuleFormat
|
|
10
|
+
* @typedef {import('rollup').OutputOptions} OutputOptions
|
|
11
|
+
* @typedef {import('./types.js').BuildConfiguration} BuildConfiguration
|
|
12
|
+
* @typedef {import('./types.js').PackageProcessingResult} PackageProcessingResult
|
|
13
|
+
* @typedef {import('./types.js').PkgbldRollupPlugin} PkgbldRollupPlugin
|
|
14
|
+
* @typedef {import('./types.js').Provider} Provider
|
|
15
|
+
* @typedef {ReturnType<typeof import('./build-plugin-lifecycle.js').createBuildPluginLifecycle>} BuildPluginLifecycle
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {[Provider, PkgbldRollupPlugin[]]} providerAndPlugins
|
|
20
|
+
* @param {PackageProcessingResult} packageResult
|
|
21
|
+
* @param {BuildConfiguration} configuration
|
|
22
|
+
* @param {ReturnType<import('./helpers.js').getHelpers>} helpers
|
|
23
|
+
* @param {BuildPluginLifecycle} pluginLifecycle
|
|
24
|
+
*/
|
|
25
|
+
export async function getRollupConfigs([provider, plugins], packageResult, configuration, helpers, pluginLifecycle) {
|
|
26
|
+
const publicEntries = packageResult.entries.values.filter(entry => entry.origin !== 'import');
|
|
27
|
+
const privateEntries = packageResult.entries.values.filter(entry => entry.origin === 'import');
|
|
28
|
+
const inputs = publicEntries.map(entry => entry.sourcePath);
|
|
29
|
+
const publicInputSet = new Set(inputs);
|
|
30
|
+
const entriesBySourcePath = new Map(publicEntries.map(entry => [entry.sourcePath, entry]));
|
|
31
|
+
const factoryInProgress = [];
|
|
32
|
+
|
|
33
|
+
const fileNamePatterns = /** @type {{ [key in InternalModuleFormat]: string }} */ ({
|
|
34
|
+
es: configuration.outputs.patterns.es,
|
|
35
|
+
cjs: configuration.outputs.patterns.cjs,
|
|
36
|
+
umd: configuration.outputs.patterns.umd,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
for (const factory of pluginFactories) {
|
|
40
|
+
factoryInProgress.push(factory(provider, configuration, packageResult));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
factoryInProgress.push(pluginLifecycle.provideRollupPlugins(provider, configuration, packageResult));
|
|
44
|
+
|
|
45
|
+
await Promise.all(factoryInProgress);
|
|
46
|
+
|
|
47
|
+
/** @type {Set<string>} */
|
|
48
|
+
const expandInputs = new Set();
|
|
49
|
+
|
|
50
|
+
for (const plugin of plugins) {
|
|
51
|
+
if (plugin.format && plugin.inputs?.some(input => publicInputSet.has(input)) && !plugin.outputPlugin) {
|
|
52
|
+
for (const format of toArray(plugin.format)) {
|
|
53
|
+
expandInputs.add(format);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const refineNext = refiner();
|
|
59
|
+
|
|
60
|
+
refineNext(doExpandInputs(/** @type {InternalModuleFormat[]} */ ([...configuration.outputs.formats])));
|
|
61
|
+
|
|
62
|
+
for (const plugin of plugins) {
|
|
63
|
+
if (plugin.format && !plugin.outputPlugin) {
|
|
64
|
+
const publicPluginInputs = plugin.inputs?.filter(input => publicInputSet.has(input));
|
|
65
|
+
if (plugin.inputs && publicPluginInputs?.length === 0) continue;
|
|
66
|
+
const formats = toArray(plugin.format);
|
|
67
|
+
if (!plugin.inputs || plugin.inputs.length === 0) {
|
|
68
|
+
refineNext(doExpandInputs(formats));
|
|
69
|
+
} else if (inputs.length === 1) {
|
|
70
|
+
refineNext(formats);
|
|
71
|
+
} else {
|
|
72
|
+
const expanded = [];
|
|
73
|
+
for (const format of formats) {
|
|
74
|
+
for (const input of /** @type {string[]} */ (publicPluginInputs)) {
|
|
75
|
+
expanded.push(`${format}.${input}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
refineNext(expanded);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const refined = refineNext();
|
|
84
|
+
/** @type {{ formats: InternalModuleFormat[]; inputs: string[] }[]} */
|
|
85
|
+
const partitions = [];
|
|
86
|
+
|
|
87
|
+
for (const partition of refined) {
|
|
88
|
+
/** @type {{ format: InternalModuleFormat; input?: string }[]} */
|
|
89
|
+
const result = [];
|
|
90
|
+
for (const format of partition) {
|
|
91
|
+
if (format.includes('.')) {
|
|
92
|
+
const [, realFormat, input] = format.split(/(.*?)\.(.*)/gm);
|
|
93
|
+
result.push({ format: /** @type {InternalModuleFormat} */ (realFormat), input });
|
|
94
|
+
} else {
|
|
95
|
+
result.push({ format: /** @type {InternalModuleFormat} */ (format) });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** @type {Map<InternalModuleFormat, Set<string>>} */
|
|
99
|
+
const mapFormatInputs = new Map();
|
|
100
|
+
/** @type {Set<InternalModuleFormat>} */
|
|
101
|
+
const formatsWithoutInputs = new Set();
|
|
102
|
+
for (const { format, input } of result) {
|
|
103
|
+
if (input) {
|
|
104
|
+
if (mapFormatInputs.has(format)) {
|
|
105
|
+
/** @type {Set<string>} */ (mapFormatInputs.get(format)).add(input);
|
|
106
|
+
} else {
|
|
107
|
+
mapFormatInputs.set(format, new Set([input]));
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
formatsWithoutInputs.add(format);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const format of formatsWithoutInputs) {
|
|
114
|
+
if (mapFormatInputs.has(format)) {
|
|
115
|
+
throw new Error(
|
|
116
|
+
`${format} is both used with inputs and without in plugins configuration and was not expanded / handled correctly. Please file an issue for pkgbld.`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
mapFormatInputs.set(format, new Set(inputs));
|
|
120
|
+
}
|
|
121
|
+
/** @type {Set<string> | undefined} */
|
|
122
|
+
let prevInputs;
|
|
123
|
+
for (const inputs of mapFormatInputs.values()) {
|
|
124
|
+
if (prevInputs) {
|
|
125
|
+
if (!areSetsEqual(inputs, prevInputs)) {
|
|
126
|
+
throw new Error(`unbalanced inputs for partition: ${JSON.stringify(partition)}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
prevInputs = inputs;
|
|
130
|
+
}
|
|
131
|
+
partitions.push({ formats: [...mapFormatInputs.keys()], inputs: [.../** @type {Set<string>} */ (prevInputs)] });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const publicConfigs = partitions.map(({ formats, inputs }) => {
|
|
135
|
+
return {
|
|
136
|
+
input: Object.fromEntries(
|
|
137
|
+
inputs.map(input => [/** @type {import('./types.js').BuildEntry} */ (entriesBySourcePath.get(input)).name, input])
|
|
138
|
+
),
|
|
139
|
+
|
|
140
|
+
output: formats.map(format => ({
|
|
141
|
+
format,
|
|
142
|
+
dir: configuration.paths.outputDir,
|
|
143
|
+
entryFileNames: fileNamePatterns[format],
|
|
144
|
+
plugins: getPlugins([format], inputs, true),
|
|
145
|
+
sourcemap: configuration.outputs.sourcemaps.some(value => value === format),
|
|
146
|
+
...getExtraOutputSettings(format, inputs),
|
|
147
|
+
})),
|
|
148
|
+
|
|
149
|
+
plugins: getPlugins(formats, inputs, false),
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const privateConfigs = privateEntries.map(entry => {
|
|
154
|
+
const [[format, outputPath]] = Object.entries(entry.outputPaths);
|
|
155
|
+
const input = entry.sourcePath;
|
|
156
|
+
const selectedFormat = /** @type {InternalModuleFormat} */ (format);
|
|
157
|
+
return {
|
|
158
|
+
input,
|
|
159
|
+
output: [
|
|
160
|
+
{
|
|
161
|
+
format: selectedFormat,
|
|
162
|
+
dir: configuration.paths.outputDir,
|
|
163
|
+
entryFileNames: path
|
|
164
|
+
.relative(path.resolve(configuration.paths.outputDir), path.resolve(outputPath))
|
|
165
|
+
.replaceAll('\\', '/'),
|
|
166
|
+
plugins: getPlugins([selectedFormat], [input], true, true),
|
|
167
|
+
sourcemap: configuration.outputs.sourcemaps.includes(/** @type {import('./types.js').BuildFormat} */ (selectedFormat)),
|
|
168
|
+
...getExtraOutputSettings(selectedFormat, [input]),
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
plugins: getPlugins([selectedFormat], [input], false, true),
|
|
172
|
+
};
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
return [...publicConfigs, ...privateConfigs];
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @param {InternalModuleFormat} format
|
|
179
|
+
* @param {string[]} inputs
|
|
180
|
+
* @returns {Partial<OutputOptions>}
|
|
181
|
+
*/
|
|
182
|
+
function getExtraOutputSettings(format, inputs) {
|
|
183
|
+
let result = {};
|
|
184
|
+
switch (format) {
|
|
185
|
+
case 'cjs':
|
|
186
|
+
case 'es':
|
|
187
|
+
result = { chunkFileNames: fileNamePatterns[format] };
|
|
188
|
+
break;
|
|
189
|
+
case 'umd':
|
|
190
|
+
if (inputs.length <= 0) {
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
if (inputs.length > 1) {
|
|
194
|
+
throw new Error(`Cannot produce global name for multiple umd inputs in one output: ${inputs}`);
|
|
195
|
+
}
|
|
196
|
+
result = {
|
|
197
|
+
name: helpers.getGlobalName(inputs.join('_')),
|
|
198
|
+
globals: helpers.getExternalGlobalName,
|
|
199
|
+
};
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
pluginLifecycle.extendOutputSettings(result, format, inputs, configuration);
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @param {InternalModuleFormat[]} formats
|
|
208
|
+
* @param {string[]} inputs
|
|
209
|
+
* @param {boolean} outputPlugin
|
|
210
|
+
* @param {boolean} [privateOutput]
|
|
211
|
+
*/
|
|
212
|
+
function getPlugins(formats, inputs, outputPlugin, privateOutput = false) {
|
|
213
|
+
const filteredPlugins = [];
|
|
214
|
+
for (const plugin of plugins) {
|
|
215
|
+
if (!!plugin.outputPlugin === outputPlugin) {
|
|
216
|
+
const publicPluginInputs = plugin.inputs?.filter(input => publicInputSet.has(input));
|
|
217
|
+
if (
|
|
218
|
+
(!plugin.format || toArray(plugin.format).some(format => formats.includes(format))) &&
|
|
219
|
+
(!plugin.inputs ||
|
|
220
|
+
plugin.inputs.length === 0 ||
|
|
221
|
+
(privateOutput
|
|
222
|
+
? plugin.inputs.some(input => inputs.includes(input))
|
|
223
|
+
: publicPluginInputs?.length > 0 && publicPluginInputs.every(input => inputs.includes(input))))
|
|
224
|
+
) {
|
|
225
|
+
filteredPlugins.push({
|
|
226
|
+
instance: plugin.plugin(),
|
|
227
|
+
priority: plugin.priority,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
filteredPlugins.sort((a, b) => a.priority - b.priority);
|
|
233
|
+
return filteredPlugins.map(plugin => plugin.instance);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @param {InternalModuleFormat[]} formats
|
|
238
|
+
*/
|
|
239
|
+
function doExpandInputs(formats) {
|
|
240
|
+
if (inputs.length === 1) {
|
|
241
|
+
return formats;
|
|
242
|
+
}
|
|
243
|
+
const expanded = [];
|
|
244
|
+
for (const format of formats) {
|
|
245
|
+
if (expandInputs.has(format)) {
|
|
246
|
+
if (format !== 'umd') {
|
|
247
|
+
for (const input of inputs) {
|
|
248
|
+
expanded.push(`${format}.${input}`);
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
for (const entryName of configuration.outputs.umdEntries) {
|
|
252
|
+
expanded.push(`${format}.${packageResult.entries.require(entryName).sourcePath}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
expanded.push(format);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return expanded;
|
|
260
|
+
}
|
|
261
|
+
}
|
package/src/helpers.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { access, constants, readFile } from 'node:fs/promises';
|
|
2
|
+
import path, { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
import { cyan, magenta } from '@niceties/ansi';
|
|
6
|
+
|
|
7
|
+
import { processPackageJson } from './options/index.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {import('rollup').OutputOptions} OutputOptions
|
|
11
|
+
* @typedef {import('type-fest').PackageJson} PackageJson
|
|
12
|
+
* @typedef {import('./options/index.js').PackageJson} PackageJsonO
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {unknown} value
|
|
19
|
+
* @returns {string}
|
|
20
|
+
*/
|
|
21
|
+
export function camelCase(value) {
|
|
22
|
+
const words = String(value)
|
|
23
|
+
.normalize('NFKD')
|
|
24
|
+
.replaceAll(/\p{Mark}/gu, '')
|
|
25
|
+
.replaceAll(/([\p{Ll}\d])(\p{Lu})/gu, '$1 $2')
|
|
26
|
+
.replaceAll(/(\p{Lu}+)(\p{Lu}\p{Ll})/gu, '$1 $2')
|
|
27
|
+
.match(/[\p{L}\d]+/gu);
|
|
28
|
+
|
|
29
|
+
return (words ?? [])
|
|
30
|
+
.map((word, index) => {
|
|
31
|
+
const lowerCaseWord = word.toLowerCase();
|
|
32
|
+
return index === 0 ? lowerCaseWord : lowerCaseWord[0].toUpperCase() + lowerCaseWord.slice(1);
|
|
33
|
+
})
|
|
34
|
+
.join('');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {string} pkgName
|
|
39
|
+
*/
|
|
40
|
+
export function getHelpers(pkgName) {
|
|
41
|
+
/**
|
|
42
|
+
* @param {string} anInput
|
|
43
|
+
*/
|
|
44
|
+
function getGlobalName(anInput) {
|
|
45
|
+
return camelCase(
|
|
46
|
+
path.join(
|
|
47
|
+
pkgName,
|
|
48
|
+
path.basename(anInput, path.extname(anInput)) !== 'index' ? path.basename(anInput, path.extname(anInput)) : ''
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {string} id
|
|
55
|
+
*/
|
|
56
|
+
function getExternalGlobalName(id) {
|
|
57
|
+
if (path.isAbsolute(id)) {
|
|
58
|
+
return getGlobalName(path.relative(__dirname, id));
|
|
59
|
+
}
|
|
60
|
+
return camelCase(id);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
getGlobalName,
|
|
65
|
+
getExternalGlobalName,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @template T
|
|
71
|
+
* @param {T | T[] | undefined} object
|
|
72
|
+
* @returns {T[]}
|
|
73
|
+
*/
|
|
74
|
+
export function toArray(object) {
|
|
75
|
+
if (Array.isArray(object)) {
|
|
76
|
+
return object;
|
|
77
|
+
}
|
|
78
|
+
if (object == null) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
return [object];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @param {string[] | string} input
|
|
86
|
+
* @returns {string}
|
|
87
|
+
*/
|
|
88
|
+
export function formatInput(input) {
|
|
89
|
+
return (Array.isArray(input) ? input : [input ?? '']).map(item => magenta(path.basename(item, path.extname(item)))).join(', ');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {OutputOptions | OutputOptions[] | undefined} output
|
|
94
|
+
* @param {'dir' | 'format'} field
|
|
95
|
+
* @returns {string}
|
|
96
|
+
*/
|
|
97
|
+
export function formatOutput(output, field) {
|
|
98
|
+
if (output == null) {
|
|
99
|
+
return '';
|
|
100
|
+
}
|
|
101
|
+
return (Array.isArray(output) ? output : [output ?? '']).map(item => cyan(/** @type {string} */ (item[field]))).join(', ');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {number} starting
|
|
106
|
+
* @returns {string}
|
|
107
|
+
*/
|
|
108
|
+
export function getTimeDiff(starting) {
|
|
109
|
+
const diff = Date.now() - starting;
|
|
110
|
+
return diff >= 1000 ? `${(diff / 1000).toFixed(1)}s` : `${diff}ms`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @template T
|
|
115
|
+
* @param {Set<T>} a
|
|
116
|
+
* @param {Set<T>} b
|
|
117
|
+
* @returns {boolean}
|
|
118
|
+
*/
|
|
119
|
+
export const areSetsEqual = (a, b) => (a.size === b.size ? [...a].every(value => b.has(value)) : false);
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @param {PackageJson} pkg
|
|
123
|
+
* @returns {PackageJson}
|
|
124
|
+
*/
|
|
125
|
+
export function formatPackageJson(pkg) {
|
|
126
|
+
return /** @type {PackageJson} */ (
|
|
127
|
+
processPackageJson(
|
|
128
|
+
/** @type {PackageJsonO} */ (pkg),
|
|
129
|
+
key => key in pkg,
|
|
130
|
+
key => /** @type {Record<string, unknown>} */ (pkg)[key]
|
|
131
|
+
)
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @param {string} file
|
|
137
|
+
* @returns {Promise<string | false>}
|
|
138
|
+
*/
|
|
139
|
+
export async function isExists(file) {
|
|
140
|
+
try {
|
|
141
|
+
await access(file);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
if (typeof e === 'object' && e != null && 'code' in e && e.code === 'ENOENT') {
|
|
144
|
+
return /** @type {const} */ (false);
|
|
145
|
+
}
|
|
146
|
+
throw e;
|
|
147
|
+
}
|
|
148
|
+
return file;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @param {string} file
|
|
153
|
+
* @returns {Promise<boolean>}
|
|
154
|
+
*/
|
|
155
|
+
export async function isReadable(file) {
|
|
156
|
+
try {
|
|
157
|
+
await access(file, constants.R_OK);
|
|
158
|
+
return true;
|
|
159
|
+
} catch {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* @param {string} root
|
|
166
|
+
* @param {string} file
|
|
167
|
+
*/
|
|
168
|
+
function hasFile(root, file) {
|
|
169
|
+
const path = join(root, file);
|
|
170
|
+
return isExists(path);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @param {string} root
|
|
175
|
+
* @returns {Promise<boolean>}
|
|
176
|
+
*/
|
|
177
|
+
async function hasWorkspacePackageJson(root) {
|
|
178
|
+
const path = join(root, 'package.json');
|
|
179
|
+
if (!(await isReadable(path))) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
const content = /** @type {PackageJson} */ (JSON.parse(await readFile(path, 'utf-8')) || {});
|
|
184
|
+
return !!content.workspaces;
|
|
185
|
+
} catch {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @param {string} current
|
|
192
|
+
* @returns {Promise<string>}
|
|
193
|
+
*/
|
|
194
|
+
export async function searchForPackageRoot(current) {
|
|
195
|
+
const root = current;
|
|
196
|
+
let dir = current;
|
|
197
|
+
|
|
198
|
+
while (dir) {
|
|
199
|
+
if (await hasFile(dir, 'package.json')) return dir;
|
|
200
|
+
|
|
201
|
+
const parentDir = dirname(dir);
|
|
202
|
+
if (parentDir === dir) break;
|
|
203
|
+
|
|
204
|
+
dir = parentDir;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return root;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @param {string} current
|
|
212
|
+
* @returns {Promise<string>}
|
|
213
|
+
*/
|
|
214
|
+
export async function searchForWorkspaceRoot(current) {
|
|
215
|
+
const root = await searchForPackageRoot(current);
|
|
216
|
+
let dir = current;
|
|
217
|
+
|
|
218
|
+
while (dir) {
|
|
219
|
+
if (await hasFile(dir, 'pnpm-workspace.yaml')) return dir;
|
|
220
|
+
if (await hasWorkspacePackageJson(dir)) return dir;
|
|
221
|
+
|
|
222
|
+
const parentDir = dirname(dir);
|
|
223
|
+
if (parentDir === dir) break;
|
|
224
|
+
|
|
225
|
+
dir = parentDir;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return root;
|
|
229
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/// <reference path="./rollup-plugin-preprocess.d.ts" />
|
|
2
|
+
import '@niceties/draftlog-appender';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { rollup } from 'rollup';
|
|
6
|
+
|
|
7
|
+
import { green } from '@niceties/ansi';
|
|
8
|
+
import { createLogger, LogLevel } from '@niceties/logger';
|
|
9
|
+
|
|
10
|
+
import { resolveBuildConfiguration } from './build-configuration.js';
|
|
11
|
+
import { createBuildPluginLifecycle } from './build-plugin-lifecycle.js';
|
|
12
|
+
import { createEjectProvider, ejectConfig } from './eject.js';
|
|
13
|
+
import { getJson } from './get-json.js';
|
|
14
|
+
import { createProvider } from './get-plugins.js';
|
|
15
|
+
import { getRollupConfigs } from './get-rollup-configs.js';
|
|
16
|
+
import { formatInput, formatOutput, formatPackageJson, getHelpers, getTimeDiff, searchForWorkspaceRoot, toArray } from './helpers.js';
|
|
17
|
+
import { loadPlugins } from './load-plugins.js';
|
|
18
|
+
import { mainLoggerText } from './messages.js';
|
|
19
|
+
import { processPackage } from './process-pkg.js';
|
|
20
|
+
import { checkTsConfig } from './process-ts-config.js';
|
|
21
|
+
import { writeJson } from './write-json.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {import('rollup').RollupOptions} RollupOptions
|
|
25
|
+
* @typedef {import('type-fest').PackageJson} PackageJson
|
|
26
|
+
* @typedef {import('./types.js').PkgbldPlugin} PkgbldPlugin
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
execute();
|
|
30
|
+
|
|
31
|
+
async function execute() {
|
|
32
|
+
const time = Date.now();
|
|
33
|
+
const mainLogger = createLogger();
|
|
34
|
+
mainLogger.update('preparing..');
|
|
35
|
+
try {
|
|
36
|
+
/** @type {PackageJson} */
|
|
37
|
+
let pkg;
|
|
38
|
+
/** @type {string} */
|
|
39
|
+
let pkgPath;
|
|
40
|
+
[pkgPath, pkg] = /** @type {[string, PackageJson]} */ (await getJson('package.json'));
|
|
41
|
+
/** @type {Set<string>} */
|
|
42
|
+
const loadedPlugins = new Set();
|
|
43
|
+
const plugins = await loadPlugins(pkg, loadedPlugins, pkgPath);
|
|
44
|
+
const [rootPackagePath, rootPkg] = await getJson(join(await searchForWorkspaceRoot(dirname(pkgPath)), 'package.json'));
|
|
45
|
+
if (rootPackagePath !== pkgPath) {
|
|
46
|
+
plugins.push(...(await loadPlugins(rootPkg, loadedPlugins, rootPackagePath)));
|
|
47
|
+
}
|
|
48
|
+
const pluginLifecycle = createBuildPluginLifecycle(plugins);
|
|
49
|
+
mainLogger.update('');
|
|
50
|
+
process.stdout.moveCursor?.(0, -1);
|
|
51
|
+
const configuration = resolveBuildConfiguration({ packageJson: pkg, pluginLifecycle });
|
|
52
|
+
process.stdout.moveCursor?.(0, 1);
|
|
53
|
+
mainLogger.update('preparing...');
|
|
54
|
+
await checkTsConfig(configuration, mainLogger, pluginLifecycle);
|
|
55
|
+
const packageResult = await processPackage(pkg, configuration, pluginLifecycle);
|
|
56
|
+
if (configuration.packageJson.format) {
|
|
57
|
+
pkg = formatPackageJson(pkg);
|
|
58
|
+
}
|
|
59
|
+
const helpers = getHelpers(/** @type {{ name: string }} */ (pkg).name);
|
|
60
|
+
const provider = configuration.execution.eject ? await createEjectProvider() : createProvider();
|
|
61
|
+
const rollupConfigs = await getRollupConfigs(provider, packageResult, configuration, helpers, pluginLifecycle);
|
|
62
|
+
|
|
63
|
+
if (!configuration.execution.bundle) {
|
|
64
|
+
rollupConfigs.length = 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (configuration.execution.eject) {
|
|
68
|
+
await ejectConfig(rollupConfigs, pkgPath, configuration, packageResult, helpers, pkg);
|
|
69
|
+
mainLogger.finish(`ejected config in ${getTimeDiff(time)}`);
|
|
70
|
+
if (configuration.packageJson.update) {
|
|
71
|
+
await writeJson(pkgPath, pkg);
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
const updater = mainLoggerText(configuration.paths.sourceDir, configuration.paths.outputDir, rollupConfigs.length, time);
|
|
75
|
+
mainLogger.start(updater());
|
|
76
|
+
|
|
77
|
+
await Promise.all(rollupConfigs.map(config => buildConfig(config, updater)));
|
|
78
|
+
|
|
79
|
+
if (configuration.packageJson.update) {
|
|
80
|
+
await writeJson(pkgPath, pkg);
|
|
81
|
+
}
|
|
82
|
+
await pluginLifecycle.buildEnd(configuration);
|
|
83
|
+
|
|
84
|
+
mainLogger.finish(updater(true));
|
|
85
|
+
}
|
|
86
|
+
} catch (e) {
|
|
87
|
+
mainLogger.finish(String(e), LogLevel.error);
|
|
88
|
+
process.exit(-1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {RollupOptions} config
|
|
93
|
+
* @param {() => string} updater
|
|
94
|
+
*/
|
|
95
|
+
async function buildConfig(config, updater) {
|
|
96
|
+
const bundle = await rollup(config);
|
|
97
|
+
await Promise.all(toArray(config.output).map(config => bundle.write(config)));
|
|
98
|
+
await bundle.close();
|
|
99
|
+
mainLogger(
|
|
100
|
+
`${green('✓')} ${formatInput(
|
|
101
|
+
/** @type {string | string[]} */ (
|
|
102
|
+
typeof config.input === 'object' && !Array.isArray(config.input) ? Object.values(config.input) : config.input
|
|
103
|
+
)
|
|
104
|
+
)} [${formatOutput(config.output, 'format')}]`
|
|
105
|
+
);
|
|
106
|
+
mainLogger.update(updater());
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** @typedef {import('./types.js').Json} Json */
|
|
111
|
+
/** @typedef {import('./types.js').BuildConfiguration} BuildConfiguration */
|
|
112
|
+
/** @typedef {import('./types.js').BuildFormat} BuildFormat */
|
|
113
|
+
/** @typedef {import('./types.js').BuildConfigurationDraft} BuildConfigurationDraft */
|
|
114
|
+
/** @typedef {import('./types.js').BuildConfigurationSources} BuildConfigurationSources */
|
|
115
|
+
/** @typedef {import('./types.js').BuildEntry} BuildEntry */
|
|
116
|
+
/** @typedef {import('./types.js').BuildEntries} BuildEntries */
|
|
117
|
+
/** @typedef {import('./types.js').BuildEntryContribution} BuildEntryContribution */
|
|
118
|
+
/** @typedef {import('./types.js').BuildEntryContributions} BuildEntryContributions */
|
|
119
|
+
/** @typedef {import('./types.js').BuildEntryIssue} BuildEntryIssue */
|
|
120
|
+
/** @typedef {import('./types.js').ParsedOptions} ParsedOptions */
|
|
121
|
+
/** @typedef {import('./types.js').PackageProcessingResult} PackageProcessingResult */
|
|
122
|
+
/** @typedef {import('./types.js').PluginSharedState} PluginSharedState */
|
|
123
|
+
/** @typedef {import('./types.js').PluginConfigureContext} PluginConfigureContext */
|
|
124
|
+
/** @typedef {import('./types.js').PluginContributeEntriesContext} PluginContributeEntriesContext */
|
|
125
|
+
/** @typedef {import('./types.js').PluginPackageContext} PluginPackageContext */
|
|
126
|
+
/** @typedef {import('./types.js').PluginTsConfigContext} PluginTsConfigContext */
|
|
127
|
+
/** @typedef {import('./types.js').PluginRollupContext} PluginRollupContext */
|
|
128
|
+
/** @typedef {import('./types.js').PluginOutputContext} PluginOutputContext */
|
|
129
|
+
/** @typedef {import('./types.js').PluginBuildEndContext} PluginBuildEndContext */
|
|
130
|
+
/** @typedef {import('./types.js').PkgbldPluginFactory} PkgbldPluginFactory */
|
|
131
|
+
/** @typedef {import('./types.js').Provider} Provider */
|
|
132
|
+
/** @typedef {import('./types.js').ProvideFunction} ProvideFunction */
|
|
133
|
+
/** @typedef {import('./types.js').PkgbldRollupPlugin} PkgbldRollupPlugin */
|