@mirta/rollup 0.3.2 → 0.3.4

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/dist/index.d.mts CHANGED
@@ -3,6 +3,7 @@ import { Plugin, RollupOptions, ExternalOption } from 'rollup';
3
3
  interface RollupConfigOptions {
4
4
  /** Текущая рабочая директория. */
5
5
  cwd?: string;
6
+ input?: string | string[] | Record<string, string>;
6
7
  external?: (string | RegExp)[];
7
8
  plugins?: Plugin[];
8
9
  }
package/dist/index.mjs CHANGED
@@ -4,7 +4,7 @@ import commonjs from '@rollup/plugin-commonjs';
4
4
  import replace from '@rollup/plugin-replace';
5
5
  import dts from 'rollup-plugin-dts';
6
6
  import { deleteAsync } from 'del';
7
- import nodePath, { resolve } from 'node:path';
7
+ import nodePath from 'node:path';
8
8
  import { readFileSync } from 'fs';
9
9
  import multi from '@rollup/plugin-multi-entry';
10
10
  import ts$1 from 'rollup-plugin-typescript2';
@@ -37,62 +37,223 @@ function del(options = {}) {
37
37
  };
38
38
  }
39
39
 
40
+ class BuildError extends Error {
41
+ constructor(message) {
42
+ super(message);
43
+ // Убедимся, что экземпляр имеет правильный прототип
44
+ Object.setPrototypeOf(this, BuildError.prototype);
45
+ this.name = 'BuildError';
46
+ this.message = message;
47
+ Error.captureStackTrace(this, BuildError);
48
+ }
49
+ }
50
+ const dtsOutputDir = 'dist/dts';
51
+ function normalizeInput(input) {
52
+ const inputs = [];
53
+ // Нормализация входных данных.
54
+ // Строка, массив или объект преобразуются в единый массив строк inputs.
55
+ if (typeof input === 'string') {
56
+ inputs.push(input);
57
+ }
58
+ else if (Array.isArray(input)) {
59
+ inputs.push(...input);
60
+ }
61
+ else if (typeof input === 'object') {
62
+ inputs.push(...Object.values(input));
63
+ }
64
+ if (inputs.length === 0)
65
+ throw new BuildError('[Mirta Rollup] Input configuration cannot be empty');
66
+ return inputs;
67
+ }
68
+ /**
69
+ * Связывает исходные файлы проекта (`src/...`) с точками входа,
70
+ * определенными в `package.exports`. Ее основная цель — создать
71
+ * отображение между входными файлами (например, `src/index.ts`)
72
+ * и их выходными файлами (например, `dist/index.js`), а также источниками типов (`.d.ts`).
73
+ *
74
+ * @param inputs Массив путей к исходным файлам (например, `['src/index.ts', 'src/utils.ts']`)
75
+ * @param exports Объект из `package.exports`, описывающий точки входа пакета.
76
+ *
77
+ **/
78
+ function getInputBindings(inputs, exports) {
79
+ if (!inputs.length || !exports)
80
+ return {};
81
+ const candidates = {};
82
+ for (const [key, value] of Object.entries(exports)) {
83
+ if (!value.import?.default || !key.startsWith('.'))
84
+ continue;
85
+ // Формируем outputFile на основе данных package.json,
86
+ // убирая префикс `dist/` из путей, так как он
87
+ // уже указан в настройках сборки (output.dir).
88
+ //
89
+ const outputFile = value.import.default.startsWith('./dist/')
90
+ ? value.import.default.slice(7)
91
+ : value.import.default;
92
+ const source = key === '.' ? 'index' : key.slice(2);
93
+ // Генерация кандидатов для входных файлов.
94
+ //
95
+ // Для каждого ключа экспорта создает возможные пути
96
+ // к исходным файлам (например, `src/utils.ts` и `src/utils/index.ts`),
97
+ // учитывая как явные, так и неявные структуры каталогов.
98
+ Object.assign(candidates, {
99
+ // Варианты явного пути (например, `src/setup.ts`)
100
+ [`src/${source}.ts`]: { key, outputFile, dtsSource: source },
101
+ [`src/${source}.js`]: { key, outputFile, dtsSource: source },
102
+ // Варианты неявного пути (например, `src/setup/index.ts`):
103
+ [`src/${source}/index.ts`]: { key, outputFile, dtsSource: `${source}/index` },
104
+ [`src/${source}/index.js`]: { key, outputFile, dtsSource: `${source}/index` },
105
+ });
106
+ }
107
+ const result = {};
108
+ // Сопоставление с реальными входными файлами.
109
+ //
110
+ // Ппроверяет, какие из сгенерированных путей действительно существуют в массиве inputs.
111
+ //
112
+ for (const input of inputs) {
113
+ const entry = candidates[input];
114
+ // Если точка входа не ассоциирована с конфигурацией `package.json` — выбрасываем ошибку и прерываем сборку.
115
+ if (!entry)
116
+ throw new BuildError(`[Mirta Rollup] The input file "${input}" is not associated with corresponding export in the package.json`);
117
+ // Формирует итоговый объект result, где ключи — это точки входа из package.exports,
118
+ // а значения — связи между исходными файлами, выходными файлами и источниками типов.
119
+ //
120
+ result[entry.key] = {
121
+ sourceFile: input,
122
+ outputFile: entry.outputFile,
123
+ dtsSource: entry.dtsSource,
124
+ };
125
+ }
126
+ for (const [key, value] of Object.entries(exports)) {
127
+ if ((!value.import?.default && value.import?.types))
128
+ continue;
129
+ if (!(key in result))
130
+ throw new BuildError(`[Mirta Rollup] Export "${key}" defined in package.json has no corresponding input file in Rollup configuration`);
131
+ }
132
+ return result;
133
+ }
134
+ /**
135
+ * Создаёт отображение между файлами типов `.d.ts` и их выходными путями
136
+ * на основе данных из `package.exports` и ранее сформированных связей ({@link inputBindings})
137
+ *
138
+ * @param inputBindings
139
+ * @param exports
140
+ * @returns
141
+ */
142
+ function getDtsMappings(inputBindings, exports) {
143
+ if (!exports)
144
+ return {};
145
+ const result = {};
146
+ // Для каждой точки входа из package.exports
147
+ //
148
+ for (const [key, value] of Object.entries(exports)) {
149
+ // Где указан import.types
150
+ //
151
+ if (!value.import?.types || !key.startsWith('.'))
152
+ continue;
153
+ // Определяет путь к выходному файлу типов, убирая префикс `./dist/`
154
+ //
155
+ const outputFile = value.import.types.startsWith('./dist/')
156
+ ? value.import.types.slice(7)
157
+ : value.import.types;
158
+ const binding = inputBindings[key];
159
+ // Если для указанного ключа отсутствует точка входа — выбрасываем ошибку и прерываем сборку.
160
+ if (!binding)
161
+ throw new BuildError(`[Mirta Rollup] Type definition "${outputFile}" has no corresponding input file`);
162
+ // Связывает с исходным файлом типов.
163
+ //
164
+ const dtsSource = binding.dtsSource;
165
+ result[`${dtsOutputDir}/${dtsSource}.d.ts`] = outputFile;
166
+ }
167
+ return result;
168
+ }
40
169
  // Проверка TypeScript выполняется только для первой конфигурации.
