maishu-scripts 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/modules/actions/less-compile.d.ts +8 -0
- package/out/modules/actions/less-compile.js +33 -0
- package/out/modules/actions/scss-compile.d.ts +9 -0
- package/out/modules/actions/scss-compile.js +55 -0
- package/out/modules/compile.js +5 -9
- package/out/modules/project-compiler.d.ts +0 -22
- package/out/modules/project-compiler.js +0 -158
- package/package.json +4 -1
- package/src/modules/actions/biel-compile.ts +2 -0
- package/src/modules/actions/less-compile.test.ts +34 -0
- package/src/modules/actions/less-compile.ts +35 -0
- package/src/modules/actions/scss-compile.test.ts +38 -0
- package/src/modules/actions/scss-compile.ts +35 -0
- package/src/modules/compile.test.ts +0 -15
- package/src/modules/compile.ts +5 -13
- package/src/modules/project-compiler.ts +1 -170
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const less_1 = __importDefault(require("less"));
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
/**
|
|
11
|
+
* 编译特定Less文件,并生成到指定目录
|
|
12
|
+
* @param filePath 源文件路径,绝对路径
|
|
13
|
+
* @param outDir 输出目录,相对于项目路径
|
|
14
|
+
* @param projectPath 项目路径,绝对路径
|
|
15
|
+
*/
|
|
16
|
+
const compileFile = async (filePath, outDir, projectPath) => {
|
|
17
|
+
if (!filePath)
|
|
18
|
+
throw errors_1.errors.argumentNull('filePath');
|
|
19
|
+
if (!outDir)
|
|
20
|
+
throw errors_1.errors.argumentNull('outDir');
|
|
21
|
+
if (!projectPath)
|
|
22
|
+
throw errors_1.errors.argumentNull('projectPath');
|
|
23
|
+
let content = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
24
|
+
let result = await less_1.default.render(content, { filename: filePath });
|
|
25
|
+
let ext = path_1.default.extname(filePath);
|
|
26
|
+
let outExt = '.css';
|
|
27
|
+
let targetPath = path_1.default.join(projectPath, outDir, path_1.default.basename(filePath).replace(ext, outExt));
|
|
28
|
+
let outDirPath = path_1.default.resolve(targetPath, "..");
|
|
29
|
+
if (!fs_1.default.existsSync(outDirPath))
|
|
30
|
+
fs_1.default.mkdirSync(outDirPath, { recursive: true });
|
|
31
|
+
fs_1.default.writeFileSync(targetPath, result.css);
|
|
32
|
+
};
|
|
33
|
+
exports.default = compileFile;
|
|
@@ -0,0 +1,55 @@
|
|
|
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 = void 0;
|
|
27
|
+
const sass = __importStar(require("sass"));
|
|
28
|
+
const errors_1 = require("../errors");
|
|
29
|
+
const fs = __importStar(require("fs"));
|
|
30
|
+
const path = __importStar(require("path"));
|
|
31
|
+
/**
|
|
32
|
+
* 编译特定SCSS文件,并生成到指定目录
|
|
33
|
+
* @param filePath 源文件路径,绝对路径
|
|
34
|
+
* @param outDir 输出目录,相对于项目路径
|
|
35
|
+
* @param projectPath 项目路径,绝对路径
|
|
36
|
+
*/
|
|
37
|
+
const compileFile = (filePath, outDir, projectPath) => {
|
|
38
|
+
if (!filePath)
|
|
39
|
+
throw errors_1.errors.argumentNull('filePath');
|
|
40
|
+
if (!outDir)
|
|
41
|
+
throw errors_1.errors.argumentNull('outDir');
|
|
42
|
+
if (!projectPath)
|
|
43
|
+
throw errors_1.errors.argumentNull('projectPath');
|
|
44
|
+
let content = fs.readFileSync(filePath, 'utf-8');
|
|
45
|
+
let result = sass.renderSync({ data: content });
|
|
46
|
+
let ext = path.extname(filePath);
|
|
47
|
+
let outExt = '.css';
|
|
48
|
+
let targetPath = path.join(projectPath, outDir, path.basename(filePath).replace(ext, outExt));
|
|
49
|
+
let outDirPath = path.resolve(targetPath, "..");
|
|
50
|
+
if (!fs.existsSync(outDirPath))
|
|
51
|
+
fs.mkdirSync(outDirPath, { recursive: true });
|
|
52
|
+
fs.writeFileSync(targetPath, result.css.toString());
|
|
53
|
+
};
|
|
54
|
+
exports.compileFile = compileFile;
|
|
55
|
+
exports.default = exports.compileFile;
|
package/out/modules/compile.js
CHANGED
|
@@ -35,11 +35,15 @@ const path = __importStar(require("path"));
|
|
|
35
35
|
const errors_1 = require("./errors");
|
|
36
36
|
const biel_compile_1 = require("./actions/biel-compile");
|
|
37
37
|
const copy_file_1 = __importDefault(require("./actions/copy-file"));
|
|
38
|
+
const scss_compile_1 = __importDefault(require("./actions/scss-compile"));
|
|
39
|
+
const less_compile_1 = __importDefault(require("./actions/less-compile"));
|
|
38
40
|
const skipFiles = ["\\S+\\.d\\.tsx?$", "\\S+\\.test\\.tsx?$", "\\S+\\.spec\\.tsx?$"];
|
|
39
|
-
const extCopy = [".js", ".html", ".css", ".jpg", ".png", ".gif", ".
|
|
41
|
+
const extCopy = [".js", ".html", ".css", ".jpg", ".png", ".gif", ".less"];
|
|
40
42
|
let fileActions = {
|
|
41
43
|
".ts": biel_compile_1.compileFile,
|
|
42
44
|
".tsx": biel_compile_1.compileFile,
|
|
45
|
+
".scss": scss_compile_1.default,
|
|
46
|
+
".less": less_compile_1.default,
|
|
43
47
|
};
|
|
44
48
|
extCopy.forEach(ext => fileActions[ext] = copy_file_1.default);
|
|
45
49
|
/** 将 sourceDir 目录下所有文件生成到 outDir */
|
|
@@ -105,14 +109,6 @@ function watchDirectory(sourceRoot, outRoot, projectPath, callback) {
|
|
|
105
109
|
}
|
|
106
110
|
});
|
|
107
111
|
}
|
|
108
|
-
// export function copyFile(filePath: string, outDir: string) {
|
|
109
|
-
// if (!filePath) throw errors.argumentNull("filePath");
|
|
110
|
-
// if (!outDir) throw errors.argumentNull("outDir");
|
|
111
|
-
// let out = filePath.replace(path.dirname(filePath), outDir);
|
|
112
|
-
// let outDirPath = path.resolve(out, "..");
|
|
113
|
-
// fs.mkdirSync(outDirPath, { recursive: true });
|
|
114
|
-
// fs.copyFileSync(filePath, out);
|
|
115
|
-
// }
|
|
116
112
|
function isIgnoredFile(filePath) {
|
|
117
113
|
if (!filePath)
|
|
118
114
|
throw errors_1.errors.argumentNull("filePath");
|
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
import * as babel from "@babel/core";
|
|
2
2
|
export declare class ProjectCompiler {
|
|
3
|
-
private projectPath;
|
|
4
|
-
private sourceDirectoryNanme;
|
|
5
|
-
private outputDirectoryName;
|
|
6
|
-
private fileActions;
|
|
7
3
|
private skipFiles;
|
|
8
4
|
static tsOutExt: string;
|
|
9
|
-
constructor(projectPath: string, sourceDirectoryNanme: string, outputDirectoryName: string);
|
|
10
|
-
/**
|
|
11
|
-
* 编译特定文件,并生成到制定目录
|
|
12
|
-
* @param sourcePath 源文件路径
|
|
13
|
-
* @param outDir 输出目录
|
|
14
|
-
* */
|
|
15
|
-
compileFile(filePath: string, outDir: string): Promise<void>;
|
|
16
|
-
private compileTypeScriptFileByBabel;
|
|
17
5
|
static loadBabelConfig(configPath: string): babel.TransformOptions;
|
|
18
6
|
static findBabelConfigPath(projectPath: string, directoryPath: string): string | null;
|
|
19
7
|
static getBabelConfig(projectPath: string, directoryPath: string): {
|
|
@@ -21,14 +9,4 @@ export declare class ProjectCompiler {
|
|
|
21
9
|
path: string;
|
|
22
10
|
};
|
|
23
11
|
static getDefaultBabelConfig(): babel.TransformOptions;
|
|
24
|
-
/**
|
|
25
|
-
* 获取源文件所对应生成文件的扩展名
|
|
26
|
-
* @param file 源文件名
|
|
27
|
-
* */
|
|
28
|
-
private fileOutExt;
|
|
29
|
-
private isIgnoredFile;
|
|
30
|
-
generateCode(): void;
|
|
31
|
-
generateCode(sourceDir: string, outDir: string): void;
|
|
32
|
-
watchDirectory(): void;
|
|
33
|
-
run(): void;
|
|
34
12
|
}
|
|
@@ -22,104 +22,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
26
|
exports.ProjectCompiler = void 0;
|
|
30
|
-
const nodemon_1 = __importDefault(require("nodemon"));
|
|
31
27
|
const errors_1 = require("./errors");
|
|
32
28
|
const fs = __importStar(require("fs"));
|
|
33
29
|
const path = __importStar(require("path"));
|
|
34
|
-
const babel = __importStar(require("@babel/core"));
|
|
35
|
-
const import_path_rewrite_1 = require("./import-path-rewrite");
|
|
36
|
-
const node_watch_1 = __importDefault(require("node-watch"));
|
|
37
30
|
const tsOutExt = ".js";
|
|
38
31
|
class ProjectCompiler {
|
|
39
|
-
projectPath;
|
|
40
|
-
sourceDirectoryNanme;
|
|
41
|
-
outputDirectoryName;
|
|
42
|
-
fileActions;
|
|
43
32
|
skipFiles = ["\\S+\\.d\\.tsx?$", "\\S+\\.test\\.tsx?$", "\\S+\\.spec\\.tsx?$"];
|
|
44
33
|
static tsOutExt = tsOutExt;
|
|
45
|
-
constructor(projectPath, sourceDirectoryNanme, outputDirectoryName) {
|
|
46
|
-
this.projectPath = projectPath;
|
|
47
|
-
this.sourceDirectoryNanme = sourceDirectoryNanme;
|
|
48
|
-
this.outputDirectoryName = outputDirectoryName;
|
|
49
|
-
if (!projectPath)
|
|
50
|
-
throw errors_1.errors.argumentNull("projectPath");
|
|
51
|
-
if (!sourceDirectoryNanme)
|
|
52
|
-
throw errors_1.errors.argumentNull("sourceDirectoryNanme");
|
|
53
|
-
if (!outputDirectoryName)
|
|
54
|
-
throw errors_1.errors.argumentNull("outputDirectoryName");
|
|
55
|
-
if (!path.isAbsolute(projectPath))
|
|
56
|
-
throw errors_1.errors.notAbsolutePath(projectPath);
|
|
57
|
-
let sourcePath = path.join(projectPath, sourceDirectoryNanme);
|
|
58
|
-
if (!fs.existsSync(sourcePath))
|
|
59
|
-
throw errors_1.errors.pathNotExists(sourcePath);
|
|
60
|
-
this.fileActions = {
|
|
61
|
-
".ts": this.compileFile.bind(this),
|
|
62
|
-
".tsx": this.compileFile.bind(this),
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* 编译特定文件,并生成到制定目录
|
|
67
|
-
* @param sourcePath 源文件路径
|
|
68
|
-
* @param outDir 输出目录
|
|
69
|
-
* */
|
|
70
|
-
async compileFile(filePath, outDir) {
|
|
71
|
-
this.compileTypeScriptFileByBabel(filePath, outDir);
|
|
72
|
-
}
|
|
73
|
-
async compileTypeScriptFileByBabel(sourcePath, outDir) {
|
|
74
|
-
if (!sourcePath)
|
|
75
|
-
throw errors_1.errors.argumentNull("sourcePath");
|
|
76
|
-
if (!outDir)
|
|
77
|
-
throw errors_1.errors.argumentNull("outDir");
|
|
78
|
-
if (!fs.existsSync(sourcePath))
|
|
79
|
-
throw errors_1.errors.pathNotExists(sourcePath);
|
|
80
|
-
let sourceDir = path.dirname(sourcePath);
|
|
81
|
-
let babelConfig = ProjectCompiler.getBabelConfig(this.projectPath, sourceDir);
|
|
82
|
-
let babelOptions = babelConfig.options;
|
|
83
|
-
let babelPath = babelConfig.path;
|
|
84
|
-
babelOptions.filename = sourcePath;
|
|
85
|
-
babelOptions.code = false;
|
|
86
|
-
babelOptions.ast = true;
|
|
87
|
-
let fileResult = babel.transformFileSync(sourcePath, babelOptions);
|
|
88
|
-
if (!fileResult)
|
|
89
|
-
throw errors_1.errors.compileError(sourcePath);
|
|
90
|
-
let ast = fileResult.ast;
|
|
91
|
-
if (!ast)
|
|
92
|
-
throw errors_1.errors.compileError(sourcePath);
|
|
93
|
-
new import_path_rewrite_1.ImportPathRewrite(sourcePath, ast, tsOutExt);
|
|
94
|
-
let r = babel.transformFromAstSync(ast, undefined, {
|
|
95
|
-
filename: sourcePath, plugins: babelOptions.plugins,
|
|
96
|
-
presets: babelOptions.presets, sourceMaps: true
|
|
97
|
-
});
|
|
98
|
-
if (!r || r.code == null)
|
|
99
|
-
throw errors_1.errors.compileError(sourcePath);
|
|
100
|
-
let ext = path.extname(sourcePath);
|
|
101
|
-
let outExt = this.fileOutExt(sourcePath);
|
|
102
|
-
let targetPath = path.join(outDir, path.basename(sourcePath).replace(ext, outExt));
|
|
103
|
-
let outDirPath = path.resolve(targetPath, "..");
|
|
104
|
-
if (r.map) {
|
|
105
|
-
r.map.file = path.basename(targetPath);
|
|
106
|
-
let sources = r.map.sources || [];
|
|
107
|
-
let sourceDir = path.dirname(sourcePath);
|
|
108
|
-
sources.forEach((s, i) => {
|
|
109
|
-
sources[i] = path.relative(outDirPath, path.join(sourceDir, s));
|
|
110
|
-
});
|
|
111
|
-
r.map.sources = sources;
|
|
112
|
-
let mapPath = targetPath + ".map";
|
|
113
|
-
if (!fs.existsSync(outDirPath))
|
|
114
|
-
fs.mkdirSync(outDirPath, { recursive: true });
|
|
115
|
-
fs.writeFileSync(mapPath, JSON.stringify(r.map));
|
|
116
|
-
r.code += `\n//babelPath:${babelPath}`;
|
|
117
|
-
r.code += "\n//# sourceMappingURL=" + path.basename(sourcePath);
|
|
118
|
-
}
|
|
119
|
-
if (!fs.existsSync(outDirPath))
|
|
120
|
-
fs.mkdirSync(outDirPath, { recursive: true });
|
|
121
|
-
fs.writeFileSync(targetPath, r.code);
|
|
122
|
-
}
|
|
123
34
|
static loadBabelConfig(configPath) {
|
|
124
35
|
if (!configPath)
|
|
125
36
|
throw errors_1.errors.argumentNull("configPath");
|
|
@@ -182,74 +93,5 @@ class ProjectCompiler {
|
|
|
182
93
|
let babelOptions = { plugins, presets };
|
|
183
94
|
return babelOptions;
|
|
184
95
|
}
|
|
185
|
-
/**
|
|
186
|
-
* 获取源文件所对应生成文件的扩展名
|
|
187
|
-
* @param file 源文件名
|
|
188
|
-
* */
|
|
189
|
-
fileOutExt(file) {
|
|
190
|
-
let ext = path.extname(file);
|
|
191
|
-
if (ext === ".ts")
|
|
192
|
-
return tsOutExt;
|
|
193
|
-
if (ext === ".tsx")
|
|
194
|
-
return tsOutExt;
|
|
195
|
-
return ext;
|
|
196
|
-
}
|
|
197
|
-
isIgnoredFile(filePath) {
|
|
198
|
-
if (!filePath)
|
|
199
|
-
throw errors_1.errors.argumentNull("filePath");
|
|
200
|
-
let isSkip = this.skipFiles.some(pattern => new RegExp(pattern).test(filePath));
|
|
201
|
-
return isSkip;
|
|
202
|
-
}
|
|
203
|
-
generateCode(sourceDir, outDir) {
|
|
204
|
-
// if (!sourceDir) throw errors.argumentNull("sourceDir");
|
|
205
|
-
// if (!outDir) throw errors.argumentNull("outDir");
|
|
206
|
-
if (!sourceDir)
|
|
207
|
-
sourceDir = path.join(this.projectPath, this.sourceDirectoryNanme);
|
|
208
|
-
if (!outDir)
|
|
209
|
-
outDir = path.join(this.projectPath, this.outputDirectoryName);
|
|
210
|
-
let fileActions = this.fileActions;
|
|
211
|
-
if (!fs.existsSync(sourceDir))
|
|
212
|
-
throw errors_1.errors.pathNotExists(sourceDir);
|
|
213
|
-
let files = fs.readdirSync(sourceDir);
|
|
214
|
-
for (let file of files) {
|
|
215
|
-
let filePath = path.join(sourceDir, file);
|
|
216
|
-
if (!fs.statSync(filePath).isFile()) {
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
let isSkip = this.isIgnoredFile(filePath); //skipFiles.some(pattern => new RegExp(pattern).test(filePath));
|
|
220
|
-
if (isSkip) {
|
|
221
|
-
console.log(`Skip ${filePath}`);
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
let ext = path.extname(file);
|
|
225
|
-
let action = fileActions[ext];
|
|
226
|
-
if (action) {
|
|
227
|
-
action(filePath, outDir);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
let dirs = fs.readdirSync(sourceDir);
|
|
231
|
-
for (let dir of dirs) {
|
|
232
|
-
let fullPath = path.join(sourceDir, dir);
|
|
233
|
-
let outDirPath = path.join(outDir, dir);
|
|
234
|
-
if (fs.statSync(fullPath).isDirectory()) {
|
|
235
|
-
this.generateCode(fullPath, outDirPath);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
watchDirectory() {
|
|
240
|
-
(0, node_watch_1.default)(this.sourceDirectoryNanme, { recursive: true }, async (evt, name) => {
|
|
241
|
-
let action = this.fileActions[path.extname(name)];
|
|
242
|
-
let outPath = path.dirname(name).replace(this.sourceDirectoryNanme, this.outputDirectoryName);
|
|
243
|
-
if (action) {
|
|
244
|
-
action(name, outPath);
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
run() {
|
|
249
|
-
(0, nodemon_1.default)({
|
|
250
|
-
script: `./${this.outputDirectoryName}/main.js`,
|
|
251
|
-
watch: [`./${this.outputDirectoryName}/`],
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
96
|
}
|
|
255
97
|
exports.ProjectCompiler = ProjectCompiler;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maishu-scripts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "用于对 node 项目进行代码生成,打包,运行",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@babel/core": "^7.24.3",
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
"@babel/plugin-transform-typescript": "^7.24.1",
|
|
10
10
|
"@types/node": "^20.12.2",
|
|
11
11
|
"babel-plugin-transform-typescript-metadata": "^0.3.2",
|
|
12
|
+
"less": "^4.5.1",
|
|
12
13
|
"maishu-toolkit": "^1.12.6",
|
|
13
14
|
"node-watch": "^0.7.4",
|
|
14
15
|
"nodemon": "^3.1.4",
|
|
16
|
+
"sass": "^1.97.1",
|
|
15
17
|
"typescript": "^5.4.5"
|
|
16
18
|
},
|
|
17
19
|
"devDependencies": {
|
|
@@ -19,6 +21,7 @@
|
|
|
19
21
|
"@babel/preset-typescript": "^7.24.1",
|
|
20
22
|
"@types/babel__core": "^7.20.5",
|
|
21
23
|
"@types/jest": "^29.5.12",
|
|
24
|
+
"@types/less": "^3.0.8",
|
|
22
25
|
"jest": "^29.7.0"
|
|
23
26
|
},
|
|
24
27
|
"main": "./out/index.js",
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import lessCompile from './less-compile';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
|
|
5
|
+
describe('less-compile', () => {
|
|
6
|
+
it('should compile less files', async () => {
|
|
7
|
+
// generate a less test file
|
|
8
|
+
const lessTestFile = path.join(__dirname, 'test.less');
|
|
9
|
+
let lessTestFileContent = `
|
|
10
|
+
.test {
|
|
11
|
+
color: red;
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
fs.writeFileSync(lessTestFile, lessTestFileContent);
|
|
15
|
+
|
|
16
|
+
// compile the less test file
|
|
17
|
+
await lessCompile(lessTestFile, 'dist', __dirname);
|
|
18
|
+
|
|
19
|
+
const lessTestCompiledFile = path.join(__dirname, 'dist', 'test.css');
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
// check if the compiled file exists
|
|
23
|
+
// 移除 lessTestFileContent 空格,换行符
|
|
24
|
+
lessTestFileContent = lessTestFileContent.replace(/\s/g, '').replace(/[\r\n]/g, '');
|
|
25
|
+
let compiledFileContent = fs.readFileSync(lessTestCompiledFile, 'utf-8');
|
|
26
|
+
compiledFileContent = compiledFileContent.replace(/\s/g, '').replace(/[\r\n]/g, '');
|
|
27
|
+
expect(compiledFileContent).toBe(lessTestFileContent);
|
|
28
|
+
|
|
29
|
+
// clean up
|
|
30
|
+
fs.unlinkSync(lessTestFile);
|
|
31
|
+
fs.unlinkSync(lessTestCompiledFile);
|
|
32
|
+
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import less from 'less';
|
|
2
|
+
import { errors } from '../errors';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { FileAction } from '../../types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 编译特定Less文件,并生成到指定目录
|
|
9
|
+
* @param filePath 源文件路径,绝对路径
|
|
10
|
+
* @param outDir 输出目录,相对于项目路径
|
|
11
|
+
* @param projectPath 项目路径,绝对路径
|
|
12
|
+
*/
|
|
13
|
+
const compileFile = async (filePath: string, outDir: string, projectPath: string) => {
|
|
14
|
+
if (!filePath)
|
|
15
|
+
throw errors.argumentNull('filePath');
|
|
16
|
+
if (!outDir)
|
|
17
|
+
throw errors.argumentNull('outDir');
|
|
18
|
+
if (!projectPath)
|
|
19
|
+
throw errors.argumentNull('projectPath');
|
|
20
|
+
|
|
21
|
+
let content = fs.readFileSync(filePath, 'utf-8');
|
|
22
|
+
let result = await less.render(content, { filename: filePath });
|
|
23
|
+
|
|
24
|
+
let ext = path.extname(filePath);
|
|
25
|
+
let outExt = '.css';
|
|
26
|
+
let targetPath = path.join(projectPath, outDir, path.basename(filePath).replace(ext, outExt));
|
|
27
|
+
let outDirPath = path.resolve(targetPath, "..");
|
|
28
|
+
|
|
29
|
+
if (!fs.existsSync(outDirPath))
|
|
30
|
+
fs.mkdirSync(outDirPath, { recursive: true });
|
|
31
|
+
|
|
32
|
+
fs.writeFileSync(targetPath, result.css);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default compileFile;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import scssCompile from './scss-compile';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
|
|
5
|
+
describe('scss-compile', () => {
|
|
6
|
+
|
|
7
|
+
it('should compile scss files', () => {
|
|
8
|
+
|
|
9
|
+
// generate test file
|
|
10
|
+
const testFile = path.join(__dirname, 'test.scss');
|
|
11
|
+
const testContent = `$color: red;
|
|
12
|
+
.test {
|
|
13
|
+
background-color: $color;
|
|
14
|
+
}`;
|
|
15
|
+
fs.writeFileSync(testFile, testContent);
|
|
16
|
+
|
|
17
|
+
scssCompile(testFile, 'dist', __dirname);
|
|
18
|
+
|
|
19
|
+
const expectedFile = path.join(__dirname, 'dist', 'test.css');
|
|
20
|
+
let expectedContent = `.test {
|
|
21
|
+
background-color: red;
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
// 移除 expectedContent 中空格和换行符
|
|
25
|
+
expectedContent = expectedContent.replace(/\s+/g, '').replace(/[\r\n]/g, '');
|
|
26
|
+
let fileContent = fs.readFileSync(expectedFile, 'utf-8');
|
|
27
|
+
fileContent = fileContent.replace(/\s+/g, '').replace(/[\r\n]/g, '');
|
|
28
|
+
|
|
29
|
+
expect(fileContent).toBe(expectedContent);
|
|
30
|
+
|
|
31
|
+
// clean up
|
|
32
|
+
fs.unlinkSync(testFile);
|
|
33
|
+
fs.unlinkSync(expectedFile);
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as sass from 'sass';
|
|
2
|
+
import { errors } from '../errors';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import type { FileAction } from '../../types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 编译特定SCSS文件,并生成到指定目录
|
|
9
|
+
* @param filePath 源文件路径,绝对路径
|
|
10
|
+
* @param outDir 输出目录,相对于项目路径
|
|
11
|
+
* @param projectPath 项目路径,绝对路径
|
|
12
|
+
*/
|
|
13
|
+
export const compileFile: FileAction = (filePath: string, outDir: string, projectPath: string) => {
|
|
14
|
+
if (!filePath)
|
|
15
|
+
throw errors.argumentNull('filePath');
|
|
16
|
+
if (!outDir)
|
|
17
|
+
throw errors.argumentNull('outDir');
|
|
18
|
+
if (!projectPath)
|
|
19
|
+
throw errors.argumentNull('projectPath');
|
|
20
|
+
|
|
21
|
+
let content = fs.readFileSync(filePath, 'utf-8');
|
|
22
|
+
let result = sass.renderSync({ data: content });
|
|
23
|
+
|
|
24
|
+
let ext = path.extname(filePath);
|
|
25
|
+
let outExt = '.css';
|
|
26
|
+
let targetPath = path.join(projectPath, outDir, path.basename(filePath).replace(ext, outExt));
|
|
27
|
+
let outDirPath = path.resolve(targetPath, "..");
|
|
28
|
+
|
|
29
|
+
if (!fs.existsSync(outDirPath))
|
|
30
|
+
fs.mkdirSync(outDirPath, { recursive: true });
|
|
31
|
+
|
|
32
|
+
fs.writeFileSync(targetPath, result.css.toString());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default compileFile;
|
|
@@ -30,19 +30,4 @@ describe("Compile Test", function () {
|
|
|
30
30
|
expect(ignored).toBe(true);
|
|
31
31
|
})
|
|
32
32
|
|
|
33
|
-
test("temp", function () {
|
|
34
|
-
let sourceFile = "D:\\startdard-process\\plm-projects\\tc-api-proxy\\src\\app.controller.ts";
|
|
35
|
-
let sourceCode = fs.readFileSync(sourceFile, "utf8");
|
|
36
|
-
let r = ts.transpileModule(sourceCode, {
|
|
37
|
-
compilerOptions: {
|
|
38
|
-
module: ts.ModuleKind.CommonJS,
|
|
39
|
-
target: ts.ScriptTarget.ES2015,
|
|
40
|
-
sourceMap: true
|
|
41
|
-
}
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
console.log(r);
|
|
45
|
-
|
|
46
|
-
})
|
|
47
|
-
|
|
48
33
|
})
|
package/src/modules/compile.ts
CHANGED
|
@@ -5,13 +5,17 @@ import { errors } from "./errors";
|
|
|
5
5
|
import { compileFile as bielCompileFile } from "./actions/biel-compile";
|
|
6
6
|
import copyFile from "./actions/copy-file";
|
|
7
7
|
import { FileAction } from "../types";
|
|
8
|
+
import scssCompile from "./actions/scss-compile";
|
|
9
|
+
import lessCompile from "./actions/less-compile";
|
|
8
10
|
|
|
9
11
|
const skipFiles = ["\\S+\\.d\\.tsx?$", "\\S+\\.test\\.tsx?$", "\\S+\\.spec\\.tsx?$"]
|
|
10
|
-
const extCopy = [".js", ".html", ".css", ".jpg", ".png", ".gif", ".
|
|
12
|
+
const extCopy = [".js", ".html", ".css", ".jpg", ".png", ".gif", ".less"];
|
|
11
13
|
|
|
12
14
|
let fileActions: { [ext: string]: FileAction } = {
|
|
13
15
|
".ts": bielCompileFile,
|
|
14
16
|
".tsx": bielCompileFile,
|
|
17
|
+
".scss": scssCompile,
|
|
18
|
+
".less": lessCompile,
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
extCopy.forEach(ext => fileActions[ext] = copyFile);
|
|
@@ -85,18 +89,6 @@ export function watchDirectory(sourceRoot: string, outRoot: string, projectPath:
|
|
|
85
89
|
})
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
// export function copyFile(filePath: string, outDir: string) {
|
|
89
|
-
// if (!filePath) throw errors.argumentNull("filePath");
|
|
90
|
-
// if (!outDir) throw errors.argumentNull("outDir");
|
|
91
|
-
|
|
92
|
-
// let out = filePath.replace(path.dirname(filePath), outDir);
|
|
93
|
-
// let outDirPath = path.resolve(out, "..");
|
|
94
|
-
|
|
95
|
-
// fs.mkdirSync(outDirPath, { recursive: true });
|
|
96
|
-
|
|
97
|
-
// fs.copyFileSync(filePath, out);
|
|
98
|
-
// }
|
|
99
|
-
|
|
100
92
|
export function isIgnoredFile(filePath: string) {
|
|
101
93
|
if (!filePath) throw errors.argumentNull("filePath");
|
|
102
94
|
|
|
@@ -12,96 +12,10 @@ type FileAction = (filePath: string, outDir: string) => void;
|
|
|
12
12
|
|
|
13
13
|
export class ProjectCompiler {
|
|
14
14
|
|
|
15
|
-
private fileActions: { [ext: string]: FileAction };
|
|
16
15
|
private skipFiles = ["\\S+\\.d\\.tsx?$", "\\S+\\.test\\.tsx?$", "\\S+\\.spec\\.tsx?$"];
|
|
17
16
|
|
|
18
17
|
static tsOutExt = tsOutExt;
|
|
19
18
|
|
|
20
|
-
constructor(private projectPath: string, private sourceDirectoryNanme: string, private outputDirectoryName: string) {
|
|
21
|
-
if (!projectPath) throw errors.argumentNull("projectPath");
|
|
22
|
-
if (!sourceDirectoryNanme) throw errors.argumentNull("sourceDirectoryNanme");
|
|
23
|
-
if (!outputDirectoryName) throw errors.argumentNull("outputDirectoryName");
|
|
24
|
-
|
|
25
|
-
if (!path.isAbsolute(projectPath))
|
|
26
|
-
throw errors.notAbsolutePath(projectPath);
|
|
27
|
-
|
|
28
|
-
let sourcePath = path.join(projectPath, sourceDirectoryNanme);
|
|
29
|
-
if (!fs.existsSync(sourcePath))
|
|
30
|
-
throw errors.pathNotExists(sourcePath);
|
|
31
|
-
|
|
32
|
-
this.fileActions = {
|
|
33
|
-
".ts": this.compileFile.bind(this),
|
|
34
|
-
".tsx": this.compileFile.bind(this),
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 编译特定文件,并生成到制定目录
|
|
41
|
-
* @param sourcePath 源文件路径
|
|
42
|
-
* @param outDir 输出目录
|
|
43
|
-
* */
|
|
44
|
-
async compileFile(filePath: string, outDir: string) {
|
|
45
|
-
this.compileTypeScriptFileByBabel(filePath, outDir);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
private async compileTypeScriptFileByBabel(sourcePath: string, outDir: string) {
|
|
49
|
-
if (!sourcePath) throw errors.argumentNull("sourcePath");
|
|
50
|
-
if (!outDir) throw errors.argumentNull("outDir");
|
|
51
|
-
if (!fs.existsSync(sourcePath)) throw errors.pathNotExists(sourcePath);
|
|
52
|
-
|
|
53
|
-
let sourceDir = path.dirname(sourcePath);
|
|
54
|
-
let babelConfig = ProjectCompiler.getBabelConfig(this.projectPath, sourceDir);
|
|
55
|
-
let babelOptions = babelConfig.options;
|
|
56
|
-
let babelPath = babelConfig.path;
|
|
57
|
-
babelOptions.filename = sourcePath;
|
|
58
|
-
babelOptions.code = false;
|
|
59
|
-
babelOptions.ast = true;
|
|
60
|
-
|
|
61
|
-
let fileResult = babel.transformFileSync(sourcePath, babelOptions);
|
|
62
|
-
if (!fileResult)
|
|
63
|
-
throw errors.compileError(sourcePath);
|
|
64
|
-
|
|
65
|
-
let ast = fileResult.ast;
|
|
66
|
-
if (!ast)
|
|
67
|
-
throw errors.compileError(sourcePath);
|
|
68
|
-
|
|
69
|
-
new ImportPathRewrite(sourcePath, ast, tsOutExt);
|
|
70
|
-
let r = babel.transformFromAstSync(ast, undefined, {
|
|
71
|
-
filename: sourcePath, plugins: babelOptions.plugins,
|
|
72
|
-
presets: babelOptions.presets, sourceMaps: true
|
|
73
|
-
});
|
|
74
|
-
if (!r || r.code == null)
|
|
75
|
-
throw errors.compileError(sourcePath);
|
|
76
|
-
|
|
77
|
-
let ext = path.extname(sourcePath);
|
|
78
|
-
let outExt = this.fileOutExt(sourcePath);
|
|
79
|
-
let targetPath = path.join(outDir, path.basename(sourcePath).replace(ext, outExt));
|
|
80
|
-
let outDirPath = path.resolve(targetPath, "..");
|
|
81
|
-
|
|
82
|
-
if (r.map) {
|
|
83
|
-
r.map.file = path.basename(targetPath);
|
|
84
|
-
let sources = r.map.sources || [];
|
|
85
|
-
let sourceDir = path.dirname(sourcePath);
|
|
86
|
-
sources.forEach((s, i) => {
|
|
87
|
-
sources[i] = path.relative(outDirPath, path.join(sourceDir, s));
|
|
88
|
-
});
|
|
89
|
-
r.map.sources = sources;
|
|
90
|
-
let mapPath = targetPath + ".map";
|
|
91
|
-
if (!fs.existsSync(outDirPath))
|
|
92
|
-
fs.mkdirSync(outDirPath, { recursive: true });
|
|
93
|
-
|
|
94
|
-
fs.writeFileSync(mapPath, JSON.stringify(r.map));
|
|
95
|
-
r.code += `\n//babelPath:${babelPath}`;
|
|
96
|
-
r.code += "\n//# sourceMappingURL=" + path.basename(sourcePath);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (!fs.existsSync(outDirPath))
|
|
100
|
-
fs.mkdirSync(outDirPath, { recursive: true });
|
|
101
|
-
|
|
102
|
-
fs.writeFileSync(targetPath, r.code);
|
|
103
|
-
|
|
104
|
-
}
|
|
105
19
|
|
|
106
20
|
static loadBabelConfig(configPath: string): babel.TransformOptions {
|
|
107
21
|
if (!configPath) throw errors.argumentNull("configPath");
|
|
@@ -179,90 +93,7 @@ export class ProjectCompiler {
|
|
|
179
93
|
return babelOptions;
|
|
180
94
|
}
|
|
181
95
|
|
|
182
|
-
/**
|
|
183
|
-
* 获取源文件所对应生成文件的扩展名
|
|
184
|
-
* @param file 源文件名
|
|
185
|
-
* */
|
|
186
|
-
private fileOutExt(file: string) {
|
|
187
|
-
let ext = path.extname(file);
|
|
188
|
-
if (ext === ".ts")
|
|
189
|
-
return tsOutExt;
|
|
190
|
-
|
|
191
|
-
if (ext === ".tsx")
|
|
192
|
-
return tsOutExt;
|
|
193
|
-
|
|
194
|
-
return ext;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
private isIgnoredFile(filePath: string) {
|
|
198
|
-
if (!filePath) throw errors.argumentNull("filePath");
|
|
199
|
-
|
|
200
|
-
let isSkip = this.skipFiles.some(pattern => new RegExp(pattern).test(filePath));
|
|
201
|
-
return isSkip;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
generateCode(): void;
|
|
205
|
-
generateCode(sourceDir: string, outDir: string): void;
|
|
206
|
-
generateCode(sourceDir?: string, outDir?: string): void {
|
|
207
|
-
|
|
208
|
-
// if (!sourceDir) throw errors.argumentNull("sourceDir");
|
|
209
|
-
// if (!outDir) throw errors.argumentNull("outDir");
|
|
210
|
-
if (!sourceDir)
|
|
211
|
-
sourceDir = path.join(this.projectPath, this.sourceDirectoryNanme);
|
|
212
|
-
|
|
213
|
-
if (!outDir)
|
|
214
|
-
outDir = path.join(this.projectPath, this.outputDirectoryName);
|
|
215
|
-
|
|
216
|
-
let fileActions = this.fileActions;
|
|
217
|
-
|
|
218
|
-
if (!fs.existsSync(sourceDir))
|
|
219
|
-
throw errors.pathNotExists(sourceDir);
|
|
220
|
-
|
|
221
|
-
let files = fs.readdirSync(sourceDir);
|
|
222
|
-
for (let file of files) {
|
|
223
|
-
let filePath = path.join(sourceDir, file);
|
|
224
|
-
if (!fs.statSync(filePath).isFile()) {
|
|
225
|
-
continue;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
let isSkip = this.isIgnoredFile(filePath);//skipFiles.some(pattern => new RegExp(pattern).test(filePath));
|
|
229
|
-
if (isSkip) {
|
|
230
|
-
console.log(`Skip ${filePath}`);
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
let ext = path.extname(file);
|
|
235
|
-
let action = fileActions[ext];
|
|
236
|
-
if (action) {
|
|
237
|
-
action(filePath, outDir);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
let dirs = fs.readdirSync(sourceDir);
|
|
242
|
-
for (let dir of dirs) {
|
|
243
|
-
let fullPath = path.join(sourceDir, dir);
|
|
244
|
-
let outDirPath = path.join(outDir, dir);
|
|
245
|
-
if (fs.statSync(fullPath).isDirectory()) {
|
|
246
|
-
this.generateCode(fullPath, outDirPath);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
watchDirectory() {//sourceRoot: string, outRoot: string
|
|
252
|
-
watch(this.sourceDirectoryNanme, { recursive: true }, async (evt, name) => {
|
|
253
|
-
let action = this.fileActions[path.extname(name)];
|
|
254
|
-
let outPath = path.dirname(name).replace(this.sourceDirectoryNanme, this.outputDirectoryName);
|
|
255
|
-
if (action) {
|
|
256
|
-
action(name, outPath);
|
|
257
|
-
}
|
|
258
|
-
})
|
|
259
|
-
}
|
|
260
96
|
|
|
261
97
|
|
|
262
|
-
|
|
263
|
-
nodemon({
|
|
264
|
-
script: `./${this.outputDirectoryName}/main.js`,
|
|
265
|
-
watch: [`./${this.outputDirectoryName}/`],
|
|
266
|
-
})
|
|
267
|
-
}
|
|
98
|
+
|
|
268
99
|
}
|