@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.
Files changed (2) hide show
  1. package/dist/build-tools.js +6 -253
  2. package/package.json +2 -2
@@ -1,255 +1,8 @@
1
- // ../packages/build-tools/src/lib/plugin.ts
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
- // ../packages/build-tools/src/lib/costants.ts
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
- ${indent}${initFn}();
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.5",
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.5",
18
+ "@xaendar/compiler": "0.4.9",
19
19
  "vite": "^8.0.14"
20
20
  }
21
21
  }