41
170
  let hasTsChecked = false;
42
- let typesOutFile;
43
171
  function definePackageConfig(options) {
44
- const { cwd = process.cwd(), external = [], plugins } = options;
45
- const pkgPath = resolve(cwd, 'package.json');
172
+ const { cwd = process.cwd(), input = 'src/index.ts', external = [], plugins, } = options;
173
+ const pkgPath = nodePath.resolve(cwd, 'package.json');
46
174
  const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
47
- const { exports: { '.': root } = {} } = pkg;
48
- typesOutFile = root?.import?.types;
175
+ const { exports = {} } = pkg;
49
176
  const externalModules = [
50
177
  /node_modules/,
51
178
  pkgPath,
52
179
  ...external,
53
180
  ];
181
+ const inputBindings = getInputBindings(normalizeInput(input), exports);
182
+ const outputMappings = Object.keys(inputBindings)
183
+ .reduce((mappings, nextKey) => {
184
+ const inputMap = inputBindings[nextKey];
185
+ mappings[inputMap.sourceFile] = inputMap.outputFile;
186
+ return mappings;
187
+ }, {});
188
+ const dtsMappings = getDtsMappings(inputBindings, exports);
189
+ const dtsInputs = Object.keys(dtsMappings);
54
190
  const rollupConfigs = [
55
191
  createBuildConfig('mjs', {
56
192
  cwd,
193
+ input,
57
194
  external: externalModules,
195
+ emitDeclarations: dtsInputs.length > 0,
196
+ plugins,
58
197
  output: {
59
- file: 'dist/index.mjs',
198
+ dir: 'dist/',
60
199
  format: 'es',
61
200
  importAttributesKey: 'with',
62
- }}),
201
+ entryFileNames(chunk) {
202
+ if (chunk.facadeModuleId) {
203
+ const localPath = nodePath
204
+ .relative(cwd, chunk.facadeModuleId)
205
+ .replaceAll(nodePath.sep, nodePath.posix.sep);
206
+ if (outputMappings[localPath])
207
+ return outputMappings[localPath];
208
+ }
209
+ return `${chunk.name}.mjs`;
210
+ },
211
+ chunkFileNames: '[name].mjs',
212
+ },
213
+ }),
63
214
  ];
