file-lane 2.0.1-alpha.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.
Files changed (44) hide show
  1. package/README.md +13 -0
  2. package/lib/FileLane.d.ts +82 -0
  3. package/lib/FileLane.js +361 -0
  4. package/lib/FileLane.js.map +1 -0
  5. package/lib/FileLaneCompilation.d.ts +7 -0
  6. package/lib/FileLaneCompilation.js +14 -0
  7. package/lib/FileLaneCompilation.js.map +1 -0
  8. package/lib/event/CompilationEvent.d.ts +11 -0
  9. package/lib/event/CompilationEvent.js +18 -0
  10. package/lib/event/CompilationEvent.js.map +1 -0
  11. package/lib/event/FileEvent.d.ts +10 -0
  12. package/lib/event/FileEvent.js +16 -0
  13. package/lib/event/FileEvent.js.map +1 -0
  14. package/lib/event/IEventDispatcher.d.ts +9 -0
  15. package/lib/event/IEventDispatcher.js +4 -0
  16. package/lib/event/IEventDispatcher.js.map +1 -0
  17. package/lib/event/asyncEvent/AsyncEventDispatcher.d.ts +14 -0
  18. package/lib/event/asyncEvent/AsyncEventDispatcher.js +71 -0
  19. package/lib/event/asyncEvent/AsyncEventDispatcher.js.map +1 -0
  20. package/lib/event/asyncEvent/DataEvent.d.ts +9 -0
  21. package/lib/event/asyncEvent/DataEvent.js +14 -0
  22. package/lib/event/asyncEvent/DataEvent.js.map +1 -0
  23. package/lib/index.d.ts +7 -0
  24. package/lib/index.js +10 -0
  25. package/lib/index.js.map +1 -0
  26. package/lib/interface/IFileLaneConfig.d.ts +82 -0
  27. package/lib/interface/IFileLaneConfig.js +4 -0
  28. package/lib/interface/IFileLaneConfig.js.map +1 -0
  29. package/lib/interface/IFileLaneContext.d.ts +9 -0
  30. package/lib/interface/IFileLaneContext.js +4 -0
  31. package/lib/interface/IFileLaneContext.js.map +1 -0
  32. package/lib/interface/IFileParam.d.ts +11 -0
  33. package/lib/interface/IFileParam.js +4 -0
  34. package/lib/interface/IFileParam.js.map +1 -0
  35. package/lib/interface/ILoader.d.ts +9 -0
  36. package/lib/interface/ILoader.js +4 -0
  37. package/lib/interface/ILoader.js.map +1 -0
  38. package/lib/interface/IPlugin.d.ts +10 -0
  39. package/lib/interface/IPlugin.js +4 -0
  40. package/lib/interface/IPlugin.js.map +1 -0
  41. package/lib/utils/FileLaneUtil.d.ts +20 -0
  42. package/lib/utils/FileLaneUtil.js +85 -0
  43. package/lib/utils/FileLaneUtil.js.map +1 -0
  44. package/package.json +37 -0
