@xaendar/build-tools 0.4.5 → 0.4.9
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/dist/build-tools.js +6 -253
- package/package.json +2 -2
package/dist/build-tools.js
CHANGED
|
@@ -1,255 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import { compile } from "@xaendar/compiler";
|
|
3
|
-
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
1
|
+
import{compile as b}from"@xaendar/compiler";import{dirname as P,resolve as m}from"path";var d=/\.xd\.component\.ts$/;import{existsSync as g,readdirSync as f,readFileSync as h,realpathSync as y,statSync as x}from"fs";import{dirname as $,resolve as S}from"path";var c=class{readFile(t){try{return h(t,"utf-8")}catch{return}}fileExists(t){return g(t)}resolvePath(t,n){return S($(t),n)}getDirectoryEntries(t){try{return f(t)}catch{return[]}}isDirectory(t){try{return x(t).isDirectory()}catch{return!1}}getRealPath(t){try{return y(t)}catch{return t}}getCurrentDirectory(){return process.cwd()}};function k(){let e=new c;return{name:"xaendar",transform(t,n){if(!d.test(n))return null;let{templatePath:r,stylePath:s}=w(t,P(n));if(!r||!e.fileExists(r))return this.warn(`Xaendar: could not find template at ${r}`),null;this.addWatchFile(r);let i=e.readFile(r);if(i===void 0)return this.warn(`Xaendar: could not read template at ${r}`),null;let a;s&&e.fileExists(s)&&(this.addWatchFile(s),a=e.readFile(s)??"");let p,o=a?`__${_(n)}_sheet`:void 0;try{p=b(i,o)}catch(u){this.error(`Xaendar: failed to compile template ${r}: ${String(u)}`)}let l;try{l=F(E(t,p,o,a))}catch(u){this.error(String(u))}return{code:l}}}}function w(e,t){let n=e.match(/templateUrl\s*:\s*["'](.+?)["']/)?.[1],r=e.match(/styleUrl\s*:\s*["'](.+?)["']/)?.[1];return{templatePath:n?m(t,n):void 0,stylePath:r?m(t,r):void 0}}function E(e,t,n,r){let s=r?.trim().length?C(n,r):"",i=e;s&&(i=i.replace(/^(class\s+\w+\s+extends)/m,`${s}$1`));let a=/static\s*\{\s*\n(\s*)(\w+)\(\);\s*\n\s*\}/;if(!a.test(i))throw new Error("Xaendar: could not find the static initializer block in the transpiled output. Make sure @rolldown/plugin-babel with @babel/plugin-proposal-decorators runs before xaendarPlugin() in your Vite config.");return i=`import { effect } from "@xaendar/signals";
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
var COMPONENT_FILE_RE = /\.xd\.component\.ts$/;
|
|
7
|
-
|
|
8
|
-
// ../packages/build-tools/src/lib/node-compiler-host.model.ts
|
|
9
|
-
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "fs";
|
|
10
|
-
import { dirname, resolve } from "path";
|
|
11
|
-
var NodeCompilerHost = class {
|
|
12
|
-
/**
|
|
13
|
-
* Reads the content of a file from disk as a UTF-8 string.
|
|
14
|
-
*
|
|
15
|
-
* Returns `undefined` instead of throwing when the file does not exist,
|
|
16
|
-
* is a directory, or cannot be read due to permission restrictions.
|
|
17
|
-
* The compiler treats `undefined` as a missing-file condition and emits
|
|
18
|
-
* an appropriate diagnostic.
|
|
19
|
-
*
|
|
20
|
-
* @param filePath - Absolute path of the file to read.
|
|
21
|
-
* @returns The file content as a UTF-8 string, or `undefined` on any
|
|
22
|
-
* filesystem error.
|
|
23
|
-
*/
|
|
24
|
-
readFile(filePath) {
|
|
25
|
-
try {
|
|
26
|
-
return readFileSync(filePath, "utf-8");
|
|
27
|
-
} catch {
|
|
28
|
-
return void 0;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Checks whether a file exists and is accessible on disk.
|
|
33
|
-
*
|
|
34
|
-
* Uses `existsSync` rather than `accessSync` to avoid throwing —
|
|
35
|
-
* a missing file is an expected condition during path resolution,
|
|
36
|
-
* not an exceptional one.
|
|
37
|
-
*
|
|
38
|
-
* Returns `true` for both regular files and directories. Callers that
|
|
39
|
-
* need to distinguish between the two should combine this method with
|
|
40
|
-
* {@link isDirectory}.
|
|
41
|
-
*
|
|
42
|
-
* @param filePath - Absolute path of the file to check.
|
|
43
|
-
* @returns `true` if the path exists and is accessible, `false` otherwise.
|
|
44
|
-
*/
|
|
45
|
-
fileExists(filePath) {
|
|
46
|
-
return existsSync(filePath);
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Resolves a path relative to the **directory** containing the source file.
|
|
50
|
-
*
|
|
51
|
-
* Delegates to `path.resolve(path.dirname(from), to)` so that relative
|
|
52
|
-
* paths like `./button.xd.component.html` are resolved against the
|
|
53
|
-
* directory of the referencing file, not the current working directory.
|
|
54
|
-
*
|
|
55
|
-
* Absolute paths passed as `to` are returned unchanged by `path.resolve`
|
|
56
|
-
* and therefore work correctly without any special handling.
|
|
57
|
-
*
|
|
58
|
-
* Does not resolve path aliases (e.g. `@components/button.html`).
|
|
59
|
-
* Alias resolution must be performed by the caller before invoking
|
|
60
|
-
* this method, or by providing a subclass that overrides it.
|
|
61
|
-
*
|
|
62
|
-
* @param from - Absolute path of the source file that contains the
|
|
63
|
-
* reference (e.g. the `.ts` file of the component).
|
|
64
|
-
* @param to - Relative or absolute path to resolve.
|
|
65
|
-
* @returns The resolved absolute path of the target file.
|
|
66
|
-
*
|
|
67
|
-
* @example
|
|
68
|
-
* host.resolvePath(
|
|
69
|
-
* '/src/features/user/user.xd.component.ts',
|
|
70
|
-
* './user.xd.component.html',
|
|
71
|
-
* );
|
|
72
|
-
* // → '/src/features/user/user.xd.component.html'
|
|
73
|
-
*/
|
|
74
|
-
resolvePath(from, to) {
|
|
75
|
-
return resolve(dirname(from), to);
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Returns the names of all entries (files and subdirectories) inside
|
|
79
|
-
* a directory.
|
|
80
|
-
*
|
|
81
|
-
* Returns an empty array instead of throwing when the directory does
|
|
82
|
-
* not exist, is not readable, or `dirPath` points to a regular file.
|
|
83
|
-
* This matches the behaviour expected by the compiler during the
|
|
84
|
-
* discovery phase, where missing directories are not errors.
|
|
85
|
-
*
|
|
86
|
-
* The returned names are entry names only — not absolute paths. Callers
|
|
87
|
-
* must combine them with `dirPath` via {@link resolvePath} to obtain
|
|
88
|
-
* usable absolute paths.
|
|
89
|
-
*
|
|
90
|
-
* @param dirPath - Absolute path of the directory to read.
|
|
91
|
-
* @returns An array of entry names inside `dirPath`, or an empty array
|
|
92
|
-
* if the directory does not exist or cannot be read.
|
|
93
|
-
*
|
|
94
|
-
* @example
|
|
95
|
-
* host.getDirectoryEntries('/src/components');
|
|
96
|
-
* // → ['button', 'input', 'modal']
|
|
97
|
-
*/
|
|
98
|
-
getDirectoryEntries(dirPath) {
|
|
99
|
-
try {
|
|
100
|
-
return readdirSync(dirPath);
|
|
101
|
-
} catch {
|
|
102
|
-
return [];
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Checks whether the given path refers to a directory.
|
|
107
|
-
*
|
|
108
|
-
* Uses `statSync` rather than `lstatSync` so that symlinks to directories
|
|
109
|
-
* are correctly reported as directories. Returns `false` for non-existent
|
|
110
|
-
* paths, regular files, symlinks to files, and any path that causes
|
|
111
|
-
* `statSync` to throw (e.g. permission denied).
|
|
112
|
-
*
|
|
113
|
-
* @param filePath - Absolute path to check.
|
|
114
|
-
* @returns `true` if the path exists and is a directory (or a symlink
|
|
115
|
-
* to one), `false` in all other cases.
|
|
116
|
-
*/
|
|
117
|
-
isDirectory(filePath) {
|
|
118
|
-
try {
|
|
119
|
-
return statSync(filePath).isDirectory();
|
|
120
|
-
} catch {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Resolves all symlinks in a path and returns the real physical path.
|
|
126
|
-
*
|
|
127
|
-
* Critical in npm monorepos where workspace packages are symlinked inside
|
|
128
|
-
* `node_modules`. Without real-path resolution the compiler may process
|
|
129
|
-
* the same physical file twice under different apparent paths, producing
|
|
130
|
-
* duplicate entries in the module graph and the output bundle.
|
|
131
|
-
*
|
|
132
|
-
* Falls back to returning `filePath` unchanged when `realpathSync` throws
|
|
133
|
-
* (e.g. the path does not exist or a symlink is dangling). This keeps the
|
|
134
|
-
* compiler operational even when the path cannot be fully resolved.
|
|
135
|
-
*
|
|
136
|
-
* @param filePath - Absolute path, potentially containing symlinks.
|
|
137
|
-
* @returns The real absolute path with all symlinks resolved, or
|
|
138
|
-
* `filePath` unchanged if resolution fails.
|
|
139
|
-
*
|
|
140
|
-
* @example
|
|
141
|
-
* // In an npm monorepo:
|
|
142
|
-
* // /app/node_modules/@xaendar/core → /packages/core/src
|
|
143
|
-
* host.getRealPath('/app/node_modules/@xaendar/core/index.ts');
|
|
144
|
-
* // → '/packages/core/src/index.ts'
|
|
145
|
-
*/
|
|
146
|
-
getRealPath(filePath) {
|
|
147
|
-
try {
|
|
148
|
-
return realpathSync(filePath);
|
|
149
|
-
} catch {
|
|
150
|
-
return filePath;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Returns the current working directory of the Node.js process.
|
|
155
|
-
*
|
|
156
|
-
* Used by the compiler as the base for resolving relative paths that
|
|
157
|
-
* have no associated source file — for example paths passed as CLI
|
|
158
|
-
* arguments or specified in the project configuration file.
|
|
159
|
-
*
|
|
160
|
-
* @returns The absolute path of the current working directory.
|
|
161
|
-
*/
|
|
162
|
-
getCurrentDirectory() {
|
|
163
|
-
return process.cwd();
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
// ../packages/build-tools/src/lib/plugin.ts
|
|
168
|
-
function xaendarPlugin() {
|
|
169
|
-
const host = new NodeCompilerHost();
|
|
170
|
-
return {
|
|
171
|
-
name: "xaendar",
|
|
172
|
-
transform(code, id) {
|
|
173
|
-
if (!COMPONENT_FILE_RE.test(id)) {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
const { templatePath, stylePath } = extractDecoratorPaths(code, dirname2(id));
|
|
177
|
-
if (!templatePath || !host.fileExists(templatePath)) {
|
|
178
|
-
this.warn(`Xaendar: could not find template at ${templatePath}`);
|
|
179
|
-
return null;
|
|
180
|
-
}
|
|
181
|
-
this.addWatchFile(templatePath);
|
|
182
|
-
const templateSource = host.readFile(templatePath);
|
|
183
|
-
if (templateSource === void 0) {
|
|
184
|
-
this.warn(`Xaendar: could not read template at ${templatePath}`);
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
let cssContent;
|
|
188
|
-
if (stylePath && host.fileExists(stylePath)) {
|
|
189
|
-
this.addWatchFile(stylePath);
|
|
190
|
-
cssContent = host.readFile(stylePath) ?? "";
|
|
191
|
-
}
|
|
192
|
-
let compiledMethods;
|
|
193
|
-
const varName = cssContent ? `__${extractClassName(id)}_sheet` : void 0;
|
|
194
|
-
try {
|
|
195
|
-
compiledMethods = compile(templateSource, varName);
|
|
196
|
-
} catch (err) {
|
|
197
|
-
this.error(`Xaendar: failed to compile template ${templatePath}: ${String(err)}`);
|
|
198
|
-
}
|
|
199
|
-
let transformed;
|
|
200
|
-
try {
|
|
201
|
-
transformed = fixDecoratorExport(injectRenderMethods(code, compiledMethods, varName, cssContent));
|
|
202
|
-
} catch (err) {
|
|
203
|
-
this.error(String(err));
|
|
204
|
-
}
|
|
205
|
-
return {
|
|
206
|
-
code: transformed
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
function extractDecoratorPaths(jsSource, componentDir) {
|
|
212
|
-
const templateUrl = jsSource.match(/templateUrl\s*:\s*["'](.+?)["']/)?.[1];
|
|
213
|
-
const styleUrl = jsSource.match(/styleUrl\s*:\s*["'](.+?)["']/)?.[1];
|
|
214
|
-
return {
|
|
215
|
-
templatePath: templateUrl ? resolve2(componentDir, templateUrl) : void 0,
|
|
216
|
-
stylePath: styleUrl ? resolve2(componentDir, styleUrl) : void 0
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
function injectRenderMethods(jsSource, compiledMethods, varName, cssContent) {
|
|
220
|
-
const styleSnippet = cssContent?.trim().length ? buildStyleSnippet(varName, cssContent) : "";
|
|
221
|
-
let result = jsSource;
|
|
222
|
-
if (styleSnippet) {
|
|
223
|
-
result = result.replace(/^(class\s+\w+\s+extends)/m, `${styleSnippet}$1`);
|
|
224
|
-
}
|
|
225
|
-
const lastStaticBlock = /static\s*\{\s*\n(\s*)(\w+)\(\);\s*\n\s*\}/;
|
|
226
|
-
if (!lastStaticBlock.test(result)) {
|
|
227
|
-
throw new Error("Xaendar: could not find the static initializer block in the transpiled output. Make sure @rolldown/plugin-babel with @babel/plugin-proposal-decorators runs before xaendarPlugin() in your Vite config.");
|
|
228
|
-
}
|
|
229
|
-
result = `import { effect } from "@xaendar/signals";
|
|
230
|
-
|
|
231
|
-
${result}`;
|
|
232
|
-
return result.replace(lastStaticBlock, (_, indent, initFn) => `${compiledMethods}
|
|
3
|
+
${i}`,i.replace(a,(p,o,l)=>`${t}
|
|
233
4
|
static {
|
|
234
|
-
${
|
|
235
|
-
}`);
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
function extractClassName(jsSource) {
|
|
239
|
-
const match = jsSource.match(/class\s+(\w+)\s+extends/);
|
|
240
|
-
return match?.[1] ?? "__Component";
|
|
241
|
-
}
|
|
242
|
-
function buildStyleSnippet(varName, css) {
|
|
243
|
-
const escaped = css.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
244
|
-
return [
|
|
245
|
-
`const ${varName} = new CSSStyleSheet();`,
|
|
246
|
-
`${varName}.replaceSync(\`${escaped}\`);`,
|
|
247
|
-
""
|
|
248
|
-
].join("\n");
|
|
249
|
-
}
|
|
250
|
-
function fixDecoratorExport(code) {
|
|
251
|
-
return code.replace(/^export\s+(@\w+[\s\S]*?)\s+(class\s)/gm, "$1\nexport $2");
|
|
252
|
-
}
|
|
253
|
-
export {
|
|
254
|
-
xaendarPlugin
|
|
255
|
-
};
|
|
5
|
+
${o}${l}();
|
|
6
|
+
}`)}function _(e){return e.match(/class\s+(\w+)\s+extends/)?.[1]??"__Component"}function C(e,t){let n=t.replace(/\\/g,"\\\\").replace(/`/g,"\\`").replace(/\$\{/g,"\\${");return[`const ${e} = new CSSStyleSheet();`,`${e}.replaceSync(\`${n}\`);`,""].join(`
|
|
7
|
+
`)}function F(e){return e.replace(/^export\s+(@\w+[\s\S]*?)\s+(class\s)/gm,`$1
|
|
8
|
+
export $2`)}export{k as xaendarPlugin};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xaendar/build-tools",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.9",
|
|
4
4
|
"description": "A library containing build tools for Xaendar framework",
|
|
5
5
|
"author": "Kaitenjo",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"main": "./dist/build-tools.js",
|
|
16
16
|
"types": "./dist/build-tools.d.ts",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@xaendar/compiler": "0.4.
|
|
18
|
+
"@xaendar/compiler": "0.4.9",
|
|
19
19
|
"vite": "^8.0.14"
|
|
20
20
|
}
|
|
21
21
|
}
|