@foxford/tsup-config 1.0.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.mdx ADDED
@@ -0,0 +1,62 @@
1
+ # @foxford/tsup-config
2
+
3
+ Общая сборка публикуемых пакетов монорепо. Решает одну задачу: **точки входа пакета
4
+ объявляются один раз**, и из этой декларации получаются и сборка, и публикуемый
5
+ `package.json`, и проверка, что исходный `package.json` им соответствует.
6
+
7
+ ## Зачем
8
+
9
+ Без единого источника правды подпути разъезжаются: в монорепо пакет резолвится по одним
10
+ путям, а опубликованный — по другим, и расхождение всплывает уже у потребителя. Типовые
11
+ грабли, которые это ловит:
12
+
13
+ - `exports` в исходном `package.json` ведёт на `build/*`, которого при разработке нет;
14
+ - в `build/package.json` уезжает `files: ["build"]` — внутри артефакта такой папки нет,
15
+ и npm публикует пустой пакет;
16
+ - ESM-артефакт называется `index.js`, а `exports.import` ссылается на `index.mjs`;
17
+ - добавили подпуть в `exports`, забыли в `entry` — импорт падает только после публикации.
18
+
19
+ ## Использование
20
+
21
+ Точки входа объявляются прямо в конфиге сборки — отдельного файла-декларации нет:
22
+
23
+ ```ts
24
+ import { createTsupConfig, defineEntries } from '@foxford/tsup-config'
25
+ import { defineConfig } from 'tsup'
26
+
27
+ export default defineConfig(
28
+ createTsupConfig({
29
+ entries: defineEntries({
30
+ '.': 'src/index.ts',
31
+ './slot': 'src/slot.tsx',
32
+ }),
33
+ })
34
+ )
35
+ ```
36
+
37
+ `package.json` пакета описывает те же подпути и ведёт **на исходники** (в монорепо
38
+ потребители едят `src`); соответствие проверяется при каждой сборке:
39
+
40
+ ```json
41
+ "exports": {
42
+ ".": { "types": "./src/index.ts", "import": "./src/index.ts", "default": "./src/index.ts" },
43
+ "./slot": { "types": "./src/slot.tsx", "import": "./src/slot.tsx", "default": "./src/slot.tsx" }
44
+ }
45
+ ```
46
+
47
+ ## Что делает сборка
48
+
49
+ 1. `entry` для tsup — из декларации;
50
+ 2. ESM → `.mjs`, CJS → `.cjs` (явно, иначе при `"type": "module"` ESM уходит в `.js`);
51
+ 3. `build/package.json`: метаданные без dev-полей, `exports` внутрь артефакта,
52
+ `files` — по фактическому содержимому `build/`;
53
+ 4. падает, если объявленного подпути нет в `exports` исходного package.json,
54
+ если `exports` ведёт не на исходник, или если файла из `exports` нет в `build/`.
55
+
56
+ ## Пакеты со своей сборкой
57
+
58
+ `@foxford/den-vike` собирается `tsc`, а не tsup: его vike-хуки связаны импортами
59
+ `with { type: 'vike:pointer' }` — esbuild такие import attributes при бандлинге не
60
+ поддерживает, а в transform-режиме молча их выбрасывает, что ломает расширение.
61
+ Декларацию точек входа и генерацию публикуемого `package.json` он берёт отсюда же —
62
+ расходится только инструмент транспиляции.
package/index.cjs ADDED
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ }
20
+ return a;
21
+ };
22
+ var __export = (target, all) => {
23
+ for (var name in all)
24
+ __defProp(target, name, { get: all[name], enumerable: true });
25
+ };
26
+ var __copyProps = (to, from, except, desc) => {
27
+ if (from && typeof from === "object" || typeof from === "function") {
28
+ for (let key of __getOwnPropNames(from))
29
+ if (!__hasOwnProp.call(to, key) && key !== except)
30
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
31
+ }
32
+ return to;
33
+ };
34
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
35
+ // If the importer is in node compatibility mode or this is not an ESM
36
+ // file that has been converted to a CommonJS file using a Babel-
37
+ // compatible transform (i.e. "__esModule" has not been set), then set
38
+ // "default" to the CommonJS "module.exports" for node compatibility.
39
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
40
+ mod
41
+ ));
42
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
43
+ var __async = (__this, __arguments, generator) => {
44
+ return new Promise((resolve, reject) => {
45
+ var fulfilled = (value) => {
46
+ try {
47
+ step(generator.next(value));
48
+ } catch (e) {
49
+ reject(e);
50
+ }
51
+ };
52
+ var rejected = (value) => {
53
+ try {
54
+ step(generator.throw(value));
55
+ } catch (e) {
56
+ reject(e);
57
+ }
58
+ };
59
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
60
+ step((generator = generator.apply(__this, __arguments)).next());
61
+ });
62
+ };
63
+
64
+ // src/index.js
65
+ var src_exports = {};
66
+ __export(src_exports, {
67
+ assertSourceExports: () => assertSourceExports,
68
+ copyReadme: () => copyReadme,
69
+ createTsupConfig: () => createTsupConfig,
70
+ defineEntries: () => defineEntries,
71
+ toBuildExports: () => toBuildExports,
72
+ toTsupEntry: () => toTsupEntry,
73
+ updateBuildFiles: () => updateBuildFiles,
74
+ verifyBuildExports: () => verifyBuildExports,
75
+ writeBuildPackageJson: () => writeBuildPackageJson
76
+ });
77
+ module.exports = __toCommonJS(src_exports);
78
+ var import_node_fs = __toESM(require("fs"), 1);
79
+ var import_node_path = __toESM(require("path"), 1);
80
+ function defineEntries(map) {
81
+ for (const [subpath, source] of Object.entries(map)) {
82
+ if (!subpath.startsWith(".")) {
83
+ throw new Error(`entries: \u043F\u043E\u0434\u043F\u0443\u0442\u044C \xAB${subpath}\xBB \u0434\u043E\u043B\u0436\u0435\u043D \u043D\u0430\u0447\u0438\u043D\u0430\u0442\u044C\u0441\u044F \u0441 "."`);
84
+ }
85
+ if (!source.startsWith("src/")) {
86
+ throw new Error(`entries: \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A \xAB${source}\xBB \u0434\u043E\u043B\u0436\u0435\u043D \u043B\u0435\u0436\u0430\u0442\u044C \u0432 src/`);
87
+ }
88
+ }
89
+ return map;
90
+ }
91
+ function artifactName(subpath, source) {
92
+ if (subpath === ".") return import_node_path.default.basename(source).replace(/\.[cm]?[jt]sx?$/, "");
93
+ return source.replace(/^src\//, "").replace(/\.[cm]?[jt]sx?$/, "");
94
+ }
95
+ function toTsupEntry(entries) {
96
+ return Object.fromEntries(Object.entries(entries).map(([subpath, source]) => [artifactName(subpath, source), source]));
97
+ }
98
+ function assertSourceExports(entries, packageJson) {
99
+ var _a;
100
+ const declared = new Set(Object.keys(entries));
101
+ const actual = new Set(Object.keys((_a = packageJson.exports) != null ? _a : {}).filter((key) => !key.endsWith(".mdx")));
102
+ const missing = [...declared].filter((key) => !actual.has(key));
103
+ const extra = [...actual].filter((key) => !declared.has(key));
104
+ if (missing.length > 0 || extra.length > 0) {
105
+ throw new Error(
106
+ `package.json exports \u0440\u0430\u0437\u043E\u0448\u0451\u043B\u0441\u044F \u0441 \u0434\u0435\u043A\u043B\u0430\u0440\u0430\u0446\u0438\u0435\u0439 entries:` + (missing.length > 0 ? ` \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 [${missing.join(", ")}]` : "") + (extra.length > 0 ? ` \u043B\u0438\u0448\u043D\u0438\u0435 [${extra.join(", ")}]` : "")
107
+ );
108
+ }
109
+ for (const [subpath, source] of Object.entries(entries)) {
110
+ const entry = packageJson.exports[subpath];
111
+ const declaration = `./${source.replace(/\.[cm]?[jt]sx?$/, ".d.ts")}`;
112
+ const allowed = (condition, value) => value === `./${source}` || condition === "types" && value === declaration;
113
+ const pairs = typeof entry === "string" ? [["default", entry]] : Object.entries(entry);
114
+ const wrong = pairs.filter(([condition, value]) => !allowed(condition, value)).map(([, value]) => value);
115
+ if (wrong.length > 0) {
116
+ throw new Error(
117
+ `package.json exports["${subpath}"] \u0434\u043E\u043B\u0436\u0435\u043D \u0432\u0435\u0441\u0442\u0438 \u043D\u0430 ./${source} (\u0432 \u043C\u043E\u043D\u043E\u0440\u0435\u043F\u043E \u0435\u0434\u0438\u043C \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u0438), \u0430 \u0432\u0435\u0434\u0451\u0442 \u043D\u0430 ${wrong.join(", ")}`
118
+ );
119
+ }
120
+ }
121
+ }
122
+ function toBuildExports(entries, { extensions }) {
123
+ return Object.fromEntries(
124
+ Object.entries(entries).map(([subpath, source]) => {
125
+ const name = artifactName(subpath, source);
126
+ return [subpath, __spreadValues({}, extensions(name))];
127
+ })
128
+ );
129
+ }
130
+ function writeBuildPackageJson({ entries, extensions, main, module: moduleField, outDir = "build" }) {
131
+ const source = JSON.parse(import_node_fs.default.readFileSync("package.json", "utf-8"));
132
+ assertSourceExports(entries, source);
133
+ const DEV_ONLY = /* @__PURE__ */ new Set([
134
+ "devDependencies",
135
+ "scripts",
136
+ "exports",
137
+ "main",
138
+ "module",
139
+ "types",
140
+ "browserslist",
141
+ "files"
142
+ ]);
143
+ const packageJson = Object.fromEntries(Object.entries(source).filter(([field]) => !DEV_ONLY.has(field)));
144
+ packageJson.main = main;
145
+ packageJson.module = moduleField;
146
+ packageJson.exports = toBuildExports(entries, { extensions });
147
+ import_node_fs.default.writeFileSync(import_node_path.default.join(outDir, "package.json"), `${JSON.stringify(packageJson, null, 2)}
148
+ `);
149
+ }
150
+ function verifyBuildExports(outDir = "build") {
151
+ var _a;
152
+ const packageJson = JSON.parse(import_node_fs.default.readFileSync(import_node_path.default.join(outDir, "package.json"), "utf-8"));
153
+ const missing = Object.values((_a = packageJson.exports) != null ? _a : {}).flatMap((entry) => typeof entry === "string" ? [entry] : Object.values(entry)).filter((file) => !import_node_fs.default.existsSync(import_node_path.default.join(outDir, file)));
154
+ if (missing.length > 0) {
155
+ throw new Error(`\u0432 ${outDir}/ \u043D\u0435\u0442 \u0444\u0430\u0439\u043B\u043E\u0432 \u0434\u043B\u044F exports: ${[...new Set(missing)].join(", ")}`);
156
+ }
157
+ }
158
+ function updateBuildFiles(outDir = "build") {
159
+ try {
160
+ const file = import_node_path.default.join(outDir, "package.json");
161
+ const packageJson = JSON.parse(import_node_fs.default.readFileSync(file, "utf-8"));
162
+ packageJson.files = import_node_fs.default.readdirSync(outDir).filter((name) => name !== ".tsbuildinfo");
163
+ import_node_fs.default.writeFileSync(file, `${JSON.stringify(packageJson, null, 2)}
164
+ `);
165
+ } catch (error) {
166
+ console.error("\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C files \u0432 build/package.json:", error);
167
+ }
168
+ }
169
+ function copyReadme(outDir = "build") {
170
+ import_node_fs.default.copyFileSync("README.mdx", import_node_path.default.join(outDir, "README.mdx"));
171
+ }
172
+ function createTsupConfig({ entries, overrides = {} }) {
173
+ const extensions = (name) => ({
174
+ import: `./${name}.mjs`,
175
+ require: `./${name}.cjs`,
176
+ types: `./${name}.d.ts`
177
+ });
178
+ process.on("beforeExit", (code) => {
179
+ if (code !== 0) return;
180
+ updateBuildFiles();
181
+ try {
182
+ verifyBuildExports();
183
+ } catch (error) {
184
+ console.error(String(error instanceof Error ? error.message : error));
185
+ process.exitCode = 1;
186
+ }
187
+ });
188
+ return __spreadValues({
189
+ bundle: true,
190
+ clean: true,
191
+ dts: true,
192
+ entry: toTsupEntry(entries),
193
+ format: ["cjs", "esm"],
194
+ onSuccess: () => __async(null, null, function* () {
195
+ copyReadme();
196
+ writeBuildPackageJson({
197
+ entries,
198
+ extensions,
199
+ main: "./index.cjs",
200
+ module: "./index.mjs"
201
+ });
202
+ }),
203
+ outDir: "build",
204
+ // Явные расширения: при "type": "module" tsup по умолчанию отдаёт ESM как .js,
205
+ // и ссылки на ./*.mjs в build/package.json оказываются битыми
206
+ outExtension: ({ format }) => ({ js: format === "cjs" ? ".cjs" : ".mjs" }),
207
+ sourcemap: false,
208
+ splitting: false
209
+ }, overrides);
210
+ }
211
+ // Annotate the CommonJS export names for ESM import in node:
212
+ 0 && (module.exports = {
213
+ assertSourceExports,
214
+ copyReadme,
215
+ createTsupConfig,
216
+ defineEntries,
217
+ toBuildExports,
218
+ toTsupEntry,
219
+ updateBuildFiles,
220
+ verifyBuildExports,
221
+ writeBuildPackageJson
222
+ });
package/index.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import type { Options } from 'tsup'
2
+
3
+ /** Декларация точек входа: подпуть exports → файл-исходник в src/. */
4
+ export type Entries = Record<string, string>
5
+
6
+ /** Проверяет и возвращает декларацию точек входа пакета. */
7
+ export function defineEntries(map: Entries): Entries
8
+
9
+ /** entry для tsup: имя артефакта → исходник. */
10
+ export function toTsupEntry(entries: Entries): Record<string, string>
11
+
12
+ /** Падает, если exports исходного package.json разошёлся с декларацией. */
13
+ export function assertSourceExports(entries: Entries, packageJson: Record<string, unknown>): void
14
+
15
+ /** exports для публикуемого package.json (пути внутрь build/). */
16
+ export function toBuildExports(
17
+ entries: Entries,
18
+ options: { extensions: (name: string) => Record<string, string> }
19
+ ): Record<string, Record<string, string>>
20
+
21
+ /** Пишет build/package.json: метаданные, exports по декларации, проверка наличия файлов. */
22
+ export function writeBuildPackageJson(options: {
23
+ entries: Entries
24
+ extensions: (name: string) => Record<string, string>
25
+ main: string
26
+ module: string
27
+ outDir?: string
28
+ }): void
29
+
30
+ /** Досыпает files по фактическому содержимому build/ (вызывать на beforeExit). */
31
+ export function updateBuildFiles(outDir?: string): void
32
+
33
+ /** Падает, если какой-то цели exports нет в build/ (вызывать после сборки типов). */
34
+ export function verifyBuildExports(outDir?: string): void
35
+
36
+ /** Копирует README.mdx рядом с артефактом. */
37
+ export function copyReadme(outDir?: string): void
38
+
39
+ /** Готовый tsup-конфиг публикуемого пакета монорепо. */
40
+ export function createTsupConfig(options: { entries: Entries; overrides?: Options }): Options
package/index.mjs ADDED
@@ -0,0 +1,182 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __spreadValues = (a, b) => {
7
+ for (var prop in b || (b = {}))
8
+ if (__hasOwnProp.call(b, prop))
9
+ __defNormalProp(a, prop, b[prop]);
10
+ if (__getOwnPropSymbols)
11
+ for (var prop of __getOwnPropSymbols(b)) {
12
+ if (__propIsEnum.call(b, prop))
13
+ __defNormalProp(a, prop, b[prop]);
14
+ }
15
+ return a;
16
+ };
17
+ var __async = (__this, __arguments, generator) => {
18
+ return new Promise((resolve, reject) => {
19
+ var fulfilled = (value) => {
20
+ try {
21
+ step(generator.next(value));
22
+ } catch (e) {
23
+ reject(e);
24
+ }
25
+ };
26
+ var rejected = (value) => {
27
+ try {
28
+ step(generator.throw(value));
29
+ } catch (e) {
30
+ reject(e);
31
+ }
32
+ };
33
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
34
+ step((generator = generator.apply(__this, __arguments)).next());
35
+ });
36
+ };
37
+
38
+ // src/index.js
39
+ import fs from "fs";
40
+ import path from "path";
41
+ function defineEntries(map) {
42
+ for (const [subpath, source] of Object.entries(map)) {
43
+ if (!subpath.startsWith(".")) {
44
+ throw new Error(`entries: \u043F\u043E\u0434\u043F\u0443\u0442\u044C \xAB${subpath}\xBB \u0434\u043E\u043B\u0436\u0435\u043D \u043D\u0430\u0447\u0438\u043D\u0430\u0442\u044C\u0441\u044F \u0441 "."`);
45
+ }
46
+ if (!source.startsWith("src/")) {
47
+ throw new Error(`entries: \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A \xAB${source}\xBB \u0434\u043E\u043B\u0436\u0435\u043D \u043B\u0435\u0436\u0430\u0442\u044C \u0432 src/`);
48
+ }
49
+ }
50
+ return map;
51
+ }
52
+ function artifactName(subpath, source) {
53
+ if (subpath === ".") return path.basename(source).replace(/\.[cm]?[jt]sx?$/, "");
54
+ return source.replace(/^src\//, "").replace(/\.[cm]?[jt]sx?$/, "");
55
+ }
56
+ function toTsupEntry(entries) {
57
+ return Object.fromEntries(Object.entries(entries).map(([subpath, source]) => [artifactName(subpath, source), source]));
58
+ }
59
+ function assertSourceExports(entries, packageJson) {
60
+ var _a;
61
+ const declared = new Set(Object.keys(entries));
62
+ const actual = new Set(Object.keys((_a = packageJson.exports) != null ? _a : {}).filter((key) => !key.endsWith(".mdx")));
63
+ const missing = [...declared].filter((key) => !actual.has(key));
64
+ const extra = [...actual].filter((key) => !declared.has(key));
65
+ if (missing.length > 0 || extra.length > 0) {
66
+ throw new Error(
67
+ `package.json exports \u0440\u0430\u0437\u043E\u0448\u0451\u043B\u0441\u044F \u0441 \u0434\u0435\u043A\u043B\u0430\u0440\u0430\u0446\u0438\u0435\u0439 entries:` + (missing.length > 0 ? ` \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 [${missing.join(", ")}]` : "") + (extra.length > 0 ? ` \u043B\u0438\u0448\u043D\u0438\u0435 [${extra.join(", ")}]` : "")
68
+ );
69
+ }
70
+ for (const [subpath, source] of Object.entries(entries)) {
71
+ const entry = packageJson.exports[subpath];
72
+ const declaration = `./${source.replace(/\.[cm]?[jt]sx?$/, ".d.ts")}`;
73
+ const allowed = (condition, value) => value === `./${source}` || condition === "types" && value === declaration;
74
+ const pairs = typeof entry === "string" ? [["default", entry]] : Object.entries(entry);
75
+ const wrong = pairs.filter(([condition, value]) => !allowed(condition, value)).map(([, value]) => value);
76
+ if (wrong.length > 0) {
77
+ throw new Error(
78
+ `package.json exports["${subpath}"] \u0434\u043E\u043B\u0436\u0435\u043D \u0432\u0435\u0441\u0442\u0438 \u043D\u0430 ./${source} (\u0432 \u043C\u043E\u043D\u043E\u0440\u0435\u043F\u043E \u0435\u0434\u0438\u043C \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u0438), \u0430 \u0432\u0435\u0434\u0451\u0442 \u043D\u0430 ${wrong.join(", ")}`
79
+ );
80
+ }
81
+ }
82
+ }
83
+ function toBuildExports(entries, { extensions }) {
84
+ return Object.fromEntries(
85
+ Object.entries(entries).map(([subpath, source]) => {
86
+ const name = artifactName(subpath, source);
87
+ return [subpath, __spreadValues({}, extensions(name))];
88
+ })
89
+ );
90
+ }
91
+ function writeBuildPackageJson({ entries, extensions, main, module: moduleField, outDir = "build" }) {
92
+ const source = JSON.parse(fs.readFileSync("package.json", "utf-8"));
93
+ assertSourceExports(entries, source);
94
+ const DEV_ONLY = /* @__PURE__ */ new Set([
95
+ "devDependencies",
96
+ "scripts",
97
+ "exports",
98
+ "main",
99
+ "module",
100
+ "types",
101
+ "browserslist",
102
+ "files"
103
+ ]);
104
+ const packageJson = Object.fromEntries(Object.entries(source).filter(([field]) => !DEV_ONLY.has(field)));
105
+ packageJson.main = main;
106
+ packageJson.module = moduleField;
107
+ packageJson.exports = toBuildExports(entries, { extensions });
108
+ fs.writeFileSync(path.join(outDir, "package.json"), `${JSON.stringify(packageJson, null, 2)}
109
+ `);
110
+ }
111
+ function verifyBuildExports(outDir = "build") {
112
+ var _a;
113
+ const packageJson = JSON.parse(fs.readFileSync(path.join(outDir, "package.json"), "utf-8"));
114
+ const missing = Object.values((_a = packageJson.exports) != null ? _a : {}).flatMap((entry) => typeof entry === "string" ? [entry] : Object.values(entry)).filter((file) => !fs.existsSync(path.join(outDir, file)));
115
+ if (missing.length > 0) {
116
+ throw new Error(`\u0432 ${outDir}/ \u043D\u0435\u0442 \u0444\u0430\u0439\u043B\u043E\u0432 \u0434\u043B\u044F exports: ${[...new Set(missing)].join(", ")}`);
117
+ }
118
+ }
119
+ function updateBuildFiles(outDir = "build") {
120
+ try {
121
+ const file = path.join(outDir, "package.json");
122
+ const packageJson = JSON.parse(fs.readFileSync(file, "utf-8"));
123
+ packageJson.files = fs.readdirSync(outDir).filter((name) => name !== ".tsbuildinfo");
124
+ fs.writeFileSync(file, `${JSON.stringify(packageJson, null, 2)}
125
+ `);
126
+ } catch (error) {
127
+ console.error("\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C files \u0432 build/package.json:", error);
128
+ }
129
+ }
130
+ function copyReadme(outDir = "build") {
131
+ fs.copyFileSync("README.mdx", path.join(outDir, "README.mdx"));
132
+ }
133
+ function createTsupConfig({ entries, overrides = {} }) {
134
+ const extensions = (name) => ({
135
+ import: `./${name}.mjs`,
136
+ require: `./${name}.cjs`,
137
+ types: `./${name}.d.ts`
138
+ });
139
+ process.on("beforeExit", (code) => {
140
+ if (code !== 0) return;
141
+ updateBuildFiles();
142
+ try {
143
+ verifyBuildExports();
144
+ } catch (error) {
145
+ console.error(String(error instanceof Error ? error.message : error));
146
+ process.exitCode = 1;
147
+ }
148
+ });
149
+ return __spreadValues({
150
+ bundle: true,
151
+ clean: true,
152
+ dts: true,
153
+ entry: toTsupEntry(entries),
154
+ format: ["cjs", "esm"],
155
+ onSuccess: () => __async(null, null, function* () {
156
+ copyReadme();
157
+ writeBuildPackageJson({
158
+ entries,
159
+ extensions,
160
+ main: "./index.cjs",
161
+ module: "./index.mjs"
162
+ });
163
+ }),
164
+ outDir: "build",
165
+ // Явные расширения: при "type": "module" tsup по умолчанию отдаёт ESM как .js,
166
+ // и ссылки на ./*.mjs в build/package.json оказываются битыми
167
+ outExtension: ({ format }) => ({ js: format === "cjs" ? ".cjs" : ".mjs" }),
168
+ sourcemap: false,
169
+ splitting: false
170
+ }, overrides);
171
+ }
172
+ export {
173
+ assertSourceExports,
174
+ copyReadme,
175
+ createTsupConfig,
176
+ defineEntries,
177
+ toBuildExports,
178
+ toTsupEntry,
179
+ updateBuildFiles,
180
+ verifyBuildExports,
181
+ writeBuildPackageJson
182
+ };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@foxford/tsup-config",
3
+ "version": "1.0.0",
4
+ "description": "Общая сборка публикуемых пакетов: декларация точек входа, tsup-конфиг, генерация публикуемого package.json",
5
+ "keywords": [
6
+ "foxford",
7
+ "tsup",
8
+ "build",
9
+ "config"
10
+ ],
11
+ "license": "MIT",
12
+ "author": "Foxford Co",
13
+ "maintainers": [
14
+ {
15
+ "name": "Roman Olin",
16
+ "email": "r.v.olin@foxford.ru",
17
+ "team": "core-frontend"
18
+ }
19
+ ],
20
+ "type": "module",
21
+ "peerDependencies": {
22
+ "tsup": "*"
23
+ },
24
+ "main": "./index.cjs",
25
+ "module": "./index.mjs",
26
+ "exports": {
27
+ ".": {
28
+ "import": "./index.mjs",
29
+ "require": "./index.cjs",
30
+ "types": "./index.d.ts"
31
+ }
32
+ },
33
+ "files": [
34
+ "README.mdx",
35
+ "index.cjs",
36
+ "index.d.ts",
37
+ "index.mjs",
38
+ "package.json"
39
+ ],
40
+ "sha": "fd3591a",
41
+ "scripts": {}
42
+ }