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.
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @typedef {import('rollup').InternalModuleFormat} InternalModuleFormat
3
+ * @typedef {import('rollup').OutputOptions} OutputOptions
4
+ * @typedef {import('type-fest').JsonObject} JsonObject
5
+ * @typedef {import('type-fest').PackageJson} PackageJson
6
+ * @typedef {import('./types.js').BuildConfiguration} BuildConfiguration
7
+ * @typedef {import('./types.js').BuildConfigurationDraft} BuildConfigurationDraft
8
+ * @typedef {import('./types.js').BuildConfigurationSources} BuildConfigurationSources
9
+ * @typedef {import('./types.js').BuildEntries} BuildEntries
10
+ * @typedef {import('./types.js').BuildEntryContributions} BuildEntryContributions
11
+ * @typedef {import('./types.js').PackageProcessingResult} PackageProcessingResult
12
+ * @typedef {import('./types.js').PkgbldPlugin} PkgbldPlugin
13
+ * @typedef {import('./types.js').PluginSharedState} PluginSharedState
14
+ * @typedef {import('./types.js').Provider} Provider
15
+ */
16
+
17
+ /**
18
+ * Owns Build plugin invocation and shared state for one build.
19
+ *
20
+ * The lifecycle preserves phase boundaries, but does not guarantee plugin order
21
+ * within a phase. Asynchronous hooks in the same phase run concurrently.
22
+ * Build plugins must not rely on same-phase shared-state reads and writes.
23
+ *
24
+ * @param {Partial<PkgbldPlugin>[]} plugins
25
+ */
26
+ export function createBuildPluginLifecycle(plugins) {
27
+ /** @type {PluginSharedState} */
28
+ const shared = new Map();
29
+
30
+ return {
31
+ /**
32
+ * @param {BuildConfigurationDraft} draft
33
+ * @param {BuildConfigurationSources} sources
34
+ */
35
+ configure(draft, sources) {
36
+ for (const plugin of plugins) {
37
+ plugin.configure?.({ draft, sources, shared });
38
+ }
39
+ },
40
+
41
+ /**
42
+ * @param {BuildEntryContributions} entries
43
+ * @param {BuildConfiguration} configuration
44
+ */
45
+ contributeEntries(entries, configuration) {
46
+ for (const plugin of plugins) {
47
+ plugin.contributeEntries?.({ entries, configuration, shared });
48
+ }
49
+ },
50
+
51
+ /**
52
+ * @param {JsonObject} config
53
+ * @param {BuildConfiguration} configuration
54
+ */
55
+ processTsConfig(config, configuration) {
56
+ for (const plugin of plugins) {
57
+ plugin.processTsConfig?.({ config, configuration, shared });
58
+ }
59
+ },
60
+
61
+ /**
62
+ * @param {PackageJson} packageJson
63
+ * @param {BuildEntries} entries
64
+ * @param {BuildConfiguration} configuration
65
+ */
66
+ processPackageJson(packageJson, entries, configuration) {
67
+ for (const plugin of plugins) {
68
+ plugin.processPackageJson?.({ packageJson, entries, configuration, shared });
69
+ }
70
+ },
71
+
72
+ /**
73
+ * @param {Provider} provider
74
+ * @param {BuildConfiguration} configuration
75
+ * @param {PackageProcessingResult} packageResult
76
+ */
77
+ async provideRollupPlugins(provider, configuration, packageResult) {
78
+ await Promise.all(plugins.map(plugin => plugin.providePlugins?.({ provider, configuration, packageResult, shared })));
79
+ },
80
+
81
+ /**
82
+ * @param {Partial<OutputOptions>} settings
83
+ * @param {InternalModuleFormat} format
84
+ * @param {string[]} inputs
85
+ * @param {BuildConfiguration} configuration
86
+ */
87
+ extendOutputSettings(settings, format, inputs, configuration) {
88
+ for (const plugin of plugins) {
89
+ if (plugin.getExtraOutputSettings) {
90
+ Object.assign(settings, plugin.getExtraOutputSettings({ format, inputs, configuration, shared }));
91
+ }
92
+ }
93
+ },
94
+
95
+ /** @param {BuildConfiguration} configuration */
96
+ async buildEnd(configuration) {
97
+ await Promise.all(plugins.map(plugin => plugin.buildEnd?.({ configuration, shared })));
98
+ },
99
+ };
100
+ }
@@ -0,0 +1,31 @@
1
+ import { Priority } from '../priorities.js';
2
+
3
+ /**
4
+ * @typedef {import('rollup').OutputChunk} OutputChunk
5
+ * @typedef {import('../types.js').BuildConfiguration} BuildConfiguration
6
+ * @typedef {import('../types.js').PackageProcessingResult} PackageProcessingResult
7
+ * @typedef {import('../types.js').Provider} Provider
8
+ */
9
+
10
+ /**
11
+ * @param {Provider} provider
12
+ * @param {BuildConfiguration} configuration
13
+ * @param {PackageProcessingResult} packageResult
14
+ */
15
+ export default async function (provider, configuration, packageResult) {
16
+ if (packageResult.executableOutputs.length > 0) {
17
+ const pluginBinify = await provider.import('@rollup-extras/plugin-binify');
18
+
19
+ provider.provide(
20
+ () =>
21
+ pluginBinify({
22
+ filter: (/** @type {OutputChunk} */ item) =>
23
+ item.type === 'chunk' &&
24
+ item.isEntry &&
25
+ packageResult.executableOutputs.some(input => input === `./${configuration.paths.outputDir}/${item.fileName}`),
26
+ }),
27
+ Priority.finalize,
28
+ { outputPlugin: true, format: 'cjs' }
29
+ );
30
+ }
31
+ }
@@ -0,0 +1,30 @@
1
+ import { Priority } from '../priorities.js';
2
+
3
+ /**
4
+ * @typedef {import('../types.js').BuildConfiguration} BuildConfiguration
5
+ * @typedef {import('../types.js').Provider} Provider
6
+ */
7
+
8
+ /**
9
+ * @param {Provider} provider
10
+ * @param {BuildConfiguration} configuration
11
+ */
12
+ export default async function (provider, configuration) {
13
+ if (!configuration.execution.clean) {
14
+ return;
15
+ }
16
+
17
+ const pluginClean = await provider.import('@rollup-extras/plugin-clean');
18
+
19
+ const pluginInstance = pluginClean();
20
+
21
+ provider.provide(pluginFactory, Priority.cleanup, { outputPlugin: true });
22
+
23
+ let firstPluginInstance = true;
24
+
25
+ function pluginFactory() {
26
+ const result = firstPluginInstance ? pluginInstance : pluginInstance.api.addInstance();
27
+ firstPluginInstance = false;
28
+ return result;
29
+ }
30
+ }
@@ -0,0 +1,14 @@
1
+ import { Priority } from '../priorities.js';
2
+
3
+ /**
4
+ * @typedef {import('../types.js').Provider} Provider
5
+ */
6
+
7
+ /**
8
+ * @param {Provider} provider
9
+ */
10
+ export default async function (provider) {
11
+ const pluginCommonjs = await provider.import('@rollup/plugin-commonjs');
12
+
13
+ provider.provide(() => pluginCommonjs(), Priority.commonjs);
14
+ }
@@ -0,0 +1,108 @@
1
+ import path from 'node:path';
2
+
3
+ import { Priority } from '../priorities.js';
4
+
5
+ /**
6
+ * @param {(...args: any[]) => any} fn
7
+ * @param {any[]} args
8
+ * @returns {any}
9
+ */
10
+ export function curry(fn, ...args) {
11
+ return args.length >= fn.length
12
+ ? fn(...args)
13
+ : /** @type {(...nextArgs: any[]) => any} */ ((...nextArgs) => curry(fn, ...args, ...nextArgs));
14
+ }
15
+
16
+ /**
17
+ * @typedef {import('rollup').InternalModuleFormat} InternalModuleFormat
18
+ * @typedef {import('../types.js').BuildConfiguration} BuildConfiguration
19
+ * @typedef {import('../types.js').PackageProcessingResult} PackageProcessingResult
20
+ * @typedef {import('../types.js').Provider} Provider
21
+ */
22
+
23
+ /**
24
+ * @param {Provider} provider
25
+ * @param {BuildConfiguration} configuration
26
+ * @param {PackageProcessingResult} packageResult
27
+ */
28
+ export default async function (provider, configuration, packageResult) {
29
+ const inputs = packageResult.entries.values.filter(entry => entry.origin !== 'import').map(entry => entry.sourcePath);
30
+ if (configuration.transforms.includeExternals === true) {
31
+ return;
32
+ }
33
+
34
+ const pluginExternals = await provider.import('@rollup-extras/plugin-externals');
35
+
36
+ const allowGenericUmd = configuration.outputs.umdEntries.length === 1 && inputs.length === 1;
37
+
38
+ if (configuration.outputs.formats.length > 0) {
39
+ const format = /** @type {InternalModuleFormat[]} */ (
40
+ allowGenericUmd ? undefined : configuration.outputs.formats.filter(format => format !== 'umd')
41
+ );
42
+ provider.provide(
43
+ () =>
44
+ pluginExternals(
45
+ configuration.transforms.includeExternals === false && !configuration.resolution.imports
46
+ ? {}
47
+ : (/** @type {string} */ id, /** @type {boolean} */ external, /** @type {string} */ importer) =>
48
+ includeExternals(importer, external, id, configuration)
49
+ ),
50
+ Priority.externals,
51
+ { format }
52
+ );
53
+ provider.globalImport('path', 'path');
54
+ provider.globalSetup(includeExternals);
55
+ }
56
+
57
+ if (!allowGenericUmd && configuration.outputs.umdEntries.length > 0) {
58
+ const curryForConfig = /** @type {typeof curry} */ (provider.globalSetup(curry) ?? curry);
59
+ for (const entryName of configuration.outputs.umdEntries) {
60
+ const currentInput = packageResult.entries.require(entryName).sourcePath;
61
+ const isExternal = curryForConfig(
62
+ (
63
+ /** @type {string} */ currentInput,
64
+ /** @type {string} */ id,
65
+ /** @type {boolean} */ external,
66
+ /** @type {string} */ importer
67
+ ) => includeExternals(importer, external, id, configuration) || isExternalInput(currentInput, inputs, id)
68
+ )(currentInput);
69
+ provider.provide(() => pluginExternals(isExternal), Priority.externals, {
70
+ format: 'umd',
71
+ inputs: [currentInput],
72
+ });
73
+ }
74
+ if (configuration.outputs.formats.length === 0) {
75
+ provider.globalImport('path', 'path');
76
+ provider.globalSetup(includeExternals);
77
+ }
78
+ provider.globalSetup(isExternalInput);
79
+ }
80
+ }
81
+
82
+ /**
83
+ * @param {string} _importer
84
+ * @param {boolean} external
85
+ * @param {string} id
86
+ * @param {BuildConfiguration} configuration
87
+ */
88
+ function includeExternals(_importer, external, id, configuration) {
89
+ if (configuration.resolution.imports && id.startsWith('#')) return false;
90
+ if (configuration.transforms.includeExternals === false) return external;
91
+ if (!external) return false;
92
+ const internals = /** @type {readonly string[]} */ (configuration.transforms.includeExternals);
93
+ if (internals.includes(id) || internals.some(internal => id.includes(internal))) {
94
+ return false;
95
+ }
96
+ return true;
97
+ }
98
+
99
+ /**
100
+ * @param {string} currentInput
101
+ * @param {string | readonly string[]} inputs
102
+ * @param {string} id
103
+ */
104
+ function isExternalInput(currentInput, inputs, id) {
105
+ const normalizedPath = path.isAbsolute(currentInput) ? `./${path.relative(process.cwd(), currentInput)}` : currentInput;
106
+ const normalizedId = path.isAbsolute(id) ? `./${path.relative(process.cwd(), id)}` : id;
107
+ return normalizedPath !== normalizedId && inputs.includes(normalizedPath);
108
+ }
@@ -0,0 +1,14 @@
1
+ import { Priority } from '../priorities.js';
2
+
3
+ /**
4
+ * @typedef {import('../types.js').Provider} Provider
5
+ */
6
+
7
+ /**
8
+ * @param {Provider} provider
9
+ */
10
+ export default async function (provider) {
11
+ const pluginJson = await provider.import('@rollup/plugin-json');
12
+
13
+ provider.provide(() => pluginJson(), Priority.preprocess);
14
+ }
@@ -0,0 +1,79 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ import { Priority } from '../priorities.js';
5
+
6
+ /**
7
+ * @typedef {import('../types.js').BuildConfiguration} BuildConfiguration
8
+ * @typedef {import('../types.js').Provider} Provider
9
+ */
10
+
11
+ /**
12
+ * @param {Provider} provider
13
+ * @param {BuildConfiguration} configuration
14
+ */
15
+ export default function (provider, configuration) {
16
+ if (!configuration.resolution.imports) return;
17
+
18
+ provider.globalImport('node:fs/promises', 'fs');
19
+ provider.globalImport('path', 'path');
20
+ const createPlugin = /** @type {typeof createPackageImportsPlugin} */ (
21
+ provider.globalSetup(createPackageImportsPlugin) ?? createPackageImportsPlugin
22
+ );
23
+ provider.provide(() => createPlugin(), Priority.packageImports);
24
+ }
25
+
26
+ /**
27
+ * Keep the package's private specifiers for runtime resolution. Each importer
28
+ * is assigned to its nearest real package boundary, so linked dependencies and
29
+ * nested workspace packages retain ownership of their own private imports.
30
+ */
31
+ export function createPackageImportsPlugin() {
32
+ const packageRoot = fs.realpath(process.cwd());
33
+ /** @type {Map<string, string | null>} */
34
+ const owners = new Map();
35
+ return {
36
+ name: 'pkgbld:package-imports',
37
+ /** @param {string} id @param {string | undefined} importer */
38
+ async resolveId(id, importer) {
39
+ if (!id.startsWith('#') || !importer || importer.includes('\0')) return null;
40
+ let realImporter;
41
+ try {
42
+ realImporter = await fs.realpath(importer.split('?', 1)[0]);
43
+ } catch (error) {
44
+ if (['ENOENT', 'EINVAL'].includes(/** @type {NodeJS.ErrnoException} */ (error).code ?? '')) return null;
45
+ throw error;
46
+ }
47
+ const owner = await findOwner(path.dirname(realImporter));
48
+ return owner === (await packageRoot) ? { id, external: true } : null;
49
+ },
50
+ };
51
+
52
+ /** @param {string} start */
53
+ async function findOwner(start) {
54
+ let directory = start;
55
+ /** @type {string[]} */
56
+ const visited = [];
57
+ while (true) {
58
+ if (owners.has(directory)) {
59
+ const owner = /** @type {string | null} */ (owners.get(directory));
60
+ for (const visitedDirectory of visited) owners.set(visitedDirectory, owner);
61
+ return owner;
62
+ }
63
+ visited.push(directory);
64
+ try {
65
+ await fs.access(path.join(directory, 'package.json'));
66
+ for (const visitedDirectory of visited) owners.set(visitedDirectory, directory);
67
+ return directory;
68
+ } catch (error) {
69
+ if (/** @type {NodeJS.ErrnoException} */ (error).code !== 'ENOENT') throw error;
70
+ }
71
+ const parent = path.dirname(directory);
72
+ if (parent === directory) {
73
+ for (const visitedDirectory of visited) owners.set(visitedDirectory, null);
74
+ return null;
75
+ }
76
+ directory = parent;
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,37 @@
1
+ import { Priority } from '../priorities.js';
2
+
3
+ /**
4
+ * @typedef {import('rollup').InternalModuleFormat} InternalModuleFormat
5
+ * @typedef {import('../types.js').BuildConfiguration} BuildConfiguration
6
+ * @typedef {import('../types.js').PackageProcessingResult} PackageProcessingResult
7
+ * @typedef {import('../types.js').Provider} Provider
8
+ */
9
+
10
+ /**
11
+ * @param {Provider} provider
12
+ * @param {BuildConfiguration} configuration
13
+ * @param {PackageProcessingResult} packageResult
14
+ */
15
+ export default async function (provider, configuration, packageResult) {
16
+ if (configuration.transforms.preprocess.length > 0) {
17
+ const pluginPreprocess = /** @type {typeof import('rollup-plugin-preprocess')} */ (
18
+ await provider.import('rollup-plugin-preprocess')
19
+ );
20
+
21
+ const include = configuration.transforms.preprocess.map(name => packageResult.entries.require(name).sourcePath);
22
+
23
+ for (const format of /** @type {readonly InternalModuleFormat[]} */ (configuration.outputs.formats)) {
24
+ if (format !== 'umd') {
25
+ provider.provide(() => pluginPreprocess.default({ include, context: { [format]: true } }), Priority.preprocess, { format });
26
+ } else {
27
+ for (const entryName of configuration.outputs.umdEntries) {
28
+ const currentInput = packageResult.entries.require(entryName).sourcePath;
29
+ provider.provide(() => pluginPreprocess.default({ include, context: { umd: true } }), Priority.preprocess, {
30
+ format,
31
+ inputs: [currentInput],
32
+ });
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,22 @@
1
+ import { Priority } from '../priorities.js';
2
+
3
+ /**
4
+ * @typedef {import('../types.js').Provider} Provider
5
+ * @typedef {import('../types.js').BuildConfiguration} BuildConfiguration
6
+ */
7
+
8
+ /**
9
+ * @param {Provider} provider
10
+ * @param {BuildConfiguration} configuration
11
+ */
12
+ export default async function (provider, configuration) {
13
+ const pluginResolve = await provider.import('@rollup/plugin-node-resolve');
14
+
15
+ provider.provide(
16
+ () =>
17
+ configuration.resolution.conditions.length > 0
18
+ ? pluginResolve({ exportConditions: [...configuration.resolution.conditions] })
19
+ : pluginResolve(),
20
+ Priority.resolve
21
+ );
22
+ }
@@ -0,0 +1,50 @@
1
+ import { Priority } from '../priorities.js';
2
+
3
+ /**
4
+ * @typedef {import('rollup').InternalModuleFormat} InternalModuleFormat
5
+ * @typedef {import('../types.js').BuildConfiguration} BuildConfiguration
6
+ * @typedef {import('../types.js').PackageProcessingResult} PackageProcessingResult
7
+ * @typedef {import('../types.js').Provider} Provider
8
+ */
9
+
10
+ /**
11
+ * @param {Provider} provider
12
+ * @param {BuildConfiguration} configuration
13
+ * @param {PackageProcessingResult} packageResult
14
+ */
15
+ export default async function (provider, configuration, packageResult) {
16
+ const filteredFormats = configuration.transforms.compress.filter(format => configuration.outputs.formats.includes(format));
17
+
18
+ if (filteredFormats.length > 0) {
19
+ const pluginTerser = await provider.import('@rollup/plugin-terser');
20
+
21
+ const options = {
22
+ mangle: {
23
+ properties: {
24
+ regex: /_$/,
25
+ },
26
+ },
27
+ };
28
+
29
+ if (configuration.transforms.removeLegalComments) {
30
+ /** @type {any} */ (options).output = {
31
+ comments: false,
32
+ };
33
+ }
34
+
35
+ for (const format of /** @type {InternalModuleFormat[]} */ (filteredFormats)) {
36
+ if (format !== 'umd') {
37
+ provider.provide(() => pluginTerser(options), Priority.compress, { format, outputPlugin: true });
38
+ } else {
39
+ for (const entryName of configuration.outputs.umdEntries) {
40
+ const currentInput = packageResult.entries.require(entryName).sourcePath;
41
+ provider.provide(() => pluginTerser(options), Priority.compress, {
42
+ format,
43
+ outputPlugin: true,
44
+ inputs: [currentInput],
45
+ });
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
package/src/eject.js ADDED
@@ -0,0 +1,151 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ import pkgbldPkg from '../package.json' with { type: 'json' };
5
+ import { camelCase } from './helpers.js';
6
+
7
+ /**
8
+ * @typedef {import('rollup').RollupOptions} RollupOptions
9
+ * @typedef {import('type-fest').PackageJson} PackageJson
10
+ * @typedef {import('./types.js').BuildConfiguration} BuildConfiguration
11
+ * @typedef {import('./types.js').PackageProcessingResult} PackageProcessingResult
12
+ * @typedef {import('./types.js').PkgbldRollupPlugin} PkgbldRollupPlugin
13
+ * @typedef {import('./types.js').Provider} Provider
14
+ */
15
+
16
+ const imports = new Map();
17
+ const setup = new Set();
18
+
19
+ /** @type {<T extends object>(object: T) => string | boolean | RegExp | null | undefined} */
20
+ let generate;
21
+ /** @type {() => string} */
22
+ let generateGlobals;
23
+
24
+ /**
25
+ * @returns {Promise<[Provider, PkgbldRollupPlugin[]]>}
26
+ */
27
+ export async function createEjectProvider() {
28
+ const createMockProvider = (await import('@slimlib/smart-mock')).default;
29
+ const provider = createMockProvider();
30
+ const createMock = provider.createMock;
31
+ generate = provider.generate;
32
+ generateGlobals = provider.generateGlobals;
33
+ /** @type {PkgbldRollupPlugin[]} */
34
+ const plugins = [];
35
+ return [
36
+ {
37
+ provide: (
38
+ /** @type {PkgbldRollupPlugin['plugin']} */ plugin,
39
+ /** @type {PkgbldRollupPlugin['priority']} */ priority,
40
+ /** @type {Omit<PkgbldRollupPlugin, 'plugin' | 'priority'>=} */ options
41
+ ) => {
42
+ plugins.push({ priority, plugin, format: options?.format, inputs: options?.inputs, outputPlugin: options?.outputPlugin });
43
+ },
44
+ import: async (/** @type {string} */ name, /** @type {string=} */ exportName) => {
45
+ const result = await import(name);
46
+ const exports = result[exportName ?? 'default'];
47
+ const mangledName = camelCase(name);
48
+ imports.set(name, mangledName);
49
+ return createMock(exports, mangledName);
50
+ },
51
+ globalImport: (/** @type {string} */ module, /** @type {string | string[]=} */ exportName) => {
52
+ imports.set(module, exportName ?? 'default');
53
+ },
54
+ globalSetup: (/** @type {((...args: any[]) => any) | string} */ code) => {
55
+ if (typeof code === 'function') {
56
+ setup.add(code.toString());
57
+ return createMock(code, code.name);
58
+ }
59
+ setup.add(String(code));
60
+ },
61
+ },
62
+ plugins,
63
+ ];
64
+ }
65
+
66
+ /**
67
+ * @param {RollupOptions[]} config
68
+ * @param {string} pkgPath
69
+ * @param {BuildConfiguration} configuration
70
+ * @param {PackageProcessingResult} packageResult
71
+ * @param {ReturnType<import('./helpers.js').getHelpers>} helpers
72
+ * @param {PackageJson} pkg
73
+ */
74
+ export async function ejectConfig(config, pkgPath, configuration, packageResult, helpers, pkg) {
75
+ const pkgName = /** @type {{ name: string }} */ (pkg).name;
76
+
77
+ const text = generate(config);
78
+ setup.add(generateGlobals());
79
+
80
+ setup.add(`const configuration = ${generate(configuration)}`);
81
+ setup.add(`const packageResult = { executableOutputs: ${generate(packageResult.executableOutputs)} }`);
82
+ setup.add(`const inputs = ${generate(packageResult.entries.values.map(entry => entry.sourcePath))}`);
83
+
84
+ if (configuration.outputs.formats.includes('umd')) {
85
+ imports.set('path', 'path');
86
+ imports.set('url', 'url');
87
+ setup.add(`const pkgName = ${generate(/** @type {never} */ (pkgName))}`);
88
+ setup.add(camelCase.toString());
89
+ setup.add(helpers.getGlobalName.toString());
90
+ setup.add("const __dirname = url.fileURLToPath(new URL('.', import.meta.url));");
91
+ }
92
+
93
+ const importsString = Array.from(imports)
94
+ .map(value => `import ${value[1]} from '${value[0]}';`)
95
+ .join('\n');
96
+ const setupString = Array.from(setup).join('\n');
97
+
98
+ const { minify } = await import('terser');
99
+
100
+ const result = await minify(`${importsString}\n${setupString}\nexport default ${text};`, {
101
+ module: true,
102
+ compress: {
103
+ booleans: false,
104
+ ecma: 2020,
105
+ module: true,
106
+ passes: 3,
107
+ unsafe: true,
108
+ },
109
+ mangle: false,
110
+ output: {
111
+ beautify: true,
112
+ ecma: 2020,
113
+ quote_style: 1,
114
+ },
115
+ });
116
+ await fs.writeFile(path.join(path.dirname(pkgPath), 'rollup.config.mjs'), /** @type {string} */ (result.code));
117
+
118
+ await updatePackageJson(pkg);
119
+ }
120
+
121
+ /**
122
+ * @param {PackageJson} pkg
123
+ */
124
+ async function updatePackageJson(pkg) {
125
+ if (typeof pkg.devDependencies !== 'object') {
126
+ pkg.devDependencies = {};
127
+ }
128
+ const devDependencies = pkg.devDependencies;
129
+ if ('pkgbld' in devDependencies) {
130
+ devDependencies.pkgbld = undefined;
131
+ }
132
+ devDependencies.rollup = /** @type {Record<string, string>} */ (pkgbldPkg.dependencies).rollup ?? '*';
133
+ const isBuiltin = (await import('is-builtin-module')).default;
134
+ for (const key of imports.keys()) {
135
+ const packageName = getPackageName(key);
136
+ if (!isBuiltin(packageName)) {
137
+ devDependencies[packageName] = /** @type {Record<string, string>} */ (pkgbldPkg.dependencies)[packageName] ?? '*';
138
+ }
139
+ }
140
+ }
141
+
142
+ /**
143
+ * @param {string} key
144
+ * @returns {string}
145
+ */
146
+ function getPackageName(key) {
147
+ return key
148
+ .split('/')
149
+ .slice(0, key.startsWith('@') ? 2 : 1)
150
+ .join('/');
151
+ }
@@ -0,0 +1,16 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ /**
5
+ * @typedef {import('type-fest').JsonObject} JsonObject
6
+ */
7
+
8
+ /**
9
+ * @param {string} fileName
10
+ * @returns {Promise<[string, JsonObject]>}
11
+ */
12
+ export async function getJson(fileName) {
13
+ const pkgPath = path.resolve(fileName);
14
+ const buffer = await fs.readFile(pkgPath);
15
+ return [pkgPath, /** @type {JsonObject} */ (JSON.parse(buffer.toString()))];
16
+ }