maishu-scripts 1.4.2 → 1.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,436 @@
1
+ import { create, generateDeclarationFile } from './babel-compile';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+
5
+ describe('compileFile (via create)', () => {
6
+ let testDir: string;
7
+ let fixturesDir: string;
8
+ let outDir: string;
9
+ let sourceFile: string;
10
+
11
+ const defaultBabelOptions: any = {
12
+ presets: ['@babel/preset-typescript'],
13
+ ast: true,
14
+ code: false,
15
+ };
16
+
17
+ beforeAll(() => {
18
+ fixturesDir = path.join(__dirname, '..', '..', '..', 'test', 'fixtures', 'compile');
19
+ outDir = path.join(fixturesDir, 'out');
20
+
21
+ if (!fs.existsSync(fixturesDir)) {
22
+ fs.mkdirSync(fixturesDir, { recursive: true });
23
+ }
24
+
25
+ sourceFile = path.join(fixturesDir, 'simple.ts');
26
+ const sourceContent = `
27
+ export interface Config {
28
+ name: string;
29
+ value: number;
30
+ }
31
+
32
+ export function greet(name: string): string {
33
+ return \`Hello, \${name}!\`;
34
+ }
35
+
36
+ export const VERSION = '1.0.0';
37
+ `;
38
+ fs.writeFileSync(sourceFile, sourceContent);
39
+ });
40
+
41
+ afterEach(async () => {
42
+ if (fs.existsSync(outDir)) {
43
+ fs.rmSync(outDir, { recursive: true, force: true });
44
+ }
45
+ });
46
+
47
+ afterAll(() => {
48
+ if (fs.existsSync(sourceFile)) {
49
+ fs.rmSync(sourceFile, { force: true });
50
+ }
51
+ if (fs.existsSync(fixturesDir)) {
52
+ fs.rmSync(fixturesDir, { recursive: true, force: true });
53
+ }
54
+ });
55
+
56
+ describe('basic compilation', () => {
57
+ test('should compile .ts file and generate output', async () => {
58
+ expect(fs.existsSync(sourceFile)).toBeTruthy();
59
+
60
+ const compileFile = create({
61
+ defaultBabelOptions: {
62
+ ...defaultBabelOptions,
63
+ sourceMaps: false,
64
+ }
65
+ });
66
+
67
+ await compileFile(sourceFile, outDir, fixturesDir);
68
+
69
+ const expectedOutput = path.join(outDir, 'simple.js');
70
+ expect(fs.existsSync(expectedOutput)).toBeTruthy();
71
+
72
+ const content = fs.readFileSync(expectedOutput, 'utf-8');
73
+ expect(content.length).toBeGreaterThan(0);
74
+ });
75
+
76
+ test('should compile .ts file with source maps', async () => {
77
+ const compileFile = create({
78
+ defaultBabelOptions: {
79
+ ...defaultBabelOptions,
80
+ sourceMaps: true,
81
+ }
82
+ });
83
+
84
+ await compileFile(sourceFile, outDir, fixturesDir);
85
+
86
+ const expectedOutput = path.join(outDir, 'simple.js');
87
+ expect(fs.existsSync(expectedOutput)).toBeTruthy();
88
+
89
+ const mapFile = path.join(outDir, 'simple.js.map');
90
+ expect(fs.existsSync(mapFile)).toBeTruthy();
91
+
92
+ const mapContent = JSON.parse(fs.readFileSync(mapFile, 'utf-8'));
93
+ expect(mapContent.file).toBe('simple.js');
94
+ expect(mapContent.sources).toBeDefined();
95
+ });
96
+
97
+ test('should create output directory if not exists', async () => {
98
+ const nestedOutDir = path.join(fixturesDir, 'nested', 'deep', 'out');
99
+
100
+ const compileFile = create({
101
+ defaultBabelOptions
102
+ });
103
+
104
+ await compileFile(sourceFile, nestedOutDir, fixturesDir);
105
+
106
+ const expectedOutput = path.join(nestedOutDir, 'simple.js');
107
+ expect(fs.existsSync(expectedOutput)).toBeTruthy();
108
+
109
+ fs.rmSync(path.join(fixturesDir, 'nested'), { recursive: true, force: true });
110
+ });
111
+ });
112
+
113
+ describe('error handling', () => {
114
+ test('should warn and return early when source file does not exist', async () => {
115
+ const nonExistentFile = path.join(fixturesDir, 'non-existent.ts');
116
+ const warnSpy = jest.spyOn(console, 'warn').mockImplementation();
117
+
118
+ const compileFile = create({
119
+ defaultBabelOptions
120
+ });
121
+
122
+ await compileFile(nonExistentFile, outDir, fixturesDir);
123
+
124
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Path not exists'));
125
+ warnSpy.mockRestore();
126
+
127
+ const expectedOutput = path.join(outDir, 'non-existent.js');
128
+ expect(fs.existsSync(expectedOutput)).toBeFalsy();
129
+ });
130
+
131
+ test('should throw error when babel transform fails', async () => {
132
+ const invalidFile = path.join(fixturesDir, 'invalid.ts');
133
+ fs.writeFileSync(invalidFile, 'const x: = invalid syntax;');
134
+
135
+ const compileFile = create({
136
+ defaultBabelOptions
137
+ });
138
+
139
+ await expect(compileFile(invalidFile, outDir, fixturesDir)).rejects.toThrow();
140
+
141
+ fs.rmSync(invalidFile, { force: true });
142
+ });
143
+ });
144
+
145
+ describe('output extensions', () => {
146
+ test('should output .mjs file when specified', async () => {
147
+ const compileFile = create({
148
+ defaultBabelOptions,
149
+ outExt: '.mjs'
150
+ });
151
+
152
+ await compileFile(sourceFile, outDir, fixturesDir);
153
+
154
+ const expectedOutput = path.join(outDir, 'simple.mjs');
155
+ expect(fs.existsSync(expectedOutput)).toBeTruthy();
156
+ });
157
+
158
+ test('should output .cjs file when specified', async () => {
159
+ const compileFile = create({
160
+ defaultBabelOptions,
161
+ outExt: '.cjs'
162
+ });
163
+
164
+ await compileFile(sourceFile, outDir, fixturesDir);
165
+
166
+ const expectedOutput = path.join(outDir, 'simple.cjs');
167
+ expect(fs.existsSync(expectedOutput)).toBeTruthy();
168
+ });
169
+ });
170
+
171
+ describe('declaration file generation', () => {
172
+ test('should generate declaration file when generateDeclaration is true', async () => {
173
+ const declSourceFile = path.join(fixturesDir, 'decl-test.ts');
174
+ const sourceContent = `
175
+ export interface User {
176
+ id: number;
177
+ name: string;
178
+ }
179
+
180
+ export function greet(name: string): string {
181
+ return \`Hello, \${name}\`;
182
+ }
183
+ `;
184
+ fs.writeFileSync(declSourceFile, sourceContent);
185
+
186
+ const compileFile = create({
187
+ defaultBabelOptions,
188
+ generateDeclaration: true
189
+ });
190
+
191
+ await compileFile(declSourceFile, outDir, fixturesDir);
192
+
193
+ const expectedJs = path.join(outDir, 'decl-test.js');
194
+ const expectedDecl = path.join(outDir, 'decl-test.d.ts');
195
+
196
+ expect(fs.existsSync(expectedJs)).toBeTruthy();
197
+ expect(fs.existsSync(expectedDecl)).toBeTruthy();
198
+
199
+ const declContent = fs.readFileSync(expectedDecl, 'utf-8');
200
+ expect(declContent).toContain('User');
201
+ expect(declContent).toContain('greet');
202
+
203
+ fs.rmSync(declSourceFile, { force: true });
204
+ });
205
+
206
+ test('should not generate declaration file when generateDeclaration is false', async () => {
207
+ const noDeclSourceFile = path.join(fixturesDir, 'no-decl-test.ts');
208
+ const sourceContent = `
209
+ export interface Config {
210
+ key: string;
211
+ }
212
+ `;
213
+ fs.writeFileSync(noDeclSourceFile, sourceContent);
214
+
215
+ const compileFile = create({
216
+ defaultBabelOptions,
217
+ generateDeclaration: false
218
+ });
219
+
220
+ await compileFile(noDeclSourceFile, outDir, fixturesDir);
221
+
222
+ const expectedJs = path.join(outDir, 'no-decl-test.js');
223
+ const expectedDecl = path.join(outDir, 'no-decl-test.d.ts');
224
+
225
+ expect(fs.existsSync(expectedJs)).toBeTruthy();
226
+ expect(fs.existsSync(expectedDecl)).toBeFalsy();
227
+
228
+ fs.rmSync(noDeclSourceFile, { force: true });
229
+ });
230
+ });
231
+
232
+ describe('source map behavior', () => {
233
+ test('should generate map file when sourceMaps is enabled', async () => {
234
+ const compileWithMaps = create({
235
+ defaultBabelOptions: {
236
+ ...defaultBabelOptions,
237
+ sourceMaps: true,
238
+ }
239
+ });
240
+ await compileWithMaps(sourceFile, outDir, fixturesDir);
241
+
242
+ const mapFile = path.join(outDir, 'simple.js.map');
243
+ expect(fs.existsSync(mapFile)).toBeTruthy();
244
+
245
+ const outputFile = path.join(outDir, 'simple.js');
246
+ const content = fs.readFileSync(outputFile, 'utf-8');
247
+ expect(content).toContain('sourceMappingURL=');
248
+ });
249
+
250
+ test('should not generate map file when sourceMaps is disabled', async () => {
251
+ const compileWithoutMaps = create({
252
+ defaultBabelOptions: {
253
+ ...defaultBabelOptions,
254
+ sourceMaps: false,
255
+ }
256
+ });
257
+ await compileWithoutMaps(sourceFile, outDir, fixturesDir);
258
+
259
+ const outputFile = path.join(outDir, 'simple.js');
260
+ expect(fs.existsSync(outputFile)).toBeTruthy();
261
+
262
+ const content = fs.readFileSync(outputFile, 'utf-8');
263
+ expect(content).not.toContain('sourceMappingURL=');
264
+ });
265
+ });
266
+ });
267
+
268
+ describe('generateDeclarationFile', () => {
269
+ let testDir: string;
270
+ let fixturesDir: string;
271
+
272
+ beforeAll(() => {
273
+ testDir = path.join(__dirname, '..', '..', '..', 'test');
274
+ fixturesDir = path.join(testDir, 'fixtures', 'declaration');
275
+
276
+ if (!fs.existsSync(fixturesDir)) {
277
+ fs.mkdirSync(fixturesDir, { recursive: true });
278
+ }
279
+ });
280
+
281
+ afterEach(() => {
282
+ if (fs.existsSync(fixturesDir)) {
283
+ fs.readdirSync(fixturesDir).forEach(file => {
284
+ fs.rmSync(path.join(fixturesDir, file), { force: true });
285
+ });
286
+ }
287
+ });
288
+
289
+ afterAll(() => {
290
+ if (fs.existsSync(fixturesDir)) {
291
+ fs.rmSync(fixturesDir, { recursive: true, force: true });
292
+ }
293
+ });
294
+
295
+ test('should generate declaration file for .ts source', async () => {
296
+ const sourcePath = path.join(fixturesDir, 'sample.ts');
297
+ fs.writeFileSync(sourcePath, 'export const x: number = 1;');
298
+
299
+ const targetPath = path.join(fixturesDir, 'sample.js');
300
+ const outExt: '.js' = '.js';
301
+ const expectedDeclPath = path.join(fixturesDir, 'sample.d.ts');
302
+
303
+ await generateDeclarationFile(path.resolve(), sourcePath, targetPath, outExt);
304
+
305
+ expect(fs.existsSync(expectedDeclPath)).toBeTruthy();
306
+ const content = fs.readFileSync(expectedDeclPath, 'utf-8');
307
+ expect(content.length).toBeGreaterThan(0);
308
+ });
309
+
310
+ test('should generate declaration file for .tsx source', async () => {
311
+ const tsxSource = path.join(fixturesDir, 'component.tsx');
312
+ const tsxContent = `
313
+ export interface ComponentProps {
314
+ name: string;
315
+ value?: number;
316
+ }
317
+
318
+ export function Component(props: ComponentProps): string {
319
+ return props.name;
320
+ }
321
+ `;
322
+ fs.writeFileSync(tsxSource, tsxContent);
323
+
324
+ const targetPath = path.join(fixturesDir, 'component.js');
325
+ const outExt: '.js' = '.js';
326
+ const expectedDeclPath = path.join(fixturesDir, 'component.d.ts');
327
+
328
+ await generateDeclarationFile(path.resolve(), tsxSource, targetPath, outExt);
329
+
330
+ expect(fs.existsSync(expectedDeclPath)).toBeTruthy();
331
+ const content = fs.readFileSync(expectedDeclPath, 'utf-8');
332
+ expect(content).toContain('ComponentProps');
333
+ expect(content).toContain('Component');
334
+ });
335
+
336
+ test('should skip for .js source file', async () => {
337
+ const sourcePath = path.join(fixturesDir, 'sample.js');
338
+ fs.writeFileSync(sourcePath, 'const x = 1;');
339
+
340
+ const targetPath = path.join(fixturesDir, 'sample.js');
341
+ const outExt: '.js' = '.js';
342
+ const expectedDeclPath = path.join(fixturesDir, 'sample.d.ts');
343
+
344
+ await generateDeclarationFile(path.resolve(), sourcePath, targetPath, outExt);
345
+
346
+ expect(fs.existsSync(expectedDeclPath)).toBeFalsy();
347
+ });
348
+
349
+ test('should skip for .mjs source file', async () => {
350
+ const sourcePath = path.join(fixturesDir, 'sample.mjs');
351
+ fs.writeFileSync(sourcePath, 'export const x = 1;');
352
+
353
+ const targetPath = path.join(fixturesDir, 'sample.mjs');
354
+ const outExt: '.mjs' = '.mjs';
355
+ const expectedDeclPath = path.join(fixturesDir, 'sample.d.ts');
356
+
357
+ await generateDeclarationFile(path.resolve(), sourcePath, targetPath, outExt);
358
+
359
+ expect(fs.existsSync(expectedDeclPath)).toBeFalsy();
360
+ });
361
+
362
+ test('should handle .cjs extension correctly', async () => {
363
+ const sourcePath = path.join(fixturesDir, 'sample.cjs');
364
+ fs.writeFileSync(sourcePath, 'module.exports = {};');
365
+
366
+ const targetPath = path.join(fixturesDir, 'sample.cjs');
367
+ const outExt: '.cjs' = '.cjs';
368
+ const expectedDeclPath = path.join(fixturesDir, 'sample.d.ts');
369
+
370
+ await generateDeclarationFile(path.resolve(), sourcePath, targetPath, outExt);
371
+
372
+ expect(fs.existsSync(expectedDeclPath)).toBeFalsy();
373
+ });
374
+
375
+ test('should generate declaration for module with exports', async () => {
376
+ const sourcePath = path.join(fixturesDir, 'exports.ts');
377
+ const exportsContent = `
378
+ export interface User {
379
+ id: number;
380
+ name: string;
381
+ }
382
+
383
+ export type Status = 'active' | 'inactive';
384
+
385
+ export function greet(name: string): string {
386
+ return \`Hello, \${name}!\`;
387
+ }
388
+
389
+ export const VERSION = '1.0.0';
390
+ `;
391
+ fs.writeFileSync(sourcePath, exportsContent);
392
+
393
+ const targetPath = path.join(fixturesDir, 'exports.js');
394
+ const outExt: '.js' = '.js';
395
+ const expectedDeclPath = path.join(fixturesDir, 'exports.d.ts');
396
+
397
+ await generateDeclarationFile(path.resolve(), sourcePath, targetPath, outExt);
398
+
399
+ expect(fs.existsSync(expectedDeclPath)).toBeTruthy();
400
+ const content = fs.readFileSync(expectedDeclPath, 'utf-8');
401
+ expect(content).toContain('User');
402
+ expect(content).toContain('Status');
403
+ expect(content).toContain('greet');
404
+ expect(content).toContain('VERSION');
405
+ });
406
+
407
+ test('should handle file with type errors and still generate declaration', async () => {
408
+ const sourcePath = path.join(fixturesDir, 'with-error.ts');
409
+ const errorContent = `
410
+ export function add(a: number, b: string): number {
411
+ return a + b;
412
+ }
413
+ `;
414
+ fs.writeFileSync(sourcePath, errorContent);
415
+
416
+ const targetPath = path.join(fixturesDir, 'with-error.js');
417
+ const outExt: '.js' = '.js';
418
+ const expectedDeclPath = path.join(fixturesDir, 'with-error.d.ts');
419
+
420
+ await expect(generateDeclarationFile(path.resolve(), sourcePath, targetPath, outExt)).resolves.not.toThrow();
421
+ expect(fs.existsSync(expectedDeclPath)).toBeTruthy();
422
+ });
423
+
424
+ test('should correctly replace output extension with .d.ts', async () => {
425
+ const sourcePath = path.join(fixturesDir, 'test.ts');
426
+ fs.writeFileSync(sourcePath, 'export const x = 1;');
427
+
428
+ const targetPath = path.join(fixturesDir, 'output.mjs');
429
+ const outExt: '.mjs' = '.mjs';
430
+ const expectedDeclPath = path.join(fixturesDir, 'output.d.ts');
431
+
432
+ await generateDeclarationFile(path.resolve(), sourcePath, targetPath, outExt);
433
+
434
+ expect(fs.existsSync(expectedDeclPath)).toBeTruthy();
435
+ });
436
+ });
@@ -2,6 +2,7 @@
2
2
  import * as babel from "@babel/core";
