-
Notifications
You must be signed in to change notification settings - Fork 9
/
esbuild-component-decorator.js
160 lines (132 loc) · 4.47 KB
/
esbuild-component-decorator.js
1
2
3
4
5
6
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
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
const fs = require('fs');
const path = require('path');
const { log, convertMessage } = require('../lib/log');
const publicWorker = require('../lib/scss-worker');
const componentBuffer = {
num: 1,
};
/**
* Check the file is an scss file.
* @param {String} cssPath path of a file
* @returns true when the file extension is scss, otherwise false
*/
const isScss = (cssPath) => {
return /\.scss$/.test(cssPath);
};
/**
*
* @param {RegExp} regex regular expression for read a value from a string
* @param {String} str base string
* @returns a string value by the regex.
*/
const getValueByPattern = (regex = new RegExp(''), str = '') => {
let m;
let results = [];
let array1 = null;
while ((array1 = regex.exec(str)) !== null) {
results.push(array1[1]);
}
return results.pop();
};
const injectStyle = async (options, instance, args, contents = '') => {
const styleUrls = getValueByPattern(
/^ *styleUrls *\: *\[['"]([^'"\]]*)/gm,
contents
);
let fileContent = '';
if (styleUrls) {
fileContent = await publicWorker.scssProcessor(JSON.stringify({
scssPath: path.join(
path.dirname(args.path),
styleUrls,
),
projectDir: instance.workDir,
outDir: path.join(instance.workDir, options.outputPath),
}));
}
return contents.replace(
/^ *styleUrls *\: *\[['"]([^'"\]]*)['"]\]\,*/gm,
` styles: [\`${fileContent}\`],`
);
};
/**
* Place @Inject statements
* @param {String} contents content of the target .ts file
* @returns the new conent that changed
*/
const addInjects = (contents) => {
if (/constructor *\(([^\)]*)/gm.test(contents)) {
let requireInjectImport = false;
const matches = contents.matchAll(/constructor *\(([^\)]*)/gm);
for (let match of matches) {
if (match[1] && /\:/gm.test(match[1])) {
requireInjectImport = true;
let flat = match[1].replace(/[\n\r]/gm, '');
const flatArray = flat.split(',').map(inject => {
const parts = inject.split(':');
return parts.length === 2 && !/\@Inject/.test(inject)
? `@Inject(${parts[1]}) ${inject}`
: inject;
});
contents = contents.replace(
/constructor *\([^\)]*\)/gm,
`constructor(${flatArray.join(',')})`
);
}
}
if (requireInjectImport && !/Inject[ ,\}\n\r].*'@angular\/core.*\;/.test(contents)) {
contents = `import { Inject } from '@angular/core';\n\r${contents}`;
}
}
return contents;
}
/**
* Esbuild plugin to changing special angular components.
* @returns an esbuild plugin object
*/
const angularComponentDecoratorPlugin = (instance) => {
return {
name: 'angularComponentProcessor',
async setup(build) {
const options = await instance.getAngularOptions();
build.onLoad({ filter: /src.*\.(component|pipe|service|directive|guard|module)\.ts$/ }, async (args) => {
// Check the cache.
const instanceName = path.basename(args.path).replace(/\.[a-zA-Z]*$/, '');
if (!instance.lastUpdatedFileList.find( n => n.includes(instanceName) ) && instance.componentBuffer[args.path]) {
return { contents: instance.componentBuffer[args.path], loader: 'ts' };
}
// Load the file from the file system
let source = await fs.promises.readFile(args.path, 'utf8');
// Changes.
try {
let contents = source;
let componentName = '';
let componentID = '';
// Import compiler.
if (/module\.ts$/.test(args.path)) {
contents = `import '@angular/compiler';\n${contents}`;
}
if (/^ *templateUrl *\: *['"]*([^'"]*)/gm.test(contents)) {
const templateUrl =
getValueByPattern(/^ *templateUrl *\: *['"]*([^'"]*)/gm, source);
contents = `import templateSource from '${templateUrl}';
${contents}`
.replace(
/^ *templateUrl *\: *['"]*([^'"]*)['"]/gm,
`template: templateSource || ''`
);
}
if (/^ *styleUrls *\: *\[['"]([^'"\]]*)/gm.test(contents)) {
contents = await injectStyle(options, instance, args, contents);
}
contents = addInjects(contents);
instance.componentBuffer[args.path] = contents;
return { contents, loader: 'ts' };
} catch (e) {
return { errors: [convertMessage(e)] }
}
});
},
}
};
module.exports = angularComponentDecoratorPlugin;