maishu-scripts 1.4.0 → 1.4.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/out/modules/actions/babel-compile.d.ts +2 -2
- package/out/modules/actions/babel-compile.js +38 -32
- package/out/modules/actions/ts-compile.d.ts +2 -2
- package/out/modules/actions/ts-compile.js +8 -7
- package/out/modules/compile.d.ts +1 -0
- package/out/modules/compile.js +15 -13
- package/out/types.d.ts +1 -0
- package/package.json +4 -3
- package/src/modules/actions/babel-compile.ts +39 -33
- package/src/modules/actions/ts-compile.ts +10 -7
- package/src/modules/compile.test.ts +236 -188
- package/src/modules/compile.ts +21 -15
- package/src/types.ts +2 -1
- package/out/modules/actions/biel-compile.d.ts +0 -7
- package/out/modules/actions/biel-compile.js +0 -153
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import * as babel from "@babel/core";
|
|
2
|
-
import { FileAction } from "../../types";
|
|
3
|
-
export declare function create(
|
|
2
|
+
import { FileAction, JavaScriptExtension } from "../../types";
|
|
3
|
+
export declare function create(defaultBabelOptions?: babel.TransformOptions, outExit?: JavaScriptExtension): FileAction;
|
|
@@ -39,26 +39,30 @@ const fs = __importStar(require("fs"));
|
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const errors_1 = require("../errors");
|
|
41
41
|
const project_compiler_1 = require("../project-compiler");
|
|
42
|
-
const outExt =
|
|
43
|
-
function create(
|
|
42
|
+
// const outExt = ProjectCompiler.tsOutExt;
|
|
43
|
+
function create(defaultBabelOptions, outExit) {
|
|
44
44
|
const action = (sourcePath, outputPath, projectPath) => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (projectPath) {
|
|
49
|
-
let c = project_compiler_1.ProjectCompiler.getBabelConfig(projectPath, sourceDir);
|
|
50
|
-
bablePath = c.path;
|
|
51
|
-
babelOptions = c.options;
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
babelOptions = project_compiler_1.ProjectCompiler.getDefaultBabelConfig();
|
|
55
|
-
bablePath = '';
|
|
56
|
-
}
|
|
57
|
-
babelOptions.filename = sourcePath;
|
|
58
|
-
babelOptions.code = false;
|
|
59
|
-
babelOptions.ast = true;
|
|
45
|
+
outExit = outExit || ".js";
|
|
46
|
+
if (defaultBabelOptions) {
|
|
47
|
+
return compileFile(sourcePath, outputPath, projectPath, defaultBabelOptions, outExit);
|
|
60
48
|
}
|
|
61
|
-
|
|
49
|
+
// 如果没有 babelOptions,则尝试从项目目录查找 babel 配置文件,如果没有,则使用默认配置。
|
|
50
|
+
let babelOptions;
|
|
51
|
+
let bablePath;
|
|
52
|
+
let sourceDir = path.dirname(sourcePath);
|
|
53
|
+
if (projectPath) {
|
|
54
|
+
let c = project_compiler_1.ProjectCompiler.getBabelConfig(projectPath, sourceDir);
|
|
55
|
+
bablePath = c.path;
|
|
56
|
+
babelOptions = c.options;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
babelOptions = project_compiler_1.ProjectCompiler.getDefaultBabelConfig();
|
|
60
|
+
bablePath = '';
|
|
61
|
+
}
|
|
62
|
+
babelOptions.filename = sourcePath;
|
|
63
|
+
babelOptions.code = false;
|
|
64
|
+
babelOptions.ast = true;
|
|
65
|
+
return compileFile(sourcePath, outputPath, projectPath, babelOptions, outExit);
|
|
62
66
|
};
|
|
63
67
|
return action;
|
|
64
68
|
}
|
|
@@ -68,7 +72,7 @@ function create(babelOptions) {
|
|
|
68
72
|
* @param outputPath 输出目录
|
|
69
73
|
* @param projectPath 项目路径
|
|
70
74
|
* */
|
|
71
|
-
async function compileFile(sourcePath, outputPath, projectPath, babelOptions) {
|
|
75
|
+
async function compileFile(sourcePath, outputPath, projectPath, babelOptions, outExt) {
|
|
72
76
|
if (!sourcePath)
|
|
73
77
|
throw errors_1.errors.argumentNull("sourcePath");
|
|
74
78
|
if (!outputPath)
|
|
@@ -107,7 +111,7 @@ async function compileFile(sourcePath, outputPath, projectPath, babelOptions) {
|
|
|
107
111
|
let ast = fileResult.ast;
|
|
108
112
|
if (!ast)
|
|
109
113
|
throw errors_1.errors.compileError(sourcePath);
|
|
110
|
-
new ImportPathRewrite(sourcePath, ast);
|
|
114
|
+
new ImportPathRewrite(sourcePath, ast, outExt);
|
|
111
115
|
let r = babel.transformFromAstSync(ast, undefined, {
|
|
112
116
|
filename: sourcePath, plugins: babelOptions.plugins,
|
|
113
117
|
presets: babelOptions.presets, sourceMaps: babelOptions.sourceMaps
|
|
@@ -115,7 +119,7 @@ async function compileFile(sourcePath, outputPath, projectPath, babelOptions) {
|
|
|
115
119
|
if (!r || r.code == null)
|
|
116
120
|
throw errors_1.errors.compileError(sourcePath);
|
|
117
121
|
let ext = extname(sourcePath);
|
|
118
|
-
let outExt = fileOutExt(sourcePath);
|
|
122
|
+
//let outExt = fileOutExt(sourcePath);
|
|
119
123
|
let targetPath = path.join(outputPath, path.basename(sourcePath).replace(ext, outExt)); //sourcePath.replace(new RegExp(ext + "$"), outExt).replace(path.dirname(sourcePath), outDir);
|
|
120
124
|
let outDirPath = path.resolve(targetPath, "..");
|
|
121
125
|
let mapPath = targetPath + ".map";
|
|
@@ -144,18 +148,20 @@ function extname(file) {
|
|
|
144
148
|
* 获取源文件所对应生成文件的扩展名
|
|
145
149
|
* @param file 源文件名
|
|
146
150
|
* */
|
|
147
|
-
function fileOutExt(file) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
151
|
+
// function fileOutExt(file: string) {
|
|
152
|
+
// let ext = extname(file);
|
|
153
|
+
// if (ext === ".ts")
|
|
154
|
+
// return outExt;
|
|
155
|
+
// if (ext === ".tsx")
|
|
156
|
+
// return outExt;
|
|
157
|
+
// return ext;
|
|
158
|
+
// }
|
|
155
159
|
class ImportPathRewrite {
|
|
156
160
|
filePath;
|
|
157
|
-
|
|
161
|
+
outExt;
|
|
162
|
+
constructor(filePath, node, outExt) {
|
|
158
163
|
this.filePath = filePath;
|
|
164
|
+
this.outExt = outExt;
|
|
159
165
|
this.traverse(node);
|
|
160
166
|
}
|
|
161
167
|
traverse(node) {
|
|
@@ -169,14 +175,14 @@ class ImportPathRewrite {
|
|
|
169
175
|
case "ImportDeclaration":
|
|
170
176
|
if (node.source.type === "StringLiteral" && node.source.value.startsWith(".")) {
|
|
171
177
|
let ext = extname(node.source.value);
|
|
172
|
-
if (ext != outExt) {
|
|
178
|
+
if (ext != this.outExt) {
|
|
173
179
|
let dir = path.dirname(this.filePath);
|
|
174
180
|
let fullPath = path.join(dir, node.source.value);
|
|
175
181
|
console.log(`ImportDeclaration: ${fullPath} -> ${ext}`);
|
|
176
182
|
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isDirectory()) {
|
|
177
183
|
node.source.value = node.source.value + "/index";
|
|
178
184
|
}
|
|
179
|
-
node.source.value += outExt;
|
|
185
|
+
node.source.value += this.outExt;
|
|
180
186
|
}
|
|
181
187
|
}
|
|
182
188
|
break;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { FileAction } from '../../types';
|
|
3
|
-
export declare function create(
|
|
2
|
+
import { FileAction, JavaScriptExtension } from '../../types';
|
|
3
|
+
export declare function create(defaultCompilerOptions?: ts.CompilerOptions, outExt?: JavaScriptExtension): FileAction;
|
|
4
4
|
export declare function getTypescriptConfig(projectPath: string, directoryPath: string): ts.CompilerOptions;
|
|
5
5
|
export declare function findTypeScriptConfigPath(projectPath: string, directoryPath: string): string | null;
|
|
@@ -40,14 +40,16 @@ const ts = __importStar(require("typescript"));
|
|
|
40
40
|
const errors_1 = require("../errors");
|
|
41
41
|
const fs = __importStar(require("fs"));
|
|
42
42
|
const path = __importStar(require("path"));
|
|
43
|
-
const project_compiler_1 = require("../project-compiler");
|
|
44
43
|
const TS_CONFIG_FILE = 'tsconfig.json';
|
|
45
|
-
function create(
|
|
44
|
+
function create(defaultCompilerOptions, outExt) {
|
|
45
|
+
outExt = outExt || ".js";
|
|
46
46
|
const action = async (filePath, outDir, projectPath) => {
|
|
47
|
-
if (
|
|
48
|
-
|
|
47
|
+
if (defaultCompilerOptions) {
|
|
48
|
+
return compileFile(filePath, outDir, projectPath, defaultCompilerOptions, outExt);
|
|
49
49
|
}
|
|
50
|
-
|
|
50
|
+
// 如果没有指定默认编译选项,则尝试从项目目录查找 tsconfig.json 文件,并使用其中的配置进行编译
|
|
51
|
+
const compilerOptions = getTypescriptConfig(projectPath, path.dirname(filePath));
|
|
52
|
+
return compileFile(filePath, outDir, projectPath, compilerOptions, outExt);
|
|
51
53
|
};
|
|
52
54
|
return action;
|
|
53
55
|
}
|
|
@@ -57,7 +59,7 @@ function create(compilerOptions) {
|
|
|
57
59
|
* @param outDir 输出目录,相对于项目路径
|
|
58
60
|
* @param projectPath 项目路径,绝对路径
|
|
59
61
|
* */
|
|
60
|
-
async function compileFile(filePath, outDir, projectPath, compilerOptions) {
|
|
62
|
+
async function compileFile(filePath, outDir, projectPath, compilerOptions, outExt) {
|
|
61
63
|
if (!filePath)
|
|
62
64
|
throw errors_1.errors.argumentNull('sourcePath');
|
|
63
65
|
if (!outDir)
|
|
@@ -68,7 +70,6 @@ async function compileFile(filePath, outDir, projectPath, compilerOptions) {
|
|
|
68
70
|
// let compilerOptions = getTypescriptConfig(projectPath, path.dirname(filePath));
|
|
69
71
|
let result = ts.transpileModule(content, { compilerOptions });
|
|
70
72
|
let ext = path.extname(filePath);
|
|
71
|
-
let outExt = project_compiler_1.ProjectCompiler.tsOutExt;
|
|
72
73
|
let targetPath = path.join(projectPath, outDir, path.basename(filePath).replace(ext, outExt));
|
|
73
74
|
let outDirPath = path.resolve(targetPath, "..");
|
|
74
75
|
if (!fs.existsSync(outDirPath))
|
package/out/modules/compile.d.ts
CHANGED
package/out/modules/compile.js
CHANGED
|
@@ -104,7 +104,9 @@ function extname(file) {
|
|
|
104
104
|
return ext;
|
|
105
105
|
}
|
|
106
106
|
function generateCodeByOptions(options) {
|
|
107
|
-
let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback } = options;
|
|
107
|
+
let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback, defaultAction } = options;
|
|
108
|
+
if (!defaultAction)
|
|
109
|
+
defaultAction = copy_file_1.default;
|
|
108
110
|
if (!sourceDir)
|
|
109
111
|
throw errors_1.errors.argumentNull("sourceDir");
|
|
110
112
|
if (!outDir)
|
|
@@ -126,11 +128,7 @@ function generateCodeByOptions(options) {
|
|
|
126
128
|
console.log(`Skip ${filePath}`);
|
|
127
129
|
continue;
|
|
128
130
|
}
|
|
129
|
-
|
|
130
|
-
const ext = path.extname(fileName);
|
|
131
|
-
return configs_1.default.fileActions[ext];
|
|
132
|
-
};
|
|
133
|
-
let action = fileActions(filePath);
|
|
131
|
+
let action = fileActions?.(filePath) || configs_1.default.fileActions[ext] || defaultAction;
|
|
134
132
|
if (action) {
|
|
135
133
|
action(filePath, outDir, projectPath);
|
|
136
134
|
if (callback) {
|
|
@@ -143,14 +141,18 @@ function generateCodeByOptions(options) {
|
|
|
143
141
|
let fullPath = path.join(sourceDir, dir);
|
|
144
142
|
let outDirPath = path.join(outDir, dir);
|
|
145
143
|
if (fs.statSync(fullPath).isDirectory()) {
|
|
146
|
-
generateCodeByOptions({ sourceDir: fullPath, outDir: outDirPath, projectPath: projectPath, skipFiles, fileAction: fileActions, callback });
|
|
144
|
+
generateCodeByOptions({ sourceDir: fullPath, outDir: outDirPath, projectPath: projectPath, skipFiles, fileAction: fileActions, callback, defaultAction });
|
|
147
145
|
}
|
|
148
146
|
}
|
|
149
147
|
}
|
|
150
148
|
function watchDirectoryByOptions(options) {
|
|
151
|
-
let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback } = options;
|
|
149
|
+
let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback, defaultAction } = options;
|
|
150
|
+
if (!defaultAction)
|
|
151
|
+
defaultAction = copy_file_1.default;
|
|
152
152
|
(0, node_watch_1.default)(sourceDir, { recursive: true }, async (evt, name) => {
|
|
153
|
-
const filePath = name;
|
|
153
|
+
const filePath = name.replace(/\\/g, "/");
|
|
154
|
+
sourceDir = sourceDir.replace(/\\/g, "/");
|
|
155
|
+
outDir = outDir.replace(/\\/g, "/");
|
|
154
156
|
const ext = extname(filePath);
|
|
155
157
|
skipFiles = skipFiles || configs_1.default.skipFiles[ext] || [];
|
|
156
158
|
let isSkip = skipFiles.some(pattern => pattern.test(filePath)); //isIgnoredFile(filePath);//skipFiles.some(pattern => new RegExp(pattern).test(filePath));
|
|
@@ -161,15 +163,15 @@ function watchDirectoryByOptions(options) {
|
|
|
161
163
|
if (evt === "remove") {
|
|
162
164
|
return;
|
|
163
165
|
}
|
|
164
|
-
let action = fileActions?.(filePath) || configs_1.default.fileActions[ext];
|
|
166
|
+
let action = fileActions?.(filePath) || configs_1.default.fileActions[ext] || defaultAction;
|
|
165
167
|
if (!action) {
|
|
166
168
|
return;
|
|
167
169
|
}
|
|
168
170
|
try {
|
|
169
|
-
let outPath = path.dirname(
|
|
170
|
-
action(
|
|
171
|
+
let outPath = path.dirname(filePath).replace(sourceDir, outDir);
|
|
172
|
+
action(filePath, outPath, projectPath);
|
|
171
173
|
if (callback)
|
|
172
|
-
callback(
|
|
174
|
+
callback(filePath, outPath, projectPath);
|
|
173
175
|
}
|
|
174
176
|
catch (e) {
|
|
175
177
|
console.error(e);
|
package/out/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maishu-scripts",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "用于对 node 项目进行代码生成,打包,运行",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@babel/core": "^7.24.3",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"src"
|
|
32
32
|
],
|
|
33
33
|
"scripts": {
|
|
34
|
-
"build": "tsc"
|
|
34
|
+
"build": "tsc -p tsconfig.build.json",
|
|
35
|
+
"test": "jest"
|
|
35
36
|
}
|
|
36
|
-
}
|
|
37
|
+
}
|
|
@@ -4,31 +4,37 @@ import * as fs from "fs";
|
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import { errors } from "../errors";
|
|
6
6
|
import { ProjectCompiler } from "../project-compiler";
|
|
7
|
-
import { FileAction } from "../../types";
|
|
7
|
+
import { FileAction, JavaScriptExtension } from "../../types";
|
|
8
8
|
|
|
9
|
-
const outExt = ProjectCompiler.tsOutExt;
|
|
9
|
+
// const outExt = ProjectCompiler.tsOutExt;
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
export function create(
|
|
12
|
+
export function create(defaultBabelOptions?: babel.TransformOptions, outExit?: JavaScriptExtension): FileAction {
|
|
13
13
|
const action: FileAction = (sourcePath: string, outputPath: string, projectPath: string) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (projectPath) {
|
|
18
|
-
let c = ProjectCompiler.getBabelConfig(projectPath, sourceDir);
|
|
19
|
-
bablePath = c.path;
|
|
20
|
-
babelOptions = c.options;
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
babelOptions = ProjectCompiler.getDefaultBabelConfig();
|
|
24
|
-
bablePath = '';
|
|
25
|
-
}
|
|
26
|
-
babelOptions.filename = sourcePath;
|
|
27
|
-
babelOptions.code = false;
|
|
28
|
-
babelOptions.ast = true;
|
|
14
|
+
outExit = outExit || ".js";
|
|
15
|
+
if (defaultBabelOptions) {
|
|
16
|
+
return compileFile(sourcePath, outputPath, projectPath, defaultBabelOptions, outExit);
|
|
29
17
|
}
|
|
30
18
|
|
|
31
|
-
|
|
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;
|
|
36
|
+
|
|
37
|
+
return compileFile(sourcePath, outputPath, projectPath, babelOptions, outExit);
|
|
32
38
|
}
|
|
33
39
|
return action;
|
|
34
40
|
}
|
|
@@ -39,7 +45,7 @@ export function create(babelOptions?: babel.TransformOptions): FileAction {
|
|
|
39
45
|
* @param outputPath 输出目录
|
|
40
46
|
* @param projectPath 项目路径
|
|
41
47
|
* */
|
|
42
|
-
async function compileFile(sourcePath: string, outputPath: string, projectPath: string, babelOptions: babel.TransformOptions) {
|
|
48
|
+
async function compileFile(sourcePath: string, outputPath: string, projectPath: string, babelOptions: babel.TransformOptions, outExt: JavaScriptExtension) {
|
|
43
49
|
if (!sourcePath) throw errors.argumentNull("sourcePath");
|
|
44
50
|
if (!outputPath) throw errors.argumentNull("outputPath");
|
|
45
51
|
if (!projectPath) throw errors.argumentNull("projectPath");
|
|
@@ -82,7 +88,7 @@ async function compileFile(sourcePath: string, outputPath: string, projectPath:
|
|
|
82
88
|
if (!ast)
|
|
83
89
|
throw errors.compileError(sourcePath);
|
|
84
90
|
|
|
85
|
-
new ImportPathRewrite(sourcePath, ast);
|
|
91
|
+
new ImportPathRewrite(sourcePath, ast, outExt);
|
|
86
92
|
let r = babel.transformFromAstSync(ast, undefined, {
|
|
87
93
|
filename: sourcePath, plugins: babelOptions.plugins,
|
|
88
94
|
presets: babelOptions.presets, sourceMaps: babelOptions.sourceMaps
|
|
@@ -91,7 +97,7 @@ async function compileFile(sourcePath: string, outputPath: string, projectPath:
|
|
|
91
97
|
throw errors.compileError(sourcePath);
|
|
92
98
|
|
|
93
99
|
let ext = extname(sourcePath);
|
|
94
|
-
let outExt = fileOutExt(sourcePath);
|
|
100
|
+
//let outExt = fileOutExt(sourcePath);
|
|
95
101
|
let targetPath = path.join(outputPath, path.basename(sourcePath).replace(ext, outExt));//sourcePath.replace(new RegExp(ext + "$"), outExt).replace(path.dirname(sourcePath), outDir);
|
|
96
102
|
let outDirPath = path.resolve(targetPath, "..");
|
|
97
103
|
|
|
@@ -128,20 +134,20 @@ function extname(file: string) {
|
|
|
128
134
|
* 获取源文件所对应生成文件的扩展名
|
|
129
135
|
* @param file 源文件名
|
|
130
136
|
* */
|
|
131
|
-
function fileOutExt(file: string) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
// function fileOutExt(file: string) {
|
|
138
|
+
// let ext = extname(file);
|
|
139
|
+
// if (ext === ".ts")
|
|
140
|
+
// return outExt;
|
|
135
141
|
|
|
136
|
-
|
|
137
|
-
|
|
142
|
+
// if (ext === ".tsx")
|
|
143
|
+
// return outExt;
|
|
138
144
|
|
|
139
|
-
|
|
140
|
-
}
|
|
145
|
+
// return ext;
|
|
146
|
+
// }
|
|
141
147
|
|
|
142
148
|
|
|
143
149
|
class ImportPathRewrite {
|
|
144
|
-
constructor(private filePath: string, node: babel.types.File) {
|
|
150
|
+
constructor(private filePath: string, node: babel.types.File, private outExt: JavaScriptExtension) {
|
|
145
151
|
this.traverse(node);
|
|
146
152
|
}
|
|
147
153
|
|
|
@@ -156,14 +162,14 @@ class ImportPathRewrite {
|
|
|
156
162
|
case "ImportDeclaration":
|
|
157
163
|
if (node.source.type === "StringLiteral" && node.source.value.startsWith(".")) {
|
|
158
164
|
let ext = extname(node.source.value);
|
|
159
|
-
if (ext != outExt) {
|
|
165
|
+
if (ext != this.outExt) {
|
|
160
166
|
let dir = path.dirname(this.filePath);
|
|
161
167
|
let fullPath = path.join(dir, node.source.value);
|
|
162
168
|
console.log(`ImportDeclaration: ${fullPath} -> ${ext}`)
|
|
163
169
|
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isDirectory()) {
|
|
164
170
|
node.source.value = node.source.value + "/index";
|
|
165
171
|
}
|
|
166
|
-
node.source.value += outExt;
|
|
172
|
+
node.source.value += this.outExt;
|
|
167
173
|
}
|
|
168
174
|
}
|
|
169
175
|
break;
|
|
@@ -3,7 +3,7 @@ import { errors } from '../errors';
|
|
|
3
3
|
import * as fs from 'fs';
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { ProjectCompiler } from '../project-compiler';
|
|
6
|
-
import { FileAction } from '../../types';
|
|
6
|
+
import { FileAction, JavaScriptExtension } from '../../types';
|
|
7
7
|
|
|
8
8
|
const TS_CONFIG_FILE = 'tsconfig.json';
|
|
9
9
|
|
|
@@ -11,12 +11,16 @@ type TypeScriptProjectConfig = {
|
|
|
11
11
|
compilerOptions: ts.CompilerOptions;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export function create(
|
|
14
|
+
export function create(defaultCompilerOptions?: ts.CompilerOptions, outExt?: JavaScriptExtension): FileAction {
|
|
15
|
+
outExt = outExt || ".js";
|
|
15
16
|
const action: FileAction = async (filePath: string, outDir: string, projectPath: string) => {
|
|
16
|
-
if (
|
|
17
|
-
|
|
17
|
+
if (defaultCompilerOptions) {
|
|
18
|
+
return compileFile(filePath, outDir, projectPath, defaultCompilerOptions, outExt);
|
|
18
19
|
}
|
|
19
|
-
|
|
20
|
+
|
|
21
|
+
// 如果没有指定默认编译选项,则尝试从项目目录查找 tsconfig.json 文件,并使用其中的配置进行编译
|
|
22
|
+
const compilerOptions = getTypescriptConfig(projectPath, path.dirname(filePath));
|
|
23
|
+
return compileFile(filePath, outDir, projectPath, compilerOptions, outExt);
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
return action;
|
|
@@ -28,7 +32,7 @@ export function create(compilerOptions?: ts.CompilerOptions): FileAction {
|
|
|
28
32
|
* @param outDir 输出目录,相对于项目路径
|
|
29
33
|
* @param projectPath 项目路径,绝对路径
|
|
30
34
|
* */
|
|
31
|
-
async function compileFile(filePath: string, outDir: string, projectPath: string, compilerOptions: ts.CompilerOptions) {
|
|
35
|
+
async function compileFile(filePath: string, outDir: string, projectPath: string, compilerOptions: ts.CompilerOptions, outExt: JavaScriptExtension) {
|
|
32
36
|
if (!filePath)
|
|
33
37
|
throw errors.argumentNull('sourcePath');
|
|
34
38
|
if (!outDir)
|
|
@@ -42,7 +46,6 @@ async function compileFile(filePath: string, outDir: string, projectPath: string
|
|
|
42
46
|
let result = ts.transpileModule(content, { compilerOptions });
|
|
43
47
|
|
|
44
48
|
let ext = path.extname(filePath);
|
|
45
|
-
let outExt = ProjectCompiler.tsOutExt;
|
|
46
49
|
let targetPath = path.join(projectPath, outDir, path.basename(filePath).replace(ext, outExt));
|
|
47
50
|
let outDirPath = path.resolve(targetPath, "..");
|
|
48
51
|
|
|
@@ -1,188 +1,236 @@
|
|
|
1
|
-
import { generateCode, isIgnoredFile, watchDirectory } from "./compile";
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
import * as fs from "fs";
|
|
4
|
-
import { create as createTsCompiler } from "
|
|
5
|
-
import ts from "typescript";
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
generateCode(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
expect(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
fs.writeFileSync(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
1
|
+
import { generateCode, isIgnoredFile, watchDirectory } from "./compile";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
import { create as createTsCompiler } from "./actions/ts-compile";
|
|
5
|
+
import ts from "typescript";
|
|
6
|
+
import copyFile from "./actions/copy-file";
|
|
7
|
+
import { errors } from "./errors";
|
|
8
|
+
|
|
9
|
+
// 公共常量
|
|
10
|
+
const SRC_PATH = "test/src";
|
|
11
|
+
const DEST_PATH = "test/out";
|
|
12
|
+
const PROJECT_PATH = path.join(__dirname, "..", "..");
|
|
13
|
+
|
|
14
|
+
// 清理输出目录的工具函数
|
|
15
|
+
function cleanDir(dir: string) {
|
|
16
|
+
if (fs.existsSync(dir)) {
|
|
17
|
+
fs.rmSync(dir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("Compile Test", function () {
|
|
22
|
+
|
|
23
|
+
test("copyFile test", function () {
|
|
24
|
+
let srcExists = fs.existsSync(SRC_PATH);
|
|
25
|
+
expect(srcExists).toBe(true);
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test("generateCode test", function () {
|
|
29
|
+
cleanDir(DEST_PATH);
|
|
30
|
+
generateCode(SRC_PATH, DEST_PATH, PROJECT_PATH);
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test("generateCode with callback test", function () {
|
|
34
|
+
cleanDir(DEST_PATH);
|
|
35
|
+
const callback = jest.fn();
|
|
36
|
+
generateCode(SRC_PATH, DEST_PATH, PROJECT_PATH, callback);
|
|
37
|
+
expect(callback.mock.calls.length).toBeGreaterThan(0);
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test("generateCode with skipFiles test", function () {
|
|
41
|
+
cleanDir(DEST_PATH);
|
|
42
|
+
|
|
43
|
+
let executedPaths: string[] = [];
|
|
44
|
+
generateCode(SRC_PATH, DEST_PATH, PROJECT_PATH, (filePath: string) => {
|
|
45
|
+
executedPaths.push(filePath);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(executedPaths.some(p => p.includes("controllers"))).toBe(true);
|
|
49
|
+
|
|
50
|
+
// 忽略掉 controllers 目录
|
|
51
|
+
const skipFiles = [new RegExp("controllers")];
|
|
52
|
+
executedPaths = [];
|
|
53
|
+
generateCode({
|
|
54
|
+
sourceDir: SRC_PATH, outDir: DEST_PATH, projectPath: PROJECT_PATH, skipFiles,
|
|
55
|
+
callback(filePath: string) {
|
|
56
|
+
executedPaths.push(filePath);
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
expect(executedPaths.some(p => p.includes("controllers"))).toBe(false);
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test("generateCode 根据文件夹使用不同的 TS 编译器", async function () {
|
|
63
|
+
cleanDir(DEST_PATH);
|
|
64
|
+
|
|
65
|
+
const srcCompiler = createTsCompiler({
|
|
66
|
+
target: ts.ScriptTarget.ES2015,
|
|
67
|
+
module: ts.ModuleKind.CommonJS,
|
|
68
|
+
declaration: true,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const staticCompiler = createTsCompiler({
|
|
72
|
+
target: ts.ScriptTarget.ES5,
|
|
73
|
+
module: ts.ModuleKind.AMD,
|
|
74
|
+
declaration: false,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const mainFile = "main.ts";
|
|
78
|
+
const staticFile = "static/index.ts";
|
|
79
|
+
const mainFilePath = path.resolve(SRC_PATH, mainFile);
|
|
80
|
+
expect(fs.existsSync(mainFilePath)).toBeTruthy();
|
|
81
|
+
const staticFilePath = path.resolve(SRC_PATH, staticFile);
|
|
82
|
+
expect(fs.existsSync(staticFilePath)).toBeTruthy();
|
|
83
|
+
|
|
84
|
+
generateCode({
|
|
85
|
+
sourceDir: SRC_PATH, outDir: DEST_PATH, projectPath: PROJECT_PATH,
|
|
86
|
+
fileAction(filePath: string) {
|
|
87
|
+
const ext = path.extname(filePath);
|
|
88
|
+
if (ext !== ".ts" && ext !== ".tsx") {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
filePath = filePath.replace(/\\/g, "/");
|
|
92
|
+
if (filePath.startsWith("test/src/static/")) {
|
|
93
|
+
return staticCompiler;
|
|
94
|
+
}
|
|
95
|
+
return srcCompiler;
|
|
96
|
+
},
|
|
97
|
+
callback(_filePath: string) {
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
// 等待异步编译完成
|
|
102
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
103
|
+
|
|
104
|
+
const mainOutFile = "main.js";
|
|
105
|
+
const staticOutFile = "static/index.js";
|
|
106
|
+
const mainOutFilePath = path.resolve(DEST_PATH, mainOutFile);
|
|
107
|
+
const staticOutFilePath = path.resolve(DEST_PATH, staticOutFile);
|
|
108
|
+
expect(fs.existsSync(mainOutFilePath)).toBeTruthy();
|
|
109
|
+
expect(fs.existsSync(staticOutFilePath)).toBeTruthy();
|
|
110
|
+
|
|
111
|
+
const mainFileContent = fs.readFileSync(mainOutFilePath, "utf-8");
|
|
112
|
+
const staticFileContent = fs.readFileSync(staticOutFilePath, "utf-8");
|
|
113
|
+
|
|
114
|
+
expect(mainFileContent.includes("Object.defineProperty(exports, \"__esModule\"")).toBe(true);
|
|
115
|
+
expect(staticFileContent.includes("define([")).toBe(true);
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
test("generateCode 参数校验", function () {
|
|
119
|
+
expect(() => generateCode("", DEST_PATH, PROJECT_PATH)).toThrow();
|
|
120
|
+
expect(() => generateCode(SRC_PATH, "", PROJECT_PATH)).toThrow();
|
|
121
|
+
expect(() => generateCode(SRC_PATH, DEST_PATH, "")).toThrow();
|
|
122
|
+
expect(() => generateCode("/nonexistent/path", DEST_PATH, PROJECT_PATH)).toThrow();
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
test("generateCode with defaultAction", function () {
|
|
126
|
+
cleanDir(DEST_PATH);
|
|
127
|
+
|
|
128
|
+
const customAction = jest.fn();
|
|
129
|
+
generateCode({
|
|
130
|
+
sourceDir: SRC_PATH, outDir: DEST_PATH, projectPath: PROJECT_PATH,
|
|
131
|
+
fileAction() {
|
|
132
|
+
return undefined; // fileAction 始终返回 undefined
|
|
133
|
+
},
|
|
134
|
+
defaultAction: customAction as any,
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
// defaultAction 应该被调用
|
|
138
|
+
expect(customAction.mock.calls.length).toBeGreaterThan(0);
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
test("generateCode defaultAction 默认为 copyFile", function () {
|
|
142
|
+
cleanDir(DEST_PATH);
|
|
143
|
+
|
|
144
|
+
// 不指定 fileAction 和 defaultAction,未知扩展名应使用 copyFile 作为兜底
|
|
145
|
+
const jsFile = path.join(SRC_PATH, "test-default-action.js");
|
|
146
|
+
fs.writeFileSync(jsFile, "console.log('test');");
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
generateCode({
|
|
150
|
+
sourceDir: SRC_PATH, outDir: DEST_PATH, projectPath: PROJECT_PATH,
|
|
151
|
+
fileAction() {
|
|
152
|
+
return undefined; // 不提供任何 action
|
|
153
|
+
},
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// copyFile 应该将 .js 文件复制到输出目录
|
|
157
|
+
const outFile = path.resolve(DEST_PATH, "test-default-action.js");
|
|
158
|
+
expect(fs.existsSync(outFile)).toBe(true);
|
|
159
|
+
} finally {
|
|
160
|
+
// 清理临时文件
|
|
161
|
+
if (fs.existsSync(jsFile)) fs.unlinkSync(jsFile);
|
|
162
|
+
const outFile = path.resolve(DEST_PATH, "test-default-action.js");
|
|
163
|
+
if (fs.existsSync(outFile)) fs.unlinkSync(outFile);
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
describe("isIgnoredFile", function () {
|
|
168
|
+
|
|
169
|
+
test(".spec.ts 文件应该被忽略", function () {
|
|
170
|
+
let filePath = "D:\\project\\src\\app.controller.spec.ts";
|
|
171
|
+
let ignored = isIgnoredFile(filePath);
|
|
172
|
+
expect(ignored).toBe(true);
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
test(".test.ts 文件应该被忽略", function () {
|
|
176
|
+
let filePath = "D:\\project\\src\\app.controller.test.ts";
|
|
177
|
+
let ignored = isIgnoredFile(filePath);
|
|
178
|
+
expect(ignored).toBe(true);
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
test(".d.ts 文件应该被忽略", function () {
|
|
182
|
+
let filePath = "D:\\project\\src\\app.d.ts";
|
|
183
|
+
let ignored = isIgnoredFile(filePath);
|
|
184
|
+
expect(ignored).toBe(true);
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
test("普通 .ts 文件不应被忽略", function () {
|
|
188
|
+
let filePath = "D:\\project\\src\\app.controller.ts";
|
|
189
|
+
let ignored = isIgnoredFile(filePath);
|
|
190
|
+
expect(ignored).toBe(false);
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test("空参数应抛出异常", function () {
|
|
194
|
+
expect(() => isIgnoredFile("")).toThrow();
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
test("watchDirectory test, 修改文件应该触发回调, 删除文件不应该触发回调", async function () {
|
|
200
|
+
let filePath = path.join(SRC_PATH, "test.txt");
|
|
201
|
+
filePath = filePath.replace(/\\/g, "/");
|
|
202
|
+
fs.writeFileSync(filePath, "test");
|
|
203
|
+
const fileAction = jest.fn();
|
|
204
|
+
|
|
205
|
+
setTimeout(() => {
|
|
206
|
+
let executedPaths: string[] = [];
|
|
207
|
+
watchDirectory({
|
|
208
|
+
sourceDir: SRC_PATH, outDir: DEST_PATH, projectPath: PROJECT_PATH,
|
|
209
|
+
fileAction: () => {
|
|
210
|
+
return fileAction;
|
|
211
|
+
},
|
|
212
|
+
callback(filePath: string) {
|
|
213
|
+
executedPaths.push(filePath);
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
}, 0);
|
|
217
|
+
|
|
218
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
219
|
+
// 修改文件
|
|
220
|
+
fs.writeFileSync(filePath, "test2");
|
|
221
|
+
|
|
222
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
223
|
+
expect(fileAction.mock.calls.length).toBe(1);
|
|
224
|
+
expect(fileAction.mock.calls[0][0]).toBe(filePath);
|
|
225
|
+
|
|
226
|
+
const calltimes = fileAction.mock.calls.length;
|
|
227
|
+
setTimeout(() => {
|
|
228
|
+
// 删除文件
|
|
229
|
+
fs.unlinkSync(filePath);
|
|
230
|
+
}, 1000);
|
|
231
|
+
|
|
232
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
233
|
+
expect(fileAction.mock.calls.length).toBe(calltimes);
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
})
|
package/src/modules/compile.ts
CHANGED
|
@@ -84,11 +84,15 @@ type Options = {
|
|
|
84
84
|
sourceDir: string, outDir: string, projectPath: string,
|
|
85
85
|
skipFiles?: RegExp[],
|
|
86
86
|
fileAction?: (fileName: string) => FileAction | undefined,
|
|
87
|
-
callback?: Callback
|
|
87
|
+
callback?: Callback,
|
|
88
|
+
defaultAction?: FileAction
|
|
88
89
|
}
|
|
89
90
|
function generateCodeByOptions(options: Options) {
|
|
90
91
|
|
|
91
|
-
let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback } = options;
|
|
92
|
+
let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback, defaultAction } = options;
|
|
93
|
+
|
|
94
|
+
if (!defaultAction)
|
|
95
|
+
defaultAction = copyFile;
|
|
92
96
|
|
|
93
97
|
|
|
94
98
|
if (!sourceDir) throw errors.argumentNull("sourceDir");
|
|
@@ -116,11 +120,7 @@ function generateCodeByOptions(options: Options) {
|
|
|
116
120
|
continue;
|
|
117
121
|
}
|
|
118
122
|
|
|
119
|
-
|
|
120
|
-
const ext = path.extname(fileName);
|
|
121
|
-
return configs.fileActions[ext];
|
|
122
|
-
};
|
|
123
|
-
let action = fileActions(filePath);
|
|
123
|
+
let action = fileActions?.(filePath) || configs.fileActions[ext] || defaultAction;
|
|
124
124
|
if (action) {
|
|
125
125
|
action(filePath, outDir, projectPath);
|
|
126
126
|
if (callback) {
|
|
@@ -134,16 +134,22 @@ function generateCodeByOptions(options: Options) {
|
|
|
134
134
|
let fullPath = path.join(sourceDir, dir);
|
|
135
135
|
let outDirPath = path.join(outDir, dir);
|
|
136
136
|
if (fs.statSync(fullPath).isDirectory()) {
|
|
137
|
-
generateCodeByOptions({ sourceDir: fullPath, outDir: outDirPath, projectPath: projectPath, skipFiles, fileAction: fileActions, callback });
|
|
137
|
+
generateCodeByOptions({ sourceDir: fullPath, outDir: outDirPath, projectPath: projectPath, skipFiles, fileAction: fileActions, callback, defaultAction });
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
function watchDirectoryByOptions(options: Options) {
|
|
143
|
-
let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback } = options;
|
|
143
|
+
let { sourceDir, outDir, projectPath, skipFiles, fileAction: fileActions, callback, defaultAction } = options;
|
|
144
|
+
|
|
145
|
+
if (!defaultAction)
|
|
146
|
+
defaultAction = copyFile;
|
|
147
|
+
|
|
148
|
+
watch(sourceDir, { recursive: true }, async (evt: "update" | "remove", name: string) => {
|
|
149
|
+
const filePath = name.replace(/\\/g, "/");
|
|
150
|
+
sourceDir = sourceDir.replace(/\\/g, "/");
|
|
151
|
+
outDir = outDir.replace(/\\/g, "/");
|
|
144
152
|
|
|
145
|
-
watch(sourceDir, { recursive: true }, async (evt, name) => {
|
|
146
|
-
const filePath = name;
|
|
147
153
|
const ext = extname(filePath);
|
|
148
154
|
skipFiles = skipFiles || configs.skipFiles[ext] || [];
|
|
149
155
|
let isSkip = skipFiles.some(pattern => pattern.test(filePath));//isIgnoredFile(filePath);//skipFiles.some(pattern => new RegExp(pattern).test(filePath));
|
|
@@ -156,16 +162,16 @@ function watchDirectoryByOptions(options: Options) {
|
|
|
156
162
|
return;
|
|
157
163
|
}
|
|
158
164
|
|
|
159
|
-
let action = fileActions?.(filePath) || configs.fileActions[ext];
|
|
165
|
+
let action = fileActions?.(filePath) || configs.fileActions[ext] || defaultAction;
|
|
160
166
|
if (!action) {
|
|
161
167
|
return;
|
|
162
168
|
}
|
|
163
169
|
|
|
164
170
|
try {
|
|
165
|
-
let outPath = path.dirname(
|
|
166
|
-
action(
|
|
171
|
+
let outPath = path.dirname(filePath).replace(sourceDir, outDir);
|
|
172
|
+
action(filePath, outPath, projectPath);
|
|
167
173
|
if (callback)
|
|
168
|
-
callback(
|
|
174
|
+
callback(filePath, outPath, projectPath);
|
|
169
175
|
}
|
|
170
176
|
catch (e) {
|
|
171
177
|
console.error(e);
|
package/src/types.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export type FileAction = (filePath: string, outPath: string, projectPath: string) => void;
|
|
1
|
+
export type FileAction = (filePath: string, outPath: string, projectPath: string) => void;
|
|
2
|
+
export type JavaScriptExtension = ".js" | ".mjs" | ".cjs";
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.compileFile = compileFile;
|
|
27
|
-
const babel = __importStar(require("@babel/core"));
|
|
28
|
-
const fs = __importStar(require("fs"));
|
|
29
|
-
const path = __importStar(require("path"));
|
|
30
|
-
const errors_1 = require("../errors");
|
|
31
|
-
const project_compiler_1 = require("../project-compiler");
|
|
32
|
-
const outExt = project_compiler_1.ProjectCompiler.tsOutExt;
|
|
33
|
-
/**
|
|
34
|
-
* 编译特定文件,并生成到制定目录
|
|
35
|
-
* @param sourcePath 源文件路径
|
|
36
|
-
* @param outputPath 输出目录
|
|
37
|
-
* @param projectPath 项目路径
|
|
38
|
-
* */
|
|
39
|
-
async function compileFile(sourcePath, outputPath, projectPath) {
|
|
40
|
-
if (!sourcePath)
|
|
41
|
-
throw errors_1.errors.argumentNull("sourcePath");
|
|
42
|
-
if (!outputPath)
|
|
43
|
-
throw errors_1.errors.argumentNull("outputPath");
|
|
44
|
-
if (!projectPath)
|
|
45
|
-
throw errors_1.errors.argumentNull("projectPath");
|
|
46
|
-
// if (!fs.existsSync(sourcePath)) throw errors.pathNotExists(sourcePath);
|
|
47
|
-
if (!fs.existsSync(sourcePath)) {
|
|
48
|
-
console.warn(`Path not exists: ${sourcePath}`);
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
let sourceDir = path.dirname(sourcePath);
|
|
52
|
-
let babelOptions;
|
|
53
|
-
let bablePath;
|
|
54
|
-
//= projectPath ?
|
|
55
|
-
// ProjectCompiler.getBabelConfig(projectPath, sourceDir) : ProjectCompiler.getDefaultBabelConfig();
|
|
56
|
-
if (projectPath) {
|
|
57
|
-
let c = project_compiler_1.ProjectCompiler.getBabelConfig(projectPath, sourceDir);
|
|
58
|
-
bablePath = c.path;
|
|
59
|
-
babelOptions = c.options;
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
babelOptions = project_compiler_1.ProjectCompiler.getDefaultBabelConfig();
|
|
63
|
-
bablePath = '';
|
|
64
|
-
}
|
|
65
|
-
babelOptions.filename = sourcePath;
|
|
66
|
-
babelOptions.code = false;
|
|
67
|
-
babelOptions.ast = true;
|
|
68
|
-
// let fileResult = babel.transformFileSync(sourcePath, {
|
|
69
|
-
// filename: sourcePath, code: false, ast: true, plugins,
|
|
70
|
-
// presets
|
|
71
|
-
// });
|
|
72
|
-
let fileResult = babel.transformFileSync(sourcePath, babelOptions);
|
|
73
|
-
if (!fileResult)
|
|
74
|
-
throw errors_1.errors.compileError(sourcePath);
|
|
75
|
-
let ast = fileResult.ast;
|
|
76
|
-
if (!ast)
|
|
77
|
-
throw errors_1.errors.compileError(sourcePath);
|
|
78
|
-
new ImportPathRewrite(sourcePath, ast);
|
|
79
|
-
let r = babel.transformFromAstSync(ast, undefined, {
|
|
80
|
-
filename: sourcePath, plugins: babelOptions.plugins,
|
|
81
|
-
presets: babelOptions.presets, sourceMaps: babelOptions.sourceMaps
|
|
82
|
-
});
|
|
83
|
-
if (!r || r.code == null)
|
|
84
|
-
throw errors_1.errors.compileError(sourcePath);
|
|
85
|
-
let ext = extname(sourcePath);
|
|
86
|
-
let outExt = fileOutExt(sourcePath);
|
|
87
|
-
let targetPath = path.join(outputPath, path.basename(sourcePath).replace(ext, outExt)); //sourcePath.replace(new RegExp(ext + "$"), outExt).replace(path.dirname(sourcePath), outDir);
|
|
88
|
-
let outDirPath = path.resolve(targetPath, "..");
|
|
89
|
-
let mapPath = targetPath + ".map";
|
|
90
|
-
if (r.map) {
|
|
91
|
-
r.map.file = path.basename(targetPath);
|
|
92
|
-
r.map.sources = [path.relative(outputPath, sourcePath)];
|
|
93
|
-
if (!fs.existsSync(outDirPath))
|
|
94
|
-
fs.mkdirSync(outDirPath, { recursive: true });
|
|
95
|
-
fs.writeFileSync(mapPath, JSON.stringify(r.map));
|
|
96
|
-
r.code += `\n//babel file path = ${bablePath}`;
|
|
97
|
-
r.code += "\n//# sourceMappingURL=" + path.basename(mapPath);
|
|
98
|
-
}
|
|
99
|
-
else if (fs.existsSync(mapPath)) {
|
|
100
|
-
fs.rmSync(targetPath);
|
|
101
|
-
}
|
|
102
|
-
if (!fs.existsSync(outDirPath))
|
|
103
|
-
fs.mkdirSync(outDirPath, { recursive: true });
|
|
104
|
-
fs.writeFileSync(targetPath, r.code);
|
|
105
|
-
}
|
|
106
|
-
function extname(file) {
|
|
107
|
-
// let ext = /\.[a-zA-Z]+/.exec(file)?.[0] || '';
|
|
108
|
-
let ext = path.extname(file);
|
|
109
|
-
return ext;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* 获取源文件所对应生成文件的扩展名
|
|
113
|
-
* @param file 源文件名
|
|
114
|
-
* */
|
|
115
|
-
function fileOutExt(file) {
|
|
116
|
-
let ext = extname(file);
|
|
117
|
-
if (ext === ".ts")
|
|
118
|
-
return outExt;
|
|
119
|
-
if (ext === ".tsx")
|
|
120
|
-
return outExt;
|
|
121
|
-
return ext;
|
|
122
|
-
}
|
|
123
|
-
class ImportPathRewrite {
|
|
124
|
-
filePath;
|
|
125
|
-
constructor(filePath, node) {
|
|
126
|
-
this.filePath = filePath;
|
|
127
|
-
this.traverse(node);
|
|
128
|
-
}
|
|
129
|
-
traverse(node) {
|
|
130
|
-
switch (node.type) {
|
|
131
|
-
case "Program":
|
|
132
|
-
node.body.forEach(c => this.traverse(c));
|
|
133
|
-
break;
|
|
134
|
-
case "File":
|
|
135
|
-
this.traverse(node.program);
|
|
136
|
-
break;
|
|
137
|
-
case "ImportDeclaration":
|
|
138
|
-
if (node.source.type === "StringLiteral" && node.source.value.startsWith(".")) {
|
|
139
|
-
let ext = extname(node.source.value);
|
|
140
|
-
if (ext != outExt) {
|
|
141
|
-
let dir = path.dirname(this.filePath);
|
|
142
|
-
let fullPath = path.join(dir, node.source.value);
|
|
143
|
-
console.log(`ImportDeclaration: ${fullPath} -> ${ext}`);
|
|
144
|
-
if (fs.existsSync(fullPath) && fs.statSync(fullPath).isDirectory()) {
|
|
145
|
-
node.source.value = node.source.value + "/index";
|
|
146
|
-
}
|
|
147
|
-
node.source.value += outExt;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|