3
3
  import * as fs from "fs";
4
4
  import * as path from "path";
5
+ import * as ts from "typescript";
5
6
  import { errors } from "../errors";
6
7
  import { ProjectCompiler } from "../project-compiler";
7
8
  import { FileAction, JavaScriptExtension } from "../../types";
@@ -9,32 +10,41 @@ import { FileAction, JavaScriptExtension } from "../../types";
9
10
  // const outExt = ProjectCompiler.tsOutExt;
10
11
 
11
12
 
12
- export function create(defaultBabelOptions?: babel.TransformOptions, outExit?: JavaScriptExtension): FileAction {
13
+ export function create(defaultBabelOptions?: babel.TransformOptions & { declaration?: boolean }, outExt?: JavaScriptExtension): FileAction {
13
14
  const action: FileAction = (sourcePath: string, outputPath: string, projectPath: string) => {
14
- outExit = outExit || ".js";
15
- if (defaultBabelOptions) {
16
- return compileFile(sourcePath, outputPath, projectPath, defaultBabelOptions, outExit);
15
+ outExt = outExt || ".js";
16
+
17
+ let babelOptions = defaultBabelOptions;
18
+ if (!babelOptions) {
19
+ // 如果没有 babelOptions,则尝试从项目目录查找 babel 配置文件,如果没有,则使用默认配置。
20
+ // let babelOptions: babel.TransformOptions;
21
+ let bablePath: string;
22
+ let sourceDir = path.dirname(sourcePath);
23
+ if (projectPath) {
24
+ let c = ProjectCompiler.getBabelConfig(projectPath, sourceDir);
25
+ bablePath = c.path;
26
+ babelOptions = c.options;
27
+ }
28
+ else {
29
+ babelOptions = ProjectCompiler.getDefaultBabelConfig();
30
+ bablePath = '';
31
+ }
32
+
33
+ babelOptions.filename = sourcePath;
34
+ babelOptions.code = false;
35
+ babelOptions.ast = true;
17
36
  }
18
37
 
19
- // 如果没有 babelOptions,则尝试从项目目录查找 babel 配置文件,如果没有,则使用默认配置。
20
- let babelOptions: babel.TransformOptions;
21
- let bablePath: string;
22
- let sourceDir = path.dirname(sourcePath);
23
- if (projectPath) {
24
- let c = ProjectCompiler.getBabelConfig(projectPath, sourceDir);
25
- bablePath = c.path;
26
- babelOptions = c.options;
38
+ const declaration = babelOptions.declaration || false;
39
+ delete babelOptions.declaration;
40
+ if (declaration) {
41
+ // 如果需要生成声明文件,则调用 ts-compile 模块的生成声明文件方法
42
+ const ext = path.extname(sourcePath);
43
+ let targetPath = path.join(outputPath, path.basename(sourcePath).replace(ext, outExt));
44
+ generateDeclarationFile(projectPath, sourcePath, targetPath, outExt);
27
45
  }
28
- else {
29
- babelOptions = ProjectCompiler.getDefaultBabelConfig();
30
- bablePath = '';
31
- }
32
-
33
- babelOptions.filename = sourcePath;
34
- babelOptions.code = false;
35
- babelOptions.ast = true;
36
46
 
37
- return compileFile(sourcePath, outputPath, projectPath, babelOptions, outExit);
47
+ return compileFile(sourcePath, outputPath, projectPath, babelOptions, outExt);
38
48
  }
39
49
  return action;
40
50
  }
@@ -45,41 +55,16 @@ export function create(defaultBabelOptions?: babel.TransformOptions, outExit?: J
45
55
  * @param outputPath 输出目录
46
56
  * @param projectPath 项目路径
47
57
  * */
48
- async function compileFile(sourcePath: string, outputPath: string, projectPath: string, babelOptions: babel.TransformOptions, outExt: JavaScriptExtension) {
58
+ async function compileFile(sourcePath: string, outputPath: string, projectPath: string, babelOptions: babel.TransformOptions, outExt: JavaScriptExtension, generateDeclaration = false): Promise<void> {
49
59
  if (!sourcePath) throw errors.argumentNull("sourcePath");
50
60
  if (!outputPath) throw errors.argumentNull("outputPath");
51
61
  if (!projectPath) throw errors.argumentNull("projectPath");
52
62
 
53
- // if (!fs.existsSync(sourcePath)) throw errors.pathNotExists(sourcePath);
54
63
  if (!fs.existsSync(sourcePath)) {
55
64
  console.warn(`Path not exists: ${sourcePath}`);
56
65
  return;
57
66
  }
58
67
 
59
- let sourceDir = path.dirname(sourcePath);
60
- // let babelOptions: babel.TransformOptions;
61
- let bablePath: string;
62
- //= projectPath ?
63
- // ProjectCompiler.getBabelConfig(projectPath, sourceDir) : ProjectCompiler.getDefaultBabelConfig();
64
- if (projectPath) {
65
- // let c = ProjectCompiler.getBabelConfig(projectPath, sourceDir);
66
- // bablePath = c.path;
67
- // babelOptions = c.options;
68
- }
69
- else {
70
- // babelOptions = ProjectCompiler.getDefaultBabelConfig();
71
- // bablePath = '';
72
- }
73
-
74
- // babelOptions.filename = sourcePath;
75
- // babelOptions.code = false;
76
- // babelOptions.ast = true;
77
-
78
-
79
- // let fileResult = babel.transformFileSync(sourcePath, {
80
- // filename: sourcePath, code: false, ast: true, plugins,
81
- // presets
82
- // });
83
68
  let fileResult = babel.transformFileSync(sourcePath, babelOptions);
84
69
  if (!fileResult)
85
70
  throw errors.compileError(sourcePath);
@@ -122,6 +107,10 @@ async function compileFile(sourcePath: string, outputPath: string, projectPath:
122
107
 
123
108
  fs.writeFileSync(targetPath, r.code);
124
109
 
110
+ if (generateDeclaration) {
111
+ await generateDeclarationFile(projectPath, sourcePath, targetPath, outExt);
112
+ }
113
+
125
114
  }
126
115
 
127
116
  function extname(file: string) {
@@ -130,22 +119,6 @@ function extname(file: string) {
130
119
  return ext;
131
120
  }
132
121
 
133
- /**
134
- * 获取源文件所对应生成文件的扩展名
135
- * @param file 源文件名
136
- * */
137
- // function fileOutExt(file: string) {
138
- // let ext = extname(file);
139
- // if (ext === ".ts")
140
- // return outExt;
141
-
142
- // if (ext === ".tsx")
143
- // return outExt;
144
-
145
- // return ext;
146
- // }
147
-
148
-
149
122
  class ImportPathRewrite {
150
123
  constructor(private filePath: string, node: babel.types.File, private outExt: JavaScriptExtension) {
151
124
  this.traverse(node);
@@ -176,7 +149,50 @@ class ImportPathRewrite {
176
149
 
177
150
  }
178
151
  }
179
-
180
152
  }
181
153
 
182
154
 
155
+ /**
156
+ * 生成声明文件
157
+ * @param projectPath 项目路径
158
+ * @param sourcePath 源文件
159
+ * @param targetPath 目标文件
160
+ * @param outExt 输出扩展名
161
+ */
162
+ export function generateDeclarationFile(projectPath: string, sourcePath: string, targetPath: string, outExt: JavaScriptExtension): Promise<void> {
163
+ if (!projectPath) throw errors.argumentNull("projectPath");
164
+ if (!sourcePath) throw errors.argumentNull("sourcePath");
165
+ if (!targetPath) throw errors.argumentNull("targetPath");
166
+
167
+ const sourceExt = path.extname(sourcePath);
168
+ if (!sourceExt || (sourceExt !== ".ts" && sourceExt !== ".tsx")) {
169
+ return Promise.resolve();
170
+ }
171
+
172
+ const declarationPath = targetPath.endsWith(outExt)
173
+ ? targetPath.slice(0, targetPath.length - outExt.length) + ".d.ts"
174
+ : targetPath.replace(path.extname(targetPath), ".d.ts");
175
+
176
+ const content = fs.readFileSync(sourcePath, "utf-8");
177
+ const result = ts.transpileDeclaration(content, {
178
+ fileName: path.basename(sourcePath),
179
+ reportDiagnostics: false,
180
+ compilerOptions: {
181
+ declaration: true,
182
+ emitDeclarationOnly: true,
183
+ skipLibCheck: true,
184
+ esModuleInterop: true,
185
+ jsx: ts.JsxEmit.React,
186
+ target: ts.ScriptTarget.ESNext,
187
+ module: ts.ModuleKind.NodeNext,
188
+ }
189
+ });
190
+
191
+ const outDir = path.dirname(declarationPath);
192
+ if (!fs.existsSync(outDir)) {
193
+ fs.mkdirSync(outDir, { recursive: true });
194
+ }
195
+
196
+ fs.writeFileSync(declarationPath, result.outputText || "");
197
+ return Promise.resolve();
198
+ }
@@ -8,15 +8,23 @@ let copyFile: FileAction = (filePath: string, outPath: string) => {
8
8
  if (!outPath) throw errors.argumentNull("outPath");
9
9
 
10
10
  if (!fs.existsSync(filePath)) {
11
+ throw errors.pathNotExists(filePath);
12
+ }
13
+
14
+ if (!fs.statSync(filePath).isFile()) {
11
15
  return;
12
16
  }
13
17
 
14
- let out = filePath.replace(path.dirname(filePath), outPath);
15
- let outDirPath = path.resolve(out, "..");
18
+ const destFilePath = path.join(outPath, path.basename(filePath));
19
+ const destDirPath = path.dirname(destFilePath);
16
20
 
17
- fs.mkdirSync(outDirPath, { recursive: true });
21
+ fs.mkdirSync(destDirPath, { recursive: true });
18
22
 
19
- fs.copyFileSync(filePath, out);
23
+ try {
24
+ fs.copyFileSync(filePath, destFilePath);
25
+ } catch (err) {
26
+ throw errors.copyFileError(filePath, destFilePath, err as Error);
27
+ }
20
28
  }
21
29
 
22
30
  export default copyFile;
@@ -89,10 +89,10 @@ type Options = {
89
89
  }
90
90
  function generateCodeByOptions(options: Options) {
91
91
 
92
- let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback, defaultAction } = options;
93
-
94
- if (!defaultAction)
95
- defaultAction = copyFile;
92
+ let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback, defaultAction } = options;
93
+
94
+ // if (!defaultAction)
95
+ // defaultAction = copyFile;
96
96
 
97
97
 
98
98
  if (!sourceDir) throw errors.argumentNull("sourceDir");
@@ -140,9 +140,9 @@ function generateCodeByOptions(options: Options) {
140
140
  }
141
141
 
142
142
  function watchDirectoryByOptions(options: Options) {
143
- let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback, defaultAction } = options;
144
-
145
- if (!defaultAction)
143
+ let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback, defaultAction } = options;
144
+
145
+ if (!defaultAction)
146
146
  defaultAction = copyFile;
147
147
 
148
148
  watch(sourceDir, { recursive: true }, async (evt: "update" | "remove", name: string) => {