@pezkuwi/dev 0.84.2
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/.skip-deno +0 -0
- package/README.md +547 -0
- package/config/eslint.js +160 -0
- package/config/eslint.rules.js +214 -0
- package/config/prettier.cjs +22 -0
- package/config/rollup.js +113 -0
- package/config/tsconfig.json +32 -0
- package/config/typedoc.cjs +18 -0
- package/package.json +107 -0
- package/scripts/polkadot-ci-ghact-build.mjs +540 -0
- package/scripts/polkadot-ci-ghact-docs.mjs +14 -0
- package/scripts/polkadot-ci-ghpages-force.mjs +43 -0
- package/scripts/polkadot-dev-build-docs.mjs +19 -0
- package/scripts/polkadot-dev-build-ts.mjs +1518 -0
- package/scripts/polkadot-dev-circular.mjs +29 -0
- package/scripts/polkadot-dev-clean-build.mjs +61 -0
- package/scripts/polkadot-dev-contrib.mjs +74 -0
- package/scripts/polkadot-dev-copy-dir.mjs +44 -0
- package/scripts/polkadot-dev-copy-to.mjs +53 -0
- package/scripts/polkadot-dev-deno-map.mjs +35 -0
- package/scripts/polkadot-dev-run-lint.mjs +40 -0
- package/scripts/polkadot-dev-run-node-ts.mjs +9 -0
- package/scripts/polkadot-dev-run-test.mjs +163 -0
- package/scripts/polkadot-dev-version.mjs +143 -0
- package/scripts/polkadot-dev-yarn-only.mjs +11 -0
- package/scripts/polkadot-exec-eslint.mjs +7 -0
- package/scripts/polkadot-exec-ghpages.mjs +11 -0
- package/scripts/polkadot-exec-ghrelease.mjs +7 -0
- package/scripts/polkadot-exec-node-test.mjs +368 -0
- package/scripts/polkadot-exec-rollup.mjs +7 -0
- package/scripts/polkadot-exec-tsc.mjs +7 -0
- package/scripts/polkadot-exec-webpack.mjs +7 -0
- package/scripts/util.mjs +540 -0
- package/tsconfig.build.json +18 -0
- package/tsconfig.config.json +14 -0
- package/tsconfig.scripts.json +14 -0
- package/tsconfig.spec.json +18 -0
|
@@ -0,0 +1,1518 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Copyright 2017-2025 @polkadot/dev authors & contributors
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import JSON5 from 'json5';
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import process from 'node:process';
|
|
9
|
+
import ts from 'typescript';
|
|
10
|
+
|
|
11
|
+
import { copyDirSync, copyFileSync, DENO_EXT_PRE, DENO_LND_PRE, DENO_POL_PRE, engineVersionCmp, execPm, exitFatal, exitFatalEngine, logBin, mkdirpSync, PATHS_BUILD, readdirSync, rimrafSync } from './util.mjs';
|
|
12
|
+
|
|
13
|
+
/** @typedef {'babel' | 'esbuild' | 'swc' | 'tsc'} CompileType */
|
|
14
|
+
/** @typedef {{ bin?: Record<string, string>; browser?: string; bugs?: string; deno?: string; denoDependencies?: Record<string, string>; dependencies?: Record<string, string>; devDependencies?: Record<string, string>; electron?: string; engines?: { node?: string }; exports?: Record<string, unknown>; license?: string; homepage?: string; main?: string; module?: string; name?: string; optionalDependencies?: Record<string, string>; peerDependencies?: Record<string, string>; repository?: { directory?: string; type: 'git'; url: string; }; 'react-native'?: string; resolutions?: Record<string, string>; sideEffects?: boolean | string[]; scripts?: Record<string, string>; type?: 'module' | 'commonjs'; types?: string; version?: string; }} PkgJson */
|
|
15
|
+
|
|
16
|
+
const WP_CONFIGS = ['js', 'cjs'].map((e) => `webpack.config.${e}`);
|
|
17
|
+
const RL_CONFIGS = ['js', 'mjs', 'cjs'].map((e) => `rollup.config.${e}`);
|
|
18
|
+
|
|
19
|
+
logBin('polkadot-dev-build-ts');
|
|
20
|
+
|
|
21
|
+
exitFatalEngine();
|
|
22
|
+
|
|
23
|
+
// We need at least es2020 for dynamic imports. Settings here needs to align with
|
|
24
|
+
// those in packages/dev-ts/src/loader & packages/dev/config/tsconfig
|
|
25
|
+
//
|
|
26
|
+
// Node 14 === es2020 (w/ dynamic imports)
|
|
27
|
+
// Node 16 === es2021
|
|
28
|
+
// Node 18/20 === es2022 (w/ private fields)
|
|
29
|
+
//
|
|
30
|
+
// https://github.com/tsconfig/bases/tree/main/bases
|
|
31
|
+
const TARGET_TSES = ts.ScriptTarget.ES2022;
|
|
32
|
+
const TARGET_NODE = '>=18';
|
|
33
|
+
|
|
34
|
+
const IGNORE_IMPORTS = [
|
|
35
|
+
// node (new-style)
|
|
36
|
+
...['assert', 'child_process', 'crypto', 'fs', 'module', 'os', 'path', 'process', 'readline', 'test', 'url', 'util'].map((m) => `node:${m}`),
|
|
37
|
+
// other
|
|
38
|
+
'@testing-library/react',
|
|
39
|
+
'react', 'react-native', 'styled-components'
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* webpack build
|
|
44
|
+
*/
|
|
45
|
+
function buildWebpack () {
|
|
46
|
+
const config = WP_CONFIGS.find((c) => fs.existsSync(path.join(process.cwd(), c)));
|
|
47
|
+
|
|
48
|
+
execPm(`polkadot-exec-webpack --config ${config} --mode production`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* compile via tsc, either via supplied config or default
|
|
53
|
+
*
|
|
54
|
+
* @param {CompileType} compileType
|
|
55
|
+
* @param {'cjs' | 'esm'} type
|
|
56
|
+
*/
|
|
57
|
+
async function compileJs (compileType, type) {
|
|
58
|
+
const buildDir = path.join(process.cwd(), `build-${compileType}-${type}`);
|
|
59
|
+
|
|
60
|
+
mkdirpSync(buildDir);
|
|
61
|
+
|
|
62
|
+
const files = readdirSync('src', ['.ts', '.tsx']).filter((f) =>
|
|
63
|
+
!['.d.ts', '.manual.ts', '.spec.ts', '.spec.tsx', '.test.ts', '.test.tsx', 'mod.ts'].some((e) =>
|
|
64
|
+
f.endsWith(e)
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
if (compileType === 'tsc') {
|
|
69
|
+
await timeIt(`Successfully compiled ${compileType} ${type}`, () => {
|
|
70
|
+
files.forEach((filename) => {
|
|
71
|
+
// split src prefix, replace .ts extension with .js
|
|
72
|
+
const outFile = path.join(buildDir, filename.split(/[\\/]/).slice(1).join('/').replace(/\.tsx?$/, '.js'));
|
|
73
|
+
|
|
74
|
+
const source = fs.readFileSync(filename, 'utf-8');
|
|
75
|
+
|
|
76
|
+
// compile with the options aligning with our tsconfig
|
|
77
|
+
const { outputText } = ts.transpileModule(source, {
|
|
78
|
+
compilerOptions: {
|
|
79
|
+
esModuleInterop: true,
|
|
80
|
+
importHelpers: true,
|
|
81
|
+
jsx: filename.endsWith('.tsx')
|
|
82
|
+
? ts.JsxEmit.ReactJSX
|
|
83
|
+
: undefined,
|
|
84
|
+
module: type === 'cjs'
|
|
85
|
+
? ts.ModuleKind.CommonJS
|
|
86
|
+
: ts.ModuleKind.ESNext,
|
|
87
|
+
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
88
|
+
target: TARGET_TSES
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
mkdirpSync(path.dirname(outFile));
|
|
93
|
+
fs.writeFileSync(outFile, outputText);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
} else {
|
|
97
|
+
throw new Error(`Unknown --compiler ${compileType}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Writes a package.json file
|
|
103
|
+
*
|
|
104
|
+
* @param {string} path
|
|
105
|
+
* @param {PkgJson} json
|
|
106
|
+
*/
|
|
107
|
+
function witeJson (path, json) {
|
|
108
|
+
fs.writeFileSync(path, `${JSON.stringify(json, null, 2)}\n`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Adjust all imports to have .js extensions
|
|
113
|
+
*
|
|
114
|
+
* @param {string} _pkgCwd
|
|
115
|
+
* @param {PkgJson} _pkgJson
|
|
116
|
+
* @param {string} dir
|
|
117
|
+
* @param {string} f
|
|
118
|
+
* @param {boolean} [_isDeclare]
|
|
119
|
+
* @returns {string | null}
|
|
120
|
+
*/
|
|
121
|
+
function adjustJsPath (_pkgCwd, _pkgJson, dir, f, _isDeclare) {
|
|
122
|
+
if (f.startsWith('.')) {
|
|
123
|
+
if (f.endsWith('.js') || f.endsWith('.json')) {
|
|
124
|
+
// ignore, these are already fully-specified
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const dirPath = path.join(process.cwd(), dir, f);
|
|
129
|
+
const jsFile = `${f}.js`;
|
|
130
|
+
const jsPath = path.join(process.cwd(), dir, jsFile);
|
|
131
|
+
|
|
132
|
+
if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
|
133
|
+
// this is a directory, append index.js
|
|
134
|
+
return `${f}/index.js`;
|
|
135
|
+
} else if (fs.existsSync(jsPath)) {
|
|
136
|
+
// local source file
|
|
137
|
+
return jsFile;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// do not adjust
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Adjust all @polkadot imports to have .ts extensions (for Deno)
|
|
147
|
+
*
|
|
148
|
+
* @param {string} pkgCwd
|
|
149
|
+
* @param {PkgJson} pkgJson
|
|
150
|
+
* @param {string} dir
|
|
151
|
+
* @param {string} f
|
|
152
|
+
* @param {boolean} [isDeclare]
|
|
153
|
+
* @returns {string | null}
|
|
154
|
+
*/
|
|
155
|
+
function adjustDenoPath (pkgCwd, pkgJson, dir, f, isDeclare) {
|
|
156
|
+
if (f.startsWith('@polkadot')) {
|
|
157
|
+
const parts = f.split('/');
|
|
158
|
+
const thisPkg = parts.slice(0, 2).join('/');
|
|
159
|
+
const subPath = parts.slice(2).join('/');
|
|
160
|
+
const pjsPath = `${DENO_POL_PRE}/${thisPkg.replace('@polkadot/', '')}`;
|
|
161
|
+
|
|
162
|
+
if (subPath.includes("' assert { type:")) {
|
|
163
|
+
// these are for type asserts, we keep the assert
|
|
164
|
+
return `${pjsPath}/${subPath}`;
|
|
165
|
+
} else if (parts.length === 2) {
|
|
166
|
+
// if we only have 2 parts, we add deno/mod.ts
|
|
167
|
+
return `${pjsPath}/mod.ts`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// first we check in packages/* to see if we have this one
|
|
171
|
+
const pkgPath = path.join(pkgCwd, '..', parts[1]);
|
|
172
|
+
|
|
173
|
+
if (fs.existsSync(pkgPath)) {
|
|
174
|
+
// aha, this is a package in the same repo, search src
|
|
175
|
+
const checkPath = path.join(pkgPath, 'src', subPath);
|
|
176
|
+
|
|
177
|
+
if (fs.existsSync(checkPath)) {
|
|
178
|
+
if (fs.statSync(checkPath).isDirectory()) {
|
|
179
|
+
// this is a directory, append index.ts
|
|
180
|
+
return `${pjsPath}/${subPath}/index.ts`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// as-is, the path exists
|
|
184
|
+
return `${DENO_POL_PRE}/${subPath}`;
|
|
185
|
+
} else if (!fs.existsSync(`${checkPath}.ts`)) {
|
|
186
|
+
exitFatal(`Unable to find ${checkPath}.ts`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return `${pjsPath}/${subPath}.ts`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// now we check node_modules
|
|
193
|
+
const nodePath = path.join(pkgCwd, '../../node_modules', thisPkg);
|
|
194
|
+
|
|
195
|
+
if (fs.existsSync(nodePath)) {
|
|
196
|
+
// aha, this is a package in the same repo
|
|
197
|
+
const checkPath = path.join(nodePath, subPath);
|
|
198
|
+
|
|
199
|
+
if (fs.existsSync(checkPath)) {
|
|
200
|
+
if (fs.statSync(checkPath).isDirectory()) {
|
|
201
|
+
// this is a directory, append index.ts
|
|
202
|
+
return `${pjsPath}/${subPath}/index.ts`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// as-is, it exists
|
|
206
|
+
return `${pjsPath}/${subPath}`;
|
|
207
|
+
} else if (!fs.existsSync(`${checkPath}.js`)) {
|
|
208
|
+
exitFatal(`Unable to find ${checkPath}.js`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return `${pjsPath}/${subPath}.ts`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// we don't know what to do here :(
|
|
215
|
+
exitFatal(`Unable to find ${f}`);
|
|
216
|
+
} else if (f.startsWith('.')) {
|
|
217
|
+
if (f.endsWith('.ts') || f.endsWith('.tsx') || f.endsWith('.json')) {
|
|
218
|
+
// ignore, these are already fully-specified
|
|
219
|
+
return null;
|
|
220
|
+
} else if (f.endsWith('.js')) {
|
|
221
|
+
if (f.includes('./cjs/')) {
|
|
222
|
+
// import from cjs/, change it to deno
|
|
223
|
+
return f.replace('/cjs/', '/deno/');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const tsFile = f.replace('.js', '.ts');
|
|
227
|
+
const tsxFile = f.replace('.js', '.tsx');
|
|
228
|
+
|
|
229
|
+
if (fs.existsSync(path.join(process.cwd(), dir, tsFile))) {
|
|
230
|
+
// we have a .ts file for this one, rename
|
|
231
|
+
return tsFile;
|
|
232
|
+
} else if (fs.existsSync(path.join(process.cwd(), dir, tsxFile))) {
|
|
233
|
+
// we have a .tsx file for this one, rename
|
|
234
|
+
return tsxFile;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// leave the other paths as-is
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const dirPath = path.join(process.cwd(), dir, f);
|
|
242
|
+
const tsFile = `${f}.ts`;
|
|
243
|
+
const tsxFile = `${f}.tsx`;
|
|
244
|
+
const tsPath = path.join(process.cwd(), dir, tsFile);
|
|
245
|
+
const tsxPath = path.join(process.cwd(), dir, tsxFile);
|
|
246
|
+
|
|
247
|
+
if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
|
248
|
+
// this is a directory, append index.ts
|
|
249
|
+
return fs.existsSync(path.join(dirPath, 'index.tsx'))
|
|
250
|
+
? `${f}/index.tsx`
|
|
251
|
+
: `${f}/index.ts`;
|
|
252
|
+
} else if (fs.existsSync(tsPath)) {
|
|
253
|
+
// local source file
|
|
254
|
+
return tsFile;
|
|
255
|
+
} else if (fs.existsSync(tsxPath)) {
|
|
256
|
+
// local source file
|
|
257
|
+
return tsxFile;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// fully-specified file, keep it as-is (linting picks up invalids)
|
|
261
|
+
return null;
|
|
262
|
+
} else if (f.startsWith('node:')) {
|
|
263
|
+
// Since Deno 1.28 the node: specifiers is supported out-of-the-box
|
|
264
|
+
// so we just return and use these as-is
|
|
265
|
+
return f;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const depParts = f.split('/');
|
|
269
|
+
const depNameLen = f.startsWith('@')
|
|
270
|
+
? 2
|
|
271
|
+
: 1;
|
|
272
|
+
const depName = depParts.slice(0, depNameLen).join('/');
|
|
273
|
+
let depPath = depParts.length > depNameLen
|
|
274
|
+
? '/' + depParts.slice(depNameLen).join('/')
|
|
275
|
+
: null;
|
|
276
|
+
|
|
277
|
+
const depVersion = pkgJson.dependencies?.[depName] && pkgJson.dependencies[depName] !== '*'
|
|
278
|
+
? pkgJson.dependencies[depName]
|
|
279
|
+
: pkgJson.peerDependencies?.[depName]
|
|
280
|
+
? pkgJson.peerDependencies[depName]
|
|
281
|
+
: pkgJson.optionalDependencies?.[depName]
|
|
282
|
+
? pkgJson.optionalDependencies[depName]
|
|
283
|
+
: pkgJson.devDependencies
|
|
284
|
+
? pkgJson.devDependencies[depName]
|
|
285
|
+
: null;
|
|
286
|
+
let version = null;
|
|
287
|
+
|
|
288
|
+
if (depVersion) {
|
|
289
|
+
version = depVersion.replace('^', '').replace('~', '');
|
|
290
|
+
} else if (isDeclare) {
|
|
291
|
+
return f;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
let [denoDep, ...denoPath] = pkgJson.denoDependencies?.[depName]
|
|
295
|
+
? pkgJson.denoDependencies[depName].split('/')
|
|
296
|
+
: [null];
|
|
297
|
+
|
|
298
|
+
if (!denoDep) {
|
|
299
|
+
if (IGNORE_IMPORTS.includes(depName)) {
|
|
300
|
+
// ignore, we handle this below
|
|
301
|
+
} else if (depVersion) {
|
|
302
|
+
// Here we use the npm: specifier (available since Deno 1.28)
|
|
303
|
+
//
|
|
304
|
+
// FIXME We cannot enable this until there is support for git deps
|
|
305
|
+
// https://github.com/denoland/deno/issues/18557
|
|
306
|
+
// This is used by @zondax/ledger-substrate
|
|
307
|
+
// return `npm:${depName}@${depVersion}${depPath || ''}`;
|
|
308
|
+
} else {
|
|
309
|
+
exitFatal(`Unknown Deno versioned package '${f}' inside ${pkgJson.name}`);
|
|
310
|
+
}
|
|
311
|
+
} else if (denoDep === 'x') {
|
|
312
|
+
denoDep = `x/${denoPath[0]}`;
|
|
313
|
+
denoPath = denoPath.slice(1);
|
|
314
|
+
|
|
315
|
+
if (!denoDep.includes('@')) {
|
|
316
|
+
denoDep = `${denoDep}@${version}`;
|
|
317
|
+
} else if (denoDep.includes('{{VERSION}}')) {
|
|
318
|
+
if (!version) {
|
|
319
|
+
throw new Error(`Unable to extract version for deno.land/${denoDep}`);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
denoDep = denoDep.replace('{{VERSION}}', version);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Add JS specifier if required
|
|
327
|
+
if (depPath) {
|
|
328
|
+
depPath += '.js';
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return denoDep
|
|
332
|
+
? `${DENO_LND_PRE}/${denoDep}${depPath || `/${denoPath.length ? denoPath.join('/') : 'mod.ts'}`}`
|
|
333
|
+
: `${DENO_EXT_PRE}/${depName}${version ? `@${version}` : ''}${depPath || ''}`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @param {string} dir
|
|
338
|
+
* @param {string} pkgCwd
|
|
339
|
+
* @param {PkgJson} pkgJson
|
|
340
|
+
* @param {(pkgCwd: string, pkgJson: PkgJson, f: string, dir: string, isDeclare?: boolean) => string | null} replacer
|
|
341
|
+
* @returns {void}
|
|
342
|
+
*/
|
|
343
|
+
function rewriteImports (dir, pkgCwd, pkgJson, replacer) {
|
|
344
|
+
if (!fs.existsSync(dir)) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
fs
|
|
349
|
+
.readdirSync(dir)
|
|
350
|
+
.forEach((p) => {
|
|
351
|
+
const thisPath = path.join(process.cwd(), dir, p);
|
|
352
|
+
|
|
353
|
+
if (fs.statSync(thisPath).isDirectory()) {
|
|
354
|
+
rewriteImports(`${dir}/${p}`, pkgCwd, pkgJson, replacer);
|
|
355
|
+
} else if (thisPath.endsWith('.spec.js') || thisPath.endsWith('.spec.ts')) {
|
|
356
|
+
// we leave specs as-is
|
|
357
|
+
} else if (thisPath.endsWith('.js') || thisPath.endsWith('.ts') || thisPath.endsWith('.tsx') || thisPath.endsWith('.md')) {
|
|
358
|
+
fs.writeFileSync(
|
|
359
|
+
thisPath,
|
|
360
|
+
fs
|
|
361
|
+
.readFileSync(thisPath, 'utf8')
|
|
362
|
+
.split('\n')
|
|
363
|
+
.filter((line) => !line.startsWith('//'))
|
|
364
|
+
.map((line) =>
|
|
365
|
+
line
|
|
366
|
+
// handle import/export
|
|
367
|
+
.replace(/(import|export) (.*) from '(.*)'/g, (o, t, a, f) => {
|
|
368
|
+
const adjusted = replacer(pkgCwd, pkgJson, dir, f);
|
|
369
|
+
|
|
370
|
+
return adjusted
|
|
371
|
+
? `${t} ${a} from '${adjusted}'`
|
|
372
|
+
: o;
|
|
373
|
+
})
|
|
374
|
+
// handle augmented inputs
|
|
375
|
+
.replace(/(import|declare module) '(.*)'/g, (o, t, f) => {
|
|
376
|
+
const adjusted = replacer(pkgCwd, pkgJson, dir, f, t !== 'import');
|
|
377
|
+
|
|
378
|
+
return adjusted
|
|
379
|
+
? `${t} '${adjusted}'`
|
|
380
|
+
: o;
|
|
381
|
+
})
|
|
382
|
+
// handle dynamic imports
|
|
383
|
+
.replace(/( import|^import)\('(.*)'\)/g, (o, t, f) => {
|
|
384
|
+
const adjusted = replacer(pkgCwd, pkgJson, dir, f);
|
|
385
|
+
|
|
386
|
+
return adjusted
|
|
387
|
+
? `${t}('${adjusted}')`
|
|
388
|
+
: o;
|
|
389
|
+
})
|
|
390
|
+
)
|
|
391
|
+
.join('\n')
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Adds the `import { Buffer } from 'node:buffer';` to files that use `Buffer`.
|
|
399
|
+
*
|
|
400
|
+
* @param {string} dir - Directory to traverse.
|
|
401
|
+
* @param {string} pkgCwd - Current working directory of the package.
|
|
402
|
+
*/
|
|
403
|
+
function addBufferImportForDeno (dir, pkgCwd) {
|
|
404
|
+
if (!fs.existsSync(dir)) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
fs.readdirSync(dir).forEach((fileName) => {
|
|
409
|
+
const filePath = path.join(dir, fileName);
|
|
410
|
+
|
|
411
|
+
if (fs.statSync(filePath).isDirectory()) {
|
|
412
|
+
// Recursively handle subdirectories
|
|
413
|
+
addBufferImportForDeno(filePath, pkgCwd);
|
|
414
|
+
} else if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
|
|
415
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
416
|
+
|
|
417
|
+
if (content.includes('Buffer') && !content.includes("import { Buffer } from 'node:buffer';")) {
|
|
418
|
+
const updatedContent = `import { Buffer } from 'node:buffer';\n\n${content}`;
|
|
419
|
+
|
|
420
|
+
fs.writeFileSync(filePath, updatedContent, 'utf-8');
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function buildDeno () {
|
|
427
|
+
const pkgCwd = process.cwd();
|
|
428
|
+
|
|
429
|
+
if (!fs.existsSync(path.join(pkgCwd, 'src/mod.ts'))) {
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// copy the sources as-is
|
|
434
|
+
copyDirSync('src', 'build-deno', [], ['.spec.ts', '.spec.tsx', '.test.ts', '.test.tsx']);
|
|
435
|
+
copyFileSync('README.md', 'build-deno');
|
|
436
|
+
|
|
437
|
+
// remove unneeded directories
|
|
438
|
+
rimrafSync('build-deno/cjs');
|
|
439
|
+
|
|
440
|
+
addBufferImportForDeno('build-deno', pkgCwd);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* @param {string} [value]
|
|
445
|
+
* @returns {string}
|
|
446
|
+
*/
|
|
447
|
+
function relativePath (value) {
|
|
448
|
+
return `${value && value.startsWith('.') ? value : './'}${value}`.replace(/\/\//g, '/');
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* creates an entry for the cjs/esm name
|
|
453
|
+
*
|
|
454
|
+
* @param {string} rootDir
|
|
455
|
+
* @param {string} [jsPath]
|
|
456
|
+
* @param {boolean} [noTypes]
|
|
457
|
+
* @returns {[string, Record<string, unknown> | string]}
|
|
458
|
+
*/
|
|
459
|
+
function createMapEntry (rootDir, jsPath = '', noTypes) {
|
|
460
|
+
jsPath = relativePath(jsPath);
|
|
461
|
+
|
|
462
|
+
const typesPath = jsPath.replace('.js', '.d.ts');
|
|
463
|
+
const cjsPath = jsPath.replace('./', './cjs/');
|
|
464
|
+
const cjsTypesPath = typesPath.replace('./', './cjs/');
|
|
465
|
+
const hasCjs = fs.existsSync(path.join(rootDir, cjsPath));
|
|
466
|
+
const hasTypesCjs = fs.existsSync(path.join(rootDir, cjsTypesPath));
|
|
467
|
+
const hasTypes = !hasTypesCjs && !noTypes && jsPath.endsWith('.js') && fs.existsSync(path.join(rootDir, typesPath));
|
|
468
|
+
const field = hasCjs
|
|
469
|
+
? {
|
|
470
|
+
// As per TS, the types key needs to be first
|
|
471
|
+
...(
|
|
472
|
+
hasTypes
|
|
473
|
+
? { types: typesPath }
|
|
474
|
+
: {}
|
|
475
|
+
),
|
|
476
|
+
// bundler-specific path, eg. webpack & rollup
|
|
477
|
+
...(
|
|
478
|
+
jsPath.endsWith('.js')
|
|
479
|
+
? hasTypesCjs
|
|
480
|
+
// eslint-disable-next-line sort-keys
|
|
481
|
+
? { module: { types: typesPath, default: jsPath } }
|
|
482
|
+
: { module: jsPath }
|
|
483
|
+
: {}
|
|
484
|
+
),
|
|
485
|
+
require: hasTypesCjs
|
|
486
|
+
// eslint-disable-next-line sort-keys
|
|
487
|
+
? { types: cjsTypesPath, default: cjsPath }
|
|
488
|
+
: cjsPath,
|
|
489
|
+
// eslint-disable-next-line sort-keys
|
|
490
|
+
default: hasTypesCjs
|
|
491
|
+
// eslint-disable-next-line sort-keys
|
|
492
|
+
? { types: typesPath, default: jsPath }
|
|
493
|
+
: jsPath
|
|
494
|
+
}
|
|
495
|
+
: hasTypes
|
|
496
|
+
? {
|
|
497
|
+
types: typesPath,
|
|
498
|
+
// eslint-disable-next-line sort-keys
|
|
499
|
+
default: jsPath
|
|
500
|
+
}
|
|
501
|
+
: jsPath;
|
|
502
|
+
|
|
503
|
+
if (jsPath.endsWith('.js')) {
|
|
504
|
+
if (jsPath.endsWith('/index.js')) {
|
|
505
|
+
return [jsPath.replace('/index.js', ''), field];
|
|
506
|
+
} else {
|
|
507
|
+
return [jsPath.replace('.js', ''), field];
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return [jsPath, field];
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* copies all output files into the build directory
|
|
516
|
+
*
|
|
517
|
+
* @param {CompileType} compileType
|
|
518
|
+
* @param {string} dir
|
|
519
|
+
*/
|
|
520
|
+
function copyBuildFiles (compileType, dir) {
|
|
521
|
+
mkdirpSync('build/cjs');
|
|
522
|
+
|
|
523
|
+
// copy package info stuff
|
|
524
|
+
copyFileSync(['package.json', 'README.md'], 'build');
|
|
525
|
+
copyFileSync('../../LICENSE', 'build');
|
|
526
|
+
|
|
527
|
+
// copy interesting files
|
|
528
|
+
copyDirSync('src', 'build', ['.patch', '.js', '.cjs', '.mjs', '.json', '.d.ts', '.d.cts', '.d.mts', '.css', '.gif', '.hbs', '.md', '.jpg', '.png', '.rs', '.svg']);
|
|
529
|
+
|
|
530
|
+
// copy all *.d.ts files
|
|
531
|
+
const dtsPaths = ['build-tsc', path.join('../../build', dir, 'src'), path.join('../../build/packages', dir, 'src')];
|
|
532
|
+
|
|
533
|
+
copyDirSync(dtsPaths, 'build', ['.d.ts']);
|
|
534
|
+
copyDirSync(dtsPaths, 'build/cjs', ['.d.ts']);
|
|
535
|
+
|
|
536
|
+
// copy all from build-{babel|swc|tsc|...}-esm to build
|
|
537
|
+
copyDirSync(`build-${compileType}-esm`, 'build');
|
|
538
|
+
|
|
539
|
+
// copy from build-{babel|swc|tsc|...}-cjs to build/cjs (js-only)
|
|
540
|
+
copyDirSync(`build-${compileType}-cjs`, 'build/cjs', ['.js']);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* remove all extra files that were generated as part of the build
|
|
545
|
+
*
|
|
546
|
+
* @param {string} [extra]
|
|
547
|
+
* @param {string[][]} [invalids]
|
|
548
|
+
*/
|
|
549
|
+
function deleteBuildFiles (extra = '', invalids) {
|
|
550
|
+
const isTopLevel = !invalids;
|
|
551
|
+
|
|
552
|
+
invalids ??= [];
|
|
553
|
+
|
|
554
|
+
const buildDir = 'build';
|
|
555
|
+
const currDir = extra
|
|
556
|
+
? path.join('build', extra)
|
|
557
|
+
: buildDir;
|
|
558
|
+
const allFiles = fs
|
|
559
|
+
.readdirSync(currDir)
|
|
560
|
+
.map((jsName) => {
|
|
561
|
+
const jsPath = `${extra}/${jsName}`;
|
|
562
|
+
const fullPathEsm = path.join(buildDir, jsPath);
|
|
563
|
+
|
|
564
|
+
return [jsName, jsPath, fullPathEsm];
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
// We want the build config tweaked to not allow these, so error-out
|
|
568
|
+
// when they are found (it indicates a config failure)
|
|
569
|
+
invalids.push(...allFiles.filter(([jsName, jsPath]) =>
|
|
570
|
+
// no tests
|
|
571
|
+
(
|
|
572
|
+
['.manual.', '.spec.', '.test.'].some((t) => jsName.includes(t)) &&
|
|
573
|
+
// we explicitly exclude test paths, just treat as artifacts
|
|
574
|
+
!jsPath.includes('/test/')
|
|
575
|
+
) ||
|
|
576
|
+
// no deno mod.ts compiles
|
|
577
|
+
['mod.js', 'mod.d.ts', 'mod.ts'].some((e) => jsName === e)
|
|
578
|
+
));
|
|
579
|
+
|
|
580
|
+
allFiles.forEach(([jsName, jsPath, fullPathEsm]) => {
|
|
581
|
+
const toDelete = (
|
|
582
|
+
// no test paths
|
|
583
|
+
jsPath.includes('/test/') ||
|
|
584
|
+
// no rust files
|
|
585
|
+
['.rs'].some((e) => jsName.endsWith(e)) ||
|
|
586
|
+
// no tests
|
|
587
|
+
['.manual.', '.spec.', '.test.'].some((t) => jsName.includes(t)) ||
|
|
588
|
+
// no .d.ts compiled outputs
|
|
589
|
+
['.d.js', '.d.cjs', '.d.mjs'].some((e) => jsName.endsWith(e)) ||
|
|
590
|
+
// no deno mod.ts compiles
|
|
591
|
+
['mod.js', 'mod.d.ts', 'mod.ts'].some((e) => jsName === e) ||
|
|
592
|
+
(
|
|
593
|
+
// .d.ts without .js as an output
|
|
594
|
+
jsName.endsWith('.d.ts') &&
|
|
595
|
+
!['.js', '.cjs', '.mjs'].some((e) =>
|
|
596
|
+
fs.existsSync(path.join(buildDir, jsPath.replace('.d.ts', e)))
|
|
597
|
+
)
|
|
598
|
+
)
|
|
599
|
+
);
|
|
600
|
+
|
|
601
|
+
if (fs.statSync(fullPathEsm).isDirectory()) {
|
|
602
|
+
deleteBuildFiles(jsPath, invalids);
|
|
603
|
+
|
|
604
|
+
PATHS_BUILD.forEach((b) => {
|
|
605
|
+
// remove all empty directories
|
|
606
|
+
const otherPath = path.join(`${buildDir}${b}`, jsPath);
|
|
607
|
+
|
|
608
|
+
if (fs.existsSync(otherPath) && fs.readdirSync(otherPath).length === 0) {
|
|
609
|
+
rimrafSync(otherPath);
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
} else if (toDelete) {
|
|
613
|
+
PATHS_BUILD.forEach((b) => {
|
|
614
|
+
// check in the other build outputs and remove
|
|
615
|
+
// (for deno we also want the spec copies)
|
|
616
|
+
const otherPath = path.join(`${buildDir}${b}`, jsPath);
|
|
617
|
+
const otherTs = otherPath.replace(/.spec.js$/, '.spec.ts');
|
|
618
|
+
|
|
619
|
+
[otherPath, otherTs].forEach((f) => rimrafSync(f));
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
}, []);
|
|
623
|
+
|
|
624
|
+
if (isTopLevel && invalids.length) {
|
|
625
|
+
throw new Error(`Invalid build outputs found in ${process.cwd()}: ${invalids.map(([,, p]) => p).join(', ')} (These should be excluded via a noEmit option in the project config)`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* find the names of all the files in a certain directory
|
|
631
|
+
*
|
|
632
|
+
* @param {string} buildDir
|
|
633
|
+
* @param {string} [extra]
|
|
634
|
+
* @param {string[]} [exclude]
|
|
635
|
+
* @returns {[string, Record<String, unknown> | string][]}
|
|
636
|
+
*/
|
|
637
|
+
function findFiles (buildDir, extra = '', exclude = []) {
|
|
638
|
+
const currDir = extra
|
|
639
|
+
? path.join(buildDir, extra)
|
|
640
|
+
: buildDir;
|
|
641
|
+
|
|
642
|
+
return fs
|
|
643
|
+
.readdirSync(currDir)
|
|
644
|
+
.filter((f) => !exclude.includes(f))
|
|
645
|
+
.reduce((/** @type {[string, Record<String, unknown> | string][]} */ all, jsName) => {
|
|
646
|
+
const jsPath = `${extra}/${jsName}`;
|
|
647
|
+
const fullPathEsm = path.join(buildDir, jsPath);
|
|
648
|
+
|
|
649
|
+
if (fs.statSync(fullPathEsm).isDirectory()) {
|
|
650
|
+
findFiles(buildDir, jsPath).forEach((e) => all.push(e));
|
|
651
|
+
} else {
|
|
652
|
+
// this is not mapped to a compiled .js file (where we have dual esm/cjs mappings)
|
|
653
|
+
all.push(createMapEntry(buildDir, jsPath));
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return all;
|
|
657
|
+
}, []);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Tweak any CJS imports to import from the actual cjs path
|
|
662
|
+
*/
|
|
663
|
+
function tweakCjsPaths () {
|
|
664
|
+
readdirSync('build/cjs', ['.js']).forEach((thisPath) => {
|
|
665
|
+
fs.writeFileSync(
|
|
666
|
+
thisPath,
|
|
667
|
+
fs
|
|
668
|
+
.readFileSync(thisPath, 'utf8')
|
|
669
|
+
// This is actually problematic - while we don't use non-js imports (mostly),
|
|
670
|
+
// this would also match those, which creates issues. For the most part we only
|
|
671
|
+
// actually should only care about packageInfo, so add this one explicitly. If we
|
|
672
|
+
// do use path-imports for others, rather adjust them at that specific point
|
|
673
|
+
// .replace(
|
|
674
|
+
// /require\("@polkadot\/([a-z-]*)\/(.*)"\)/g,
|
|
675
|
+
// 'require("@polkadot/$1/cjs/$2")'
|
|
676
|
+
// )
|
|
677
|
+
.replace(
|
|
678
|
+
/require\("@polkadot\/([a-z-]*)\/packageInfo"\)/g,
|
|
679
|
+
'require("@polkadot/$1/cjs/packageInfo")'
|
|
680
|
+
)
|
|
681
|
+
);
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Adjusts the packageInfo.js files for the target output
|
|
687
|
+
*
|
|
688
|
+
* @param {CompileType} compileType
|
|
689
|
+
*/
|
|
690
|
+
function tweakPackageInfo (compileType) {
|
|
691
|
+
// Hack around some bundler issues, in this case Vite which has import.meta.url
|
|
692
|
+
// as undefined in production contexts (and subsequently makes URL fail)
|
|
693
|
+
// See https://github.com/vitejs/vite/issues/5558
|
|
694
|
+
const esmPathname = 'new URL(import.meta.url).pathname';
|
|
695
|
+
const esmDirname = `(import.meta && import.meta.url) ? ${esmPathname}.substring(0, ${esmPathname}.lastIndexOf('/') + 1) : 'auto'`;
|
|
696
|
+
const cjsDirname = "typeof __dirname === 'string' ? __dirname : 'auto'";
|
|
697
|
+
|
|
698
|
+
['esm', 'cjs'].forEach((jsType) => {
|
|
699
|
+
const infoFile = `build-${compileType}-${jsType}/packageInfo.js`;
|
|
700
|
+
|
|
701
|
+
fs.writeFileSync(
|
|
702
|
+
infoFile,
|
|
703
|
+
fs
|
|
704
|
+
.readFileSync(infoFile, 'utf8')
|
|
705
|
+
.replace(
|
|
706
|
+
"type: 'auto'",
|
|
707
|
+
`type: '${jsType}'`
|
|
708
|
+
)
|
|
709
|
+
.replace(
|
|
710
|
+
"path: 'auto'",
|
|
711
|
+
`path: ${jsType === 'cjs' ? cjsDirname : esmDirname}`
|
|
712
|
+
)
|
|
713
|
+
);
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
const denoFile = path.join('build-deno', 'packageInfo.ts');
|
|
717
|
+
|
|
718
|
+
// Not all packages are built for deno (if no mod.ts, don't build)
|
|
719
|
+
if (fs.existsSync(denoFile)) {
|
|
720
|
+
fs.writeFileSync(
|
|
721
|
+
denoFile,
|
|
722
|
+
fs
|
|
723
|
+
.readFileSync(denoFile, 'utf8')
|
|
724
|
+
.replace(
|
|
725
|
+
"type: 'auto'",
|
|
726
|
+
"type: 'deno'"
|
|
727
|
+
)
|
|
728
|
+
.replace(
|
|
729
|
+
"path: 'auto'",
|
|
730
|
+
`path: ${esmPathname}`
|
|
731
|
+
)
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* Adjusts the order of fiels in the package.json
|
|
738
|
+
*
|
|
739
|
+
* @param {Record<string, unknown>} pkgJson
|
|
740
|
+
* @param {string[]} fields
|
|
741
|
+
*/
|
|
742
|
+
function moveFields (pkgJson, fields) {
|
|
743
|
+
fields.forEach((k) => {
|
|
744
|
+
if (typeof pkgJson[k] !== 'undefined') {
|
|
745
|
+
const value = pkgJson[k];
|
|
746
|
+
|
|
747
|
+
delete pkgJson[k];
|
|
748
|
+
|
|
749
|
+
pkgJson[k] = value;
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* iterate through all the files that have been built, creating an exports map
|
|
756
|
+
*/
|
|
757
|
+
function buildExports () {
|
|
758
|
+
const buildDir = path.join(process.cwd(), 'build');
|
|
759
|
+
|
|
760
|
+
witeJson(path.join(buildDir, 'cjs/package.json'), { type: 'commonjs' });
|
|
761
|
+
tweakCjsPaths();
|
|
762
|
+
|
|
763
|
+
const pkgPath = path.join(buildDir, 'package.json');
|
|
764
|
+
|
|
765
|
+
/** @type {PkgJson} */
|
|
766
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
767
|
+
const listRoot = findFiles(buildDir, '', ['cjs', 'README.md', 'LICENSE']);
|
|
768
|
+
|
|
769
|
+
if (!listRoot.some(([key]) => key === '.')) {
|
|
770
|
+
const indexDef = relativePath(pkg.main).replace('.js', '.d.ts');
|
|
771
|
+
|
|
772
|
+
// for the env-specifics, add a root key (if not available)
|
|
773
|
+
listRoot.push(['.', {
|
|
774
|
+
types: indexDef,
|
|
775
|
+
// eslint-disable-next-line sort-keys
|
|
776
|
+
'react-native': createMapEntry(buildDir, pkg['react-native'], true)[1],
|
|
777
|
+
// eslint-disable-next-line sort-keys
|
|
778
|
+
browser: createMapEntry(buildDir, pkg.browser, true)[1],
|
|
779
|
+
node: createMapEntry(buildDir, pkg.main, true)[1]
|
|
780
|
+
}]);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// cleanup extraneous fields
|
|
784
|
+
delete pkg.devDependencies;
|
|
785
|
+
|
|
786
|
+
if (!pkg.main && fs.existsSync(path.join(buildDir, 'index.d.ts'))) {
|
|
787
|
+
pkg.main = 'index.js';
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
if (pkg.main) {
|
|
791
|
+
const main = pkg.main.startsWith('./')
|
|
792
|
+
? pkg.main
|
|
793
|
+
: `./${pkg.main}`;
|
|
794
|
+
|
|
795
|
+
pkg.main = main.replace(/^\.\//, './cjs/');
|
|
796
|
+
pkg.module = main;
|
|
797
|
+
pkg.types = main.replace('.js', '.d.ts');
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Ensure the top-level entries always points to the CJS version
|
|
801
|
+
(/** @type {const} */ (['browser', 'react-native'])).forEach((k) => {
|
|
802
|
+
const value = pkg[k];
|
|
803
|
+
|
|
804
|
+
if (typeof value === 'string') {
|
|
805
|
+
const entry = value.startsWith('./')
|
|
806
|
+
? value
|
|
807
|
+
: `./${value}`;
|
|
808
|
+
|
|
809
|
+
pkg[k] = entry.replace(/^\.\//, './cjs/');
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
if (Array.isArray(pkg.sideEffects)) {
|
|
814
|
+
pkg.sideEffects = pkg.sideEffects.map((s) =>
|
|
815
|
+
s.endsWith('.cjs')
|
|
816
|
+
? s.replace(/^\.\//, './cjs/').replace('.cjs', '.js')
|
|
817
|
+
: s
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
pkg.type = 'module';
|
|
822
|
+
|
|
823
|
+
pkg.exports = listRoot
|
|
824
|
+
.filter(([path, config]) =>
|
|
825
|
+
// skip d.ts files, except globals.d.ts which is needed for dev-test
|
|
826
|
+
(path.startsWith('./globals.d.ts') || !path.endsWith('.d.ts')) &&
|
|
827
|
+
// we handle the CJS path at the root below
|
|
828
|
+
path !== './cjs/package.json' &&
|
|
829
|
+
// we don't export ./deno/* paths (e.g. wasm)
|
|
830
|
+
!path.startsWith('./deno/') &&
|
|
831
|
+
// others
|
|
832
|
+
(
|
|
833
|
+
typeof config === 'object' ||
|
|
834
|
+
!listRoot.some(([, c]) =>
|
|
835
|
+
typeof c === 'object' &&
|
|
836
|
+
Object.values(c).some((v) => v === path)
|
|
837
|
+
)
|
|
838
|
+
)
|
|
839
|
+
)
|
|
840
|
+
.sort((a, b) => a[0].localeCompare(b[0]))
|
|
841
|
+
.reduce((all, [path, config]) => {
|
|
842
|
+
const entry = typeof config === 'string'
|
|
843
|
+
? config
|
|
844
|
+
// We need to force the types entry to the top,
|
|
845
|
+
// so we merge, sort and re-assemble
|
|
846
|
+
: Object
|
|
847
|
+
.entries({
|
|
848
|
+
...(pkg.exports?.[path] ?? {}),
|
|
849
|
+
...config
|
|
850
|
+
})
|
|
851
|
+
.sort(([a], [b]) =>
|
|
852
|
+
// types (first), module (first-ish), default (last)
|
|
853
|
+
a === 'types'
|
|
854
|
+
? -1
|
|
855
|
+
: b === 'types'
|
|
856
|
+
? 1
|
|
857
|
+
: a === 'module'
|
|
858
|
+
? -1
|
|
859
|
+
: b === 'module'
|
|
860
|
+
? 1
|
|
861
|
+
: a === 'default'
|
|
862
|
+
? 1
|
|
863
|
+
: b === 'default'
|
|
864
|
+
? -1
|
|
865
|
+
: 0
|
|
866
|
+
)
|
|
867
|
+
.reduce((all, [key, value]) => ({
|
|
868
|
+
...all,
|
|
869
|
+
[key]: value
|
|
870
|
+
}), {});
|
|
871
|
+
|
|
872
|
+
const pathParts = path.split(/[\\/]/);
|
|
873
|
+
|
|
874
|
+
return {
|
|
875
|
+
...all,
|
|
876
|
+
...(
|
|
877
|
+
path === '.'
|
|
878
|
+
// eslint-disable-next-line sort-keys
|
|
879
|
+
? { './cjs/package.json': './cjs/package.json', './cjs/*': './cjs/*.js' }
|
|
880
|
+
: ['./packageInfo', './shim'].includes(path)
|
|
881
|
+
? { [`${path}.js`]: entry }
|
|
882
|
+
: {}
|
|
883
|
+
),
|
|
884
|
+
[path]: entry,
|
|
885
|
+
...(
|
|
886
|
+
path.endsWith('.mjs') || path.endsWith('.cjs')
|
|
887
|
+
? { [path.replace(/\.[cm]js$/, '')]: entry }
|
|
888
|
+
: {}
|
|
889
|
+
),
|
|
890
|
+
...(
|
|
891
|
+
['index.cjs', 'index.mjs'].includes(pathParts[pathParts.length - 1])
|
|
892
|
+
? { [pathParts.slice(0, -1).join('/')]: entry }
|
|
893
|
+
: {}
|
|
894
|
+
)
|
|
895
|
+
};
|
|
896
|
+
}, {});
|
|
897
|
+
|
|
898
|
+
moveFields(pkg, ['main', 'module', 'browser', 'deno', 'react-native', 'types', 'exports', 'dependencies', 'optionalDependencies', 'peerDependencies', 'denoDependencies']);
|
|
899
|
+
witeJson(pkgPath, pkg);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Sorts a JSON file (typically package.json) by key
|
|
904
|
+
*
|
|
905
|
+
* @param {Record<string, unknown>} json
|
|
906
|
+
* @returns {Record<string, unknown>}
|
|
907
|
+
*/
|
|
908
|
+
function sortJson (json) {
|
|
909
|
+
return Object
|
|
910
|
+
.entries(json)
|
|
911
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
912
|
+
.reduce((all, [k, v]) => ({ ...all, [k]: v }), {});
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* @internal
|
|
917
|
+
*
|
|
918
|
+
* Adjusts the engine setting, highest of current and requested
|
|
919
|
+
*
|
|
920
|
+
* @param {string} [currVer]
|
|
921
|
+
* @returns {string}
|
|
922
|
+
*/
|
|
923
|
+
function getEnginesVer (currVer) {
|
|
924
|
+
return currVer && engineVersionCmp(currVer, TARGET_NODE) === 1
|
|
925
|
+
? currVer
|
|
926
|
+
: TARGET_NODE;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* @param {string} repoPath
|
|
931
|
+
* @param {string | null} dir
|
|
932
|
+
* @param {PkgJson} json
|
|
933
|
+
*/
|
|
934
|
+
function orderPackageJson (repoPath, dir, json) {
|
|
935
|
+
json.bugs = `https://github.com/${repoPath}/issues`;
|
|
936
|
+
json.homepage = `https://github.com/${repoPath}${dir ? `/tree/master/packages/${dir}` : ''}#readme`;
|
|
937
|
+
json.license = !json.license || json.license === 'Apache-2'
|
|
938
|
+
? 'Apache-2.0'
|
|
939
|
+
: json.license;
|
|
940
|
+
json.repository = {
|
|
941
|
+
...(dir
|
|
942
|
+
? { directory: `packages/${dir}` }
|
|
943
|
+
: {}
|
|
944
|
+
),
|
|
945
|
+
type: 'git',
|
|
946
|
+
url: `https://github.com/${repoPath}.git`
|
|
947
|
+
};
|
|
948
|
+
json.sideEffects = json.sideEffects || false;
|
|
949
|
+
json.engines = {
|
|
950
|
+
node: getEnginesVer(json.engines?.node)
|
|
951
|
+
};
|
|
952
|
+
|
|
953
|
+
// sort the object
|
|
954
|
+
const sorted = sortJson(json);
|
|
955
|
+
|
|
956
|
+
// remove fields we don't want to publish (may be re-added at some point)
|
|
957
|
+
['contributors', 'engine-strict', 'maintainers'].forEach((d) => {
|
|
958
|
+
delete sorted[d];
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
// move the different entry points to the (almost) end
|
|
962
|
+
(/** @type {const} */ (['browser', 'deno', 'electron', 'main', 'module', 'react-native'])).forEach((d) => {
|
|
963
|
+
delete sorted[d];
|
|
964
|
+
|
|
965
|
+
if (json[d]) {
|
|
966
|
+
sorted[d] = json[d];
|
|
967
|
+
}
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
// move bin, scripts & dependencies to the end
|
|
971
|
+
(/** @type {const} */ (['bin', 'scripts', 'exports', 'dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies', 'denoDependencies', 'resolutions'])).forEach((d) => {
|
|
972
|
+
delete sorted[d];
|
|
973
|
+
|
|
974
|
+
const value = json[d];
|
|
975
|
+
|
|
976
|
+
if (value && Object.keys(value).length) {
|
|
977
|
+
sorted[d] = sortJson(value);
|
|
978
|
+
}
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
witeJson(path.join(process.cwd(), 'package.json'), sorted);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* @param {string} full
|
|
986
|
+
* @param {string} line
|
|
987
|
+
* @param {number} lineNumber
|
|
988
|
+
* @param {string} error
|
|
989
|
+
* @returns {string}
|
|
990
|
+
*/
|
|
991
|
+
function createError (full, line, lineNumber, error) {
|
|
992
|
+
return `${full}:: ${lineNumber >= 0 ? `line ${lineNumber + 1}:: ` : ''}${error}:: \n\n\t${line}\n`;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* @param {string[]} errors
|
|
997
|
+
*/
|
|
998
|
+
function throwOnErrors (errors) {
|
|
999
|
+
if (errors.length) {
|
|
1000
|
+
exitFatal(errors.join('\n'));
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* @param {string[]} exts
|
|
1006
|
+
* @param {string} dir
|
|
1007
|
+
* @param {string} sub
|
|
1008
|
+
* @param {(path: string, line: string, lineNumber: number) => string | null | undefined} fn
|
|
1009
|
+
* @param {boolean} [allowComments]
|
|
1010
|
+
* @returns {string[]}
|
|
1011
|
+
*/
|
|
1012
|
+
function loopFiles (exts, dir, sub, fn, allowComments = false) {
|
|
1013
|
+
return fs
|
|
1014
|
+
.readdirSync(sub)
|
|
1015
|
+
.reduce((/** @type {string[]} */ errors, inner) => {
|
|
1016
|
+
const full = path.join(sub, inner);
|
|
1017
|
+
|
|
1018
|
+
if (fs.statSync(full).isDirectory()) {
|
|
1019
|
+
return errors.concat(loopFiles(exts, dir, full, fn, allowComments));
|
|
1020
|
+
} else if (exts.some((e) => full.endsWith(e))) {
|
|
1021
|
+
fs
|
|
1022
|
+
.readFileSync(full, 'utf-8')
|
|
1023
|
+
.split('\n')
|
|
1024
|
+
.forEach((l, n) => {
|
|
1025
|
+
const t = l
|
|
1026
|
+
// no leading/trailing whitespace
|
|
1027
|
+
.trim()
|
|
1028
|
+
// anything starting with * (multi-line comments)
|
|
1029
|
+
.replace(/^\*.*/, '')
|
|
1030
|
+
// anything between /* ... */
|
|
1031
|
+
.replace(/\/\*.*\*\//g, '')
|
|
1032
|
+
// single line comments with // ...
|
|
1033
|
+
.replace(allowComments ? /--------------------/ : /\/\/.*/, '');
|
|
1034
|
+
const r = fn(`${dir}/${full}`, t, n);
|
|
1035
|
+
|
|
1036
|
+
if (r) {
|
|
1037
|
+
errors.push(r);
|
|
1038
|
+
}
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
return errors;
|
|
1043
|
+
}, []);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* @param {string} dir
|
|
1048
|
+
*/
|
|
1049
|
+
function lintOutput (dir) {
|
|
1050
|
+
throwOnErrors(
|
|
1051
|
+
loopFiles(['.d.ts', '.js', '.cjs'], dir, 'build', (full, l, n) => {
|
|
1052
|
+
if ((l.includes('import(') || (l.startsWith('import ') && l.includes(" from '"))) && l.includes('/src/')) {
|
|
1053
|
+
// we are not allowed to import from /src/
|
|
1054
|
+
return createError(full, l, n, 'Invalid import from /src/');
|
|
1055
|
+
// eslint-disable-next-line no-useless-escape
|
|
1056
|
+
} else if (/[\+\-\*\/\=\<\>\|\&\%\^\(\)\{\}\[\] ][0-9]{1,}n/.test(l)) {
|
|
1057
|
+
if (l.includes(';base64,')) {
|
|
1058
|
+
// ignore base64 encoding, e.g. data uris
|
|
1059
|
+
} else if (dir !== 'dev') {
|
|
1060
|
+
// we don't want untamed BigInt literals
|
|
1061
|
+
return createError(full, l, n, 'Prefer BigInt(<digits>) to <digits>n');
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
return null;
|
|
1066
|
+
})
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* @param {string} dir
|
|
1072
|
+
*/
|
|
1073
|
+
function lintInput (dir) {
|
|
1074
|
+
throwOnErrors(
|
|
1075
|
+
loopFiles(['.ts', '.tsx'], dir, 'src', (full, l, n) => {
|
|
1076
|
+
// Sadly, we have people copying and just changing all the headers without
|
|
1077
|
+
// giving attribution - we certainly like forks, contributions, building on
|
|
1078
|
+
// stuff, but doing this type of rebrand is not cool
|
|
1079
|
+
//
|
|
1080
|
+
// This does have negative effects - proper forks that add their own source
|
|
1081
|
+
// file will also be caught in the net, i.e. we expect all files to conform
|
|
1082
|
+
if (n === 0 && (
|
|
1083
|
+
!/\/\/ Copyright .* @polkadot\//.test(l) &&
|
|
1084
|
+
!/\/\/ Auto-generated via `/.test(l) &&
|
|
1085
|
+
!/#!\/usr\/bin\/env node/.test(l)
|
|
1086
|
+
)) {
|
|
1087
|
+
return createError(full, l, n, 'Invalid header definition');
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
return null;
|
|
1091
|
+
}, true)
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* @param {string} config
|
|
1097
|
+
* @returns {[string[], boolean, string[]]}
|
|
1098
|
+
*/
|
|
1099
|
+
function getReferences (config) {
|
|
1100
|
+
const configPath = path.join(process.cwd(), config);
|
|
1101
|
+
|
|
1102
|
+
if (fs.existsSync(configPath)) {
|
|
1103
|
+
try {
|
|
1104
|
+
// We use the JSON5 parser here since we may have comments
|
|
1105
|
+
// (as allowed, per spec) in the actual tsconfig files
|
|
1106
|
+
/** @type {{ references: { path: string }[] }} */
|
|
1107
|
+
const tsconfig = JSON5.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
1108
|
+
const paths = tsconfig.references.map(({ path }) => path);
|
|
1109
|
+
|
|
1110
|
+
return [
|
|
1111
|
+
paths.map((path) =>
|
|
1112
|
+
path
|
|
1113
|
+
.replace('../', '')
|
|
1114
|
+
.replace('/tsconfig.build.json', '')
|
|
1115
|
+
),
|
|
1116
|
+
true,
|
|
1117
|
+
paths
|
|
1118
|
+
];
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
console.error(`Unable to parse ${configPath}`);
|
|
1121
|
+
|
|
1122
|
+
throw error;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
return [[], false, []];
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/**
|
|
1130
|
+
*
|
|
1131
|
+
* @param {CompileType} compileType
|
|
1132
|
+
* @param {string} dir
|
|
1133
|
+
* @param {[string, string][]} locals
|
|
1134
|
+
* @returns
|
|
1135
|
+
*/
|
|
1136
|
+
function lintDependencies (compileType, dir, locals) {
|
|
1137
|
+
const { dependencies = {}, devDependencies = {}, name, optionalDependencies = {}, peerDependencies = {}, private: isPrivate } = JSON.parse(fs.readFileSync(path.join(process.cwd(), './package.json'), 'utf-8'));
|
|
1138
|
+
|
|
1139
|
+
if (isPrivate) {
|
|
1140
|
+
return;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
const checkDep = compileType === 'babel'
|
|
1144
|
+
? '@babel/runtime'
|
|
1145
|
+
: compileType === 'swc'
|
|
1146
|
+
? '@swc/helpers'
|
|
1147
|
+
: compileType === 'esbuild'
|
|
1148
|
+
? null
|
|
1149
|
+
: 'tslib';
|
|
1150
|
+
|
|
1151
|
+
if (checkDep && !dependencies[checkDep]) {
|
|
1152
|
+
throw new Error(`${name} does not include the ${checkDep} dependency`);
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
const deps = [
|
|
1156
|
+
...Object.keys(dependencies),
|
|
1157
|
+
...Object.keys(peerDependencies),
|
|
1158
|
+
...Object.keys(optionalDependencies)
|
|
1159
|
+
];
|
|
1160
|
+
const devDeps = [
|
|
1161
|
+
...Object.keys(devDependencies),
|
|
1162
|
+
...deps
|
|
1163
|
+
];
|
|
1164
|
+
const [references] = getReferences('tsconfig.build.json');
|
|
1165
|
+
const [devRefs, hasDevConfig] = getReferences('tsconfig.spec.json');
|
|
1166
|
+
|
|
1167
|
+
/** @type {string[]} */
|
|
1168
|
+
const refsFound = [];
|
|
1169
|
+
|
|
1170
|
+
throwOnErrors(
|
|
1171
|
+
loopFiles(['.ts', '.tsx'], dir, 'src', (full, l, n) => {
|
|
1172
|
+
if (l.startsWith("import '") || (l.startsWith('import ') && l.includes(" from '"))) {
|
|
1173
|
+
const dep = l
|
|
1174
|
+
.split(
|
|
1175
|
+
l.includes(" from '")
|
|
1176
|
+
? " from '"
|
|
1177
|
+
: " '"
|
|
1178
|
+
)[1]
|
|
1179
|
+
.split("'")[0]
|
|
1180
|
+
.split('/')
|
|
1181
|
+
.slice(0, 2)
|
|
1182
|
+
.join('/');
|
|
1183
|
+
|
|
1184
|
+
if (name !== dep && !dep.startsWith('.') && !IGNORE_IMPORTS.includes(dep)) {
|
|
1185
|
+
const local = locals.find(([, name]) => name === dep);
|
|
1186
|
+
const isTest = full.endsWith('.spec.ts') || full.endsWith('.test.ts') || full.endsWith('.manual.ts') || full.includes('/test/');
|
|
1187
|
+
|
|
1188
|
+
if (!(isTest ? devDeps : deps).includes(dep) && !deps.includes(dep.split('/')[0])) {
|
|
1189
|
+
return createError(full, l, n, `${dep} is not included in package.json dependencies`);
|
|
1190
|
+
} else if (local) {
|
|
1191
|
+
const ref = local[0];
|
|
1192
|
+
|
|
1193
|
+
if (!(isTest && hasDevConfig ? devRefs : references).includes(ref)) {
|
|
1194
|
+
return createError(full, l, n, `../${ref} not included in ${(isTest && hasDevConfig ? 'tsconfig.spec.json' : 'tsconfig.build.json')} references`);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
if (!refsFound.includes(ref)) {
|
|
1198
|
+
refsFound.push(ref);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
return null;
|
|
1205
|
+
})
|
|
1206
|
+
);
|
|
1207
|
+
|
|
1208
|
+
const extraRefs = references.filter((r) => !refsFound.includes(r));
|
|
1209
|
+
|
|
1210
|
+
if (extraRefs.length) {
|
|
1211
|
+
throwOnErrors([
|
|
1212
|
+
createError(`${dir}/tsconfig.build.json`, extraRefs.join(', '), -1, 'Unused tsconfig.build.json references found')
|
|
1213
|
+
]);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
/**
|
|
1218
|
+
* @param {string} label
|
|
1219
|
+
* @param {() => unknown} fn
|
|
1220
|
+
*/
|
|
1221
|
+
async function timeIt (label, fn) {
|
|
1222
|
+
const start = Date.now();
|
|
1223
|
+
|
|
1224
|
+
await Promise.resolve(fn());
|
|
1225
|
+
|
|
1226
|
+
console.log(`${label} (${Date.now() - start}ms)`);
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
/**
|
|
1230
|
+
* @param {string} filepath
|
|
1231
|
+
* @param {boolean} withDetectImport
|
|
1232
|
+
* @returns {[string[], string[]]}
|
|
1233
|
+
*/
|
|
1234
|
+
function extractPackageInfoImports (filepath, withDetectImport) {
|
|
1235
|
+
/** @type {string[]} */
|
|
1236
|
+
const otherImports = withDetectImport
|
|
1237
|
+
? ["import { detectPackage } from '@pezkuwi/util';"]
|
|
1238
|
+
: [];
|
|
1239
|
+
/** @type {string[]} */
|
|
1240
|
+
const otherNames = [];
|
|
1241
|
+
|
|
1242
|
+
fs
|
|
1243
|
+
.readFileSync(filepath, { encoding: 'utf-8' })
|
|
1244
|
+
.split('\n')
|
|
1245
|
+
.forEach((l) => {
|
|
1246
|
+
const match = l.match(/import \{ packageInfo as (.*) \}/);
|
|
1247
|
+
|
|
1248
|
+
if (match) {
|
|
1249
|
+
otherImports.push(l);
|
|
1250
|
+
otherNames.push(match[1]);
|
|
1251
|
+
}
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
otherImports.sort((a, b) => {
|
|
1255
|
+
const am = a.match(/\} from '(.*)';/);
|
|
1256
|
+
const bm = b.match(/\} from '(.*)';/);
|
|
1257
|
+
|
|
1258
|
+
if (!am) {
|
|
1259
|
+
throw new Error(`Unable to extract from import from ${a}`);
|
|
1260
|
+
} else if (!bm) {
|
|
1261
|
+
throw new Error(`Unable to extract from import from ${b}`);
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
const af = am[1];
|
|
1265
|
+
const bf = bm[1];
|
|
1266
|
+
const pc = af.split('/')[1].localeCompare(bf.split('/')[1]);
|
|
1267
|
+
|
|
1268
|
+
return pc || af.localeCompare(bf);
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
return [otherImports, otherNames];
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* @param {CompileType} compileType
|
|
1276
|
+
* @param {string} repoPath
|
|
1277
|
+
* @param {string} dir
|
|
1278
|
+
* @param {[string, string][]} locals
|
|
1279
|
+
* @returns {Promise<void>}
|
|
1280
|
+
*/
|
|
1281
|
+
async function buildJs (compileType, repoPath, dir, locals) {
|
|
1282
|
+
const pkgJson = JSON.parse(fs.readFileSync(path.join(process.cwd(), './package.json'), 'utf-8'));
|
|
1283
|
+
const { name, version } = pkgJson;
|
|
1284
|
+
|
|
1285
|
+
if (!name.startsWith('@polkadot/')) {
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
lintInput(dir);
|
|
1290
|
+
|
|
1291
|
+
console.log(`*** ${name} ${version}`);
|
|
1292
|
+
|
|
1293
|
+
orderPackageJson(repoPath, dir, pkgJson);
|
|
1294
|
+
|
|
1295
|
+
// move the tsc-generated *.d.ts build files to build-tsc
|
|
1296
|
+
if (fs.existsSync('build')) {
|
|
1297
|
+
copyDirSync('build', 'build-tsc', ['.d.ts']);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
if (!fs.existsSync(path.join(process.cwd(), '.skip-build'))) {
|
|
1301
|
+
const srcHeader = `// Copyright 2017-${new Date().getFullYear()} ${name} authors & contributors\n// SPDX-License-Identifier: Apache-2.0\n`;
|
|
1302
|
+
const genHeader = `${srcHeader}\n// Do not edit, auto-generated by @polkadot/dev\n`;
|
|
1303
|
+
|
|
1304
|
+
fs.writeFileSync(path.join(process.cwd(), 'src/packageInfo.ts'), `${genHeader}\nexport const packageInfo = { name: '${name}', path: 'auto', type: 'auto', version: '${version}' };\n`);
|
|
1305
|
+
|
|
1306
|
+
if (!name.startsWith('@polkadot/x-')) {
|
|
1307
|
+
if (!name.startsWith('@polkadot/dev')) {
|
|
1308
|
+
const detectOld = path.join(process.cwd(), 'src/detectPackage.ts');
|
|
1309
|
+
const detectOther = path.join(process.cwd(), 'src/detectOther.ts');
|
|
1310
|
+
const detectThis = path.join(process.cwd(), 'src/packageDetect.ts');
|
|
1311
|
+
const withDetectImport = name !== '@polkadot/util';
|
|
1312
|
+
|
|
1313
|
+
/** @type {string[]} */
|
|
1314
|
+
let otherImports = withDetectImport
|
|
1315
|
+
? ["import { detectPackage } from '@pezkuwi/util';"]
|
|
1316
|
+
: [];
|
|
1317
|
+
/** @type {string[]} */
|
|
1318
|
+
let otherNames = [];
|
|
1319
|
+
const localImports = withDetectImport
|
|
1320
|
+
? []
|
|
1321
|
+
: ["import { detectPackage } from './detectPackage.js';"];
|
|
1322
|
+
|
|
1323
|
+
localImports.push("import { packageInfo } from './packageInfo.js';");
|
|
1324
|
+
|
|
1325
|
+
if (fs.existsSync(detectOther)) {
|
|
1326
|
+
[otherImports, otherNames] = extractPackageInfoImports(detectOther, withDetectImport);
|
|
1327
|
+
|
|
1328
|
+
fs.rmSync(detectOther);
|
|
1329
|
+
} else if (fs.existsSync(detectThis)) {
|
|
1330
|
+
[otherImports, otherNames] = extractPackageInfoImports(detectThis, withDetectImport);
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
if (withDetectImport) {
|
|
1334
|
+
// for @polkadot/util this file contains the detection logic, keep it
|
|
1335
|
+
fs.rmSync(detectOld, { force: true });
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
fs.writeFileSync(detectThis, `${genHeader}// (packageInfo imports will be kept as-is, user-editable)\n\n${otherImports.join('\n')}\n\n${localImports.join('\n')}\n\ndetectPackage(packageInfo, null, [${otherNames.sort().join(', ')}]);\n`);
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
const cjsRoot = path.join(process.cwd(), 'src/cjs');
|
|
1342
|
+
|
|
1343
|
+
if (fs.existsSync(path.join(cjsRoot, 'dirname.d.ts'))) {
|
|
1344
|
+
rimrafSync(cjsRoot);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
if (fs.existsSync(path.join(process.cwd(), 'public'))) {
|
|
1349
|
+
buildWebpack();
|
|
1350
|
+
} else {
|
|
1351
|
+
await compileJs(compileType, 'cjs');
|
|
1352
|
+
await compileJs(compileType, 'esm');
|
|
1353
|
+
|
|
1354
|
+
// Deno
|
|
1355
|
+
await timeIt('Successfully compiled deno', () => {
|
|
1356
|
+
buildDeno();
|
|
1357
|
+
});
|
|
1358
|
+
|
|
1359
|
+
await timeIt('Successfully rewrote imports', () => {
|
|
1360
|
+
// adjust the import paths (deno imports from .ts - can remove this on typescript 5)
|
|
1361
|
+
rewriteImports('build-deno', process.cwd(), pkgJson, adjustDenoPath);
|
|
1362
|
+
|
|
1363
|
+
// adjust all output js esm to have .js path imports
|
|
1364
|
+
['cjs', 'esm'].forEach((jsType) =>
|
|
1365
|
+
rewriteImports(`build-${compileType}-${jsType}`, process.cwd(), pkgJson, adjustJsPath)
|
|
1366
|
+
);
|
|
1367
|
+
});
|
|
1368
|
+
|
|
1369
|
+
await timeIt('Successfully combined build', () => {
|
|
1370
|
+
// adjust all packageInfo.js files for the correct usage
|
|
1371
|
+
tweakPackageInfo(compileType);
|
|
1372
|
+
|
|
1373
|
+
// copy output files (after import rewriting)
|
|
1374
|
+
copyBuildFiles(compileType, dir);
|
|
1375
|
+
});
|
|
1376
|
+
|
|
1377
|
+
await timeIt('Successfully built exports', () => {
|
|
1378
|
+
// everything combined now, delete what we don't need
|
|
1379
|
+
deleteBuildFiles();
|
|
1380
|
+
|
|
1381
|
+
// build the package.json exports
|
|
1382
|
+
buildExports();
|
|
1383
|
+
});
|
|
1384
|
+
|
|
1385
|
+
await timeIt('Successfully linted configs', () => {
|
|
1386
|
+
lintOutput(dir);
|
|
1387
|
+
lintDependencies(compileType, dir, locals);
|
|
1388
|
+
});
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
console.log();
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* Finds any tsconfig.*.json files that are not included in the root
|
|
1397
|
+
* tsconfig.build.json
|
|
1398
|
+
*/
|
|
1399
|
+
function findUnusedTsConfig () {
|
|
1400
|
+
const [,, allPaths] = getReferences('tsconfig.build.json');
|
|
1401
|
+
const allPkgs = fs
|
|
1402
|
+
.readdirSync('packages')
|
|
1403
|
+
.filter((dir) =>
|
|
1404
|
+
fs.statSync(path.join(process.cwd(), 'packages', dir)).isDirectory() &&
|
|
1405
|
+
fs.existsSync(path.join(process.cwd(), 'packages', dir, 'src'))
|
|
1406
|
+
);
|
|
1407
|
+
/** @type {string[]} */
|
|
1408
|
+
const allConfigs = [];
|
|
1409
|
+
|
|
1410
|
+
for (const pkg of allPkgs) {
|
|
1411
|
+
allConfigs.push(...fs
|
|
1412
|
+
.readdirSync(`packages/${pkg}`)
|
|
1413
|
+
.filter((f) =>
|
|
1414
|
+
f.startsWith('tsconfig.') &&
|
|
1415
|
+
f.endsWith('.json')
|
|
1416
|
+
)
|
|
1417
|
+
.map((f) => `./packages/${pkg}/${f}`)
|
|
1418
|
+
);
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
const missing = allConfigs.filter((c) => !allPaths.includes(c));
|
|
1422
|
+
|
|
1423
|
+
if (missing.length) {
|
|
1424
|
+
throw new Error(`Not reflected in the root tsconfig.build.json: ${missing.join(', ')}`);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
/**
|
|
1429
|
+
* Main entry point
|
|
1430
|
+
*/
|
|
1431
|
+
async function main () {
|
|
1432
|
+
const args = process.argv.slice(2);
|
|
1433
|
+
|
|
1434
|
+
/** @type {CompileType} */
|
|
1435
|
+
let compileType = 'tsc';
|
|
1436
|
+
|
|
1437
|
+
for (let i = 0; i < args.length; i++) {
|
|
1438
|
+
if (args[i] === '--compiler') {
|
|
1439
|
+
const type = args[++i];
|
|
1440
|
+
|
|
1441
|
+
if (type === 'tsc') {
|
|
1442
|
+
compileType = type;
|
|
1443
|
+
} else {
|
|
1444
|
+
throw new Error(`Invalid --compiler ${type}`);
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
execPm('polkadot-dev-clean-build');
|
|
1450
|
+
|
|
1451
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(), './package.json'), 'utf-8'));
|
|
1452
|
+
|
|
1453
|
+
if (pkg.scripts) {
|
|
1454
|
+
if (pkg.scripts['build:extra']) {
|
|
1455
|
+
throw new Error('Found deprecated build:extra script, use build:before or build:after instead');
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
if (pkg.scripts['build:before']) {
|
|
1459
|
+
execPm('build:before');
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
const repoPath = pkg.repository.url
|
|
1464
|
+
.split('https://github.com/')[1]
|
|
1465
|
+
.split('.git')[0];
|
|
1466
|
+
|
|
1467
|
+
orderPackageJson(repoPath, null, pkg);
|
|
1468
|
+
execPm('polkadot-exec-tsc --build tsconfig.build.json');
|
|
1469
|
+
|
|
1470
|
+
process.chdir('packages');
|
|
1471
|
+
|
|
1472
|
+
const dirs = fs
|
|
1473
|
+
.readdirSync('.')
|
|
1474
|
+
.filter((dir) =>
|
|
1475
|
+
fs.statSync(dir).isDirectory() &&
|
|
1476
|
+
fs.existsSync(path.join(process.cwd(), dir, 'src'))
|
|
1477
|
+
);
|
|
1478
|
+
|
|
1479
|
+
/** @type {[string, string][]} */
|
|
1480
|
+
const locals = [];
|
|
1481
|
+
|
|
1482
|
+
// get all package names
|
|
1483
|
+
for (const dir of dirs) {
|
|
1484
|
+
const { name } = JSON.parse(fs.readFileSync(path.join(process.cwd(), dir, './package.json'), 'utf-8'));
|
|
1485
|
+
|
|
1486
|
+
if (name.startsWith('@polkadot/')) {
|
|
1487
|
+
locals.push([dir, name]);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
// build packages
|
|
1492
|
+
for (const dir of dirs) {
|
|
1493
|
+
process.chdir(dir);
|
|
1494
|
+
|
|
1495
|
+
await buildJs(compileType, repoPath, dir, locals);
|
|
1496
|
+
|
|
1497
|
+
process.chdir('..');
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
process.chdir('..');
|
|
1501
|
+
|
|
1502
|
+
findUnusedTsConfig();
|
|
1503
|
+
|
|
1504
|
+
if (RL_CONFIGS.some((c) => fs.existsSync(path.join(process.cwd(), c)))) {
|
|
1505
|
+
execPm('polkadot-exec-rollup --config');
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
if (pkg.scripts) {
|
|
1509
|
+
if (pkg.scripts['build:after']) {
|
|
1510
|
+
execPm('build:after');
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
main().catch((error) => {
|
|
1516
|
+
console.error(error);
|
|
1517
|
+
process.exit(-1);
|
|
1518
|
+
});
|