@deot/dev-cli 1.0.8 → 1.1.1

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.es.js CHANGED
@@ -1,1132 +1,11 @@
1
1
  import { program } from 'commander';
2
2
  import { createRequire } from 'node:module';
3
- import chalk from 'chalk';
4
- import ora from 'ora';
5
- import { Utils, Logger, Shell } from '@deot/dev-shared';
6
- import * as path from 'node:path';
7
- import { resolve } from 'node:path';
8
- import fs from 'fs-extra';
9
- import inquirer from 'inquirer';
10
- import autocomplete from 'inquirer-autocomplete-prompt';
11
- import typescript from '@rollup/plugin-typescript';
12
- import { nodeResolve } from '@rollup/plugin-node-resolve';
13
- import commonjs from '@rollup/plugin-commonjs';
14
- import replace from '@rollup/plugin-replace';
15
- import { rollup } from 'rollup';
16
- import { Extractor, ExtractorConfig } from '@microsoft/api-extractor';
17
- import parser from 'conventional-commits-parser';
18
- import semver from 'semver';
19
-
20
- const cwd = process.cwd();
21
- const require$$2 = createRequire(cwd);
22
- class Shared {
23
- static config;
24
- static getNormalizePackage = (dataMap) => {
25
- Object.keys(dataMap).forEach(packageName => {
26
- const relations = dataMap[packageName];
27
- relations.forEach((packageName$) => {
28
- if (dataMap[packageName$].includes(packageName)) {
29
- throw new Error(`${packageName} ${packageName$} deps loop`);
30
- }
31
- });
32
- });
33
- const needUseMap = Object.keys(dataMap).reduce((pre, key) => (pre[key] = 0, pre), {});
34
- const queue = [];
35
- for (let key in dataMap) {
36
- const dependencies = dataMap[key];
37
- dependencies.forEach((dependency) => {
38
- needUseMap[dependency] += 1;
39
- });
40
- }
41
- for (let key in needUseMap) {
42
- if (needUseMap[key] === 0) {
43
- queue.push(key);
44
- }
45
- }
46
- const result = [];
47
- while (queue.length > 0) {
48
- const node = queue.shift();
49
- if (!node)
50
- return [];
51
- result.push(node);
52
- const dependencies = dataMap[node];
53
- for (let i = 0; i < dependencies.length; i++) {
54
- const dependency = dependencies[i];
55
- needUseMap[dependency] -= 1;
56
- if (needUseMap[dependency] === 0) {
57
- queue.push(dependency);
58
- }
59
- }
60
- }
61
- return result.reverse();
62
- };
63
- static getPackageName = (packageFolderName$) => {
64
- const { workspace, packageFolderName, packageName } = Shared.impl();
65
- if (!workspace
66
- || !packageFolderName$
67
- || packageFolderName$ === packageFolderName) {
68
- return packageName;
69
- }
70
- else {
71
- return `${packageName}-${packageFolderName$.replace(new RegExp(`${packageName}-?`), '')}`;
72
- }
73
- };
74
- static getPackageFolderName = (packageName$) => {
75
- const { workspace, packageFolderName, packageName } = Shared.impl();
76
- if (!workspace)
77
- return '';
78
- if (packageName$ === packageName)
79
- return packageFolderName;
80
- return packageName$?.replace(new RegExp(`${packageName}-?`), '');
81
- };
82
- static impl() {
83
- if (Shared.config)
84
- return Shared.config;
85
- const rootPackageOptions = require$$2(`${cwd}/package.json`);
86
- let workspace = 'packages';
87
- let isMonorepo = fs.existsSync(path.resolve(cwd, workspace));
88
- workspace = isMonorepo ? workspace : '';
89
- const packageFolderName = isMonorepo ? 'index' : '';
90
- const packageDir = path.resolve(cwd, workspace);
91
- const packageOptions = require$$2(path.resolve(packageDir, packageFolderName, 'package.json'));
92
- const packageName = packageOptions.name;
93
- const packageVersion = packageOptions.version;
94
- const packageFolderNames = !isMonorepo ? [] : fs
95
- .readdirSync(packageDir)
96
- .reduce((pre, file) => {
97
- const fullpath = path.resolve(packageDir, file);
98
- const stat = fs.statSync(fullpath);
99
- if (!(/(^_|tpl)/.test(file))
100
- && stat.isDirectory()) {
101
- pre.push(file);
102
- }
103
- return pre;
104
- }, []);
105
- const packageOptionsMap = packageFolderNames.reduce((pre, packageFolderName$) => {
106
- pre[packageFolderName$] = require$$2(path.resolve(packageDir, packageFolderName$, 'package.json'));
107
- return pre;
108
- }, {});
109
- const packageDirsMap = packageFolderNames.reduce((pre, packageFolderName$) => {
110
- pre[packageFolderName$] = path.resolve(packageDir, packageFolderName$);
111
- return pre;
112
- }, {});
113
- const packageRelation = packageFolderNames.reduce((pre, packageFolderName$) => {
114
- let packagesOptions = packageOptionsMap[packageFolderName$];
115
- let deps = {
116
- ...(packagesOptions.dependencies || {}),
117
- ...(packagesOptions.devDependencies || {}),
118
- };
119
- pre[packagesOptions.name] = Object.keys(deps).filter(i => new RegExp(`${packageName}`).test(i));
120
- return pre;
121
- }, {});
122
- const normalizePackageNames = Shared.getNormalizePackage(packageRelation);
123
- const normalizePackageFolderNames = normalizePackageNames
124
- .map(i => i.replace(new RegExp(`${packageName}-?`), '') || packageFolderName);
125
- const homepage = (rootPackageOptions.repository || packageOptions.repository || {}).url || '';
126
- const config = {
127
- cwd,
128
- workspace,
129
- homepage: homepage.replace(/(.*)(https?:\/\/.*)(#|\.git)/, '$2'),
130
- packageFolderName,
131
- packageDir,
132
- packageOptions,
133
- packageName,
134
- packageVersion,
135
- packageFolderNames,
136
- packageOptionsMap,
137
- packageDirsMap,
138
- packageRelation,
139
- normalizePackageNames,
140
- normalizePackageFolderNames
141
- };
142
- Shared.config = config;
143
- return config;
144
- }
145
- }
146
-
147
- const run$5 = (options) => Utils.autoCatch(async () => {
148
- const locals = Shared.impl();
149
- const { workspace, packageFolderNames } = locals;
150
- if (!workspace) {
151
- return Logger.log(`<link> Monorepo Supported Only.`);
152
- }
153
- if (typeof options.dryRun === 'undefined') {
154
- options.dryRun = process.env.NODE_ENV === 'UNIT';
155
- }
156
- const command = `npx pnpm link ./${workspace}/`;
157
- if (options.dryRun)
158
- return Shell.spawn(`echo ${command}`);
159
- const spinner = ora(`Links ...\n`);
160
- spinner.start();
161
- await Promise.all(packageFolderNames.map(i => {
162
- return Shell.spawn(`${command}${i}`);
163
- }));
164
- spinner.stop();
165
- Logger.log(`${chalk.green('Links Success')}`);
166
- });
167
-
168
- const { prompt: prompt$2, registerPrompt: registerPrompt$1, Separator } = inquirer;
169
- const getOptions$1 = async () => {
170
- const { packageFolderNames } = Shared.impl();
171
- const question = [
172
- {
173
- type: 'list',
174
- name: 'mode',
175
- message: 'Select Mode:',
176
- choices: [
177
- new Separator('选择添加的类型:'),
178
- 'dependent',
179
- 'package'
180
- ],
181
- default: 'package'
182
- },
183
- {
184
- type: 'autocomplete',
185
- message: 'Select Package To Install:',
186
- when: (answers) => answers.mode === 'dependent',
187
- name: 'packageFolderName',
188
- default: 'index',
189
- source: (_, input) => {
190
- input = input || '';
191
- return new Promise(($resolve => {
192
- let filter = input
193
- ? packageFolderNames.filter(item => item.includes(input))
194
- : packageFolderNames;
195
- $resolve(filter);
196
- }));
197
- }
198
- },
199
- {
200
- type: 'input',
201
- name: 'dependentName',
202
- message: 'Input Dependent Name',
203
- default: '',
204
- when: (answers) => answers.mode === 'dependent',
205
- validate: (answer) => {
206
- if (!answer) {
207
- return '请输入需要添加的模块名';
208
- }
209
- return true;
210
- }
211
- },
212
- {
213
- type: 'list',
214
- name: 'args',
215
- when: (answers) => answers.mode === 'dependent',
216
- message: 'Select Install Mode:',
217
- choices: [
218
- '-S',
219
- '-D',
220
- '-O'
221
- ]
222
- },
223
- {
224
- type: 'input',
225
- name: 'packageFolderName',
226
- message: 'Input Package Name',
227
- default: '',
228
- when: (answers) => answers.mode === 'package',
229
- validate: (answer) => {
230
- if (!answer) {
231
- return '请输入需要添加的包名';
232
- }
233
- if (packageFolderNames.includes(answer) || answer === 'dev') {
234
- return '包名已存在';
235
- }
236
- return true;
237
- }
238
- }
239
- ];
240
- registerPrompt$1('autocomplete', autocomplete);
241
- let result = await prompt$2(question);
242
- if (result.mode == 'dependent') {
243
- result.packageName = Shared.getPackageName(result.packageFolderName);
244
- }
245
- if (result.mode == 'package') {
246
- result.packageName = Shared.getPackageName(result.packageFolderName);
247
- }
248
- result.args = [result.args];
249
- return result;
250
- };
251
-
252
- const run$4 = (options) => Utils.autoCatch(async () => {
253
- const locals = Shared.impl();
254
- const { workspace, packageDir } = locals;
255
- if (!workspace) {
256
- return Logger.log(`<add> Monorepo Supported Only.`);
257
- }
258
- if (typeof options.dryRun === 'undefined') {
259
- options.dryRun = process.env.NODE_ENV === 'UNIT';
260
- }
261
- const { mode, dependentName, args, packageFolderName, packageName } = await getOptions$1();
262
- let command = mode === 'dependent'
263
- ? `npx pnpm add --filter ${packageName} ${dependentName} ${args.join(' ')}`
264
- : `npx pnpm link ./${workspace}/${packageFolderName}`;
265
- if (options.dryRun)
266
- return Shell.spawn(`echo "${command}"`);
267
- const spinner = ora(`${command}\n`).start();
268
- await Shell.spawn(command);
269
- spinner.stop();
270
- if (mode === 'package') {
271
- let dir = resolve(packageDir);
272
- fs.outputFileSync(`${dir}/${packageFolderName}/README.md`, '// TODO');
273
- fs.outputFileSync(`${dir}/${packageFolderName}/src/index.ts`, '// TODO');
274
- fs.outputFileSync(`${dir}/${packageFolderName}/__tests__/index.spec.ts`, '// TODO');
275
- fs.outputFileSync(`${dir}/${packageFolderName}/package.json`, JSON.stringify({
276
- name: packageName,
277
- version: '1.0.0',
278
- main: 'dist/index.js',
279
- types: "dist/index.d.ts",
280
- type: "module",
281
- files: [
282
- "dist"
283
- ],
284
- license: 'MIT',
285
- publishConfig: {
286
- access: 'public'
287
- },
288
- dependencies: {}
289
- }, null, 2));
290
- fs.outputFileSync(`${dir}/${packageFolderName}/api-extractor.json`, JSON.stringify({
291
- extends: "../../api-extractor.json",
292
- mainEntryPointFilePath: `./dist/${workspace}/${packageFolderName}/src/index.d.ts`,
293
- dtsRollup: {
294
- publicTrimmedFilePath: "./dist/index.d.ts"
295
- }
296
- }, null, 2));
297
- }
298
- await Shell.spawn(command);
299
- });
300
-
301
- const ALL_PACKAGE = 'All Packages';
302
- const { prompt: prompt$1, registerPrompt } = inquirer;
303
- const getOptions = async () => {
304
- const isDev = process.env.NODE_ENV === 'development';
305
- const { packageFolderNames } = Shared.impl();
306
- const packages$ = [ALL_PACKAGE, ...packageFolderNames];
307
- const question = [
308
- {
309
- type: 'autocomplete',
310
- message: `Select Package To ${isDev ? 'Develop' : 'Test'}:`,
311
- name: 'packageFolderName',
312
- default: 'cli',
313
- source: (_, input) => {
314
- input = input || '';
315
- return new Promise(($resolve => {
316
- let filter = input
317
- ? packages$.filter(item => item.includes(input))
318
- : packages$;
319
- $resolve(filter);
320
- }));
321
- }
322
- },
323
- {
324
- type: 'confirm',
325
- message: 'Watch Mode?',
326
- name: 'watch',
327
- when: () => !isDev,
328
- default: (answers) => {
329
- return answers.packageFolderName !== ALL_PACKAGE;
330
- }
331
- }
332
- ];
333
- registerPrompt('autocomplete', autocomplete);
334
- let result = await prompt$1(question);
335
- result.packageFolderName = result.packageFolderName == ALL_PACKAGE
336
- ? undefined
337
- : result.packageFolderName;
338
- result.watch = result.watch || isDev;
339
- return result;
340
- };
341
-
342
- const run$3 = (options) => Utils.autoCatch(async () => {
343
- const locals = Shared.impl();
344
- if (typeof options.dryRun === 'undefined') {
345
- options.dryRun = process.env.NODE_ENV === 'UNIT';
346
- }
347
- if (locals.workspace && !options.packageName) {
348
- const promptOptions = await getOptions();
349
- options = {
350
- ...options,
351
- ...promptOptions
352
- };
353
- }
354
- const { cwd, workspace, packageOptionsMap, packageDirsMap } = locals;
355
- const { packageName, watch, dryRun } = options;
356
- options.packageFolderName = Shared.getPackageFolderName(options.packageName) || options.packageFolderName;
357
- options.workspace = workspace;
358
- const packageOptions = packageOptionsMap[options.packageFolderName];
359
- const packageDir = packageDirsMap[options.packageFolderName];
360
- if (workspace
361
- && cwd !== packageDir
362
- && packageOptions?.scripts?.['test']) {
363
- await Shell.spawn(`npm`, ['run', 'test']);
364
- return;
365
- }
366
- if (!options.packageFolderName)
367
- delete options.packageFolderName;
368
- if (!options.workspace)
369
- delete options.workspace;
370
- delete options.packageName;
371
- const command = `cross-env NODE_ENV=${process.env.NODE_ENV || 'TEST'} TEST_OPTIONS=${encodeURIComponent(JSON.stringify(options))} jest `
372
- + ([
373
- '--passWithNoTests',
374
- `${watch ? '--watchAll' : ''}`
375
- ].join(' '));
376
- if (dryRun)
377
- return Shell.spawn(`echo ${command}`);
378
- await Shell.spawn(command);
379
- if (!watch)
380
- return;
381
- Logger.log(packageName || '', '测试已通过');
382
- }, {
383
- onError: (e) => {
384
- if (typeof e === 'number' && e === 1) {
385
- Logger.error('测试未通过');
386
- }
387
- else {
388
- Logger.error(e);
389
- }
390
- process.exit(1);
391
- }
392
- });
393
-
394
- const run$2 = (options) => Utils.autoCatch(async () => {
395
- const locals = Shared.impl();
396
- if (typeof options.dryRun === 'undefined') {
397
- options.dryRun = process.env.NODE_ENV === 'UNIT';
398
- }
399
- if (options.dryRun)
400
- return Shell.spawn(`echo development`);
401
- const { cwd, workspace, packageOptionsMap, packageDirsMap } = locals;
402
- const { packageName } = options;
403
- const getPackageFolderName = Shared.getPackageFolderName(packageName);
404
- const packageOptions = packageOptionsMap[getPackageFolderName];
405
- const packageDir = packageDirsMap[getPackageFolderName];
406
- options.watch = true;
407
- if (!workspace
408
- && packageName
409
- && packageName !== '**'
410
- && cwd !== packageDir
411
- && packageOptions?.scripts?.['dev']) {
412
- await Shell.spawn(`npm`, ['run', 'dev']);
413
- return;
414
- }
415
- await Shell.spawn(`cross-env`, [
416
- 'NODE_ENV=development',
417
- 'npm',
418
- 'run',
419
- 'test',
420
- '--',
421
- packageName ? `--package-name ${packageName}` : ''
422
- ]);
423
- });
424
-
425
- const require$$1 = createRequire(import.meta.url);
426
- class Builder {
427
- packageDir;
428
- packageName;
429
- packageOptions;
430
- config;
431
- commandOptions;
432
- constructor(config, commandOptions) {
433
- const { workspace, packageDir, packageName } = Shared.impl();
434
- if (typeof config === 'string') {
435
- let packageFolderName = config;
436
- let packageDir$ = path.resolve(packageDir, packageFolderName);
437
- config = {
438
- dir: packageDir$,
439
- name: packageFolderName || 'index',
440
- input: packageDir$ + '/src/index.ts',
441
- output: [
442
- {
443
- file: packageDir$ + '/dist/index.es.js',
444
- format: 'es',
445
- exports: 'named',
446
- sourcemap: false
447
- },
448
- {
449
- file: packageDir$ + '/dist/index.iife.js',
450
- format: 'iife',
451
- name: packageName,
452
- },
453
- {
454
- file: packageDir$ + '/dist/index.cjs.js',
455
- format: 'cjs'
456
- }
457
- ].filter(i => {
458
- return commandOptions.output.includes(i.format);
459
- })
460
- };
461
- }
462
- this.packageDir = path.resolve(packageDir, workspace ? `./${config.name}` : '');
463
- this.packageName = config.name === 'index'
464
- ? packageName
465
- : `${packageName}-${config.name}`;
466
- this.packageOptions = require$$1(`${this.packageDir}/package.json`);
467
- this.config = config;
468
- this.commandOptions = commandOptions;
469
- }
470
- async process() {
471
- const { cwd, workspace } = Shared.impl();
472
- const { packageOptions, packageName, packageDir } = this;
473
- if (workspace
474
- && packageOptions?.scripts?.build
475
- && packageDir !== cwd) {
476
- await Shell.spawn(`npm`, ['run', 'build'], {
477
- cwd: packageDir
478
- });
479
- return;
480
- }
481
- const spinner = ora(`${packageName} Build ...`);
482
- try {
483
- spinner.start();
484
- await fs.emptyDir(`${packageDir}/dist`);
485
- const stats = await this.buildSources();
486
- await this.buildTypes();
487
- spinner.stop();
488
- Logger.log(`${chalk.cyan(`${packageName}`)}: ${chalk.green('Success')}`);
489
- stats.forEach((stat) => {
490
- Logger.log(`${chalk.green(stat.format.toUpperCase())}: ${Utils.formatBytes(stat.size)}`);
491
- });
492
- }
493
- catch (e) {
494
- Logger.log('Error!', e);
495
- throw e;
496
- }
497
- }
498
- async buildSources() {
499
- const { workspace } = Shared.impl();
500
- const { name, input, output } = this.config;
501
- const { packageOptions } = this;
502
- const external = Object
503
- .keys({
504
- ...packageOptions.dependencies,
505
- ...packageOptions.peerDependencies
506
- })
507
- .map(i => new RegExp(`^${i}$`));
508
- const source = workspace ? `${workspace}/${name}/**/*` : 'src/**/*';
509
- const shims = workspace ? `${workspace}/shims.d.ts` : 'shims.d.ts';
510
- const outDir = workspace ? `${workspace}/${name}/dist` : 'dist';
511
- const builder = await rollup({
512
- input,
513
- external: [
514
- /^node:/,
515
- /^[a-zA-Z@]/,
516
- ...external
517
- ],
518
- plugins: [
519
- typescript({
520
- include: [source, shims],
521
- exclude: ['dist'],
522
- compilerOptions: {
523
- rootDir: '.',
524
- outDir,
525
- declaration: true
526
- }
527
- }),
528
- commonjs({ extensions: ['.js', '.ts'] }),
529
- nodeResolve(),
530
- replace({
531
- '1.0.6': `'${packageOptions.version}'`,
532
- false: 'false',
533
- true: true
534
- })
535
- ]
536
- });
537
- await Promise.all(output.map(builder.write));
538
- const stats = [];
539
- await output.reduce((pre, cur, index) => {
540
- pre
541
- .then(() => fs.stat(cur.file))
542
- .then((stat) => {
543
- stats[index] = {
544
- format: cur.format,
545
- size: stat.size
546
- };
547
- });
548
- return pre;
549
- }, Promise.resolve());
550
- return stats;
551
- }
552
- async buildTypes() {
553
- const { workspace } = Shared.impl();
554
- const { packageDir, packageOptions } = this;
555
- if (workspace && packageOptions?.scripts?.['build:types']) {
556
- await Shell.spawn(`npm`, ['run', 'build:types'], {
557
- cwd: packageDir
558
- });
559
- return;
560
- }
561
- const config = path.resolve(packageDir, `api-extractor.json`);
562
- if (fs.existsSync(config)) {
563
- const result = Extractor.invoke(ExtractorConfig.loadFileAndPrepare(config), {
564
- localBuild: true,
565
- showVerboseMessages: false
566
- });
567
- if (!result.succeeded) {
568
- Logger.error(`API Extractor completed with ${result.errorCount} errors and ${result.warningCount} warnings`);
569
- process.exitCode = 1;
570
- }
571
- }
572
- await fs.remove(`${packageDir}/dist/${workspace || 'src'}`);
573
- }
574
- }
575
- const builder = (options, commandOptions) => {
576
- return new Builder(options, commandOptions);
577
- };
578
-
579
- const run$1 = (options) => Utils.autoCatch(async () => {
580
- const locals = Shared.impl();
581
- if (typeof options.dryRun === 'undefined') {
582
- options.dryRun = process.env.NODE_ENV === 'UNIT';
583
- }
584
- const { normalizePackageFolderNames } = Shared.impl();
585
- let packageFolderName = Shared.getPackageFolderName(options.packageName || '**');
586
- let inputs = [];
587
- if (locals.workspace && packageFolderName === '**') {
588
- inputs = normalizePackageFolderNames;
589
- }
590
- else {
591
- inputs = [packageFolderName];
592
- }
593
- if (options.dryRun)
594
- return Shell.spawn(`echo ${inputs.join(' ')}`);
595
- await inputs
596
- .reduce((preProcess, packageFolderName$) => {
597
- preProcess = preProcess.then(() => builder(packageFolderName$, options).process());
598
- return preProcess;
599
- }, Promise.resolve());
600
- }, {
601
- onError: (e) => {
602
- if (typeof e === 'number' && e === 1) {
603
- Logger.error('编译未通过');
604
- }
605
- else {
606
- Logger.error(e);
607
- }
608
- process.exit(1);
609
- }
610
- });
611
-
612
- const require$ = createRequire(import.meta.url);
613
- const { prompt } = inquirer;
614
- const HASH = '-hash-';
615
- const SUFFIX = '🐒💨🙊';
616
- const parserOptions = {
617
- noteKeywords: ['BREAKING CHANGE', 'Breaking Change']
618
- };
619
- const reBreaking = new RegExp(`(${parserOptions.noteKeywords.join(')|(')})`);
620
- class Releaser {
621
- packageDir;
622
- packageName;
623
- packageFolderName;
624
- packageOptions;
625
- packageRelation;
626
- config;
627
- changeLog;
628
- version;
629
- commits;
630
- commandOptions;
631
- constructor(config, commandOptions) {
632
- const { packageDir, packageRelation } = Shared.impl();
633
- if (typeof config === 'string') {
634
- let packageFolderName = config;
635
- let packageDir$ = path.resolve(packageDir, packageFolderName);
636
- config = {
637
- dir: packageDir$,
638
- name: packageFolderName
639
- };
640
- }
641
- this.packageDir = config.dir;
642
- this.packageName = Shared.getPackageName(config.name);
643
- this.packageFolderName = config.name;
644
- this.packageOptions = require$(`${this.packageDir}/package.json`);
645
- this.packageRelation = packageRelation[this.packageName] || [];
646
- this.config = config;
647
- this.commits = [];
648
- this.changeLog = '';
649
- this.version = '';
650
- this.commandOptions = commandOptions;
651
- }
652
- async parseCommits() {
653
- const { workspace } = Shared.impl();
654
- const { packageFolderName, packageName, commandOptions } = this;
655
- let params = ['tag', '--list', `'${packageName}@*'`, '--sort', '-v:refname'];
656
- const { stdout: tags } = await Shell.exec('git', params);
657
- const [latestTag] = tags.split('\n');
658
- Logger.log(chalk.yellow(`Last Release Tag`) + `: ${latestTag || '<none>'}`);
659
- params = ['--no-pager', 'log', `${latestTag}..HEAD`, `--format=%B%n${HASH}%n%H${SUFFIX}`];
660
- let { stdout } = await Shell.exec('git', params);
661
- let skipGetLog = false;
662
- if (latestTag) {
663
- const log1 = await Shell.exec('git', ['rev-parse', latestTag]);
664
- const log2 = await Shell.exec('git', ['--no-pager', 'log', '-1', '--format=%H']);
665
- if (log1.stdout === log2.stdout) {
666
- skipGetLog = true;
667
- }
668
- }
669
- if (!skipGetLog && !stdout) {
670
- if (latestTag) {
671
- params.splice(2, 1, `${latestTag}`);
672
- }
673
- else {
674
- params.splice(2, 1, 'HEAD');
675
- }
676
- ({ stdout } = await Shell.exec('git', params));
677
- }
678
- const allowTypes = ['feat', `fix`, `break change`, `style`, `perf`, `types`, `refactor`, `chore`];
679
- const rePlugin = new RegExp(`^(${allowTypes.join('|')})${workspace ? `\\(${packageFolderName}\\)` : '(\\(.+\\))?'}: .*`, 'i');
680
- const allCommits = stdout.split(SUFFIX);
681
- const commits = allCommits
682
- .filter((commit) => {
683
- const chunk = commit.trim();
684
- return chunk && rePlugin.test(chunk);
685
- })
686
- .map((commit) => {
687
- const node = parser.sync(commit);
688
- const body = (node.body || node.footer);
689
- if (!node.type)
690
- node.type = parser.sync(node.header?.replace(/\(.+\)!?:/, ':') || '').type;
691
- if (!node.hash)
692
- node.hash = commit.split(HASH).pop()?.trim();
693
- node.breaking = reBreaking.test(body) || /!:/.test(node.header);
694
- node.effect = false;
695
- node.custom = false;
696
- return node;
697
- });
698
- if (!commits.length) {
699
- Logger.log(chalk.red(`No Commits Found.`));
700
- }
701
- else {
702
- Logger.log(chalk.yellow(`Found `)
703
- + chalk.bold(`${allCommits.length}`)
704
- + ` Commits, `
705
- + chalk.bold(`${commits.length}`)
706
- + ' Commits Valid');
707
- }
708
- const { skipUpdatePackage } = commandOptions;
709
- if (commits.length && skipUpdatePackage) {
710
- let skip = false;
711
- if (typeof skipUpdatePackage === 'boolean' && skipUpdatePackage) {
712
- let result = await prompt([
713
- {
714
- type: 'confirm',
715
- name: 'skip',
716
- message: `Skip Update(${this.packageName}@${this.packageOptions.version}):`,
717
- default: true
718
- }
719
- ]);
720
- skip = result.skip;
721
- }
722
- else if (typeof skipUpdatePackage === 'string'
723
- && (skipUpdatePackage === '**'
724
- || skipUpdatePackage.split(',').includes(this.packageName))) {
725
- skip = true;
726
- }
727
- if (skip) {
728
- Logger.log(chalk.red(`Skipping Update\n`));
729
- return;
730
- }
731
- }
732
- await this.updateVersion();
733
- await this.updateCommits(commits);
734
- const { forceUpdatePackage } = commandOptions;
735
- if (!commits.length && forceUpdatePackage) {
736
- let force = false;
737
- if (typeof forceUpdatePackage === 'boolean' && forceUpdatePackage) {
738
- let result = await prompt([
739
- {
740
- type: 'confirm',
741
- name: 'force',
742
- message: `Force Update(${this.packageName}@${this.packageOptions.version}):`,
743
- default: true
744
- }
745
- ]);
746
- force = result.force;
747
- }
748
- else if (typeof forceUpdatePackage === 'string'
749
- && (forceUpdatePackage === '**'
750
- || forceUpdatePackage.split(',').includes(this.packageName))) {
751
- force = true;
752
- }
753
- if (force) {
754
- const oldVersion = this.packageOptions.version;
755
- const versionChanged = `\`${oldVersion}\` -> \`${this.version}\``;
756
- this.commits = [
757
- {
758
- type: 'chore',
759
- header: `chore(${this.packageFolderName || 'release'}): force-publish ${versionChanged}`,
760
- hash: '',
761
- effect: false,
762
- breaking: false,
763
- custom: true
764
- }
765
- ];
766
- this.changeLog = `### Force Update Package\n\n- ${versionChanged}`.trim();
767
- }
768
- }
769
- }
770
- rebuildChangeLog(commits) {
771
- const { packageDir } = this;
772
- const { homepage, workspace } = Shared.impl();
773
- const logPath = path.resolve(packageDir, './CHANGELOG.md');
774
- const logFile = fs.existsSync(logPath) ? fs.readFileSync(logPath, 'utf-8') : '';
775
- const notes = {
776
- breaking: [],
777
- features: [],
778
- fixes: [],
779
- updates: []
780
- };
781
- const closeRegxp = /\(?(closes? )\(?#((\d+))\)/ig;
782
- const pullRegxp = /(?<!closes? )\((#(\d+))\)/ig;
783
- for (const commit of commits) {
784
- const { effect, breaking, hash, header, type } = commit;
785
- const ref = !hash || pullRegxp.test(header)
786
- ? ''
787
- : ` ([${hash?.substring(0, 7)}](${homepage}/commit/${hash}))`;
788
- let message = header?.trim();
789
- if (workspace && !effect) {
790
- message = message.replace(/\(.+\)!?:/, ':');
791
- }
792
- message = message
793
- .replace(pullRegxp, `[$1](${homepage}/pull/$2)`)
794
- .replace(closeRegxp, `[$1$2](${homepage}/issues/$2)`) + ref;
795
- if (breaking) {
796
- notes.breaking.push(message);
797
- }
798
- else if (type === 'fix') {
799
- notes.fixes.push(message);
800
- }
801
- else if (type === 'feat') {
802
- notes.features.push(message);
803
- }
804
- else {
805
- notes.updates.push(message);
806
- }
807
- }
808
- Object.keys(notes).forEach(i => {
809
- notes[i] = notes[i].filter((j) => {
810
- return !logFile.includes(j);
811
- });
812
- });
813
- const parts = [
814
- notes.breaking.length ? `### Breaking Changes\n\n- ${notes.breaking.join('\n- ')}`.trim() : '',
815
- notes.fixes.length ? `### Bugfixes\n\n- ${notes.fixes.join('\n- ')}`.trim() : '',
816
- notes.features.length ? `### Features\n\n- ${notes.features.join('\n- ')}`.trim() : '',
817
- notes.updates.length ? `### Updates\n\n- ${notes.updates.join('\n- ')}`.trim() : ''
818
- ].filter(Boolean);
819
- const newLog = parts.join('\n\n');
820
- return !parts.length || logFile.includes(newLog)
821
- ? ''
822
- : newLog;
823
- }
824
- async updateVersion() {
825
- const { packageOptions, commits, commandOptions } = this;
826
- const { version } = packageOptions;
827
- let newVersion = '';
828
- if (commandOptions.customVersion) {
829
- newVersion = commandOptions.customVersion;
830
- if (!(/\d+.\d+.\d+/.test(newVersion)) || version === newVersion) {
831
- let result = await prompt([
832
- {
833
- type: 'input',
834
- name: 'version',
835
- message: `Custom Update Version(${this.packageName}@${version}):`,
836
- default: '',
837
- validate: (answer) => {
838
- if (!(/\d+.\d+.\d+/.test(answer))) {
839
- return 'Version Should Be Like x.x.x';
840
- }
841
- if (answer === version) {
842
- return 'Version Should Be Diff Than Before';
843
- }
844
- return true;
845
- }
846
- }
847
- ]);
848
- newVersion = result.version;
849
- }
850
- }
851
- else {
852
- const intersection = [
853
- commandOptions.major && 'major',
854
- commandOptions.minor && 'minor',
855
- commandOptions.patch && 'patch'
856
- ].filter(i => !!i);
857
- if (intersection.length) {
858
- newVersion = semver.inc(version, intersection[0]) || '';
859
- }
860
- else {
861
- const types = new Set(commits.map(({ type }) => type));
862
- const breaking = commits.some((commit) => !!commit.breaking);
863
- const level = breaking
864
- ? 'major'
865
- : types.has('feat')
866
- ? 'minor'
867
- : 'patch';
868
- newVersion = semver.inc(version, level) || '';
869
- }
870
- }
871
- this.version = newVersion;
872
- }
873
- isChanged() {
874
- return !!this.commits.length;
875
- }
876
- async updateCommits(commits, source) {
877
- if (!commits.length)
878
- return;
879
- const { packageName } = this;
880
- const olds = this.commits.map(i => JSON.stringify(i));
881
- const newCommits = commits
882
- .filter(i => {
883
- return !olds.includes(JSON.stringify(i));
884
- })
885
- .map(j => {
886
- return {
887
- ...j,
888
- effect: !!source
889
- };
890
- });
891
- if (newCommits.length && this.commits.length) {
892
- this.commits = this.commits.filter(i => !i.custom);
893
- }
894
- const commits$ = this.commits.concat(newCommits);
895
- if (source) {
896
- Logger.log(chalk.magenta(`MERGE COMMITS: `)
897
- + chalk.bold(`${commits.length}`) + ` Commits. `
898
- + 'merge ' + chalk.yellow(source) + ' into ' + chalk.green(packageName));
899
- }
900
- else {
901
- Logger.log(``);
902
- }
903
- const changeLog = this.rebuildChangeLog(commits$);
904
- if (changeLog) {
905
- this.commits = commits$;
906
- this.changeLog = changeLog;
907
- }
908
- else if (commits.length) {
909
- Logger.log(chalk.red(`${commits.length} Commits Already Exists.`));
910
- }
911
- }
912
- async updatePackageOptions(relationVerisons = {}) {
913
- if (!this.isChanged())
914
- return;
915
- const { packageDir, packageOptions, commandOptions } = this;
916
- const { dependencies, devDependencies } = packageOptions;
917
- const newVersion = this.version;
918
- Logger.log(chalk.yellow(`New Version: `) + `${newVersion}`);
919
- packageOptions.version = newVersion;
920
- if (Object.keys(this.packageRelation).length) {
921
- for (let packageName$ in relationVerisons) {
922
- let newVersion$ = relationVerisons[packageName$];
923
- if (dependencies?.[packageName$]) {
924
- dependencies[packageName$] = newVersion$;
925
- }
926
- if (devDependencies?.[packageName$]) {
927
- devDependencies[packageName$] = newVersion$;
928
- }
929
- }
930
- }
931
- if (commandOptions.dryRun) {
932
- Logger.log(chalk.yellow(`Skipping package.json Update`));
933
- return;
934
- }
935
- Logger.log(chalk.yellow(`Updating `) + 'package.json');
936
- fs.outputFileSync(`${packageDir}/package.json`, JSON.stringify(packageOptions, null, 2));
937
- }
938
- async updateChangelog() {
939
- if (!this.isChanged())
940
- return;
941
- const { packageName, packageDir, packageOptions, commandOptions } = this;
942
- const title = `# ${packageName} ChangeLog`;
943
- const [date] = new Date().toISOString().split('T');
944
- const logPath = path.resolve(packageDir, './CHANGELOG.md');
945
- const logFile = fs.existsSync(logPath) ? fs.readFileSync(logPath, 'utf-8') : '';
946
- const oldNotes = logFile.startsWith(title) ? logFile.slice(title.length).trim() : logFile;
947
- const parts = [
948
- `## v${packageOptions.version}`,
949
- `_${date}_`,
950
- this.changeLog
951
- ].filter(Boolean);
952
- const newLog = parts.join('\n\n');
953
- if (commandOptions.dryRun) {
954
- Logger.log(chalk.yellow(`New ChangeLog:`) + `\n${newLog}`);
955
- return;
956
- }
957
- Logger.log(chalk.yellow(`Updating `) + `CHANGELOG.md`);
958
- let content = [title, newLog, oldNotes].filter(Boolean).join('\n\n');
959
- if (!content.endsWith('\n'))
960
- content += '\n';
961
- fs.writeFileSync(logPath, content, 'utf-8');
962
- }
963
- async test() {
964
- if (!this.isChanged())
965
- return;
966
- const { commandOptions } = this;
967
- if (commandOptions.dryRun) {
968
- Logger.log(chalk.yellow('Skipping Test'));
969
- return;
970
- }
971
- else {
972
- Logger.log(chalk.yellow('Test...'));
973
- }
974
- await Shell.exec(`npm run test -- --package-name ${this.packageName}`);
975
- }
976
- async build() {
977
- if (!this.isChanged())
978
- return;
979
- const { commandOptions } = this;
980
- if (commandOptions.dryRun) {
981
- Logger.log(chalk.yellow('Skipping Build'));
982
- return;
983
- }
984
- else {
985
- Logger.log(chalk.yellow('Build...'));
986
- }
987
- await Shell.exec(`npm run build -- --package-name ${this.packageName}`);
988
- }
989
- async publish() {
990
- if (!this.isChanged())
991
- return;
992
- const { commandOptions, packageDir } = this;
993
- if (commandOptions.dryRun || !commandOptions.publish) {
994
- Logger.log(chalk.yellow(`Skipping Publish`));
995
- return;
996
- }
997
- Logger.log(chalk.cyan(`\n Publishing to NPM`));
998
- await Shell.spawn('npm', ['publish', '--no-git-checks', '--access', 'public'], {
999
- cwd: packageDir
1000
- });
1001
- }
1002
- async tag() {
1003
- if (!this.isChanged())
1004
- return;
1005
- const { commandOptions, packageDir } = this;
1006
- const { packageName, packageOptions } = this;
1007
- if (commandOptions.dryRun || !commandOptions.tag) {
1008
- Logger.log(chalk.yellow(`Skipping Git Tag`));
1009
- return;
1010
- }
1011
- const tagName = `${packageName}@${packageOptions.version}`;
1012
- Logger.log(chalk.blue(`\n Tagging`) + chalk.grey(`${tagName}`));
1013
- await Shell.spawn('git', ['tag', tagName], {
1014
- cwd: packageDir
1015
- });
1016
- }
1017
- async process() {
1018
- const { workspace } = Shared.impl();
1019
- const { packageName, packageDir, packageFolderName } = this;
1020
- if (!packageDir || !fs.pathExists(packageDir)) {
1021
- throw new RangeError(`Could not find directory for package: ${packageFolderName}`);
1022
- }
1023
- Logger.log(chalk.cyan(`Releasing ${packageName}`) + ' from ' + chalk.grey(`${workspace}/${packageFolderName}`));
1024
- await this.parseCommits();
1025
- return this;
1026
- }
1027
- }
1028
- const releaser = (options, commandOptions) => {
1029
- return new Releaser(options, commandOptions);
1030
- };
1031
-
1032
- const run = (options) => Utils.autoCatch(async () => {
1033
- const locals = Shared.impl();
1034
- if (options.dryRun) {
1035
- Logger.log(chalk.magenta(`DRY RUN: `)
1036
- + 'No files will be modified.');
1037
- }
1038
- let inputs = [];
1039
- if (locals.workspace) {
1040
- inputs = locals.normalizePackageFolderNames;
1041
- }
1042
- else {
1043
- inputs = [''];
1044
- }
1045
- const instances = {};
1046
- await inputs
1047
- .reduce((preProcess, packageFolderName) => {
1048
- preProcess = preProcess
1049
- .then(() => releaser(packageFolderName, options).process())
1050
- .then((instance) => {
1051
- instances[packageFolderName] = instance;
1052
- });
1053
- return preProcess;
1054
- }, Promise.resolve());
1055
- Logger.log(chalk.blue(`---------------------\n`));
1056
- let message = `chore(release): publish\n\n`;
1057
- let relationVerisons = {};
1058
- await inputs.reduce((preProcess, packageFolderName) => {
1059
- const instance = instances[packageFolderName];
1060
- instance.packageRelation.forEach(i => {
1061
- let packageFolderName$ = Shared.getPackageFolderName(i);
1062
- let instance$ = instances[packageFolderName$];
1063
- if (instance$.commits.length > 0) {
1064
- instance.updateCommits(instance$.commits, instance$.packageName);
1065
- }
1066
- });
1067
- if (instance.commits.length) {
1068
- preProcess = preProcess
1069
- .then(() => Logger.log(chalk.magenta(`CHANGED: `) + instance.packageName))
1070
- .then(() => instance.test())
1071
- .then(() => instance.build())
1072
- .then(() => instance.updatePackageOptions(relationVerisons))
1073
- .then(() => instance.updateChangelog())
1074
- .then(() => {
1075
- message += `- ${instance.packageName}@${instance.packageOptions.version}\n`;
1076
- relationVerisons[instance.packageName] = `^${instance.packageOptions.version}`;
1077
- });
1078
- }
1079
- return preProcess;
1080
- }, Promise.resolve());
1081
- Logger.log(chalk.blue(`\n---------------------\n`));
1082
- const isChanged = Object.keys(relationVerisons).length;
1083
- if (!isChanged) {
1084
- Logger.log(chalk.magenta(`COMMIT: `) + 'Nothing Chanaged Found.');
1085
- }
1086
- else if (options.dryRun || !options.commit) {
1087
- Logger.log(chalk.magenta(`COMMIT: `) + chalk.yellow(`Skipping Git Commit`) + `\n${message}`);
1088
- }
1089
- else {
1090
- Logger.log(chalk.magenta(`CHANGED: `) + `pnpm-lock.yaml`);
1091
- await Shell.spawn('npx', ['pnpm', 'install', '--lockfile-only']);
1092
- Logger.log(chalk.magenta(`COMMIT: `) + `CHANGELOG.md, package.json, pnpm-lock.yaml`);
1093
- await Shell.spawn('git', ['add', process.cwd()]);
1094
- await Shell.spawn('git', ['commit', '--m', `'${message}'`]);
1095
- }
1096
- await inputs
1097
- .reduce((preProcess, packageFolderName) => {
1098
- const instance = instances[packageFolderName];
1099
- preProcess = preProcess
1100
- .then(() => instance.publish())
1101
- .then(() => instance.tag());
1102
- return preProcess;
1103
- }, Promise.resolve());
1104
- Logger.log(chalk.blue(`\n---------------------\n`));
1105
- if (options.dryRun || !options.push) {
1106
- Logger.log(chalk.magenta(`FINISH: `) + 'Skipping Git Push');
1107
- }
1108
- else if (!isChanged) {
1109
- Logger.log(chalk.magenta(`FINISH: `) + 'Nothing Chanaged.');
1110
- }
1111
- else {
1112
- await Shell.spawn('git', ['push']);
1113
- await Shell.spawn('git', ['push', '--tags']);
1114
- }
1115
- if (options.dryRun) {
1116
- Logger.log(chalk.green('NO DRY RUN WAY: ')
1117
- + chalk.grey(`npm run release -- --no-dry-run\n`));
1118
- }
1119
- }, {
1120
- onError: (e) => {
1121
- if (typeof e === 'number' && e === 1) {
1122
- Logger.error('发布失败');
1123
- }
1124
- else {
1125
- Logger.error(e);
1126
- }
1127
- process.exit(1);
1128
- }
1129
- });
3
+ import * as Releaser from '@deot/dev-releaser';
4
+ import * as Builder from '@deot/dev-builder';
5
+ import * as Tester from '@deot/dev-tester';
6
+ import * as Adder from '@deot/dev-adder';
7
+ import * as Linker from '@deot/dev-linker';
8
+ import * as Dever from '@deot/dev-dever';
1130
9
 
1131
10
  const require = createRequire(import.meta.url);
1132
11
  program
@@ -1138,28 +17,28 @@ program
1138
17
  .alias('l')
1139
18
  .description('pnpm link')
1140
19
  .option('--dry-run [boolean]', 'Dry Run')
1141
- .action(run$5);
20
+ .action(Linker.run);
1142
21
  program
1143
22
  .command('add')
1144
23
  .alias('a')
1145
24
  .description('add dep or create package')
1146
25
  .option('--dry-run [boolean]', 'Dry Run')
1147
- .action(run$4);
26
+ .action(Adder.run);
1148
27
  program
1149
28
  .command('dev')
1150
29
  .alias('d')
1151
30
  .description('dev')
1152
31
  .option('-p, --package-name <string>', 'Select PackageName')
1153
32
  .option('--dry-run [boolean]', 'Dry Run')
1154
- .action(run$2);
33
+ .action(Dever.run);
1155
34
  program
1156
35
  .command('build')
1157
36
  .alias('b')
1158
37
  .description('build')
1159
38
  .option('-p, --package-name <string>', 'Select packageName')
1160
- .option('--output <string>', 'Output', 'es,cjs')
39
+ .option('--formats <string>', 'Formats(Output)', 'es,cjs')
1161
40
  .option('--dry-run [boolean]', 'Dry Run')
1162
- .action(run$1);
41
+ .action(Builder.run);
1163
42
  program
1164
43
  .command('release')
1165
44
  .alias('r')
@@ -1175,7 +54,8 @@ program
1175
54
  .option('--patch [boolean]', 'Patch')
1176
55
  .option('--major [boolean]', 'Major')
1177
56
  .option('--minor [boolean]', 'Minor')
1178
- .action(run);
57
+ .option('--keep-last-tag [boolean]', 'Clean Tags, Keep Only Last Tag')
58
+ .action(Releaser.run);
1179
59
  program
1180
60
  .command('test')
1181
61
  .alias('t')
@@ -1183,7 +63,7 @@ program
1183
63
  .option('-p, --package-name <string>', 'Select PackageName')
1184
64
  .option('-w, --watch [boolean]', 'Watch Test')
1185
65
  .option('--dry-run [boolean]', 'Dry Run')
1186
- .action(run$3);
66
+ .action(Tester.run);
1187
67
  program.parse(process.argv);
1188
68
  if (!program.args.length) {
1189
69
  program.help();