package/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # `file-lane`
2
+
3
+ 用于文件转换,可1个文件转换为1个文件,也可1转多、多转1
4
+
5
+ <img src="./doc/flow.jpg" style="max-width: 1000px; width: 100%"/>
6
+
7
+ ## Usage
8
+
9
+ ```
10
+ const fileLane = require('file-lane');
11
+
12
+ // TODO: DEMONSTRATE API
13
+ ```
@@ -0,0 +1,82 @@
1
+ import IFileLaneConfig from './interface/IFileLaneConfig';
2
+ /**
3
+ * FileLane
4
+ *
5
+ * 文件车道,用于将文件进行对应转换,支持1对1、1对N、N对1
6
+ *
7
+ * @description
8
+ */
9
+ declare class FileLane<O = any> {
10
+ readonly config: IFileLaneConfig<O>;
11
+ readonly compilerOption?: O | undefined;
12
+ private context;
13
+ private watcher?;
14
+ private compilation?;
15
+ /**
16
+ * 实例化FileLane
17
+ * @param config fileLane 配置
18
+ * @param projectPath 项目路径
19
+ * @param compilerOption 编译参数,不同语言的项目具有的参数不同,即使同一项目开发者也会设置不同的参数
20
+ */
21
+ constructor(config: IFileLaneConfig<O>, projectPath?: string, compilerOption?: O | undefined);
22
+ /**
23
+ * 运行
24
+ * @param params
25
+ * @returns
26
+ */
27
+ start(params?: {
28
+ /**
29
+ * 是否开启文件监听
30
+ * 不开启--只运行一次
31
+ * 开启--文件变化时会自动再次运行
32
+ */
33
+ watch?: boolean;
34
+ }): Promise<void>;
35
+ private validateConfig;
36
+ private processExitHandler;
37
+ stop(): void;
38
+ dispose(): void;
39
+ /**
40
+ *
41
+ * @param fileList 原始文件列表
42
+ */
43
+ private build;
44
+ private initCompilation;
45
+ private buildFile;
46
+ private runLoaders;
47
+ private writeFiles;
48
+ private runLoader;
49
+ /**
50
+ * 匹配符合条件的loader
51
+ * @param filePath
52
+ * @returns
53
+ */
54
+ private findLoader;
55
+ private triggerPlugins;
56
+ /**
57
+ * 运行转换后续的任务
58
+ */
59
+ private runPreWorks;
60
+ /**
61
+ * 运行转换后续的任务
62
+ */
63
+ private runFollowWorks;
64
+ private watch;
65
+ /**
66
+ * 采集所有要处理的真实文件路径列表
67
+ * @param entryFileList
68
+ * @returns
69
+ */
70
+ private collectFile;
71
+ /**
72
+ * 监听文件变化
73
+ * @param onChange
74
+ */
75
+ private listenFileChange;
76
+ private get outputPath();
77
+ /**
78
+ * 清除输出文件夹
79
+ */
80
+ private cleanOutput;
81
+ }
82
+ export default FileLane;
@@ -0,0 +1,361 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const shared_utils_1 = require("@aiot-toolkit/shared-utils");
16
+ const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
17
+ const FileUtil_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/utils/FileUtil"));
18
+ const chokidar_1 = __importDefault(require("chokidar"));
19
+ const fs_extra_1 = __importDefault(require("fs-extra"));
20
+ const lodash_1 = __importDefault(require("lodash"));
21
+ const path_1 = __importDefault(require("path"));
22
+ const FileLaneCompilation_1 = __importDefault(require("./FileLaneCompilation"));
23
+ const CompilationEvent_1 = __importDefault(require("./event/CompilationEvent"));
24
+ const FileEvent_1 = __importDefault(require("./event/FileEvent"));
25
+ const FileLaneUtil_1 = __importDefault(require("./utils/FileLaneUtil"));
26
+ /**
27
+ * FileLane
28
+ *
29
+ * 文件车道,用于将文件进行对应转换,支持1对1、1对N、N对1
30
+ *
31
+ * @description
32
+ */
33
+ class FileLane {
34
+ /**
35
+ * 实例化FileLane
36
+ * @param config fileLane 配置
37
+ * @param projectPath 项目路径
38
+ * @param compilerOption 编译参数,不同语言的项目具有的参数不同,即使同一项目开发者也会设置不同的参数
39
+ */
40
+ constructor(config, projectPath, compilerOption) {
41
+ this.config = config;
42
+ this.compilerOption = compilerOption;
43
+ this.processExitHandler = () => {
44
+ this.dispose();
45
+ };
46
+ const cwd = process.cwd();
47
+ this.context = {
48
+ cwd,
49
+ projectPath: projectPath || cwd,
50
+ output: config.output
51
+ };
52
+ process.on('exit', this.processExitHandler);
53
+ }
54
+ /**
55
+ * 运行
56
+ * @param params
57
+ * @returns
58
+ */
59
+ start(params) {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ const errorList = this.validateConfig();
62
+ if (errorList && errorList.length) {
63
+ ColorConsole_1.default.log({
64
+ message: `\r\n${errorList.map((item, index) => `${index + 1}. ${item}`).join('\r\n')}\r\n`,
65
+ level: shared_utils_1.LOG_LEVEL.Error,
66
+ isOnlyPrintError: true
67
+ });
68
+ return;
69
+ }
70
+ this.cleanOutput();
71
+ const fileList = this.collectFile();
72
+ if (!fileList || !fileList.length) {
73
+ return;
74
+ }
75
+ yield this.build(fileList);
76
+ if (params === null || params === void 0 ? void 0 : params.watch) {
77
+ this.watch();
78
+ }
79
+ });
80
+ }
81
+ validateConfig() {
82
+ const result = [];
83
+ // 校验上下文路径,路径是否真实存在,是否为文件夹
84
+ const projectPath = this.context.projectPath;
85
+ if (fs_extra_1.default.existsSync(projectPath)) {
86
+ if (!fs_extra_1.default.statSync(projectPath).isDirectory()) {
87
+ result.push(`ProjectPath is not a folder`);
88
+ }
89
+ }
90
+ else {
91
+ result.push(`ProjectPath is not a real path`);
92
+ }
93
+ if (!this.config) {
94
+ result.push(`Missing config`);
95
+ }
96
+ else {
97
+ const { output, module } = this.config;
98
+ if (!output) {
99
+ result.push(`Config missing output attribute`);
100
+ }
101
+ if (!module) {
102
+ result.push(`Config missing module attribute`);
103
+ }
104
+ else {
105
+ if (!module.rules) {
106
+ result.push(`module missing rules attribute`);
107
+ }
108
+ else if (!module.rules.length) {
109
+ result.push(`module.rules must have at least one item`);
110
+ }
111
+ else {
112
+ module.rules.forEach((item, index) => {
113
+ if (!item.test) {
114
+ result.push(`rules[${index}] missing test attribute`);
115
+ }
116
+ if (!item.loader) {
117
+ result.push(`rules[${index}] missing loader attribute`);
118
+ }
119
+ else if (!item.loader.length) {
120
+ result.push(`rules[${index}]'loader must have at least one item`);
121
+ }
122
+ });
123
+ }
124
+ }
125
+ }
126
+ return result;
127
+ }
128
+ stop() {
129
+ this.dispose();
130
+ process.exit();
131
+ }
132
+ dispose() {
133
+ if (this.watcher) {
134
+ this.watcher.close();
135
+ }
136
+ }
137
+ /**
138
+ *
139
+ * @param fileList 原始文件列表
140
+ */
141
+ build(fileList) {
142
+ return __awaiter(this, void 0, void 0, function* () {
143
+ this.initCompilation();
144
+ yield this.runPreWorks(fileList);
145
+ this.triggerPlugins(new CompilationEvent_1.default(CompilationEvent_1.default.PROJECT_START));
146
+ for (let item of fileList) {
147
+ this.triggerPlugins(new FileEvent_1.default(FileEvent_1.default.FILE_START_COMPILATION, FileLaneUtil_1.default.pathToFileParam(item)));
148
+ yield this.buildFile(item);
149
+ this.triggerPlugins(new FileEvent_1.default(FileEvent_1.default.FILE_END_COMPILATION, FileLaneUtil_1.default.pathToFileParam(item)));
150
+ }
151
+ this.triggerPlugins(new CompilationEvent_1.default(CompilationEvent_1.default.PROJECT_END));
152
+ // 执行extra
153
+ this.triggerPlugins(new CompilationEvent_1.default(CompilationEvent_1.default.FLLOW_WORK_START));
154
+ yield this.runFollowWorks();
155
+ this.triggerPlugins(new CompilationEvent_1.default(CompilationEvent_1.default.FLLOW_WORK_END));
156
+ });
157
+ }
158
+ initCompilation() {
159
+ const { plugins } = this.config;
160
+ const compilation = new FileLaneCompilation_1.default();
161
+ plugins === null || plugins === void 0 ? void 0 : plugins.forEach((item) => {
162
+ item.compilation = compilation;
163
+ item.apply();
164
+ });
165
+ this.compilation = compilation;
166
+ }
167
+ buildFile(filePath) {
168
+ return __awaiter(this, void 0, void 0, function* () {
169
+ const fileList = yield this.runLoaders(filePath);
170
+ yield this.writeFiles(fileList);
171
+ });
172
+ }
173
+ runLoaders(filePath) {
174
+ return __awaiter(this, void 0, void 0, function* () {
175
+ // 拾取要处理的虚拟文件
176
+ const { fileCollector } = this.config;
177
+ const collectedFileList = fileCollector
178
+ ? fileCollector(filePath).map((item) => FileLaneUtil_1.default.pathToFileParam(item, true))
179
+ : [FileLaneUtil_1.default.pathToFileParam(filePath, true)];
180
+ // 查找到匹配的 loader
181
+ const loaderList = this.findLoader(filePath);
182
+ // 循环loader,转换文件
183
+ let result = collectedFileList.concat();
184
+ for (let item of loaderList) {
185
+ result = yield this.runLoader(result, item);
186
+ }
187
+ return result;
188
+ });
189
+ }
190
+ writeFiles(fileList) {
191
+ return __awaiter(this, void 0, void 0, function* () {
192
+ if (!fileList || !fileList.length) {
193
+ return;
194
+ }
195
+ const buildPath = this.outputPath;
196
+ return Promise.all(fileList.map((item) => {
197
+ const resolvePath = path_1.default.relative(this.context.projectPath, item.path);
198
+ // 将相对路径与输出路径拼接,形成最新的文件路径
199
+ const outputPath = path_1.default.join(buildPath, resolvePath);
200
+ return fs_extra_1.default.outputFile(outputPath, item.content || '', { encoding: 'utf-8' });
201
+ }));
202
+ });
203
+ }
204
+ runLoader(fileList, loaderType) {
205
+ return __awaiter(this, void 0, void 0, function* () {
206
+ const loader = new loaderType();
207
+ loader.context = this.context;
208
+ return loader.parser(fileList);
209
+ });
210
+ }
211
+ /**
212
+ * 匹配符合条件的loader
213
+ * @param filePath
214
+ * @returns
215
+ */
216
+ findLoader(filePath) {
217
+ const parse = path_1.default.basename(filePath);
218
+ const rules = this.config.module.rules;
219
+ let loaders = [];
220
+ for (let rule of rules) {
221
+ // 1. 检查filePath是否符合规则test
222
+ if (FileUtil_1.default.match(parse, rule.test) &&
223
+ FileUtil_1.default.include(filePath, rule.include, rule.exclude)) {
224
+ // 2. 符合规则就添加到返回列表中
225
+ loaders.push(...rule.loader);
226
+ }
227
+ }
228
+ return loaders;
229
+ }
230
+ triggerPlugins(event) {
231
+ return __awaiter(this, void 0, void 0, function* () {
232
+ if (this.compilation) {
233
+ return this.compilation.dispatch(event);
234
+ }
235
+ });
236
+ }
237
+ /**
238
+ * 运行转换后续的任务
239
+ */
240
+ runPreWorks(fileList) {
241
+ return __awaiter(this, void 0, void 0, function* () {
242
+ const { preWorks } = this.config;
243
+ if (preWorks) {
244
+ for (let item of preWorks) {
245
+ try {
246
+ yield item(this.context, fileList, this.config, this.compilerOption);
247
+ }
248
+ catch (error) {
249
+ // 报错 prework的item error
250
+ }
251
+ }
252
+ }
253
+ });
254
+ }
255
+ /**
256
+ * 运行转换后续的任务
257
+ */
258
+ runFollowWorks() {
259
+ return __awaiter(this, void 0, void 0, function* () {
260
+ const { followWorks } = this.config;
261
+ if (followWorks) {
262
+ for (let item of followWorks) {
263
+ yield item(this.context, this.config, this.compilerOption);
264
+ }
265
+ }
266
+ });
267
+ }
268
+ watch() {
269
+ return __awaiter(this, void 0, void 0, function* () {
270
+ // 监听文件变化,并触发 build
271
+ this.listenFileChange(() => __awaiter(this, void 0, void 0, function* () {
272
+ const fileList = this.collectFile();
273
+ yield this.build(fileList);
274
+ }));
275
+ });
276
+ }
277
+ /**
278
+ * 采集所有要处理的真实文件路径列表
279
+ * @param entryFileList
280
+ * @returns
281
+ */
282
+ collectFile(entryFileList) {
283
+ // 使用include projectPath获取所有要处理的真实文件
284
+ let files = [];
285
+ if (entryFileList) {
286
+ entryFileList.forEach((filePath) => {
287
+ if (FileUtil_1.default.include(filePath, this.config.include, this.config.exclude)) {
288
+ ColorConsole_1.default.log({
289
+ message: `file change: ${filePath}`
290
+ });
291
+ files.push(filePath);
292
+ }
293
+ });
294
+ }
295
+ else {
296
+ // 1.取出projectPath
297
+ const projectPath = this.context.projectPath;
298
+ // 2. 循环文件夹,取出所有匹配的文件路径
299
+ files = FileUtil_1.default.readAlldirSync(projectPath, this.config.include, this.config.exclude);
300
+ }
301
+ return files;
302
+ }
303
+ /**
304
+ * 监听文件变化
305
+ * @param onChange
306
+ */
307
+ listenFileChange(onChange) {
308
+ const watcher = chokidar_1.default.watch(this.context.projectPath);
309
+ const throttledOnChange = lodash_1.default.throttle(onChange, 1000, {
310
+ leading: true,
311
+ trailing: false
312
+ });
313
+ const handler = (filePath) => {
314
+ const { exclude, include } = this.config;
315
+ // 判断是否为删除,执行onChange回调
316
+ if (FileUtil_1.default.include(filePath, include, exclude)) {
317
+ throttledOnChange([filePath]);
318
+ }
319
+ };
320
+ watcher
321
+ .on('ready', () => {
322
+ ColorConsole_1.default.log({
323
+ message: 'Initial scan complete. Ready for Watch.'
324
+ });
325
+ watcher
326
+ .on('add', (path) => {
327
+ // 监听文件添加事件
328
+ handler(path);
329
+ })
330
+ .on('change', (path) => {
331
+ // 监听文件修改事件
332
+ handler(path);
333
+ })
334
+ .on('unlink', (filePath) => {
335
+ // 监听文件删除事件
336
+ handler(filePath);
337
+ });
338
+ })
339
+ .on('error', (error) => {
340
+ // 监听错误
341
+ ColorConsole_1.default.log({ level: shared_utils_1.LOG_LEVEL.Error, message: error.message });
342
+ });
343
+ if (this.watcher) {
344
+ this.watcher.close();
345
+ }
346
+ this.watcher = watcher;
347
+ }
348
+ get outputPath() {
349
+ const { output, projectPath } = this.context;
350
+ return path_1.default.join(projectPath, output);
351
+ }
352
+ /**
353
+ * 清除输出文件夹
354
+ */
355
+ cleanOutput() {
356
+ fs_extra_1.default.removeSync(this.outputPath);
357
+ }
358
+ }
359
+ exports.default = FileLane;
360
+
361
+ //# sourceMappingURL=FileLane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["FileLane.ts"],"names":[],"mappings":"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","file":"FileLane.js","sourcesContent":["import { LOG_LEVEL } from '@aiot-toolkit/shared-utils'\nimport ColorConsole from '@aiot-toolkit/shared-utils/lib/ColorConsole'\nimport FileUtil from '@aiot-toolkit/shared-utils/lib/utils/FileUtil'\nimport chokidar from 'chokidar'\nimport Fs from 'fs-extra'\nimport Lodash from 'lodash'\nimport Path from 'path'\nimport FileLaneCompilation from './FileLaneCompilation'\nimport CompilationEvent from './event/CompilationEvent'\nimport FileEvent from './event/FileEvent'\nimport DataEvent from './event/asyncEvent/DataEvent'\nimport IFileLaneConfig, { ILoaderClass } from './interface/IFileLaneConfig'\nimport IFileLaneContext from './interface/IFileLaneContext'\nimport IFileParam from './interface/IFileParam'\nimport FileLaneUtil from './utils/FileLaneUtil'\n\n/**\n * FileLane\n *\n * 文件车道,用于将文件进行对应转换,支持1对1、1对N、N对1\n *\n * @description\n */\nclass FileLane<O = any> {\n private context: IFileLaneContext\n // 创建监听实例\n private watcher?: chokidar.FSWatcher\n\n private compilation?: FileLaneCompilation\n\n /**\n * 实例化FileLane\n * @param config fileLane 配置\n * @param projectPath 项目路径\n * @param compilerOption 编译参数,不同语言的项目具有的参数不同,即使同一项目开发者也会设置不同的参数\n */\n constructor(\n public readonly config: IFileLaneConfig<O>,\n projectPath?: string,\n public readonly compilerOption?: O\n ) {\n const cwd = process.cwd()\n this.context = {\n cwd,\n projectPath: projectPath || cwd,\n output: config.output\n }\n\n process.on('exit', this.processExitHandler)\n }\n\n /**\n * 运行\n * @param params\n * @returns\n */\n public async start(params?: {\n /**\n * 是否开启文件监听\n * 不开启--只运行一次\n * 开启--文件变化时会自动再次运行\n */\n watch?: boolean\n }) {\n const errorList = this.validateConfig()\n if (errorList && errorList.length) {\n ColorConsole.log({\n message: `\\r\\n${errorList.map((item, index) => `${index + 1}. ${item}`).join('\\r\\n')}\\r\\n`,\n level: LOG_LEVEL.Error,\n isOnlyPrintError: true\n })\n return\n }\n this.cleanOutput()\n const fileList = this.collectFile()\n if (!fileList || !fileList.length) {\n return\n }\n await this.build(fileList)\n if (params?.watch) {\n this.watch()\n }\n }\n\n private validateConfig(): string[] {\n const result: string[] = []\n // 校验上下文路径,路径是否真实存在,是否为文件夹\n const projectPath = this.context.projectPath\n if (Fs.existsSync(projectPath)) {\n if (!Fs.statSync(projectPath).isDirectory()) {\n result.push(`ProjectPath is not a folder`)\n }\n } else {\n result.push(`ProjectPath is not a real path`)\n }\n if (!this.config) {\n result.push(`Missing config`)\n } else {\n const { output, module } = this.config\n if (!output) {\n result.push(`Config missing output attribute`)\n }\n\n if (!module) {\n result.push(`Config missing module attribute`)\n } else {\n if (!module.rules) {\n result.push(`module missing rules attribute`)\n } else if (!module.rules.length) {\n result.push(`module.rules must have at least one item`)\n } else {\n module.rules.forEach((item, index) => {\n if (!item.test) {\n result.push(`rules[${index}] missing test attribute`)\n }\n if (!item.loader) {\n result.push(`rules[${index}] missing loader attribute`)\n } else if (!item.loader.length) {\n result.push(`rules[${index}]'loader must have at least one item`)\n }\n })\n }\n }\n }\n return result\n }\n\n private processExitHandler = () => {\n this.dispose()\n }\n\n public stop() {\n this.dispose()\n process.exit()\n }\n\n public dispose() {\n if (this.watcher) {\n this.watcher.close()\n }\n }\n\n /**\n *\n * @param fileList 原始文件列表\n */\n private async build(fileList: string[]): Promise<void> {\n this.initCompilation()\n await this.runPreWorks(fileList)\n this.triggerPlugins(new CompilationEvent(CompilationEvent.PROJECT_START))\n for (let item of fileList) {\n this.triggerPlugins(\n new FileEvent(FileEvent.FILE_START_COMPILATION, FileLaneUtil.pathToFileParam(item))\n )\n await this.buildFile(item)\n this.triggerPlugins(\n new FileEvent(FileEvent.FILE_END_COMPILATION, FileLaneUtil.pathToFileParam(item))\n )\n }\n this.triggerPlugins(new CompilationEvent(CompilationEvent.PROJECT_END))\n // 执行extra\n this.triggerPlugins(new CompilationEvent(CompilationEvent.FLLOW_WORK_START))\n await this.runFollowWorks()\n this.triggerPlugins(new CompilationEvent(CompilationEvent.FLLOW_WORK_END))\n }\n\n private initCompilation() {\n const { plugins } = this.config\n const compilation = new FileLaneCompilation()\n plugins?.forEach((item) => {\n item.compilation = compilation\n item.apply()\n })\n this.compilation = compilation\n }\n\n private async buildFile(filePath: string): Promise<void> {\n const fileList = await this.runLoaders(filePath)\n await this.writeFiles(fileList)\n }\n\n private async runLoaders(filePath: string): Promise<IFileParam[]> {\n // 拾取要处理的虚拟文件\n const { fileCollector } = this.config\n const collectedFileList = fileCollector\n ? fileCollector(filePath).map((item) => FileLaneUtil.pathToFileParam(item, true))\n : [FileLaneUtil.pathToFileParam(filePath, true)]\n // 查找到匹配的 loader\n const loaderList = this.findLoader(filePath)\n // 循环loader,转换文件\n let result = collectedFileList.concat()\n for (let item of loaderList) {\n result = await this.runLoader(result, item)\n }\n return result\n }\n\n private async writeFiles(fileList: IFileParam[]) {\n if (!fileList || !fileList.length) {\n return\n }\n const buildPath = this.outputPath\n return Promise.all(\n fileList.map((item) => {\n const resolvePath = Path.relative(this.context.projectPath, item.path)\n // 将相对路径与输出路径拼接,形成最新的文件路径\n const outputPath = Path.join(buildPath, resolvePath)\n return Fs.outputFile(outputPath, item.content || '', { encoding: 'utf-8' })\n })\n )\n }\n\n private async runLoader(fileList: IFileParam[], loaderType: ILoaderClass): Promise<IFileParam[]> {\n const loader = new loaderType()\n loader.context = this.context\n return loader.parser(fileList)\n }\n\n /**\n * 匹配符合条件的loader\n * @param filePath\n * @returns\n */\n private findLoader(filePath: string): ILoaderClass[] {\n const parse = Path.basename(filePath)\n const rules = this.config.module.rules\n let loaders: ILoaderClass[] = []\n for (let rule of rules) {\n // 1. 检查filePath是否符合规则test\n if (\n FileUtil.match(parse, rule.test) &&\n FileUtil.include(filePath, rule.include, rule.exclude)\n ) {\n // 2. 符合规则就添加到返回列表中\n loaders.push(...rule.loader)\n }\n }\n return loaders\n }\n\n private async triggerPlugins(event: DataEvent): Promise<void> {\n if (this.compilation) {\n return this.compilation.dispatch(event)\n }\n }\n\n /**\n * 运行转换后续的任务\n */\n private async runPreWorks(fileList: string[]): Promise<void> {\n const { preWorks } = this.config\n if (preWorks) {\n for (let item of preWorks) {\n try {\n await item(this.context, fileList, this.config, this.compilerOption)\n } catch (error) {\n // 报错 prework的item error\n }\n }\n }\n }\n\n /**\n * 运行转换后续的任务\n */\n private async runFollowWorks(): Promise<void> {\n const { followWorks } = this.config\n if (followWorks) {\n for (let item of followWorks) {\n await item(this.context, this.config, this.compilerOption)\n }\n }\n }\n\n private async watch(): Promise<void> {\n // 监听文件变化,并触发 build\n this.listenFileChange(async () => {\n const fileList = this.collectFile()\n await this.build(fileList)\n })\n }\n\n /**\n * 采集所有要处理的真实文件路径列表\n * @param entryFileList\n * @returns\n */\n private collectFile(entryFileList?: string[]): string[] {\n // 使用include projectPath获取所有要处理的真实文件\n let files: string[] = []\n if (entryFileList) {\n entryFileList.forEach((filePath) => {\n if (FileUtil.include(filePath, this.config.include, this.config.exclude)) {\n ColorConsole.log({\n message: `file change: ${filePath}`\n })\n files.push(filePath)\n }\n })\n } else {\n // 1.取出projectPath\n const projectPath = this.context.projectPath\n // 2. 循环文件夹,取出所有匹配的文件路径\n files = FileUtil.readAlldirSync(projectPath, this.config.include, this.config.exclude)\n }\n return files\n }\n\n /**\n * 监听文件变化\n * @param onChange\n */\n private listenFileChange(onChange: (fileList: string[]) => void) {\n const watcher = chokidar.watch(this.context.projectPath)\n const throttledOnChange = Lodash.throttle(onChange, 1000, {\n leading: true,\n trailing: false\n })\n const handler = (filePath: string) => {\n const { exclude, include } = this.config\n // 判断是否为删除,执行onChange回调\n if (FileUtil.include(filePath, include, exclude)) {\n throttledOnChange([filePath])\n }\n }\n watcher\n .on('ready', () => {\n ColorConsole.log({\n message: 'Initial scan complete. Ready for Watch.'\n })\n\n watcher\n .on('add', (path) => {\n // 监听文件添加事件\n handler(path)\n })\n .on('change', (path) => {\n // 监听文件修改事件\n handler(path)\n })\n .on('unlink', (filePath) => {\n // 监听文件删除事件\n handler(filePath)\n })\n })\n .on('error', (error) => {\n // 监听错误\n ColorConsole.log({ level: LOG_LEVEL.Error, message: error.message })\n })\n\n if (this.watcher) {\n this.watcher.close()\n }\n this.watcher = watcher\n }\n\n private get outputPath() {\n const { output, projectPath } = this.context\n return Path.join(projectPath, output)\n }\n /**\n * 清除输出文件夹\n */\n private cleanOutput() {\n Fs.removeSync(this.outputPath)\n }\n}\nexport default FileLane\n"],"sourceRoot":"../src"}
@@ -0,0 +1,7 @@
1
+ import AsyncEventDispatcher from './event/asyncEvent/AsyncEventDispatcher';
2
+ /**
3
+ * FileLaneCompilation
4
+ */
5
+ declare class FileLaneCompilation extends AsyncEventDispatcher {
6
+ }
7
+ export default FileLaneCompilation;
@@ -0,0 +1,14 @@
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 AsyncEventDispatcher_1 = __importDefault(require("./event/asyncEvent/AsyncEventDispatcher"));
7
+ /**
8
+ * FileLaneCompilation
9
+ */
10
+ class FileLaneCompilation extends AsyncEventDispatcher_1.default {
11
+ }
12
+ exports.default = FileLaneCompilation;
13
+
14
+ //# sourceMappingURL=FileLaneCompilation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["FileLaneCompilation.ts"],"names":[],"mappings":";;;;;AAAA,mGAA0E;AAE1E;;GAEG;AACH,MAAM,mBAAoB,SAAQ,8BAAoB;CAAG;AACzD,kBAAe,mBAAmB,CAAA","file":"FileLaneCompilation.js","sourcesContent":["import AsyncEventDispatcher from './event/asyncEvent/AsyncEventDispatcher'\n\n/**\n * FileLaneCompilation\n */\nclass FileLaneCompilation extends AsyncEventDispatcher {}\nexport default FileLaneCompilation\n"],"sourceRoot":"../src"}
@@ -0,0 +1,11 @@
1
+ import DataEvent from './asyncEvent/DataEvent';
2
+ /**
3
+ * CompilationEvent
4
+ */
5
+ declare class CompilationEvent extends DataEvent {
6
+ static PROJECT_START: string;
7
+ static PROJECT_END: string;
8
+ static FLLOW_WORK_START: string;
9
+ static FLLOW_WORK_END: string;
10
+ }
11
+ export default CompilationEvent;
@@ -0,0 +1,18 @@
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 DataEvent_1 = __importDefault(require("./asyncEvent/DataEvent"));
7
+ /**
8
+ * CompilationEvent
9
+ */
10
+ class CompilationEvent extends DataEvent_1.default {
11
+ }
12
+ CompilationEvent.PROJECT_START = 'PROJECT_START';
13
+ CompilationEvent.PROJECT_END = 'PROJECT_END';
14
+ CompilationEvent.FLLOW_WORK_START = 'FLLOW_WORK_START';
15
+ CompilationEvent.FLLOW_WORK_END = 'FLLOW_WORK_END';
16
+ exports.default = CompilationEvent;
17
+
18
+ //# sourceMappingURL=CompilationEvent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["event/CompilationEvent.ts"],"names":[],"mappings":";;;;;AAAA,uEAA8C;AAE9C;;GAEG;AACH,MAAM,gBAAiB,SAAQ,mBAAS;;AAC/B,8BAAa,GAAG,eAAe,CAAA;AAC/B,4BAAW,GAAG,aAAa,CAAA;AAE3B,iCAAgB,GAAG,kBAAkB,CAAA;AACrC,+BAAc,GAAG,gBAAgB,CAAA;AAE1C,kBAAe,gBAAgB,CAAA","file":"CompilationEvent.js","sourcesContent":["import DataEvent from './asyncEvent/DataEvent'\n\n/**\n * CompilationEvent\n */\nclass CompilationEvent extends DataEvent {\n static PROJECT_START = 'PROJECT_START'\n static PROJECT_END = 'PROJECT_END'\n\n static FLLOW_WORK_START = 'FLLOW_WORK_START'\n static FLLOW_WORK_END = 'FLLOW_WORK_END'\n}\nexport default CompilationEvent\n"],"sourceRoot":"../../src"}
@@ -0,0 +1,10 @@
1
+ import IFileParam from '../interface/IFileParam';
2
+ import DataEvent from './asyncEvent/DataEvent';
3
+ /**
4
+ * FileEvent
5
+ */
6
+ declare class FileEvent extends DataEvent<IFileParam> {
7
+ static FILE_END_COMPILATION: string;
8
+ static FILE_START_COMPILATION: string;
9
+ }
10
+ export default FileEvent;
@@ -0,0 +1,16 @@
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 DataEvent_1 = __importDefault(require("./asyncEvent/DataEvent"));
7
+ /**
8
+ * FileEvent
9
+ */
10
+ class FileEvent extends DataEvent_1.default {
11
+ }
12
+ FileEvent.FILE_END_COMPILATION = 'FILE_END_COMPILATION';
13
+ FileEvent.FILE_START_COMPILATION = 'FILE_START_COMPILATION';
14
+ exports.default = FileEvent;
15
+
16
+ //# sourceMappingURL=FileEvent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["event/FileEvent.ts"],"names":[],"mappings":";;;;;AACA,uEAA8C;AAE9C;;GAEG;AACH,MAAM,SAAU,SAAQ,mBAAqB;;AACpC,8BAAoB,GAAG,sBAAsB,CAAA;AAC7C,gCAAsB,GAAG,wBAAwB,CAAA;AAE1D,kBAAe,SAAS,CAAA","file":"FileEvent.js","sourcesContent":["import IFileParam from '../interface/IFileParam'\nimport DataEvent from './asyncEvent/DataEvent'\n\n/**\n * FileEvent\n */\nclass FileEvent extends DataEvent<IFileParam> {\n static FILE_END_COMPILATION = 'FILE_END_COMPILATION'\n static FILE_START_COMPILATION = 'FILE_START_COMPILATION'\n}\nexport default FileEvent\n"],"sourceRoot":"../../src"}
@@ -0,0 +1,9 @@
1
+ import DataEvent from './asyncEvent/DataEvent';
2
+ interface IEventDispatcher<F extends Function = Function> {
3
+ addEventListener(type: string, handler: F): void;
4
+ removeEventListener(type: string, handler: F): void;
5
+ removeAllListener(type: string): void;
6
+ dispatch(event: DataEvent): Promise<void>;
7
+ clear(): void;
8
+ }
9
+ export default IEventDispatcher;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+
4
+ //# sourceMappingURL=IEventDispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["event/IEventDispatcher.ts"],"names":[],"mappings":"","file":"IEventDispatcher.js","sourcesContent":["import DataEvent from './asyncEvent/DataEvent'\n\ninterface IEventDispatcher<F extends Function = Function> {\n addEventListener(type: string, handler: F): void\n removeEventListener(type: string, handler: F): void\n removeAllListener(type: string): void\n dispatch(event: DataEvent): Promise<void>\n clear(): void\n}\n\nexport default IEventDispatcher\n"],"sourceRoot":"../../src"}
@@ -0,0 +1,14 @@
1
+ import IEventDispatcher from '../IEventDispatcher';
2
+ import DataEvent from './DataEvent';
3
+ export type AsyncEventHandler = (event: DataEvent, callback: Function) => void;
4
+ declare class AsyncEventDispatcher implements IEventDispatcher<AsyncEventHandler> {
5
+ private _eventMap;
6
+ dispatch(event: DataEvent<any>): Promise<void>;
7
+ addEventListener(type: string, handler: AsyncEventHandler): void;
8
+ removeEventListener(type: string, handler: AsyncEventHandler): void;
9
+ removeAllListener(type: string): void;
10
+ clear(): void;
11
+ private hasListener;
12
+ private getCallList;
13
+ }
14
+ export default AsyncEventDispatcher;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ class AsyncEventDispatcher {
13
+ constructor() {
14
+ this._eventMap = new Map();
15
+ }
16
+ dispatch(event) {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ return new Promise((resolve) => {
19
+ const { type } = event;
20
+ const callList = this.getCallList(type);
21
+ let callCount = 0;
22
+ if (callList) {
23
+ for (let item of callList) {
24
+ item(event, () => {
25
+ callCount++;
26
+ if (callCount === callList.length) {
27
+ resolve();
28
+ }
29
+ });
30
+ }
31
+ }
32
+ });
33
+ });
34
+ }
35
+ addEventListener(type, handler) {
36
+ if (!this.hasListener(type)) {
37
+ this._eventMap.set(type, []);
38
+ }
39
+ const callList = this.getCallList(type);
40
+ if (callList && !callList.includes(handler)) {
41
+ callList.push(handler);
42
+ }
43
+ }
44
+ removeEventListener(type, handler) {
45
+ if (!this.hasListener(type)) {
46
+ return;
47
+ }
48
+ const callList = this.getCallList(type);
49
+ if (callList) {
50
+ const index = callList.indexOf(handler);
51
+ if (index >= 0) {
52
+ callList.splice(index, 1);
53
+ }
54
+ }
55
+ }
56
+ removeAllListener(type) {
57
+ this._eventMap.delete(type);
58
+ }
59
+ clear() {
60
+ this._eventMap.clear();
61
+ }
62
+ hasListener(type) {
63
+ return this._eventMap.has(type);
64
+ }
65
+ getCallList(type) {
66
+ return this._eventMap.get(type);
67
+ }
68
+ }
69
+ exports.default = AsyncEventDispatcher;
70
+
71
+ //# sourceMappingURL=AsyncEventDispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["event/asyncEvent/AsyncEventDispatcher.ts"],"names":[],"mappings":";;;;;;;;;;;AAKA,MAAM,oBAAoB;IAA1B;QACU,cAAS,GAA0C,IAAI,GAAG,EAAE,CAAA;IAwDtE,CAAC;IAtDO,QAAQ,CAAC,KAAqB;;YAClC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC7B,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAA;gBACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;gBACvC,IAAI,SAAS,GAAG,CAAC,CAAA;gBACjB,IAAI,QAAQ,EAAE;oBACZ,KAAK,IAAI,IAAI,IAAI,QAAQ,EAAE;wBACzB,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE;4BACf,SAAS,EAAE,CAAA;4BACX,IAAI,SAAS,KAAK,QAAQ,CAAC,MAAM,EAAE;gCACjC,OAAO,EAAE,CAAA;6BACV;wBACH,CAAC,CAAC,CAAA;qBACH;iBACF;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KAAA;IAED,gBAAgB,CAAC,IAAY,EAAE,OAA0B;QACvD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE;YAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;SAC7B;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,QAAQ,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;YAC3C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;SACvB;IACH,CAAC;IAED,mBAAmB,CAAC,IAAY,EAAE,OAA0B;QAC1D,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE;YAC3B,OAAM;SACP;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,QAAQ,EAAE;YACZ,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;YACvC,IAAI,KAAK,IAAI,CAAC,EAAE;gBACd,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;aAC1B;SACF;IACH,CAAC;IACD,iBAAiB,CAAC,IAAY;QAC5B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC7B,CAAC;IACD,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC;IAEO,WAAW,CAAC,IAAY;QAC9B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;IAEO,WAAW,CAAC,IAAY;QAC9B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;CACF;AAED,kBAAe,oBAAoB,CAAA","file":"AsyncEventDispatcher.js","sourcesContent":["import IEventDispatcher from '../IEventDispatcher'\nimport DataEvent from './DataEvent'\n\nexport type AsyncEventHandler = (event: DataEvent, callback: Function) => void\n\nclass AsyncEventDispatcher implements IEventDispatcher<AsyncEventHandler> {\n private _eventMap: Map<string, Array<AsyncEventHandler>> = new Map()\n\n async dispatch(event: DataEvent<any>): Promise<void> {\n return new Promise((resolve) => {\n const { type } = event\n const callList = this.getCallList(type)\n let callCount = 0\n if (callList) {\n for (let item of callList) {\n item(event, () => {\n callCount++\n if (callCount === callList.length) {\n resolve()\n }\n })\n }\n }\n })\n }\n\n addEventListener(type: string, handler: AsyncEventHandler) {\n if (!this.hasListener(type)) {\n this._eventMap.set(type, [])\n }\n const callList = this.getCallList(type)\n if (callList && !callList.includes(handler)) {\n callList.push(handler)\n }\n }\n\n removeEventListener(type: string, handler: AsyncEventHandler) {\n if (!this.hasListener(type)) {\n return\n }\n const callList = this.getCallList(type)\n if (callList) {\n const index = callList.indexOf(handler)\n if (index >= 0) {\n callList.splice(index, 1)\n }\n }\n }\n removeAllListener(type: string) {\n this._eventMap.delete(type)\n }\n clear(): void {\n this._eventMap.clear()\n }\n\n private hasListener(type: string) {\n return this._eventMap.has(type)\n }\n\n private getCallList(type: string) {\n return this._eventMap.get(type)\n }\n}\n\nexport default AsyncEventDispatcher\n"],"sourceRoot":"../../../src"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * DataEvent
3
+ */
4
+ declare class DataEvent<T = any> {
5
+ readonly type: string;
6
+ readonly data?: T | undefined;
7
+ constructor(type: string, data?: T | undefined);
8
+ }
9
+ export default DataEvent;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * DataEvent
5
+ */
6
+ class DataEvent {
7
+ constructor(type, data) {
8
+ this.type = type;
9
+ this.data = data;
10
+ }
11
+ }
12
+ exports.default = DataEvent;
13
+
14
+ //# sourceMappingURL=DataEvent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["event/asyncEvent/DataEvent.ts"],"names":[],"mappings":";;AAAA;;GAEG;AACH,MAAM,SAAS;IACb,YACkB,IAAY,EACZ,IAAQ;QADR,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAI;IACvB,CAAC;CACL;AACD,kBAAe,SAAS,CAAA","file":"DataEvent.js","sourcesContent":["/**\n * DataEvent\n */\nclass DataEvent<T = any> {\n constructor(\n public readonly type: string,\n public readonly data?: T\n ) {}\n}\nexport default DataEvent\n"],"sourceRoot":"../../../src"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import FileLane from './FileLane';
2
+ import IFileLaneConfig from './interface/IFileLaneConfig';
3
+ import IFileLaneContext from './interface/IFileLaneContext';
4
+ import IFileParam from './interface/IFileParam';
5
+ import ILoader from './interface/ILoader';
6
+ import IPlugin from './interface/IPlugin';
7
+ export { FileLane, IFileLaneConfig, IFileLaneContext, IFileParam, ILoader, IPlugin };
package/lib/index.js ADDED
@@ -0,0 +1,10 @@
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
+ exports.FileLane = void 0;
7
+ const FileLane_1 = __importDefault(require("./FileLane"));
8
+ exports.FileLane = FileLane_1.default;
9
+
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["index.ts"],"names":[],"mappings":";;;;;;AAAA,0DAAiC;AAOxB,mBAPF,kBAAQ,CAOE","file":"index.js","sourcesContent":["import FileLane from './FileLane'\nimport IFileLaneConfig from './interface/IFileLaneConfig'\nimport IFileLaneContext from './interface/IFileLaneContext'\nimport IFileParam from './interface/IFileParam'\nimport ILoader from './interface/ILoader'\nimport IPlugin from './interface/IPlugin'\n\nexport { FileLane, IFileLaneConfig, IFileLaneContext, IFileParam, ILoader, IPlugin }\n"],"sourceRoot":"../src"}
@@ -0,0 +1,82 @@
1
+ import { MatchType } from '@aiot-toolkit/shared-utils/lib/utils/FileUtil';
2
+ import IFileLaneContext from './IFileLaneContext';
3
+ import ILoader from './ILoader';
4
+ import IPlugin from './IPlugin';
5
+ export type ILoaderClass = new (...args: any[]) => ILoader;
6
+ /**
7
+ * IFileLaneConfig
8
+ */
9
+ export default interface IFileLaneConfig<O = any> {
10
+ /**
11
+ * 文件收集器
12
+ *
13
+ *
14
+ * @param path 文件路径
15
+ *
16
+ * @returns 要合并的文件路径
17
+ *
18
+ * @description 通常用于多转1,例如 src/a.hml -->[src/a.hml, src/a.js, src/a.css]
19
+ * 不填写,表示直接使用源文件
20
+ *
21
+ */
22
+ fileCollector?: (file: string) => string[];
23
+ /**
24
+ * 指定处理的文件范围
25
+ *
26
+ * 此属性的函数形式,在多转1可能很有用
27
+ * 例如:a.js 做为js需要处理,但同目录存在 a.ux 时,则排除
28
+ *
29
+ * @example /^src/
30
+ *
31
+ */
32
+ include?: MatchType;
33
+ exclude?: MatchType;
34
+ /**
35
+ * 输出目录
36
+ *
37
+ */
38
+ output: string;
39
+ /**
40
+ * 文件转换配置
41
+ */
42
+ module: {
43
+ /**
44
+ * 转换规则
45
+ */
46
+ rules: {
47
+ /**
48
+ * 配置文件
49
+ */
50
+ test: MatchType;
51
+ loader: ILoaderClass[];
52
+ exclude?: MatchType;
53
+ include?: MatchType;
54
+ }[];
55
+ };
56
+ /**
57
+ * 插件
58
+ *
59
+ * 触发时机如下
60
+ * 1. 每个文件转换完成
61
+ * 2. 所有文件转换完成
62
+ */
63
+ plugins?: IPlugin[];
64
+ /**
65
+ * 前置工作
66
+ *
67
+ * @param context 上下文
68
+ * @param fileList 待转换的文件列表
69
+ * @returns
70
+ */
71
+ preWorks?: PreWork[];
72
+ /**
73
+ * 转换结束后续的工作
74
+ *
75
+ * xts--[zip]
76
+ * ux--[webpack, zip]
77
+ * uxInspect--[webpack, zipPhone, zipWatch, zipTv]
78
+ */
79
+ followWorks?: FollowWork<O>[];
80
+ }
81
+ export type FollowWork<O = any> = (context: IFileLaneContext, config?: IFileLaneConfig, compilerOption?: O) => Promise<any>;
82
+ export type PreWork<O = any> = (context: IFileLaneContext, fileList: string[], config: IFileLaneConfig, compilerOption?: O) => Promise<any>;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+
4
+ //# sourceMappingURL=IFileLaneConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["interface/IFileLaneConfig.ts"],"names":[],"mappings":"","file":"IFileLaneConfig.js","sourcesContent":["import { MatchType } from '@aiot-toolkit/shared-utils/lib/utils/FileUtil'\nimport IFileLaneContext from './IFileLaneContext'\nimport ILoader from './ILoader'\nimport IPlugin from './IPlugin'\n\nexport type ILoaderClass = new (...args: any[]) => ILoader\n\n/**\n * IFileLaneConfig\n */\nexport default interface IFileLaneConfig<O = any> {\n /**\n * 文件收集器\n *\n *\n * @param path 文件路径\n *\n * @returns 要合并的文件路径\n *\n * @description 通常用于多转1,例如 src/a.hml -->[src/a.hml, src/a.js, src/a.css]\n * 不填写,表示直接使用源文件\n *\n */\n fileCollector?: (file: string) => string[]\n\n /**\n * 指定处理的文件范围\n *\n * 此属性的函数形式,在多转1可能很有用\n * 例如:a.js 做为js需要处理,但同目录存在 a.ux 时,则排除\n *\n * @example /^src/\n *\n */\n include?: MatchType\n\n exclude?: MatchType\n\n /**\n * 输出目录\n *\n */\n output: string\n\n /**\n * 文件转换配置\n */\n module: {\n /**\n * 转换规则\n */\n rules: {\n /**\n * 配置文件\n */\n test: MatchType\n loader: ILoaderClass[]\n exclude?: MatchType\n include?: MatchType\n }[]\n }\n\n /**\n * 插件\n *\n * 触发时机如下\n * 1. 每个文件转换完成\n * 2. 所有文件转换完成\n */\n plugins?: IPlugin[]\n\n /**\n * 前置工作\n *\n * @param context 上下文\n * @param fileList 待转换的文件列表\n * @returns\n */\n preWorks?: PreWork[]\n\n /**\n * 转换结束后续的工作\n *\n * xts--[zip]\n * ux--[webpack, zip]\n * uxInspect--[webpack, zipPhone, zipWatch, zipTv]\n */\n followWorks?: FollowWork<O>[]\n}\n\nexport type FollowWork<O = any> = (\n context: IFileLaneContext,\n config?: IFileLaneConfig,\n compilerOption?: O\n) => Promise<any>\n\nexport type PreWork<O = any> = (\n context: IFileLaneContext,\n fileList: string[],\n config: IFileLaneConfig,\n compilerOption?: O\n) => Promise<any>\n"],"sourceRoot":"../../src"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * IFileLaneContext
3
+ */
4
+ export default interface IFileLaneContext {
5
+ cwd: string;
6
+ projectPath: string;
7
+ output: string;
8
+ [key: string]: any;
9
+ }
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+
4
+ //# sourceMappingURL=IFileLaneContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["interface/IFileLaneContext.ts"],"names":[],"mappings":"","file":"IFileLaneContext.js","sourcesContent":["/**\n * IFileLaneContext\n */\nexport default interface IFileLaneContext {\n cwd: string\n projectPath: string\n output: string\n [key: string]: any\n}\n"],"sourceRoot":"../../src"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * IFileParam
3
+ */
4
+ export default interface IFileParam<T = any> {
5
+ path: string;
6
+ content?: string;
7
+ /**
8
+ * 额外的内容,例如 sourceMap,位置映射列表等
9
+ */
10
+ extra?: T;
11
+ }
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+
4
+ //# sourceMappingURL=IFileParam.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["interface/IFileParam.ts"],"names":[],"mappings":"","file":"IFileParam.js","sourcesContent":["/**\n * IFileParam\n */\nexport default interface IFileParam<T = any> {\n path: string\n content?: string\n /**\n * 额外的内容,例如 sourceMap,位置映射列表等\n */\n extra?: T\n}\n"],"sourceRoot":"../../src"}
@@ -0,0 +1,9 @@
1
+ import IFileLaneContext from './IFileLaneContext';
2
+ import IFileParam from './IFileParam';
3
+ /**
4
+ * ILoader
5
+ */
6
+ export default interface ILoader {
7
+ context?: IFileLaneContext;
8
+ parser(files: IFileParam[]): Promise<IFileParam[]> | IFileParam[];
9
+ }
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+
4
+ //# sourceMappingURL=ILoader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["interface/ILoader.ts"],"names":[],"mappings":"","file":"ILoader.js","sourcesContent":["import IFileLaneContext from './IFileLaneContext'\nimport IFileParam from './IFileParam'\n\n/**\n * ILoader\n */\nexport default interface ILoader {\n context?: IFileLaneContext\n parser(files: IFileParam[]): Promise<IFileParam[]> | IFileParam[]\n}\n"],"sourceRoot":"../../src"}
@@ -0,0 +1,10 @@
1
+ import FileLaneCompilation from '../FileLaneCompilation';
2
+ import IFileLaneContext from './IFileLaneContext';
3
+ /**
4
+ * IPlugin
5
+ */
6
+ export default interface IPlugin {
7
+ context: IFileLaneContext;
8
+ compilation: FileLaneCompilation;
9
+ apply(): void;
10
+ }
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+
4
+ //# sourceMappingURL=IPlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["interface/IPlugin.ts"],"names":[],"mappings":"","file":"IPlugin.js","sourcesContent":["import FileLaneCompilation from '../FileLaneCompilation'\nimport IFileLaneContext from './IFileLaneContext'\n\n/**\n * IPlugin\n */\nexport default interface IPlugin {\n context: IFileLaneContext\n compilation: FileLaneCompilation\n apply(): void\n}\n"],"sourceRoot":"../../src"}
@@ -0,0 +1,20 @@
1
+ import IFileParam from '../interface/IFileParam';
2
+ /**
3
+ * FileLaneUtil
4
+ */
5
+ declare class FileLaneUtil {
6
+ /**
7
+ * 文件路径转换为文件参数
8
+ * @param path 路径
9
+ * @param readContent 是否读取文件内容以设置 content 的值,默认 false
10
+ * @returns
11
+ */
12
+ static pathToFileParam(path: string, readContent?: boolean): IFileParam;
13
+ /**
14
+ * 将buildPath文件夹的内容压缩成zip包,放置于targetPath路径下
15
+ * @param buildPath
16
+ * @param targetPath
17
+ */
18
+ static zipProject(buildPath: string[], targetFile: string): Promise<void>;
19
+ }
20
+ export default FileLaneUtil;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const shared_utils_1 = require("@aiot-toolkit/shared-utils");
16
+ const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
17
+ const archiver_1 = __importDefault(require("archiver"));
18
+ const fs_extra_1 = __importDefault(require("fs-extra"));
19
+ const path_1 = __importDefault(require("path"));
20
+ /**
21
+ * FileLaneUtil
22
+ */
23
+ class FileLaneUtil {
24
+ /**
25
+ * 文件路径转换为文件参数
26
+ * @param path 路径
27
+ * @param readContent 是否读取文件内容以设置 content 的值,默认 false
28
+ * @returns
29
+ */
30
+ static pathToFileParam(path, readContent = false) {
31
+ let content = '';
32
+ if (readContent && fs_extra_1.default.existsSync(path)) {
33
+ const stats = fs_extra_1.default.statSync(path);
34
+ if (stats.isFile()) {
35
+ content = fs_extra_1.default.readFileSync(path, 'utf-8');
36
+ }
37
+ }
38
+ return {
39
+ path,
40
+ content
41
+ };
42
+ }
43
+ /**
44
+ * 将buildPath文件夹的内容压缩成zip包,放置于targetPath路径下
45
+ * @param buildPath
46
+ * @param targetPath
47
+ */
48
+ static zipProject(buildPath, targetFile) {
49
+ return __awaiter(this, void 0, void 0, function* () {
50
+ return new Promise((resolve, reject) => {
51
+ const output = fs_extra_1.default.createWriteStream(targetFile);
52
+ const archive = archiver_1.default.create('zip', {
53
+ zlib: { level: 9 }
54
+ });
55
+ // 监听错误
56
+ archive.on('error', (err) => {
57
+ ColorConsole_1.default.log({
58
+ level: shared_utils_1.LOG_LEVEL.Error,
59
+ message: err.message
60
+ });
61
+ reject();
62
+ });
63
+ // 监听写入流打开的事件
64
+ output.on('open', () => {
65
+ ColorConsole_1.default.log({ message: `写入流已打开` });
66
+ });
67
+ output.on('close', () => {
68
+ resolve();
69
+ });
70
+ // 将压缩文件导入到输出流中
71
+ archive.pipe(output);
72
+ // 指定压缩目录
73
+ buildPath.forEach((folder) => {
74
+ const folderName = path_1.default.basename(folder); // 获取文件夹名
75
+ archive.directory(folder, folderName);
76
+ });
77
+ // 完成压缩,关闭输出流
78
+ archive.finalize();
79
+ });
80
+ });
81
+ }
82
+ }
83
+ exports.default = FileLaneUtil;
84
+
85
+ //# sourceMappingURL=FileLaneUtil.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["utils/FileLaneUtil.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,6DAAsD;AACtD,+FAAsE;AACtE,wDAA+B;AAC/B,wDAAyB;AACzB,gDAAuB;AAEvB;;GAEG;AACH,MAAM,YAAY;IAChB;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CAAC,IAAY,EAAE,cAAuB,KAAK;QAC/D,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,IAAI,WAAW,IAAI,kBAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;YACtC,MAAM,KAAK,GAAG,kBAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;YAC/B,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE;gBAClB,OAAO,GAAG,kBAAE,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;aACzC;SACF;QACD,OAAO;YACL,IAAI;YACJ,OAAO;SACR,CAAA;IACH,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAO,UAAU,CAAC,SAAmB,EAAE,UAAkB;;YAC7D,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC3C,MAAM,MAAM,GAAG,kBAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAA;gBAC/C,MAAM,OAAO,GAAG,kBAAQ,CAAC,MAAM,CAAC,KAAK,EAAE;oBACrC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;iBACnB,CAAC,CAAA;gBACF,OAAO;gBACP,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;oBAC1B,sBAAY,CAAC,GAAG,CAAC;wBACf,KAAK,EAAE,wBAAS,CAAC,KAAK;wBACtB,OAAO,EAAE,GAAG,CAAC,OAAO;qBACrB,CAAC,CAAA;oBACF,MAAM,EAAE,CAAA;gBACV,CAAC,CAAC,CAAA;gBACF,aAAa;gBACb,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;oBACrB,sBAAY,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAA;gBACzC,CAAC,CAAC,CAAA;gBACF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;oBACtB,OAAO,EAAE,CAAA;gBACX,CAAC,CAAC,CAAA;gBACF,eAAe;gBACf,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBACpB,SAAS;gBACT,SAAS,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;oBAC3B,MAAM,UAAU,GAAG,cAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA,CAAC,SAAS;oBAClD,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;gBACvC,CAAC,CAAC,CAAA;gBACF,aAAa;gBACb,OAAO,CAAC,QAAQ,EAAE,CAAA;YACpB,CAAC,CAAC,CAAA;QACJ,CAAC;KAAA;CACF;AACD,kBAAe,YAAY,CAAA","file":"FileLaneUtil.js","sourcesContent":["import { LOG_LEVEL } from '@aiot-toolkit/shared-utils'\nimport ColorConsole from '@aiot-toolkit/shared-utils/lib/ColorConsole'\nimport archiver from 'archiver'\nimport Fs from 'fs-extra'\nimport Path from 'path'\nimport IFileParam from '../interface/IFileParam'\n/**\n * FileLaneUtil\n */\nclass FileLaneUtil {\n /**\n * 文件路径转换为文件参数\n * @param path 路径\n * @param readContent 是否读取文件内容以设置 content 的值,默认 false\n * @returns\n */\n static pathToFileParam(path: string, readContent: boolean = false): IFileParam {\n let content = ''\n if (readContent && Fs.existsSync(path)) {\n const stats = Fs.statSync(path)\n if (stats.isFile()) {\n content = Fs.readFileSync(path, 'utf-8')\n }\n }\n return {\n path,\n content\n }\n }\n\n /**\n * 将buildPath文件夹的内容压缩成zip包,放置于targetPath路径下\n * @param buildPath\n * @param targetPath\n */\n static async zipProject(buildPath: string[], targetFile: string) {\n return new Promise<void>((resolve, reject) => {\n const output = Fs.createWriteStream(targetFile)\n const archive = archiver.create('zip', {\n zlib: { level: 9 }\n })\n // 监听错误\n archive.on('error', (err) => {\n ColorConsole.log({\n level: LOG_LEVEL.Error,\n message: err.message\n })\n reject()\n })\n // 监听写入流打开的事件\n output.on('open', () => {\n ColorConsole.log({ message: `写入流已打开` })\n })\n output.on('close', () => {\n resolve()\n })\n // 将压缩文件导入到输出流中\n archive.pipe(output)\n // 指定压缩目录\n buildPath.forEach((folder) => {\n const folderName = Path.basename(folder) // 获取文件夹名\n archive.directory(folder, folderName)\n })\n // 完成压缩,关闭输出流\n archive.finalize()\n })\n }\n}\nexport default FileLaneUtil\n"],"sourceRoot":"../../src"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "file-lane",
3
+ "version": "2.0.1-alpha.0",
4
+ "description": "File conversion tool, can be one-to-one, one to N, N to one",
5
+ "keywords": [
6
+ "file",
7
+ "conversion"
8
+ ],
9
+ "author": "徐俊杰 <xujunjie1@xiaomi.com>",
10
+ "homepage": "",
11
+ "license": "ISC",
12
+ "main": "lib/index.js",
13
+ "directories": {
14
+ "lib": "lib",
15
+ "test": "__tests__"
16
+ },
17
+ "files": [
18
+ "lib"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "ssh://xujunjie1@git.mioffice.cn:29418/vela/aiot-toolkit"
23
+ },
24
+ "scripts": {
25
+ "test": "node ./__tests__/file-lane.test.js"
26
+ },
27
+ "dependencies": {
28
+ "@aiot-toolkit/shared-utils": "2.0.1-alpha.0",
29
+ "archiver": "^6.0.1",
30
+ "chokidar": "^3.5.3",
31
+ "lodash": "^4.17.21"
32
+ },
33
+ "devDependencies": {
34
+ "@types/archiver": "^5.3.2"
35
+ },
36
+ "gitHead": "cde5c75fa09622188ee4f1322ff9d53faf4d8520"
37
+ }