@jk2908/cxx 0.2.6 → 0.3.3
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/README.md +18 -2
- package/dist/build.d.ts +22 -11
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +242 -73
- package/dist/build.js.map +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -7
- package/dist/index.js.map +3 -3
- package/dist/logger.d.ts +0 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/next/cxx-loader.cjs +287 -146
- package/dist/next/cxx-loader.cjs.map +7 -7
- package/dist/next/index.d.ts +34 -9
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +338 -142
- package/dist/next/index.js.map +5 -5
- package/dist/types.d.ts +5 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +16 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/vite/index.d.ts +4 -3
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +336 -139
- package/dist/vite/index.js.map +6 -6
- package/package.json +85 -81
- package/src/build.ts +312 -108
- package/src/index.ts +26 -9
- package/src/logger.ts +5 -13
- package/src/next/cxx-loader.js +9 -6
- package/src/next/index.ts +152 -100
- package/src/types.ts +5 -8
- package/src/utils.ts +81 -8
- package/src/vite/index.ts +141 -89
package/dist/vite/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
+
|
|
1
4
|
// src/build.ts
|
|
2
5
|
import { createHash } from "node:crypto";
|
|
3
6
|
import fs from "node:fs/promises";
|
|
4
7
|
import path from "node:path";
|
|
5
8
|
import { transform } from "lightningcss";
|
|
9
|
+
import MagicString from "magic-string";
|
|
6
10
|
|
|
7
11
|
// src/config.ts
|
|
8
12
|
var NAME = "cxx";
|
|
@@ -52,45 +56,93 @@ function capitalise(str) {
|
|
|
52
56
|
function pascalise(str) {
|
|
53
57
|
return str.split(/[ _-]+/).map(capitalise).join("");
|
|
54
58
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
function createBatcher(wait, flush) {
|
|
60
|
+
const pending = new Map;
|
|
61
|
+
let timer = null;
|
|
62
|
+
let current = null;
|
|
63
|
+
function drain() {
|
|
64
|
+
if (current)
|
|
65
|
+
return current;
|
|
66
|
+
const run = (async () => {
|
|
67
|
+
while (pending.size > 0) {
|
|
68
|
+
const batch = new Map(pending);
|
|
69
|
+
pending.clear();
|
|
70
|
+
await flush(batch);
|
|
71
|
+
}
|
|
72
|
+
})();
|
|
73
|
+
current = run;
|
|
74
|
+
run.then(() => {
|
|
75
|
+
if (current === run)
|
|
76
|
+
current = null;
|
|
77
|
+
}, () => {
|
|
78
|
+
if (current === run)
|
|
79
|
+
current = null;
|
|
80
|
+
});
|
|
81
|
+
return run;
|
|
82
|
+
}
|
|
83
|
+
function schedule() {
|
|
84
|
+
if (timer)
|
|
85
|
+
clearTimeout(timer);
|
|
86
|
+
timer = setTimeout(() => {
|
|
87
|
+
timer = null;
|
|
88
|
+
drain().catch(() => {});
|
|
63
89
|
}, wait);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
add(key, value) {
|
|
93
|
+
pending.set(key, value);
|
|
94
|
+
schedule();
|
|
95
|
+
},
|
|
96
|
+
flush() {
|
|
97
|
+
if (timer) {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
timer = null;
|
|
100
|
+
}
|
|
101
|
+
return drain();
|
|
102
|
+
}
|
|
64
103
|
};
|
|
65
104
|
}
|
|
66
105
|
|
|
67
106
|
// src/build.ts
|
|
107
|
+
var decoder = new TextDecoder;
|
|
108
|
+
var encoder = new TextEncoder;
|
|
68
109
|
var collectCache = new LruCache;
|
|
69
|
-
var
|
|
110
|
+
var writeChain = Promise.resolve();
|
|
70
111
|
function isENOENT(err) {
|
|
71
112
|
return err instanceof Error && "code" in err && err.code === "ENOENT";
|
|
72
113
|
}
|
|
73
|
-
async function
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
114
|
+
async function writeFileAtomic(filePath, content) {
|
|
115
|
+
const tmp = `${filePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
116
|
+
await fs.writeFile(tmp, content);
|
|
117
|
+
try {
|
|
118
|
+
await fs.rename(tmp, filePath);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
await fs.rm(tmp, { force: true });
|
|
121
|
+
throw err;
|
|
79
122
|
}
|
|
123
|
+
}
|
|
124
|
+
function enqueueWrite(task) {
|
|
125
|
+
const run = writeChain.then(task, task);
|
|
126
|
+
writeChain = run.then(() => {
|
|
127
|
+
return;
|
|
128
|
+
}, () => {
|
|
129
|
+
return;
|
|
130
|
+
});
|
|
131
|
+
return run;
|
|
132
|
+
}
|
|
133
|
+
async function maybeWrite(filePath, content) {
|
|
80
134
|
try {
|
|
81
|
-
if (await fs.readFile(filePath, "utf-8") === content)
|
|
82
|
-
fileCache.set(filePath, content);
|
|
135
|
+
if (await fs.readFile(filePath, "utf-8") === content)
|
|
83
136
|
return false;
|
|
84
|
-
}
|
|
85
137
|
} catch (err) {
|
|
86
138
|
if (!isENOENT(err))
|
|
87
139
|
throw err;
|
|
88
140
|
}
|
|
89
|
-
await
|
|
90
|
-
fileCache.set(filePath, content);
|
|
141
|
+
await writeFileAtomic(filePath, content);
|
|
91
142
|
return true;
|
|
92
143
|
}
|
|
93
|
-
var regex = /(?:const|var|let)\s*\[(\w
|
|
144
|
+
var regex = /((?:export\s+)?)(?:const|var|let)\s*\[(\w*)\s*,?\s*(\w*)\s*,?\s*(\w*)\s*\]\s*=\s*cxx(?:\s*`([\s\S]*?)`|\s*\.\s*tag(?:\s*<[^>]+>)?\s*\(\s*(['"])(.*?)\6\s*\)\s*`([\s\S]*?)`)/gm;
|
|
145
|
+
var IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
94
146
|
function hashCss(code) {
|
|
95
147
|
return `cxx-${createHash("sha256").update(code).digest("base64url").slice(0, 12)}`;
|
|
96
148
|
}
|
|
@@ -101,73 +153,137 @@ class DuplicateTagError extends Error {
|
|
|
101
153
|
super(`Tag ${tag} has already been seen. Tags must be unique across your application`);
|
|
102
154
|
}
|
|
103
155
|
}
|
|
156
|
+
|
|
157
|
+
class InvalidTagError extends Error {
|
|
158
|
+
name = "InvalidTagError";
|
|
159
|
+
constructor(tag) {
|
|
160
|
+
super(`Tag "${tag}" does not map to a valid TypeScript identifier. ` + `Use letters, numbers, spaces, "_" or "-"`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
104
163
|
function collect(source, id, config) {
|
|
105
|
-
const
|
|
164
|
+
const configKey = JSON.stringify(config);
|
|
106
165
|
const cached = collectCache.get(id);
|
|
107
|
-
if (cached?.source === source)
|
|
166
|
+
if (cached?.source === source && cached.config === configKey)
|
|
108
167
|
return cached;
|
|
109
|
-
const
|
|
168
|
+
const tags = new Map;
|
|
169
|
+
const magic = new MagicString(source);
|
|
170
|
+
let matched = false;
|
|
171
|
+
regex.lastIndex = 0;
|
|
172
|
+
let match;
|
|
173
|
+
while (match = regex.exec(source)) {
|
|
174
|
+
matched = true;
|
|
175
|
+
const [, exp, varOne, varTwo, varThree, plainCss, , tag, taggedCss] = match;
|
|
110
176
|
const css = plainCss ?? taggedCss;
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
177
|
+
const matchIndex = match.index;
|
|
178
|
+
const { code, exports: classExports = {} } = (() => {
|
|
179
|
+
try {
|
|
180
|
+
return transform({
|
|
181
|
+
minify: true,
|
|
182
|
+
cssModules: true,
|
|
183
|
+
filename: id,
|
|
184
|
+
code: encoder.encode(css)
|
|
185
|
+
});
|
|
186
|
+
} catch (err) {
|
|
187
|
+
const line = source.slice(0, matchIndex).split(`
|
|
188
|
+
`).length;
|
|
189
|
+
throw new Error(`Failed to compile cxx CSS at ${id}:${line}`, { cause: err });
|
|
190
|
+
}
|
|
191
|
+
})();
|
|
117
192
|
const href = hashCss(code);
|
|
118
|
-
const styles = Object.fromEntries(Object.entries(
|
|
193
|
+
const styles = Object.fromEntries(Object.entries(classExports).map(([k, v]) => [k, v.name]));
|
|
119
194
|
if (tag) {
|
|
120
195
|
const suffix = typeof config.typeSuffix === "string" ? config.typeSuffix : config.typeSuffix === false ? "" : "Classes";
|
|
121
196
|
const tagWithSuffix = pascalise(`${tag}${suffix}`);
|
|
197
|
+
if (!IDENTIFIER.test(tagWithSuffix))
|
|
198
|
+
throw new InvalidTagError(tag);
|
|
122
199
|
if (tags.has(tagWithSuffix))
|
|
123
200
|
throw new DuplicateTagError(tagWithSuffix);
|
|
124
201
|
tags.set(tagWithSuffix, Object.keys(styles));
|
|
125
202
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
203
|
+
const statements = [];
|
|
204
|
+
if (varOne) {
|
|
205
|
+
statements.push(`${exp}const ${varOne} = ${JSON.stringify(decoder.decode(code))}`);
|
|
206
|
+
}
|
|
207
|
+
if (varTwo) {
|
|
208
|
+
statements.push(`${exp}const ${varTwo} = ${JSON.stringify(styles)}`);
|
|
209
|
+
}
|
|
210
|
+
if (varThree) {
|
|
211
|
+
statements.push(`${exp}const ${varThree} = ${JSON.stringify(href)}`);
|
|
212
|
+
}
|
|
213
|
+
magic.overwrite(matchIndex, matchIndex + match[0].length, statements.join(`
|
|
214
|
+
`));
|
|
215
|
+
}
|
|
216
|
+
const template = magic.toString();
|
|
217
|
+
const map = matched ? magic.generateMap({ source: id, includeContent: true, hires: true }) : null;
|
|
218
|
+
const result = { source, config: configKey, template, tags, map };
|
|
219
|
+
collectCache.set(id, result);
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
function renderTypes(tags) {
|
|
223
|
+
return [
|
|
224
|
+
AUTOGEN_MSG,
|
|
225
|
+
"",
|
|
226
|
+
`import '${PKG_NAME}'`,
|
|
227
|
+
"",
|
|
228
|
+
`declare module '${PKG_NAME}' {`,
|
|
229
|
+
tagsToType(tags),
|
|
230
|
+
"}",
|
|
231
|
+
""
|
|
232
|
+
].join(`
|
|
131
233
|
`);
|
|
132
|
-
});
|
|
133
|
-
collectCache.set(id, { source, template, tags });
|
|
134
|
-
return {
|
|
135
|
-
template,
|
|
136
|
-
tags
|
|
137
|
-
};
|
|
138
234
|
}
|
|
139
|
-
async function
|
|
235
|
+
async function writeRenderedTypes(tags) {
|
|
140
236
|
const filePath = path.join(GENERATED_DIR, "index.d.ts");
|
|
141
237
|
if (!tags.size) {
|
|
142
|
-
|
|
143
|
-
await fs.rm(filePath, { force: true });
|
|
144
|
-
fileCache.delete(filePath);
|
|
145
|
-
} catch (err) {
|
|
146
|
-
if (!isENOENT(err))
|
|
147
|
-
throw err;
|
|
148
|
-
}
|
|
238
|
+
await fs.rm(filePath, { force: true });
|
|
149
239
|
return;
|
|
150
240
|
}
|
|
151
241
|
await fs.mkdir(GENERATED_DIR, { recursive: true });
|
|
152
|
-
await maybeWrite(filePath,
|
|
153
|
-
|
|
154
|
-
import '${PKG_NAME}'
|
|
155
|
-
|
|
156
|
-
declare module '${PKG_NAME}' {
|
|
157
|
-
${tagsToType(tags)}
|
|
158
|
-
}
|
|
159
|
-
`);
|
|
242
|
+
await maybeWrite(filePath, renderTypes(tags));
|
|
160
243
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
244
|
+
var PARTIAL_DIR = path.join(GENERATED_DIR, "tags");
|
|
245
|
+
var REBUILD_WAIT = 100;
|
|
246
|
+
var rebuildTimer = null;
|
|
247
|
+
var rebuildError = null;
|
|
248
|
+
function partialPath(filePath) {
|
|
249
|
+
return path.join(PARTIAL_DIR, `${createHash("sha1").update(filePath).digest("hex")}.json`);
|
|
250
|
+
}
|
|
251
|
+
async function partialDirMtime() {
|
|
252
|
+
try {
|
|
253
|
+
return (await fs.stat(PARTIAL_DIR)).mtimeMs;
|
|
254
|
+
} catch (err) {
|
|
255
|
+
if (isENOENT(err))
|
|
256
|
+
return 0;
|
|
257
|
+
throw err;
|
|
258
|
+
}
|
|
166
259
|
}
|
|
167
|
-
function
|
|
260
|
+
async function readPartials() {
|
|
261
|
+
let entries;
|
|
262
|
+
try {
|
|
263
|
+
entries = await fs.readdir(PARTIAL_DIR);
|
|
264
|
+
} catch (err) {
|
|
265
|
+
if (isENOENT(err))
|
|
266
|
+
return new Map;
|
|
267
|
+
throw err;
|
|
268
|
+
}
|
|
168
269
|
const tags = new Map;
|
|
169
|
-
for (const
|
|
170
|
-
|
|
270
|
+
for (const entry of entries) {
|
|
271
|
+
if (!entry.endsWith(".json"))
|
|
272
|
+
continue;
|
|
273
|
+
const partial = path.join(PARTIAL_DIR, entry);
|
|
274
|
+
let parsed;
|
|
275
|
+
try {
|
|
276
|
+
parsed = JSON.parse(await fs.readFile(partial, "utf-8"));
|
|
277
|
+
} catch {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
try {
|
|
281
|
+
await fs.access(parsed.file);
|
|
282
|
+
} catch {
|
|
283
|
+
await fs.rm(partial, { force: true });
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
for (const [name, classes] of Object.entries(parsed.tags)) {
|
|
171
287
|
if (tags.has(name))
|
|
172
288
|
throw new DuplicateTagError(name);
|
|
173
289
|
tags.set(name, classes);
|
|
@@ -175,6 +291,57 @@ function flattenTags(tagsByFile) {
|
|
|
175
291
|
}
|
|
176
292
|
return tags;
|
|
177
293
|
}
|
|
294
|
+
function writeTypesForFile(filePath, tags) {
|
|
295
|
+
return enqueueWrite(async () => {
|
|
296
|
+
await fs.mkdir(PARTIAL_DIR, { recursive: true });
|
|
297
|
+
const partial = partialPath(filePath);
|
|
298
|
+
if (!tags.size) {
|
|
299
|
+
await fs.rm(partial, { force: true });
|
|
300
|
+
} else {
|
|
301
|
+
await writeFileAtomic(partial, JSON.stringify({ file: filePath, tags: Object.fromEntries(tags) }));
|
|
302
|
+
}
|
|
303
|
+
}).then(() => {
|
|
304
|
+
scheduleRebuild();
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
function scheduleRebuild() {
|
|
308
|
+
if (rebuildTimer)
|
|
309
|
+
clearTimeout(rebuildTimer);
|
|
310
|
+
rebuildTimer = setTimeout(() => {
|
|
311
|
+
rebuildTimer = null;
|
|
312
|
+
flushTypes().catch((err) => {
|
|
313
|
+
rebuildError = err;
|
|
314
|
+
});
|
|
315
|
+
}, REBUILD_WAIT);
|
|
316
|
+
}
|
|
317
|
+
function flushTypes() {
|
|
318
|
+
if (rebuildTimer) {
|
|
319
|
+
clearTimeout(rebuildTimer);
|
|
320
|
+
rebuildTimer = null;
|
|
321
|
+
}
|
|
322
|
+
return enqueueWrite(async () => {
|
|
323
|
+
let before = await partialDirMtime();
|
|
324
|
+
for (let attempt = 0;attempt < 3; attempt++) {
|
|
325
|
+
await writeRenderedTypes(await readPartials());
|
|
326
|
+
const after = await partialDirMtime();
|
|
327
|
+
if (after === before)
|
|
328
|
+
return;
|
|
329
|
+
before = after;
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
function takeRebuildError() {
|
|
334
|
+
const err = rebuildError;
|
|
335
|
+
rebuildError = null;
|
|
336
|
+
return err;
|
|
337
|
+
}
|
|
338
|
+
function tagsToType(tags) {
|
|
339
|
+
return [...tags].toSorted(([a], [b]) => a.localeCompare(b)).map(([tag, classes]) => {
|
|
340
|
+
const union = classes.length > 0 ? classes.toSorted((a, b) => a.length - b.length).map((c) => `'${c}'`).join(" | ") : "never";
|
|
341
|
+
return ` export type ${tag} = ${union}`;
|
|
342
|
+
}).join(`
|
|
343
|
+
`);
|
|
344
|
+
}
|
|
178
345
|
|
|
179
346
|
// src/vite/index.ts
|
|
180
347
|
import { realpathSync } from "node:fs";
|
|
@@ -189,20 +356,14 @@ var LEVELS = {
|
|
|
189
356
|
error: 3,
|
|
190
357
|
fatal: 4
|
|
191
358
|
};
|
|
359
|
+
var defaultLevel = process.env["NODE_ENV"] === "production" ? "error" : "info";
|
|
192
360
|
|
|
193
361
|
class Logger {
|
|
194
362
|
name;
|
|
195
|
-
static #defaultLevel = "info";
|
|
196
363
|
#level;
|
|
197
364
|
constructor(level, name) {
|
|
198
365
|
this.name = name;
|
|
199
|
-
this.#level = level;
|
|
200
|
-
}
|
|
201
|
-
static set defaultLevel(level) {
|
|
202
|
-
Logger.#defaultLevel = level;
|
|
203
|
-
}
|
|
204
|
-
static get defaultLevel() {
|
|
205
|
-
return Logger.#defaultLevel;
|
|
366
|
+
this.#level = level ?? defaultLevel;
|
|
206
367
|
}
|
|
207
368
|
static toError(err) {
|
|
208
369
|
return err instanceof Error ? err : new Error(String(err), { cause: err });
|
|
@@ -225,7 +386,7 @@ ${err.stack}` : "");
|
|
|
225
386
|
this.#level = level;
|
|
226
387
|
}
|
|
227
388
|
get level() {
|
|
228
|
-
return this.#level
|
|
389
|
+
return this.#level;
|
|
229
390
|
}
|
|
230
391
|
log(level, message, error) {
|
|
231
392
|
if (LEVELS[level] < LEVELS[this.level])
|
|
@@ -273,15 +434,14 @@ var ACCEPTED_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx"]);
|
|
|
273
434
|
function normaliseWatchPath(p) {
|
|
274
435
|
return p.replace(/\\/g, "/");
|
|
275
436
|
}
|
|
437
|
+
function globToRegExp(glob) {
|
|
438
|
+
const pattern = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*(\/|$)/g, ".*$1").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
|
|
439
|
+
return new RegExp(`^${pattern}$`);
|
|
440
|
+
}
|
|
276
441
|
function cxx(pluginConfig = {}) {
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const logger = new Logger(pluginConfig?.logger?.level ?? false ? "error" : "debug");
|
|
281
|
-
const watchRoot = normaliseWatchPath(realpathSync.native(process.cwd()));
|
|
282
|
-
const watchedRoots = [`${watchRoot}/`];
|
|
283
|
-
let rebuildRunning = false;
|
|
284
|
-
let rebuildQueued = false;
|
|
442
|
+
const logger = new Logger;
|
|
443
|
+
let watchRoot = normaliseWatchPath(process.cwd());
|
|
444
|
+
const ignored = (pluginConfig.watch?.ignore ?? []).map(globToRegExp);
|
|
285
445
|
function resolveWatchFile(filePath) {
|
|
286
446
|
const absolutePath = path2.resolve(watchRoot, filePath);
|
|
287
447
|
const parentPath = path2.dirname(absolutePath);
|
|
@@ -294,75 +454,112 @@ function cxx(pluginConfig = {}) {
|
|
|
294
454
|
}
|
|
295
455
|
function watchedFile(filePath) {
|
|
296
456
|
const resolvedPath = resolveWatchFile(filePath);
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const rebuild = debounce((event, filePath) => {
|
|
300
|
-
function queue() {
|
|
301
|
-
(async () => {
|
|
302
|
-
if (rebuildRunning) {
|
|
303
|
-
rebuildQueued = true;
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
rebuildRunning = true;
|
|
307
|
-
do {
|
|
308
|
-
rebuildQueued = false;
|
|
309
|
-
try {
|
|
310
|
-
const hadTags = buildContext.tagsByFile.has(file);
|
|
311
|
-
let hasTags = false;
|
|
312
|
-
if (event === "unlink") {
|
|
313
|
-
buildContext.tagsByFile.delete(file);
|
|
314
|
-
} else {
|
|
315
|
-
const source = await fs2.readFile(file, "utf-8");
|
|
316
|
-
const { tags } = collect(source, file, pluginConfig);
|
|
317
|
-
hasTags = tags.size > 0;
|
|
318
|
-
if (hasTags) {
|
|
319
|
-
buildContext.tagsByFile.set(file, tags);
|
|
320
|
-
} else {
|
|
321
|
-
buildContext.tagsByFile.delete(file);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
if (!hadTags && !hasTags)
|
|
325
|
-
continue;
|
|
326
|
-
await writeTypes(flattenTags(buildContext.tagsByFile));
|
|
327
|
-
logger.info(`updated types from ${file}`);
|
|
328
|
-
} catch (err) {
|
|
329
|
-
if (isENOENT(err)) {
|
|
330
|
-
if (!buildContext.tagsByFile.has(file))
|
|
331
|
-
continue;
|
|
332
|
-
buildContext.tagsByFile.delete(file);
|
|
333
|
-
await writeTypes(flattenTags(buildContext.tagsByFile));
|
|
334
|
-
logger.info(`updated types from ${file}`);
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
logger.error(`failed to update types from ${file}`, err);
|
|
338
|
-
}
|
|
339
|
-
} while (rebuildQueued);
|
|
340
|
-
rebuildRunning = false;
|
|
341
|
-
})();
|
|
457
|
+
if (resolvedPath.startsWith(`${watchRoot}/`) && !resolvedPath.includes(`/${GENERATED_DIR}/`) && ACCEPTED_EXTENSIONS.has(path2.extname(resolvedPath)) && !ignored.some((regexp) => regexp.test(resolvedPath))) {
|
|
458
|
+
return resolvedPath;
|
|
342
459
|
}
|
|
343
|
-
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
async function recordFile(file) {
|
|
463
|
+
let source;
|
|
464
|
+
try {
|
|
465
|
+
source = await fs2.readFile(file, "utf-8");
|
|
466
|
+
} catch (err) {
|
|
467
|
+
if (!isENOENT(err))
|
|
468
|
+
throw err;
|
|
469
|
+
await writeTypesForFile(file, new Map);
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const tags = source.includes("cxx") ? collect(source, file, pluginConfig).tags : new Map;
|
|
473
|
+
await writeTypesForFile(file, tags);
|
|
474
|
+
}
|
|
475
|
+
async function scan(dir) {
|
|
476
|
+
let entries;
|
|
477
|
+
try {
|
|
478
|
+
entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
479
|
+
} catch {
|
|
344
480
|
return;
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
481
|
+
}
|
|
482
|
+
await Promise.all(entries.map(async (entry) => {
|
|
483
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules")
|
|
484
|
+
return;
|
|
485
|
+
const full = path2.join(dir, entry.name);
|
|
486
|
+
if (entry.isDirectory()) {
|
|
487
|
+
await scan(full);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (!ACCEPTED_EXTENSIONS.has(path2.extname(entry.name)))
|
|
491
|
+
return;
|
|
492
|
+
const resolved = resolveWatchFile(full);
|
|
493
|
+
if (ignored.some((regexp) => regexp.test(resolved)))
|
|
494
|
+
return;
|
|
495
|
+
await recordFile(resolved);
|
|
496
|
+
}));
|
|
497
|
+
}
|
|
498
|
+
const queue = createBatcher(75, async (batch) => {
|
|
499
|
+
for (const [file, event] of batch) {
|
|
500
|
+
try {
|
|
501
|
+
if (event === "unlink") {
|
|
502
|
+
await writeTypesForFile(file, new Map);
|
|
503
|
+
} else {
|
|
504
|
+
await recordFile(file);
|
|
505
|
+
}
|
|
506
|
+
logger.info(`updated types from ${file}`);
|
|
507
|
+
} catch (err) {
|
|
508
|
+
logger.error(`failed to update types from ${file}`, err);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
});
|
|
348
512
|
return {
|
|
349
513
|
name: "cxx",
|
|
350
514
|
enforce: "pre",
|
|
515
|
+
configResolved(config) {
|
|
516
|
+
const root = pluginConfig.watch?.root ?? config.root;
|
|
517
|
+
try {
|
|
518
|
+
watchRoot = normaliseWatchPath(realpathSync.native(root));
|
|
519
|
+
} catch {
|
|
520
|
+
watchRoot = normaliseWatchPath(root);
|
|
521
|
+
}
|
|
522
|
+
},
|
|
351
523
|
transform(code, id) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
524
|
+
if (id.startsWith("\x00") || id.includes("/node_modules/"))
|
|
525
|
+
return null;
|
|
526
|
+
if (!code.includes("cxx"))
|
|
527
|
+
return null;
|
|
528
|
+
const cleanId = id.split("?")[0];
|
|
529
|
+
if (!ACCEPTED_EXTENSIONS.has(path2.extname(cleanId)))
|
|
530
|
+
return null;
|
|
531
|
+
const { template, tags, map } = collect(code, cleanId, pluginConfig);
|
|
532
|
+
if (template === code)
|
|
533
|
+
return null;
|
|
534
|
+
writeTypesForFile(resolveWatchFile(cleanId), tags);
|
|
355
535
|
return {
|
|
356
536
|
code: template,
|
|
357
|
-
map
|
|
537
|
+
map
|
|
358
538
|
};
|
|
359
539
|
},
|
|
360
540
|
configureServer(server) {
|
|
361
541
|
logger.info("Watching for changes...");
|
|
362
|
-
server.watcher.on("add", (p) =>
|
|
542
|
+
server.watcher.on("add", (p) => {
|
|
543
|
+
const file = watchedFile(p);
|
|
544
|
+
if (file)
|
|
545
|
+
queue.add(file, "add");
|
|
546
|
+
}).on("change", (p) => {
|
|
547
|
+
const file = watchedFile(p);
|
|
548
|
+
if (file)
|
|
549
|
+
queue.add(file, "change");
|
|
550
|
+
}).on("unlink", (p) => {
|
|
551
|
+
const file = watchedFile(p);
|
|
552
|
+
if (file)
|
|
553
|
+
queue.add(file, "unlink");
|
|
554
|
+
});
|
|
555
|
+
scan(watchRoot).then(() => flushTypes()).then(() => {
|
|
556
|
+
const err = takeRebuildError();
|
|
557
|
+
if (err)
|
|
558
|
+
logger.error("failed to generate types", err);
|
|
559
|
+
}).catch((err) => logger.error("failed to scan for cxx templates", err));
|
|
363
560
|
},
|
|
364
561
|
async writeBundle() {
|
|
365
|
-
await
|
|
562
|
+
await flushTypes();
|
|
366
563
|
}
|
|
367
564
|
};
|
|
368
565
|
}
|
|
@@ -370,4 +567,4 @@ export {
|
|
|
370
567
|
cxx as default
|
|
371
568
|
};
|
|
372
569
|
|
|
373
|
-
//# debugId=
|
|
570
|
+
//# debugId=7C0503EFBFB9E21F64756E2164756E21
|