64
- if (typesOutFile) {
215
+ if (dtsInputs.length > 0) {
65
216
  rollupConfigs.push({
66
- input: 'dist/dts/index.d.ts',
217
+ input: dtsInputs,
67
218
  external: externalModules,
68
219
  plugins: [
69
220
  nodeResolve(),
70
221
  commonjs(),
71
222
  dts(),
72
223
  del({
73
- targets: ['dist/dts'],
224
+ targets: [dtsOutputDir],
74
225
  hook: 'closeBundle',
75
226
  }),
76
227
  ],
77
- output: [{
78
- file: typesOutFile, format: 'es',
79
- }],
228
+ output: {
229
+ dir: 'dist/',
230
+ format: 'es',
231
+ entryFileNames(chunk) {
232
+ if (chunk.facadeModuleId) {
233
+ const localPath = nodePath
234
+ .relative(cwd, chunk.facadeModuleId)
235
+ .replaceAll(nodePath.sep, nodePath.posix.sep);
236
+ if (dtsMappings[localPath])
237
+ return dtsMappings[localPath];
238
+ }
239
+ return `${chunk.name}.mts`;
240
+ },
241
+ },
80
242
  });
81
243
  }
82
244
  return rollupConfigs;
83
245
  }
84
- function createBuildConfig(buildName, options, plugins = []) {
85
- const { cwd, external, output } = options;
246
+ function createBuildConfig(buildName, options) {
247
+ const { cwd, external, input, emitDeclarations, plugins = [], output } = options;
86
248
  output.sourcemap = !!process.env.SOURCE_MAP;
87
249
  output.externalLiveBindings = false;
88
- /\.prod\.[cm]?js$/.test(output.file);
250
+ process.env.NODE_ENV === 'production';
89
251
  const tsPlugin = ts({
90
- tsconfig: resolve(cwd, './tsconfig.build.json'),
91
- // cacheRoot: resolve(rootDir, './node_modules/.rts2_cache'),
252
+ tsconfig: nodePath.resolve(cwd, './tsconfig.build.json'),
92
253
  compilerOptions: {
93
254
  noCheck: hasTsChecked,
94
- declaration: !!typesOutFile,
95
- declarationDir: typesOutFile ? 'dist/dts' : void 0,
255
+ declaration: emitDeclarations,
256
+ declarationDir: emitDeclarations ? dtsOutputDir : void 0,
96
257
  },
97
258
  exclude: [
98
259
  'packages/*/tests',
@@ -102,7 +263,7 @@ function createBuildConfig(buildName, options, plugins = []) {
102
263
  // выполняются единожды - для первой конфигурации.
103
264
  hasTsChecked = true;
104
265
  return {
105
- input: 'src/index.ts',
266
+ input,
106
267
  external,
107
268
  plugins: [
108
269
  tsPlugin,
@@ -121,6 +282,7 @@ function createBuildConfig(buildName, options, plugins = []) {
121
282
  }
122
283
  function createReplacePlugin(isProduction, isBundlerEsmBuild, isNodeBuild) {
123
284
  const replacements = {
285
+ // Preserve to be handled by bundlers
124
286
  __DEV__: `(process.env.NODE_ENV !== 'production')`
125
287
  ,
126
288
  __TEST__: `(process.env.NODE_ENV === 'test')`
@@ -277,7 +439,6 @@ function getEntry(path) {
277
439
  }
278
440
  function defineRuntimeConfig(options = {}) {
279
441
  const { cwd = process.cwd(), external, monorepo, dotenv: dotenvOptions = {}, plugins = [], } = options;
280
- const rootDir = monorepo?.rootDir;
281
442
  const defaultPlugins = [
282
443
  del({
283
444
  targets: 'dist/*',
@@ -288,9 +449,7 @@ function defineRuntimeConfig(options = {}) {
288
449
  }),
289
450
  nodeResolve(),
290
451
  ts$1({
291
- cacheRoot: rootDir
292
- ? nodePath.resolve(rootDir, './node_modules/.rts2_cache')
293
- : void 0,
452
+ clean: true,
294
453
  }),
295
454
  wbRulesImports(),
296
455
  dotenv(dotenvOptions),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mirta/rollup",
3
3
  "description": "Predefined Rollup configuration for wb-rules project builds.",
4
- "version": "0.3.2",
4
+ "version": "0.3.4",
5
5
  "license": "Unlicense",
6
6
  "keywords": [
7
7
  "mirta",
@@ -45,7 +45,7 @@
45
45
  "rollup-plugin-dts": "^6.2.3",
46
46
  "rollup-plugin-typescript2": "^0.36.0",
47
47
  "typescript": "^5.8.3",
48
- "@mirta/polyfills": "0.3.2"
48
+ "@mirta/polyfills": "0.3.4"
49
49
  },
50
50
  "devDependencies": {
51
51
  "rollup": "^4.52.4"