@collie-lang/vite 1.0.0 → 1.1.1
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 +44 -1
- package/dist/index.cjs +408 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +410 -31
- package/dist/index.js.map +1 -1
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -1,3 +1,46 @@
|
|
|
1
1
|
# @collie-lang/vite
|
|
2
2
|
|
|
3
|
-
Vite plugin
|
|
3
|
+
Vite plugin that builds the Collie template registry and virtual template modules.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -D @collie-lang/vite
|
|
9
|
+
pnpm add @collie-lang/react
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
// vite.config.ts
|
|
16
|
+
import { defineConfig } from "vite";
|
|
17
|
+
import react from "@vitejs/plugin-react";
|
|
18
|
+
import collie from "@collie-lang/vite";
|
|
19
|
+
|
|
20
|
+
export default defineConfig({
|
|
21
|
+
plugins: [collie(), react()]
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Create templates with `#id` blocks:
|
|
26
|
+
|
|
27
|
+
```collie
|
|
28
|
+
#id app.hero
|
|
29
|
+
div.hero
|
|
30
|
+
h1 {{ title }}
|
|
31
|
+
|
|
32
|
+
#id app.cta
|
|
33
|
+
button.primary {{ label }}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Render them via the runtime:
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { Collie } from "@collie-lang/react";
|
|
40
|
+
|
|
41
|
+
export function App() {
|
|
42
|
+
return <Collie id="app.hero" title="Hello" />;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Direct `.collie` imports are not supported; templates are discovered automatically by the plugin.
|
package/dist/index.cjs
CHANGED
|
@@ -35,8 +35,17 @@ __export(index_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
var import_node_path = __toESM(require("path"), 1);
|
|
37
37
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
38
|
+
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
38
39
|
var import_vite = require("vite");
|
|
39
40
|
var import_compiler = require("@collie-lang/compiler");
|
|
41
|
+
var VIRTUAL_REGISTRY_ID = "virtual:collie/registry";
|
|
42
|
+
var VIRTUAL_REGISTRY_RESOLVED = "\0collie:registry";
|
|
43
|
+
var VIRTUAL_IDS_ID = "virtual:collie/ids";
|
|
44
|
+
var VIRTUAL_IDS_RESOLVED = "\0collie:ids";
|
|
45
|
+
var VIRTUAL_TEMPLATE_PREFIX = "virtual:collie/template/";
|
|
46
|
+
var VIRTUAL_TEMPLATE_RESOLVED_PREFIX = "\0collie:template:";
|
|
47
|
+
var COLLIE_GLOB = "**/*.collie";
|
|
48
|
+
var DEFAULT_IGNORE_GLOBS = ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/build/**", "**/.vite/**"];
|
|
40
49
|
function stripQuery(id) {
|
|
41
50
|
const q = id.indexOf("?");
|
|
42
51
|
return q === -1 ? id : id.slice(0, q);
|
|
@@ -44,49 +53,419 @@ function stripQuery(id) {
|
|
|
44
53
|
function isCollieFile(id) {
|
|
45
54
|
return stripQuery(id).endsWith(".collie");
|
|
46
55
|
}
|
|
47
|
-
function
|
|
48
|
-
const
|
|
49
|
-
|
|
56
|
+
function toDisplayPath(filePath, root) {
|
|
57
|
+
const normalized = (0, import_vite.normalizePath)(filePath);
|
|
58
|
+
if (!root || !import_node_path.default.isAbsolute(filePath)) {
|
|
59
|
+
return normalized;
|
|
60
|
+
}
|
|
61
|
+
const relative = import_node_path.default.relative(root, filePath);
|
|
62
|
+
if (!relative || relative.startsWith("..")) {
|
|
63
|
+
return normalized;
|
|
64
|
+
}
|
|
65
|
+
return (0, import_vite.normalizePath)(relative);
|
|
50
66
|
}
|
|
51
|
-
function formatDiagnostic(id, diagnostic) {
|
|
52
|
-
const file = diagnostic.file ?? stripQuery(id);
|
|
53
|
-
const
|
|
54
|
-
const
|
|
67
|
+
function formatDiagnostic(id, diagnostic, root) {
|
|
68
|
+
const file = diagnostic.filePath ?? diagnostic.file ?? stripQuery(id);
|
|
69
|
+
const displayFile = toDisplayPath(file, root);
|
|
70
|
+
const range = diagnostic.range ?? diagnostic.span;
|
|
71
|
+
const where = range ? `${range.start.line}:${range.start.col}` : "";
|
|
72
|
+
const location = where ? `${displayFile}:${where}` : displayFile;
|
|
55
73
|
const code = diagnostic.code ? diagnostic.code : "COLLIE";
|
|
56
74
|
return `${location} [${code}] ${diagnostic.message}`;
|
|
57
75
|
}
|
|
76
|
+
function isVirtualCollieId(id) {
|
|
77
|
+
return id === VIRTUAL_REGISTRY_ID || id === VIRTUAL_REGISTRY_RESOLVED || id === VIRTUAL_IDS_ID || id === VIRTUAL_IDS_RESOLVED || id.startsWith(VIRTUAL_TEMPLATE_PREFIX) || id.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX);
|
|
78
|
+
}
|
|
79
|
+
function buildDirectImportError(importedId, importer, root) {
|
|
80
|
+
const importLine = stripQuery(importedId);
|
|
81
|
+
const importerLabel = importer ? toDisplayPath(importer, root) : "<unknown>";
|
|
82
|
+
const lines = [
|
|
83
|
+
"Direct .collie imports are not supported.",
|
|
84
|
+
`Importer: ${importerLabel}`,
|
|
85
|
+
`Import: ${importLine}`,
|
|
86
|
+
"Use the registry runtime instead:",
|
|
87
|
+
"import { Collie } from '@collie-lang/react'",
|
|
88
|
+
'<Collie id="Your.TemplateId" />',
|
|
89
|
+
"Templates are discovered automatically by @collie-lang/vite."
|
|
90
|
+
];
|
|
91
|
+
return new Error(lines.join("\n"));
|
|
92
|
+
}
|
|
93
|
+
function encodeTemplateId(id) {
|
|
94
|
+
return Buffer.from(id, "utf8").toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
95
|
+
}
|
|
96
|
+
function decodeTemplateId(encoded) {
|
|
97
|
+
const normalized = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
98
|
+
const padLength = normalized.length % 4;
|
|
99
|
+
const padded = padLength === 0 ? normalized : normalized + "=".repeat(4 - padLength);
|
|
100
|
+
return Buffer.from(padded, "base64").toString("utf8");
|
|
101
|
+
}
|
|
102
|
+
function formatLocation(location, root) {
|
|
103
|
+
const file = toDisplayPath(location.file, root);
|
|
104
|
+
if (typeof location.line === "number" && typeof location.col === "number") {
|
|
105
|
+
return `${file}:${location.line}:${location.col}`;
|
|
106
|
+
}
|
|
107
|
+
return file;
|
|
108
|
+
}
|
|
109
|
+
function formatDuplicateIdError(duplicates, root) {
|
|
110
|
+
const lines = ["[collie] Duplicate template ids detected:"];
|
|
111
|
+
const entries = Array.from(duplicates.entries()).sort((a, b) => a[0].localeCompare(b[0]));
|
|
112
|
+
for (const [id, locations] of entries) {
|
|
113
|
+
const formatted = locations.map((location) => formatLocation(location, root)).join(", ");
|
|
114
|
+
lines.push(`- ${id}: ${formatted}`);
|
|
115
|
+
}
|
|
116
|
+
return lines.join("\n");
|
|
117
|
+
}
|
|
118
|
+
function buildIgnoreGlobs(config) {
|
|
119
|
+
const ignore = new Set(DEFAULT_IGNORE_GLOBS);
|
|
120
|
+
if (!config) {
|
|
121
|
+
return Array.from(ignore);
|
|
122
|
+
}
|
|
123
|
+
const addRelativeDir = (dir) => {
|
|
124
|
+
if (!dir) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const absolute = import_node_path.default.isAbsolute(dir) ? dir : import_node_path.default.join(config.root, dir);
|
|
128
|
+
const relative = (0, import_vite.normalizePath)(import_node_path.default.relative(config.root, absolute));
|
|
129
|
+
if (!relative || relative.startsWith("..")) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
ignore.add(`${relative}/**`);
|
|
133
|
+
};
|
|
134
|
+
addRelativeDir(config.build?.outDir);
|
|
135
|
+
addRelativeDir(config.cacheDir);
|
|
136
|
+
addRelativeDir(config.publicDir);
|
|
137
|
+
return Array.from(ignore);
|
|
138
|
+
}
|
|
58
139
|
function colliePlugin(options = {}) {
|
|
59
140
|
let resolvedRuntime = options.jsxRuntime ?? "automatic";
|
|
141
|
+
let resolvedConfig;
|
|
142
|
+
let needsScan = true;
|
|
143
|
+
const templatesById = /* @__PURE__ */ new Map();
|
|
144
|
+
const templatesByEncodedId = /* @__PURE__ */ new Map();
|
|
145
|
+
const fileToTemplateIds = /* @__PURE__ */ new Map();
|
|
146
|
+
const templateIdToVirtualId = /* @__PURE__ */ new Map();
|
|
147
|
+
const resetTemplates = () => {
|
|
148
|
+
needsScan = true;
|
|
149
|
+
templatesById.clear();
|
|
150
|
+
templatesByEncodedId.clear();
|
|
151
|
+
fileToTemplateIds.clear();
|
|
152
|
+
templateIdToVirtualId.clear();
|
|
153
|
+
};
|
|
154
|
+
const trackTemplateRecord = (record) => {
|
|
155
|
+
templatesById.set(record.id, record);
|
|
156
|
+
templatesByEncodedId.set(record.encodedId, record);
|
|
157
|
+
templateIdToVirtualId.set(record.id, `${VIRTUAL_TEMPLATE_RESOLVED_PREFIX}${record.encodedId}`);
|
|
158
|
+
const ids = fileToTemplateIds.get(record.filePath) ?? /* @__PURE__ */ new Set();
|
|
159
|
+
ids.add(record.id);
|
|
160
|
+
fileToTemplateIds.set(record.filePath, ids);
|
|
161
|
+
};
|
|
162
|
+
const removeFileTemplates = (filePath) => {
|
|
163
|
+
const ids = fileToTemplateIds.get(filePath) ?? /* @__PURE__ */ new Set();
|
|
164
|
+
for (const id of ids) {
|
|
165
|
+
const record = templatesById.get(id);
|
|
166
|
+
if (record && record.filePath === filePath) {
|
|
167
|
+
templatesById.delete(id);
|
|
168
|
+
templatesByEncodedId.delete(record.encodedId);
|
|
169
|
+
templateIdToVirtualId.delete(id);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
fileToTemplateIds.delete(filePath);
|
|
173
|
+
return ids;
|
|
174
|
+
};
|
|
175
|
+
const collectModuleIds = (ids) => {
|
|
176
|
+
const moduleIds = /* @__PURE__ */ new Set();
|
|
177
|
+
for (const id of ids) {
|
|
178
|
+
const moduleId = templateIdToVirtualId.get(id);
|
|
179
|
+
if (moduleId) {
|
|
180
|
+
moduleIds.add(moduleId);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return moduleIds;
|
|
184
|
+
};
|
|
185
|
+
const reportHmrError = (ctx, error) => {
|
|
186
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
187
|
+
ctx.server.config.logger.error(err.message);
|
|
188
|
+
ctx.server.ws.send({
|
|
189
|
+
type: "error",
|
|
190
|
+
err: {
|
|
191
|
+
message: err.message,
|
|
192
|
+
stack: err.stack ?? ""
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
const ensureTemplates = async (watcher) => {
|
|
197
|
+
if (!needsScan) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (!resolvedConfig) {
|
|
201
|
+
throw new Error("[collie] Vite config was not resolved before scanning templates.");
|
|
202
|
+
}
|
|
203
|
+
templatesById.clear();
|
|
204
|
+
templatesByEncodedId.clear();
|
|
205
|
+
fileToTemplateIds.clear();
|
|
206
|
+
templateIdToVirtualId.clear();
|
|
207
|
+
const root = resolvedConfig.root ?? process.cwd();
|
|
208
|
+
const ignore = buildIgnoreGlobs(resolvedConfig);
|
|
209
|
+
const filePaths = await (0, import_fast_glob.default)(COLLIE_GLOB, {
|
|
210
|
+
cwd: root,
|
|
211
|
+
absolute: true,
|
|
212
|
+
onlyFiles: true,
|
|
213
|
+
ignore
|
|
214
|
+
});
|
|
215
|
+
const diagnostics = [];
|
|
216
|
+
const locationsById = /* @__PURE__ */ new Map();
|
|
217
|
+
for (const filePath of filePaths) {
|
|
218
|
+
if (watcher) {
|
|
219
|
+
watcher.addWatchFile(filePath);
|
|
220
|
+
}
|
|
221
|
+
const source = await import_promises.default.readFile(filePath, "utf-8");
|
|
222
|
+
const document = (0, import_compiler.parseCollie)(source, { filename: filePath });
|
|
223
|
+
diagnostics.push(...document.diagnostics);
|
|
224
|
+
for (const template of document.templates) {
|
|
225
|
+
const location = {
|
|
226
|
+
file: filePath,
|
|
227
|
+
line: template.span?.start.line,
|
|
228
|
+
col: template.span?.start.col
|
|
229
|
+
};
|
|
230
|
+
const encodedId = encodeTemplateId(template.id);
|
|
231
|
+
const record = {
|
|
232
|
+
id: template.id,
|
|
233
|
+
encodedId,
|
|
234
|
+
filePath,
|
|
235
|
+
template,
|
|
236
|
+
location
|
|
237
|
+
};
|
|
238
|
+
trackTemplateRecord(record);
|
|
239
|
+
const locations = locationsById.get(template.id) ?? [];
|
|
240
|
+
locations.push(location);
|
|
241
|
+
locationsById.set(template.id, locations);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const errors = diagnostics.filter((diag) => diag.severity === "error");
|
|
245
|
+
if (errors.length) {
|
|
246
|
+
const formatted = errors.map((diag) => formatDiagnostic(root, diag, root)).join("\n");
|
|
247
|
+
throw new Error(`[collie]
|
|
248
|
+
${formatted}`);
|
|
249
|
+
}
|
|
250
|
+
const duplicates = new Map(
|
|
251
|
+
Array.from(locationsById.entries()).filter(([, locations]) => locations.length > 1)
|
|
252
|
+
);
|
|
253
|
+
if (duplicates.size) {
|
|
254
|
+
throw new Error(formatDuplicateIdError(duplicates, root));
|
|
255
|
+
}
|
|
256
|
+
needsScan = false;
|
|
257
|
+
};
|
|
258
|
+
const updateFileTemplates = async (ctx) => {
|
|
259
|
+
if (needsScan) {
|
|
260
|
+
try {
|
|
261
|
+
await ensureTemplates();
|
|
262
|
+
} catch (error) {
|
|
263
|
+
reportHmrError(ctx, error);
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const filePath = ctx.file;
|
|
268
|
+
const root = resolvedConfig?.root ?? process.cwd();
|
|
269
|
+
const previousIds = fileToTemplateIds.get(filePath) ?? /* @__PURE__ */ new Set();
|
|
270
|
+
const previousModuleIds = collectModuleIds(previousIds);
|
|
271
|
+
let source = null;
|
|
272
|
+
try {
|
|
273
|
+
source = await import_promises.default.readFile(filePath, "utf-8");
|
|
274
|
+
} catch (error) {
|
|
275
|
+
if (error?.code === "ENOENT") {
|
|
276
|
+
removeFileTemplates(filePath);
|
|
277
|
+
return invalidateModules(ctx, previousModuleIds);
|
|
278
|
+
}
|
|
279
|
+
reportHmrError(ctx, error);
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
const document = (0, import_compiler.parseCollie)(source, { filename: filePath });
|
|
283
|
+
const errors = document.diagnostics.filter((diag) => diag.severity === "error");
|
|
284
|
+
if (errors.length) {
|
|
285
|
+
const formatted = errors.map((diag) => formatDiagnostic(filePath, diag, root)).join("\n");
|
|
286
|
+
reportHmrError(ctx, new Error(`[collie]
|
|
287
|
+
${formatted}`));
|
|
288
|
+
return [];
|
|
289
|
+
}
|
|
290
|
+
const duplicates = /* @__PURE__ */ new Map();
|
|
291
|
+
for (const template of document.templates) {
|
|
292
|
+
const existing = templatesById.get(template.id);
|
|
293
|
+
if (existing && existing.filePath !== filePath) {
|
|
294
|
+
const locations = duplicates.get(template.id) ?? [existing.location];
|
|
295
|
+
locations.push({
|
|
296
|
+
file: filePath,
|
|
297
|
+
line: template.span?.start.line,
|
|
298
|
+
col: template.span?.start.col
|
|
299
|
+
});
|
|
300
|
+
duplicates.set(template.id, locations);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (duplicates.size) {
|
|
304
|
+
reportHmrError(ctx, new Error(formatDuplicateIdError(duplicates, root)));
|
|
305
|
+
return [];
|
|
306
|
+
}
|
|
307
|
+
removeFileTemplates(filePath);
|
|
308
|
+
for (const template of document.templates) {
|
|
309
|
+
const record = {
|
|
310
|
+
id: template.id,
|
|
311
|
+
encodedId: encodeTemplateId(template.id),
|
|
312
|
+
filePath,
|
|
313
|
+
template,
|
|
314
|
+
location: {
|
|
315
|
+
file: filePath,
|
|
316
|
+
line: template.span?.start.line,
|
|
317
|
+
col: template.span?.start.col
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
trackTemplateRecord(record);
|
|
321
|
+
}
|
|
322
|
+
const nextIds = fileToTemplateIds.get(filePath) ?? /* @__PURE__ */ new Set();
|
|
323
|
+
const nextModuleIds = collectModuleIds(nextIds);
|
|
324
|
+
const moduleIds = /* @__PURE__ */ new Set([...previousModuleIds, ...nextModuleIds]);
|
|
325
|
+
return invalidateModules(ctx, moduleIds);
|
|
326
|
+
};
|
|
327
|
+
const invalidateModules = (ctx, moduleIds) => {
|
|
328
|
+
const modules = [];
|
|
329
|
+
const registryModule = ctx.server.moduleGraph.getModuleById(VIRTUAL_REGISTRY_RESOLVED);
|
|
330
|
+
if (registryModule) {
|
|
331
|
+
ctx.server.moduleGraph.invalidateModule(registryModule);
|
|
332
|
+
modules.push(registryModule);
|
|
333
|
+
}
|
|
334
|
+
for (const moduleId of moduleIds) {
|
|
335
|
+
const mod = ctx.server.moduleGraph.getModuleById(moduleId);
|
|
336
|
+
if (mod) {
|
|
337
|
+
ctx.server.moduleGraph.invalidateModule(mod);
|
|
338
|
+
modules.push(mod);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return modules;
|
|
342
|
+
};
|
|
60
343
|
return {
|
|
61
344
|
name: "collie",
|
|
62
345
|
enforce: "pre",
|
|
63
|
-
configResolved() {
|
|
346
|
+
configResolved(config) {
|
|
64
347
|
resolvedRuntime = options.jsxRuntime ?? "automatic";
|
|
348
|
+
resolvedConfig = config;
|
|
349
|
+
resetTemplates();
|
|
350
|
+
},
|
|
351
|
+
resolveId(id, importer) {
|
|
352
|
+
const cleanId = stripQuery(id);
|
|
353
|
+
if (cleanId === VIRTUAL_REGISTRY_ID) {
|
|
354
|
+
return VIRTUAL_REGISTRY_RESOLVED;
|
|
355
|
+
}
|
|
356
|
+
if (cleanId === VIRTUAL_IDS_ID) {
|
|
357
|
+
return VIRTUAL_IDS_RESOLVED;
|
|
358
|
+
}
|
|
359
|
+
if (cleanId === VIRTUAL_REGISTRY_RESOLVED) {
|
|
360
|
+
return cleanId;
|
|
361
|
+
}
|
|
362
|
+
if (cleanId === VIRTUAL_IDS_RESOLVED) {
|
|
363
|
+
return cleanId;
|
|
364
|
+
}
|
|
365
|
+
if (cleanId.startsWith(VIRTUAL_TEMPLATE_PREFIX)) {
|
|
366
|
+
return VIRTUAL_TEMPLATE_RESOLVED_PREFIX + cleanId.slice(VIRTUAL_TEMPLATE_PREFIX.length);
|
|
367
|
+
}
|
|
368
|
+
if (cleanId.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX)) {
|
|
369
|
+
return cleanId;
|
|
370
|
+
}
|
|
371
|
+
if (!isVirtualCollieId(cleanId) && cleanId.endsWith(".collie")) {
|
|
372
|
+
this.error(buildDirectImportError(cleanId, importer, resolvedConfig?.root));
|
|
373
|
+
}
|
|
374
|
+
return null;
|
|
65
375
|
},
|
|
66
376
|
async load(id) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
377
|
+
const cleanId = stripQuery(id);
|
|
378
|
+
if (cleanId === VIRTUAL_REGISTRY_RESOLVED) {
|
|
379
|
+
try {
|
|
380
|
+
await ensureTemplates(this);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
383
|
+
this.error(err);
|
|
384
|
+
}
|
|
385
|
+
const entries = Array.from(templatesById.values()).sort(
|
|
386
|
+
(a, b) => a.id.localeCompare(b.id)
|
|
387
|
+
);
|
|
388
|
+
const lines = entries.map(
|
|
389
|
+
(record) => ` ${JSON.stringify(record.id)}: () => import(${JSON.stringify(
|
|
390
|
+
`${VIRTUAL_TEMPLATE_PREFIX}${record.encodedId}`
|
|
391
|
+
)}),`
|
|
392
|
+
);
|
|
393
|
+
return {
|
|
394
|
+
code: [
|
|
395
|
+
"/** @type {Record<string, () => Promise<{ render: (props: any) => any }>>} */",
|
|
396
|
+
`export const registry = {
|
|
397
|
+
${lines.join("\n")}
|
|
398
|
+
};`
|
|
399
|
+
].join("\n"),
|
|
400
|
+
map: null
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
if (cleanId === VIRTUAL_IDS_RESOLVED) {
|
|
404
|
+
try {
|
|
405
|
+
await ensureTemplates(this);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
408
|
+
this.error(err);
|
|
409
|
+
}
|
|
410
|
+
const ids = Array.from(templatesById.keys()).sort((a, b) => a.localeCompare(b));
|
|
411
|
+
return {
|
|
412
|
+
code: [
|
|
413
|
+
"/** @type {readonly string[]} */",
|
|
414
|
+
`export const ids = ${JSON.stringify(ids)};`
|
|
415
|
+
].join("\n"),
|
|
416
|
+
map: null
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
if (cleanId.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX)) {
|
|
420
|
+
const encoded = cleanId.slice(VIRTUAL_TEMPLATE_RESOLVED_PREFIX.length);
|
|
421
|
+
try {
|
|
422
|
+
await ensureTemplates(this);
|
|
423
|
+
} catch (error) {
|
|
424
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
425
|
+
this.error(err);
|
|
426
|
+
}
|
|
427
|
+
const record = templatesByEncodedId.get(encoded);
|
|
428
|
+
if (!record) {
|
|
429
|
+
let decoded = encoded;
|
|
430
|
+
try {
|
|
431
|
+
decoded = decodeTemplateId(encoded);
|
|
432
|
+
} catch {
|
|
433
|
+
}
|
|
434
|
+
this.error(new Error(`[collie] Unknown template id "${decoded}".`));
|
|
435
|
+
}
|
|
436
|
+
const result = (0, import_compiler.compileTemplate)(record.template, {
|
|
437
|
+
filename: record.filePath,
|
|
438
|
+
jsxRuntime: resolvedRuntime,
|
|
439
|
+
flavor: "tsx"
|
|
440
|
+
});
|
|
441
|
+
const errors = result.diagnostics.filter((diag) => diag.severity === "error");
|
|
442
|
+
if (errors.length) {
|
|
443
|
+
const formatted = errors.map((diag) => formatDiagnostic(record.filePath, diag, resolvedConfig?.root)).join("\n");
|
|
444
|
+
this.error(new Error(`[collie]
|
|
79
445
|
${formatted}`));
|
|
446
|
+
}
|
|
447
|
+
const transformed = await (0, import_vite.transformWithEsbuild)(result.code, record.filePath, {
|
|
448
|
+
loader: "tsx",
|
|
449
|
+
jsx: resolvedRuntime === "classic" ? "transform" : "automatic",
|
|
450
|
+
jsxImportSource: "react"
|
|
451
|
+
});
|
|
452
|
+
return {
|
|
453
|
+
code: transformed.code,
|
|
454
|
+
map: transformed.map ?? null
|
|
455
|
+
};
|
|
80
456
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
return
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
457
|
+
if (isCollieFile(cleanId)) {
|
|
458
|
+
const info = this.getModuleInfo(cleanId);
|
|
459
|
+
const importer = info?.importers?.[0];
|
|
460
|
+
this.error(buildDirectImportError(cleanId, importer, resolvedConfig?.root));
|
|
461
|
+
}
|
|
462
|
+
return null;
|
|
463
|
+
},
|
|
464
|
+
handleHotUpdate(ctx) {
|
|
465
|
+
if (!isCollieFile(ctx.file)) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
return updateFileTemplates(ctx);
|
|
90
469
|
}
|
|
91
470
|
};
|
|
92
471
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport type { Plugin } from \"vite\";\nimport { transformWithEsbuild } from \"vite\";\nimport type { Diagnostic } from \"@collie-lang/compiler\";\nimport { compileToTsx } from \"@collie-lang/compiler\";\n\ntype JsxRuntime = \"automatic\" | \"classic\";\n\nexport interface ColliePluginOptions {\n jsxRuntime?: JsxRuntime;\n}\n\nfunction stripQuery(id: string): string {\n const q = id.indexOf(\"?\");\n return q === -1 ? id : id.slice(0, q);\n}\n\nfunction isCollieFile(id: string): boolean {\n return stripQuery(id).endsWith(\".collie\");\n}\n\nfunction toComponentNameHint(id: string): string {\n const base = path.basename(stripQuery(id)).replace(/\\.[^.]+$/, \"\");\n return `${base.replace(/[^a-zA-Z0-9_$]/g, \"\")}Template`;\n}\n\nfunction formatDiagnostic(id: string, diagnostic: Diagnostic): string {\n const file = diagnostic.file ?? stripQuery(id);\n const where = diagnostic.span ? `${diagnostic.span.start.line}:${diagnostic.span.start.col}` : \"\";\n const location = where ? `${file}:${where}` : file;\n const code = diagnostic.code ? diagnostic.code : \"COLLIE\";\n return `${location} [${code}] ${diagnostic.message}`;\n}\n\nexport default function colliePlugin(options: ColliePluginOptions = {}): Plugin {\n let resolvedRuntime: JsxRuntime = options.jsxRuntime ?? \"automatic\";\n\n return {\n name: \"collie\",\n enforce: \"pre\",\n\n configResolved() {\n resolvedRuntime = options.jsxRuntime ?? \"automatic\";\n },\n\n async load(id) {\n if (!isCollieFile(id)) return null;\n\n const filePath = stripQuery(id);\n const source = await fs.readFile(filePath, \"utf-8\");\n\n const result = compileToTsx(source, {\n filename: filePath,\n componentNameHint: toComponentNameHint(filePath),\n jsxRuntime: resolvedRuntime\n });\n\n const errors = result.diagnostics.filter((d) => d.severity === \"error\");\n if (errors.length) {\n const formatted = errors.map((diag) => formatDiagnostic(filePath, diag)).join(\"\\n\");\n this.error(new Error(`[collie]\\n${formatted}`));\n }\n\n // Compiler output contains JSX. Transform it to plain JS so Rollup can parse.\n const transformed = await transformWithEsbuild(result.code, filePath, {\n loader: \"tsx\",\n jsx: \"automatic\",\n jsxImportSource: \"react\"\n });\n\n return {\n code: transformed.code,\n map: transformed.map ?? null\n };\n }\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAiB;AACjB,sBAAe;AAEf,kBAAqC;AAErC,sBAA6B;AAQ7B,SAAS,WAAW,IAAoB;AACtC,QAAM,IAAI,GAAG,QAAQ,GAAG;AACxB,SAAO,MAAM,KAAK,KAAK,GAAG,MAAM,GAAG,CAAC;AACtC;AAEA,SAAS,aAAa,IAAqB;AACzC,SAAO,WAAW,EAAE,EAAE,SAAS,SAAS;AAC1C;AAEA,SAAS,oBAAoB,IAAoB;AAC/C,QAAM,OAAO,iBAAAA,QAAK,SAAS,WAAW,EAAE,CAAC,EAAE,QAAQ,YAAY,EAAE;AACjE,SAAO,GAAG,KAAK,QAAQ,mBAAmB,EAAE,CAAC;AAC/C;AAEA,SAAS,iBAAiB,IAAY,YAAgC;AACpE,QAAM,OAAO,WAAW,QAAQ,WAAW,EAAE;AAC7C,QAAM,QAAQ,WAAW,OAAO,GAAG,WAAW,KAAK,MAAM,IAAI,IAAI,WAAW,KAAK,MAAM,GAAG,KAAK;AAC/F,QAAM,WAAW,QAAQ,GAAG,IAAI,IAAI,KAAK,KAAK;AAC9C,QAAM,OAAO,WAAW,OAAO,WAAW,OAAO;AACjD,SAAO,GAAG,QAAQ,KAAK,IAAI,KAAK,WAAW,OAAO;AACpD;AAEe,SAAR,aAA8B,UAA+B,CAAC,GAAW;AAC9E,MAAI,kBAA8B,QAAQ,cAAc;AAExD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,iBAAiB;AACf,wBAAkB,QAAQ,cAAc;AAAA,IAC1C;AAAA,IAEA,MAAM,KAAK,IAAI;AACb,UAAI,CAAC,aAAa,EAAE,EAAG,QAAO;AAE9B,YAAM,WAAW,WAAW,EAAE;AAC9B,YAAM,SAAS,MAAM,gBAAAC,QAAG,SAAS,UAAU,OAAO;AAElD,YAAM,aAAS,8BAAa,QAAQ;AAAA,QAClC,UAAU;AAAA,QACV,mBAAmB,oBAAoB,QAAQ;AAAA,QAC/C,YAAY;AAAA,MACd,CAAC;AAED,YAAM,SAAS,OAAO,YAAY,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO;AACtE,UAAI,OAAO,QAAQ;AACjB,cAAM,YAAY,OAAO,IAAI,CAAC,SAAS,iBAAiB,UAAU,IAAI,CAAC,EAAE,KAAK,IAAI;AAClF,aAAK,MAAM,IAAI,MAAM;AAAA,EAAa,SAAS,EAAE,CAAC;AAAA,MAChD;AAGA,YAAM,cAAc,UAAM,kCAAqB,OAAO,MAAM,UAAU;AAAA,QACpE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,iBAAiB;AAAA,MACnB,CAAC;AAED,aAAO;AAAA,QACL,MAAM,YAAY;AAAA,QAClB,KAAK,YAAY,OAAO;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF;","names":["path","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport fg from \"fast-glob\";\nimport type { HmrContext, ModuleNode, Plugin, ResolvedConfig } from \"vite\";\nimport { normalizePath, transformWithEsbuild } from \"vite\";\nimport type { Diagnostic, TemplateUnit } from \"@collie-lang/compiler\";\nimport { compileTemplate, parseCollie } from \"@collie-lang/compiler\";\n\ntype JsxRuntime = \"automatic\" | \"classic\";\n\nexport interface ColliePluginOptions {\n jsxRuntime?: JsxRuntime;\n}\n\ninterface TemplateLocation {\n file: string;\n line?: number;\n col?: number;\n}\n\ninterface TemplateRecord {\n id: string;\n encodedId: string;\n filePath: string;\n template: TemplateUnit;\n location: TemplateLocation;\n}\n\nconst VIRTUAL_REGISTRY_ID = \"virtual:collie/registry\";\nconst VIRTUAL_REGISTRY_RESOLVED = \"\\0collie:registry\";\nconst VIRTUAL_IDS_ID = \"virtual:collie/ids\";\nconst VIRTUAL_IDS_RESOLVED = \"\\0collie:ids\";\nconst VIRTUAL_TEMPLATE_PREFIX = \"virtual:collie/template/\";\nconst VIRTUAL_TEMPLATE_RESOLVED_PREFIX = \"\\0collie:template:\";\nconst COLLIE_GLOB = \"**/*.collie\";\nconst DEFAULT_IGNORE_GLOBS = [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\", \"**/build/**\", \"**/.vite/**\"];\n\nfunction stripQuery(id: string): string {\n const q = id.indexOf(\"?\");\n return q === -1 ? id : id.slice(0, q);\n}\n\nfunction isCollieFile(id: string): boolean {\n return stripQuery(id).endsWith(\".collie\");\n}\n\nfunction toDisplayPath(filePath: string, root?: string): string {\n const normalized = normalizePath(filePath);\n if (!root || !path.isAbsolute(filePath)) {\n return normalized;\n }\n const relative = path.relative(root, filePath);\n if (!relative || relative.startsWith(\"..\")) {\n return normalized;\n }\n return normalizePath(relative);\n}\n\nfunction formatDiagnostic(id: string, diagnostic: Diagnostic, root?: string): string {\n const file = diagnostic.filePath ?? diagnostic.file ?? stripQuery(id);\n const displayFile = toDisplayPath(file, root);\n const range = diagnostic.range ?? diagnostic.span;\n const where = range ? `${range.start.line}:${range.start.col}` : \"\";\n const location = where ? `${displayFile}:${where}` : displayFile;\n const code = diagnostic.code ? diagnostic.code : \"COLLIE\";\n return `${location} [${code}] ${diagnostic.message}`;\n}\n\nfunction isVirtualCollieId(id: string): boolean {\n return (\n id === VIRTUAL_REGISTRY_ID ||\n id === VIRTUAL_REGISTRY_RESOLVED ||\n id === VIRTUAL_IDS_ID ||\n id === VIRTUAL_IDS_RESOLVED ||\n id.startsWith(VIRTUAL_TEMPLATE_PREFIX) ||\n id.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX)\n );\n}\n\nfunction buildDirectImportError(importedId: string, importer?: string, root?: string): Error {\n const importLine = stripQuery(importedId);\n const importerLabel = importer ? toDisplayPath(importer, root) : \"<unknown>\";\n const lines = [\n \"Direct .collie imports are not supported.\",\n `Importer: ${importerLabel}`,\n `Import: ${importLine}`,\n \"Use the registry runtime instead:\",\n \"import { Collie } from '@collie-lang/react'\",\n '<Collie id=\"Your.TemplateId\" />',\n \"Templates are discovered automatically by @collie-lang/vite.\"\n ];\n return new Error(lines.join(\"\\n\"));\n}\n\nfunction encodeTemplateId(id: string): string {\n return Buffer.from(id, \"utf8\")\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/g, \"\");\n}\n\nfunction decodeTemplateId(encoded: string): string {\n const normalized = encoded.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padLength = normalized.length % 4;\n const padded = padLength === 0 ? normalized : normalized + \"=\".repeat(4 - padLength);\n return Buffer.from(padded, \"base64\").toString(\"utf8\");\n}\n\nfunction formatLocation(location: TemplateLocation, root?: string): string {\n const file = toDisplayPath(location.file, root);\n if (typeof location.line === \"number\" && typeof location.col === \"number\") {\n return `${file}:${location.line}:${location.col}`;\n }\n return file;\n}\n\nfunction formatDuplicateIdError(duplicates: Map<string, TemplateLocation[]>, root?: string): string {\n const lines = [\"[collie] Duplicate template ids detected:\"];\n const entries = Array.from(duplicates.entries()).sort((a, b) => a[0].localeCompare(b[0]));\n for (const [id, locations] of entries) {\n const formatted = locations.map((location) => formatLocation(location, root)).join(\", \");\n lines.push(`- ${id}: ${formatted}`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction buildIgnoreGlobs(config?: ResolvedConfig): string[] {\n const ignore = new Set(DEFAULT_IGNORE_GLOBS);\n if (!config) {\n return Array.from(ignore);\n }\n\n const addRelativeDir = (dir?: string): void => {\n if (!dir) {\n return;\n }\n const absolute = path.isAbsolute(dir) ? dir : path.join(config.root, dir);\n const relative = normalizePath(path.relative(config.root, absolute));\n if (!relative || relative.startsWith(\"..\")) {\n return;\n }\n ignore.add(`${relative}/**`);\n };\n\n addRelativeDir(config.build?.outDir);\n addRelativeDir(config.cacheDir);\n addRelativeDir(config.publicDir);\n\n return Array.from(ignore);\n}\n\nexport default function colliePlugin(options: ColliePluginOptions = {}): Plugin {\n let resolvedRuntime: JsxRuntime = options.jsxRuntime ?? \"automatic\";\n let resolvedConfig: ResolvedConfig | undefined;\n let needsScan = true;\n const templatesById = new Map<string, TemplateRecord>();\n const templatesByEncodedId = new Map<string, TemplateRecord>();\n const fileToTemplateIds = new Map<string, Set<string>>();\n const templateIdToVirtualId = new Map<string, string>();\n\n const resetTemplates = (): void => {\n needsScan = true;\n templatesById.clear();\n templatesByEncodedId.clear();\n fileToTemplateIds.clear();\n templateIdToVirtualId.clear();\n };\n\n const trackTemplateRecord = (record: TemplateRecord): void => {\n templatesById.set(record.id, record);\n templatesByEncodedId.set(record.encodedId, record);\n templateIdToVirtualId.set(record.id, `${VIRTUAL_TEMPLATE_RESOLVED_PREFIX}${record.encodedId}`);\n const ids = fileToTemplateIds.get(record.filePath) ?? new Set<string>();\n ids.add(record.id);\n fileToTemplateIds.set(record.filePath, ids);\n };\n\n const removeFileTemplates = (filePath: string): Set<string> => {\n const ids = fileToTemplateIds.get(filePath) ?? new Set<string>();\n for (const id of ids) {\n const record = templatesById.get(id);\n if (record && record.filePath === filePath) {\n templatesById.delete(id);\n templatesByEncodedId.delete(record.encodedId);\n templateIdToVirtualId.delete(id);\n }\n }\n fileToTemplateIds.delete(filePath);\n return ids;\n };\n\n const collectModuleIds = (ids: Iterable<string>): Set<string> => {\n const moduleIds = new Set<string>();\n for (const id of ids) {\n const moduleId = templateIdToVirtualId.get(id);\n if (moduleId) {\n moduleIds.add(moduleId);\n }\n }\n return moduleIds;\n };\n\n const reportHmrError = (ctx: HmrContext, error: unknown): void => {\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.server.config.logger.error(err.message);\n ctx.server.ws.send({\n type: \"error\",\n err: {\n message: err.message,\n stack: err.stack ?? \"\"\n }\n });\n };\n\n const ensureTemplates = async (watcher?: { addWatchFile: (id: string) => void }): Promise<void> => {\n if (!needsScan) {\n return;\n }\n\n if (!resolvedConfig) {\n throw new Error(\"[collie] Vite config was not resolved before scanning templates.\");\n }\n\n templatesById.clear();\n templatesByEncodedId.clear();\n fileToTemplateIds.clear();\n templateIdToVirtualId.clear();\n\n const root = resolvedConfig.root ?? process.cwd();\n const ignore = buildIgnoreGlobs(resolvedConfig);\n const filePaths = await fg(COLLIE_GLOB, {\n cwd: root,\n absolute: true,\n onlyFiles: true,\n ignore\n });\n\n const diagnostics: Diagnostic[] = [];\n const locationsById = new Map<string, TemplateLocation[]>();\n\n for (const filePath of filePaths) {\n if (watcher) {\n watcher.addWatchFile(filePath);\n }\n const source = await fs.readFile(filePath, \"utf-8\");\n const document = parseCollie(source, { filename: filePath });\n diagnostics.push(...document.diagnostics);\n\n for (const template of document.templates) {\n const location: TemplateLocation = {\n file: filePath,\n line: template.span?.start.line,\n col: template.span?.start.col\n };\n const encodedId = encodeTemplateId(template.id);\n const record: TemplateRecord = {\n id: template.id,\n encodedId,\n filePath,\n template,\n location\n };\n trackTemplateRecord(record);\n const locations = locationsById.get(template.id) ?? [];\n locations.push(location);\n locationsById.set(template.id, locations);\n }\n }\n\n const errors = diagnostics.filter((diag) => diag.severity === \"error\");\n if (errors.length) {\n const formatted = errors\n .map((diag) => formatDiagnostic(root, diag, root))\n .join(\"\\n\");\n throw new Error(`[collie]\\n${formatted}`);\n }\n\n const duplicates = new Map(\n Array.from(locationsById.entries()).filter(([, locations]) => locations.length > 1)\n );\n if (duplicates.size) {\n throw new Error(formatDuplicateIdError(duplicates, root));\n }\n\n needsScan = false;\n };\n\n const updateFileTemplates = async (ctx: HmrContext): Promise<ModuleNode[]> => {\n if (needsScan) {\n try {\n await ensureTemplates();\n } catch (error) {\n reportHmrError(ctx, error);\n return [];\n }\n }\n\n const filePath = ctx.file;\n const root = resolvedConfig?.root ?? process.cwd();\n const previousIds = fileToTemplateIds.get(filePath) ?? new Set<string>();\n const previousModuleIds = collectModuleIds(previousIds);\n\n let source: string | null = null;\n try {\n source = await fs.readFile(filePath, \"utf-8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException)?.code === \"ENOENT\") {\n removeFileTemplates(filePath);\n return invalidateModules(ctx, previousModuleIds);\n }\n reportHmrError(ctx, error);\n return [];\n }\n\n const document = parseCollie(source, { filename: filePath });\n const errors = document.diagnostics.filter((diag) => diag.severity === \"error\");\n if (errors.length) {\n const formatted = errors.map((diag) => formatDiagnostic(filePath, diag, root)).join(\"\\n\");\n reportHmrError(ctx, new Error(`[collie]\\n${formatted}`));\n return [];\n }\n\n const duplicates = new Map<string, TemplateLocation[]>();\n for (const template of document.templates) {\n const existing = templatesById.get(template.id);\n if (existing && existing.filePath !== filePath) {\n const locations = duplicates.get(template.id) ?? [existing.location];\n locations.push({\n file: filePath,\n line: template.span?.start.line,\n col: template.span?.start.col\n });\n duplicates.set(template.id, locations);\n }\n }\n if (duplicates.size) {\n reportHmrError(ctx, new Error(formatDuplicateIdError(duplicates, root)));\n return [];\n }\n\n removeFileTemplates(filePath);\n for (const template of document.templates) {\n const record: TemplateRecord = {\n id: template.id,\n encodedId: encodeTemplateId(template.id),\n filePath,\n template,\n location: {\n file: filePath,\n line: template.span?.start.line,\n col: template.span?.start.col\n }\n };\n trackTemplateRecord(record);\n }\n\n const nextIds = fileToTemplateIds.get(filePath) ?? new Set<string>();\n const nextModuleIds = collectModuleIds(nextIds);\n const moduleIds = new Set<string>([...previousModuleIds, ...nextModuleIds]);\n return invalidateModules(ctx, moduleIds);\n };\n\n const invalidateModules = (ctx: HmrContext, moduleIds: Iterable<string>): ModuleNode[] => {\n const modules: ModuleNode[] = [];\n const registryModule = ctx.server.moduleGraph.getModuleById(VIRTUAL_REGISTRY_RESOLVED);\n if (registryModule) {\n ctx.server.moduleGraph.invalidateModule(registryModule);\n modules.push(registryModule);\n }\n for (const moduleId of moduleIds) {\n const mod = ctx.server.moduleGraph.getModuleById(moduleId);\n if (mod) {\n ctx.server.moduleGraph.invalidateModule(mod);\n modules.push(mod);\n }\n }\n return modules;\n };\n\n return {\n name: \"collie\",\n enforce: \"pre\",\n\n configResolved(config) {\n resolvedRuntime = options.jsxRuntime ?? \"automatic\";\n resolvedConfig = config;\n resetTemplates();\n },\n\n resolveId(id, importer) {\n const cleanId = stripQuery(id);\n if (cleanId === VIRTUAL_REGISTRY_ID) {\n return VIRTUAL_REGISTRY_RESOLVED;\n }\n if (cleanId === VIRTUAL_IDS_ID) {\n return VIRTUAL_IDS_RESOLVED;\n }\n if (cleanId === VIRTUAL_REGISTRY_RESOLVED) {\n return cleanId;\n }\n if (cleanId === VIRTUAL_IDS_RESOLVED) {\n return cleanId;\n }\n if (cleanId.startsWith(VIRTUAL_TEMPLATE_PREFIX)) {\n return VIRTUAL_TEMPLATE_RESOLVED_PREFIX + cleanId.slice(VIRTUAL_TEMPLATE_PREFIX.length);\n }\n if (cleanId.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX)) {\n return cleanId;\n }\n if (!isVirtualCollieId(cleanId) && cleanId.endsWith(\".collie\")) {\n this.error(buildDirectImportError(cleanId, importer, resolvedConfig?.root));\n }\n return null;\n },\n\n async load(id) {\n const cleanId = stripQuery(id);\n if (cleanId === VIRTUAL_REGISTRY_RESOLVED) {\n try {\n await ensureTemplates(this);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error(err);\n }\n\n const entries = Array.from(templatesById.values()).sort((a, b) =>\n a.id.localeCompare(b.id)\n );\n const lines = entries.map(\n (record) =>\n ` ${JSON.stringify(record.id)}: () => import(${JSON.stringify(\n `${VIRTUAL_TEMPLATE_PREFIX}${record.encodedId}`\n )}),`\n );\n return {\n code: [\n \"/** @type {Record<string, () => Promise<{ render: (props: any) => any }>>} */\",\n `export const registry = {\\n${lines.join(\"\\n\")}\\n};`\n ].join(\"\\n\"),\n map: null\n };\n }\n\n if (cleanId === VIRTUAL_IDS_RESOLVED) {\n try {\n await ensureTemplates(this);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error(err);\n }\n\n const ids = Array.from(templatesById.keys()).sort((a, b) => a.localeCompare(b));\n return {\n code: [\n \"/** @type {readonly string[]} */\",\n `export const ids = ${JSON.stringify(ids)};`\n ].join(\"\\n\"),\n map: null\n };\n }\n\n if (cleanId.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX)) {\n const encoded = cleanId.slice(VIRTUAL_TEMPLATE_RESOLVED_PREFIX.length);\n try {\n await ensureTemplates(this);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error(err);\n }\n\n const record = templatesByEncodedId.get(encoded);\n if (!record) {\n let decoded = encoded;\n try {\n decoded = decodeTemplateId(encoded);\n } catch {\n // Keep encoded value for the error message.\n }\n this.error(new Error(`[collie] Unknown template id \"${decoded}\".`));\n }\n\n const result = compileTemplate(record.template, {\n filename: record.filePath,\n jsxRuntime: resolvedRuntime,\n flavor: \"tsx\"\n });\n\n const errors = result.diagnostics.filter((diag) => diag.severity === \"error\");\n if (errors.length) {\n const formatted = errors\n .map((diag) => formatDiagnostic(record.filePath, diag, resolvedConfig?.root))\n .join(\"\\n\");\n this.error(new Error(`[collie]\\n${formatted}`));\n }\n\n const transformed = await transformWithEsbuild(result.code, record.filePath, {\n loader: \"tsx\",\n jsx: resolvedRuntime === \"classic\" ? \"transform\" : \"automatic\",\n jsxImportSource: \"react\"\n });\n\n return {\n code: transformed.code,\n map: transformed.map ?? null\n };\n }\n if (isCollieFile(cleanId)) {\n const info = this.getModuleInfo(cleanId);\n const importer = info?.importers?.[0];\n this.error(buildDirectImportError(cleanId, importer, resolvedConfig?.root));\n }\n\n return null;\n },\n\n handleHotUpdate(ctx: HmrContext) {\n if (!isCollieFile(ctx.file)) {\n return;\n }\n\n return updateFileTemplates(ctx);\n }\n };\n}\n"],"mappings":"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","names":["path","fg","fs"]}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import path from "path";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
4
|
+
import fg from "fast-glob";
|
|
5
|
+
import { normalizePath, transformWithEsbuild } from "vite";
|
|
6
|
+
import { compileTemplate, parseCollie } from "@collie-lang/compiler";
|
|
7
|
+
var VIRTUAL_REGISTRY_ID = "virtual:collie/registry";
|
|
8
|
+
var VIRTUAL_REGISTRY_RESOLVED = "\0collie:registry";
|
|
9
|
+
var VIRTUAL_IDS_ID = "virtual:collie/ids";
|
|
10
|
+
var VIRTUAL_IDS_RESOLVED = "\0collie:ids";
|
|
11
|
+
var VIRTUAL_TEMPLATE_PREFIX = "virtual:collie/template/";
|
|
12
|
+
var VIRTUAL_TEMPLATE_RESOLVED_PREFIX = "\0collie:template:";
|
|
13
|
+
var COLLIE_GLOB = "**/*.collie";
|
|
14
|
+
var DEFAULT_IGNORE_GLOBS = ["**/node_modules/**", "**/.git/**", "**/dist/**", "**/build/**", "**/.vite/**"];
|
|
6
15
|
function stripQuery(id) {
|
|
7
16
|
const q = id.indexOf("?");
|
|
8
17
|
return q === -1 ? id : id.slice(0, q);
|
|
@@ -10,49 +19,419 @@ function stripQuery(id) {
|
|
|
10
19
|
function isCollieFile(id) {
|
|
11
20
|
return stripQuery(id).endsWith(".collie");
|
|
12
21
|
}
|
|
13
|
-
function
|
|
14
|
-
const
|
|
15
|
-
|
|
22
|
+
function toDisplayPath(filePath, root) {
|
|
23
|
+
const normalized = normalizePath(filePath);
|
|
24
|
+
if (!root || !path.isAbsolute(filePath)) {
|
|
25
|
+
return normalized;
|
|
26
|
+
}
|
|
27
|
+
const relative = path.relative(root, filePath);
|
|
28
|
+
if (!relative || relative.startsWith("..")) {
|
|
29
|
+
return normalized;
|
|
30
|
+
}
|
|
31
|
+
return normalizePath(relative);
|
|
16
32
|
}
|
|
17
|
-
function formatDiagnostic(id, diagnostic) {
|
|
18
|
-
const file = diagnostic.file ?? stripQuery(id);
|
|
19
|
-
const
|
|
20
|
-
const
|
|
33
|
+
function formatDiagnostic(id, diagnostic, root) {
|
|
34
|
+
const file = diagnostic.filePath ?? diagnostic.file ?? stripQuery(id);
|
|
35
|
+
const displayFile = toDisplayPath(file, root);
|
|
36
|
+
const range = diagnostic.range ?? diagnostic.span;
|
|
37
|
+
const where = range ? `${range.start.line}:${range.start.col}` : "";
|
|
38
|
+
const location = where ? `${displayFile}:${where}` : displayFile;
|
|
21
39
|
const code = diagnostic.code ? diagnostic.code : "COLLIE";
|
|
22
40
|
return `${location} [${code}] ${diagnostic.message}`;
|
|
23
41
|
}
|
|
42
|
+
function isVirtualCollieId(id) {
|
|
43
|
+
return id === VIRTUAL_REGISTRY_ID || id === VIRTUAL_REGISTRY_RESOLVED || id === VIRTUAL_IDS_ID || id === VIRTUAL_IDS_RESOLVED || id.startsWith(VIRTUAL_TEMPLATE_PREFIX) || id.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX);
|
|
44
|
+
}
|
|
45
|
+
function buildDirectImportError(importedId, importer, root) {
|
|
46
|
+
const importLine = stripQuery(importedId);
|
|
47
|
+
const importerLabel = importer ? toDisplayPath(importer, root) : "<unknown>";
|
|
48
|
+
const lines = [
|
|
49
|
+
"Direct .collie imports are not supported.",
|
|
50
|
+
`Importer: ${importerLabel}`,
|
|
51
|
+
`Import: ${importLine}`,
|
|
52
|
+
"Use the registry runtime instead:",
|
|
53
|
+
"import { Collie } from '@collie-lang/react'",
|
|
54
|
+
'<Collie id="Your.TemplateId" />',
|
|
55
|
+
"Templates are discovered automatically by @collie-lang/vite."
|
|
56
|
+
];
|
|
57
|
+
return new Error(lines.join("\n"));
|
|
58
|
+
}
|
|
59
|
+
function encodeTemplateId(id) {
|
|
60
|
+
return Buffer.from(id, "utf8").toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
61
|
+
}
|
|
62
|
+
function decodeTemplateId(encoded) {
|
|
63
|
+
const normalized = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
64
|
+
const padLength = normalized.length % 4;
|
|
65
|
+
const padded = padLength === 0 ? normalized : normalized + "=".repeat(4 - padLength);
|
|
66
|
+
return Buffer.from(padded, "base64").toString("utf8");
|
|
67
|
+
}
|
|
68
|
+
function formatLocation(location, root) {
|
|
69
|
+
const file = toDisplayPath(location.file, root);
|
|
70
|
+
if (typeof location.line === "number" && typeof location.col === "number") {
|
|
71
|
+
return `${file}:${location.line}:${location.col}`;
|
|
72
|
+
}
|
|
73
|
+
return file;
|
|
74
|
+
}
|
|
75
|
+
function formatDuplicateIdError(duplicates, root) {
|
|
76
|
+
const lines = ["[collie] Duplicate template ids detected:"];
|
|
77
|
+
const entries = Array.from(duplicates.entries()).sort((a, b) => a[0].localeCompare(b[0]));
|
|
78
|
+
for (const [id, locations] of entries) {
|
|
79
|
+
const formatted = locations.map((location) => formatLocation(location, root)).join(", ");
|
|
80
|
+
lines.push(`- ${id}: ${formatted}`);
|
|
81
|
+
}
|
|
82
|
+
return lines.join("\n");
|
|
83
|
+
}
|
|
84
|
+
function buildIgnoreGlobs(config) {
|
|
85
|
+
const ignore = new Set(DEFAULT_IGNORE_GLOBS);
|
|
86
|
+
if (!config) {
|
|
87
|
+
return Array.from(ignore);
|
|
88
|
+
}
|
|
89
|
+
const addRelativeDir = (dir) => {
|
|
90
|
+
if (!dir) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const absolute = path.isAbsolute(dir) ? dir : path.join(config.root, dir);
|
|
94
|
+
const relative = normalizePath(path.relative(config.root, absolute));
|
|
95
|
+
if (!relative || relative.startsWith("..")) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
ignore.add(`${relative}/**`);
|
|
99
|
+
};
|
|
100
|
+
addRelativeDir(config.build?.outDir);
|
|
101
|
+
addRelativeDir(config.cacheDir);
|
|
102
|
+
addRelativeDir(config.publicDir);
|
|
103
|
+
return Array.from(ignore);
|
|
104
|
+
}
|
|
24
105
|
function colliePlugin(options = {}) {
|
|
25
106
|
let resolvedRuntime = options.jsxRuntime ?? "automatic";
|
|
107
|
+
let resolvedConfig;
|
|
108
|
+
let needsScan = true;
|
|
109
|
+
const templatesById = /* @__PURE__ */ new Map();
|
|
110
|
+
const templatesByEncodedId = /* @__PURE__ */ new Map();
|
|
111
|
+
const fileToTemplateIds = /* @__PURE__ */ new Map();
|
|
112
|
+
const templateIdToVirtualId = /* @__PURE__ */ new Map();
|
|
113
|
+
const resetTemplates = () => {
|
|
114
|
+
needsScan = true;
|
|
115
|
+
templatesById.clear();
|
|
116
|
+
templatesByEncodedId.clear();
|
|
117
|
+
fileToTemplateIds.clear();
|
|
118
|
+
templateIdToVirtualId.clear();
|
|
119
|
+
};
|
|
120
|
+
const trackTemplateRecord = (record) => {
|
|
121
|
+
templatesById.set(record.id, record);
|
|
122
|
+
templatesByEncodedId.set(record.encodedId, record);
|
|
123
|
+
templateIdToVirtualId.set(record.id, `${VIRTUAL_TEMPLATE_RESOLVED_PREFIX}${record.encodedId}`);
|
|
124
|
+
const ids = fileToTemplateIds.get(record.filePath) ?? /* @__PURE__ */ new Set();
|
|
125
|
+
ids.add(record.id);
|
|
126
|
+
fileToTemplateIds.set(record.filePath, ids);
|
|
127
|
+
};
|
|
128
|
+
const removeFileTemplates = (filePath) => {
|
|
129
|
+
const ids = fileToTemplateIds.get(filePath) ?? /* @__PURE__ */ new Set();
|
|
130
|
+
for (const id of ids) {
|
|
131
|
+
const record = templatesById.get(id);
|
|
132
|
+
if (record && record.filePath === filePath) {
|
|
133
|
+
templatesById.delete(id);
|
|
134
|
+
templatesByEncodedId.delete(record.encodedId);
|
|
135
|
+
templateIdToVirtualId.delete(id);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
fileToTemplateIds.delete(filePath);
|
|
139
|
+
return ids;
|
|
140
|
+
};
|
|
141
|
+
const collectModuleIds = (ids) => {
|
|
142
|
+
const moduleIds = /* @__PURE__ */ new Set();
|
|
143
|
+
for (const id of ids) {
|
|
144
|
+
const moduleId = templateIdToVirtualId.get(id);
|
|
145
|
+
if (moduleId) {
|
|
146
|
+
moduleIds.add(moduleId);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return moduleIds;
|
|
150
|
+
};
|
|
151
|
+
const reportHmrError = (ctx, error) => {
|
|
152
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
153
|
+
ctx.server.config.logger.error(err.message);
|
|
154
|
+
ctx.server.ws.send({
|
|
155
|
+
type: "error",
|
|
156
|
+
err: {
|
|
157
|
+
message: err.message,
|
|
158
|
+
stack: err.stack ?? ""
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
const ensureTemplates = async (watcher) => {
|
|
163
|
+
if (!needsScan) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (!resolvedConfig) {
|
|
167
|
+
throw new Error("[collie] Vite config was not resolved before scanning templates.");
|
|
168
|
+
}
|
|
169
|
+
templatesById.clear();
|
|
170
|
+
templatesByEncodedId.clear();
|
|
171
|
+
fileToTemplateIds.clear();
|
|
172
|
+
templateIdToVirtualId.clear();
|
|
173
|
+
const root = resolvedConfig.root ?? process.cwd();
|
|
174
|
+
const ignore = buildIgnoreGlobs(resolvedConfig);
|
|
175
|
+
const filePaths = await fg(COLLIE_GLOB, {
|
|
176
|
+
cwd: root,
|
|
177
|
+
absolute: true,
|
|
178
|
+
onlyFiles: true,
|
|
179
|
+
ignore
|
|
180
|
+
});
|
|
181
|
+
const diagnostics = [];
|
|
182
|
+
const locationsById = /* @__PURE__ */ new Map();
|
|
183
|
+
for (const filePath of filePaths) {
|
|
184
|
+
if (watcher) {
|
|
185
|
+
watcher.addWatchFile(filePath);
|
|
186
|
+
}
|
|
187
|
+
const source = await fs.readFile(filePath, "utf-8");
|
|
188
|
+
const document = parseCollie(source, { filename: filePath });
|
|
189
|
+
diagnostics.push(...document.diagnostics);
|
|
190
|
+
for (const template of document.templates) {
|
|
191
|
+
const location = {
|
|
192
|
+
file: filePath,
|
|
193
|
+
line: template.span?.start.line,
|
|
194
|
+
col: template.span?.start.col
|
|
195
|
+
};
|
|
196
|
+
const encodedId = encodeTemplateId(template.id);
|
|
197
|
+
const record = {
|
|
198
|
+
id: template.id,
|
|
199
|
+
encodedId,
|
|
200
|
+
filePath,
|
|
201
|
+
template,
|
|
202
|
+
location
|
|
203
|
+
};
|
|
204
|
+
trackTemplateRecord(record);
|
|
205
|
+
const locations = locationsById.get(template.id) ?? [];
|
|
206
|
+
locations.push(location);
|
|
207
|
+
locationsById.set(template.id, locations);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const errors = diagnostics.filter((diag) => diag.severity === "error");
|
|
211
|
+
if (errors.length) {
|
|
212
|
+
const formatted = errors.map((diag) => formatDiagnostic(root, diag, root)).join("\n");
|
|
213
|
+
throw new Error(`[collie]
|
|
214
|
+
${formatted}`);
|
|
215
|
+
}
|
|
216
|
+
const duplicates = new Map(
|
|
217
|
+
Array.from(locationsById.entries()).filter(([, locations]) => locations.length > 1)
|
|
218
|
+
);
|
|
219
|
+
if (duplicates.size) {
|
|
220
|
+
throw new Error(formatDuplicateIdError(duplicates, root));
|
|
221
|
+
}
|
|
222
|
+
needsScan = false;
|
|
223
|
+
};
|
|
224
|
+
const updateFileTemplates = async (ctx) => {
|
|
225
|
+
if (needsScan) {
|
|
226
|
+
try {
|
|
227
|
+
await ensureTemplates();
|
|
228
|
+
} catch (error) {
|
|
229
|
+
reportHmrError(ctx, error);
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const filePath = ctx.file;
|
|
234
|
+
const root = resolvedConfig?.root ?? process.cwd();
|
|
235
|
+
const previousIds = fileToTemplateIds.get(filePath) ?? /* @__PURE__ */ new Set();
|
|
236
|
+
const previousModuleIds = collectModuleIds(previousIds);
|
|
237
|
+
let source = null;
|
|
238
|
+
try {
|
|
239
|
+
source = await fs.readFile(filePath, "utf-8");
|
|
240
|
+
} catch (error) {
|
|
241
|
+
if (error?.code === "ENOENT") {
|
|
242
|
+
removeFileTemplates(filePath);
|
|
243
|
+
return invalidateModules(ctx, previousModuleIds);
|
|
244
|
+
}
|
|
245
|
+
reportHmrError(ctx, error);
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
const document = parseCollie(source, { filename: filePath });
|
|
249
|
+
const errors = document.diagnostics.filter((diag) => diag.severity === "error");
|
|
250
|
+
if (errors.length) {
|
|
251
|
+
const formatted = errors.map((diag) => formatDiagnostic(filePath, diag, root)).join("\n");
|
|
252
|
+
reportHmrError(ctx, new Error(`[collie]
|
|
253
|
+
${formatted}`));
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
const duplicates = /* @__PURE__ */ new Map();
|
|
257
|
+
for (const template of document.templates) {
|
|
258
|
+
const existing = templatesById.get(template.id);
|
|
259
|
+
if (existing && existing.filePath !== filePath) {
|
|
260
|
+
const locations = duplicates.get(template.id) ?? [existing.location];
|
|
261
|
+
locations.push({
|
|
262
|
+
file: filePath,
|
|
263
|
+
line: template.span?.start.line,
|
|
264
|
+
col: template.span?.start.col
|
|
265
|
+
});
|
|
266
|
+
duplicates.set(template.id, locations);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (duplicates.size) {
|
|
270
|
+
reportHmrError(ctx, new Error(formatDuplicateIdError(duplicates, root)));
|
|
271
|
+
return [];
|
|
272
|
+
}
|
|
273
|
+
removeFileTemplates(filePath);
|
|
274
|
+
for (const template of document.templates) {
|
|
275
|
+
const record = {
|
|
276
|
+
id: template.id,
|
|
277
|
+
encodedId: encodeTemplateId(template.id),
|
|
278
|
+
filePath,
|
|
279
|
+
template,
|
|
280
|
+
location: {
|
|
281
|
+
file: filePath,
|
|
282
|
+
line: template.span?.start.line,
|
|
283
|
+
col: template.span?.start.col
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
trackTemplateRecord(record);
|
|
287
|
+
}
|
|
288
|
+
const nextIds = fileToTemplateIds.get(filePath) ?? /* @__PURE__ */ new Set();
|
|
289
|
+
const nextModuleIds = collectModuleIds(nextIds);
|
|
290
|
+
const moduleIds = /* @__PURE__ */ new Set([...previousModuleIds, ...nextModuleIds]);
|
|
291
|
+
return invalidateModules(ctx, moduleIds);
|
|
292
|
+
};
|
|
293
|
+
const invalidateModules = (ctx, moduleIds) => {
|
|
294
|
+
const modules = [];
|
|
295
|
+
const registryModule = ctx.server.moduleGraph.getModuleById(VIRTUAL_REGISTRY_RESOLVED);
|
|
296
|
+
if (registryModule) {
|
|
297
|
+
ctx.server.moduleGraph.invalidateModule(registryModule);
|
|
298
|
+
modules.push(registryModule);
|
|
299
|
+
}
|
|
300
|
+
for (const moduleId of moduleIds) {
|
|
301
|
+
const mod = ctx.server.moduleGraph.getModuleById(moduleId);
|
|
302
|
+
if (mod) {
|
|
303
|
+
ctx.server.moduleGraph.invalidateModule(mod);
|
|
304
|
+
modules.push(mod);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return modules;
|
|
308
|
+
};
|
|
26
309
|
return {
|
|
27
310
|
name: "collie",
|
|
28
311
|
enforce: "pre",
|
|
29
|
-
configResolved() {
|
|
312
|
+
configResolved(config) {
|
|
30
313
|
resolvedRuntime = options.jsxRuntime ?? "automatic";
|
|
314
|
+
resolvedConfig = config;
|
|
315
|
+
resetTemplates();
|
|
316
|
+
},
|
|
317
|
+
resolveId(id, importer) {
|
|
318
|
+
const cleanId = stripQuery(id);
|
|
319
|
+
if (cleanId === VIRTUAL_REGISTRY_ID) {
|
|
320
|
+
return VIRTUAL_REGISTRY_RESOLVED;
|
|
321
|
+
}
|
|
322
|
+
if (cleanId === VIRTUAL_IDS_ID) {
|
|
323
|
+
return VIRTUAL_IDS_RESOLVED;
|
|
324
|
+
}
|
|
325
|
+
if (cleanId === VIRTUAL_REGISTRY_RESOLVED) {
|
|
326
|
+
return cleanId;
|
|
327
|
+
}
|
|
328
|
+
if (cleanId === VIRTUAL_IDS_RESOLVED) {
|
|
329
|
+
return cleanId;
|
|
330
|
+
}
|
|
331
|
+
if (cleanId.startsWith(VIRTUAL_TEMPLATE_PREFIX)) {
|
|
332
|
+
return VIRTUAL_TEMPLATE_RESOLVED_PREFIX + cleanId.slice(VIRTUAL_TEMPLATE_PREFIX.length);
|
|
333
|
+
}
|
|
334
|
+
if (cleanId.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX)) {
|
|
335
|
+
return cleanId;
|
|
336
|
+
}
|
|
337
|
+
if (!isVirtualCollieId(cleanId) && cleanId.endsWith(".collie")) {
|
|
338
|
+
this.error(buildDirectImportError(cleanId, importer, resolvedConfig?.root));
|
|
339
|
+
}
|
|
340
|
+
return null;
|
|
31
341
|
},
|
|
32
342
|
async load(id) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
343
|
+
const cleanId = stripQuery(id);
|
|
344
|
+
if (cleanId === VIRTUAL_REGISTRY_RESOLVED) {
|
|
345
|
+
try {
|
|
346
|
+
await ensureTemplates(this);
|
|
347
|
+
} catch (error) {
|
|
348
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
349
|
+
this.error(err);
|
|
350
|
+
}
|
|
351
|
+
const entries = Array.from(templatesById.values()).sort(
|
|
352
|
+
(a, b) => a.id.localeCompare(b.id)
|
|
353
|
+
);
|
|
354
|
+
const lines = entries.map(
|
|
355
|
+
(record) => ` ${JSON.stringify(record.id)}: () => import(${JSON.stringify(
|
|
356
|
+
`${VIRTUAL_TEMPLATE_PREFIX}${record.encodedId}`
|
|
357
|
+
)}),`
|
|
358
|
+
);
|
|
359
|
+
return {
|
|
360
|
+
code: [
|
|
361
|
+
"/** @type {Record<string, () => Promise<{ render: (props: any) => any }>>} */",
|
|
362
|
+
`export const registry = {
|
|
363
|
+
${lines.join("\n")}
|
|
364
|
+
};`
|
|
365
|
+
].join("\n"),
|
|
366
|
+
map: null
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
if (cleanId === VIRTUAL_IDS_RESOLVED) {
|
|
370
|
+
try {
|
|
371
|
+
await ensureTemplates(this);
|
|
372
|
+
} catch (error) {
|
|
373
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
374
|
+
this.error(err);
|
|
375
|
+
}
|
|
376
|
+
const ids = Array.from(templatesById.keys()).sort((a, b) => a.localeCompare(b));
|
|
377
|
+
return {
|
|
378
|
+
code: [
|
|
379
|
+
"/** @type {readonly string[]} */",
|
|
380
|
+
`export const ids = ${JSON.stringify(ids)};`
|
|
381
|
+
].join("\n"),
|
|
382
|
+
map: null
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
if (cleanId.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX)) {
|
|
386
|
+
const encoded = cleanId.slice(VIRTUAL_TEMPLATE_RESOLVED_PREFIX.length);
|
|
387
|
+
try {
|
|
388
|
+
await ensureTemplates(this);
|
|
389
|
+
} catch (error) {
|
|
390
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
391
|
+
this.error(err);
|
|
392
|
+
}
|
|
393
|
+
const record = templatesByEncodedId.get(encoded);
|
|
394
|
+
if (!record) {
|
|
395
|
+
let decoded = encoded;
|
|
396
|
+
try {
|
|
397
|
+
decoded = decodeTemplateId(encoded);
|
|
398
|
+
} catch {
|
|
399
|
+
}
|
|
400
|
+
this.error(new Error(`[collie] Unknown template id "${decoded}".`));
|
|
401
|
+
}
|
|
402
|
+
const result = compileTemplate(record.template, {
|
|
403
|
+
filename: record.filePath,
|
|
404
|
+
jsxRuntime: resolvedRuntime,
|
|
405
|
+
flavor: "tsx"
|
|
406
|
+
});
|
|
407
|
+
const errors = result.diagnostics.filter((diag) => diag.severity === "error");
|
|
408
|
+
if (errors.length) {
|
|
409
|
+
const formatted = errors.map((diag) => formatDiagnostic(record.filePath, diag, resolvedConfig?.root)).join("\n");
|
|
410
|
+
this.error(new Error(`[collie]
|
|
45
411
|
${formatted}`));
|
|
412
|
+
}
|
|
413
|
+
const transformed = await transformWithEsbuild(result.code, record.filePath, {
|
|
414
|
+
loader: "tsx",
|
|
415
|
+
jsx: resolvedRuntime === "classic" ? "transform" : "automatic",
|
|
416
|
+
jsxImportSource: "react"
|
|
417
|
+
});
|
|
418
|
+
return {
|
|
419
|
+
code: transformed.code,
|
|
420
|
+
map: transformed.map ?? null
|
|
421
|
+
};
|
|
46
422
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
return
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
423
|
+
if (isCollieFile(cleanId)) {
|
|
424
|
+
const info = this.getModuleInfo(cleanId);
|
|
425
|
+
const importer = info?.importers?.[0];
|
|
426
|
+
this.error(buildDirectImportError(cleanId, importer, resolvedConfig?.root));
|
|
427
|
+
}
|
|
428
|
+
return null;
|
|
429
|
+
},
|
|
430
|
+
handleHotUpdate(ctx) {
|
|
431
|
+
if (!isCollieFile(ctx.file)) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
return updateFileTemplates(ctx);
|
|
56
435
|
}
|
|
57
436
|
};
|
|
58
437
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport type { Plugin } from \"vite\";\nimport { transformWithEsbuild } from \"vite\";\nimport type { Diagnostic } from \"@collie-lang/compiler\";\nimport { compileToTsx } from \"@collie-lang/compiler\";\n\ntype JsxRuntime = \"automatic\" | \"classic\";\n\nexport interface ColliePluginOptions {\n jsxRuntime?: JsxRuntime;\n}\n\nfunction stripQuery(id: string): string {\n const q = id.indexOf(\"?\");\n return q === -1 ? id : id.slice(0, q);\n}\n\nfunction isCollieFile(id: string): boolean {\n return stripQuery(id).endsWith(\".collie\");\n}\n\nfunction toComponentNameHint(id: string): string {\n const base = path.basename(stripQuery(id)).replace(/\\.[^.]+$/, \"\");\n return `${base.replace(/[^a-zA-Z0-9_$]/g, \"\")}Template`;\n}\n\nfunction formatDiagnostic(id: string, diagnostic: Diagnostic): string {\n const file = diagnostic.file ?? stripQuery(id);\n const where = diagnostic.span ? `${diagnostic.span.start.line}:${diagnostic.span.start.col}` : \"\";\n const location = where ? `${file}:${where}` : file;\n const code = diagnostic.code ? diagnostic.code : \"COLLIE\";\n return `${location} [${code}] ${diagnostic.message}`;\n}\n\nexport default function colliePlugin(options: ColliePluginOptions = {}): Plugin {\n let resolvedRuntime: JsxRuntime = options.jsxRuntime ?? \"automatic\";\n\n return {\n name: \"collie\",\n enforce: \"pre\",\n\n configResolved() {\n resolvedRuntime = options.jsxRuntime ?? \"automatic\";\n },\n\n async load(id) {\n if (!isCollieFile(id)) return null;\n\n const filePath = stripQuery(id);\n const source = await fs.readFile(filePath, \"utf-8\");\n\n const result = compileToTsx(source, {\n filename: filePath,\n componentNameHint: toComponentNameHint(filePath),\n jsxRuntime: resolvedRuntime\n });\n\n const errors = result.diagnostics.filter((d) => d.severity === \"error\");\n if (errors.length) {\n const formatted = errors.map((diag) => formatDiagnostic(filePath, diag)).join(\"\\n\");\n this.error(new Error(`[collie]\\n${formatted}`));\n }\n\n // Compiler output contains JSX. Transform it to plain JS so Rollup can parse.\n const transformed = await transformWithEsbuild(result.code, filePath, {\n loader: \"tsx\",\n jsx: \"automatic\",\n jsxImportSource: \"react\"\n });\n\n return {\n code: transformed.code,\n map: transformed.map ?? null\n };\n }\n };\n}\n"],"mappings":";AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AAEf,SAAS,4BAA4B;AAErC,SAAS,oBAAoB;AAQ7B,SAAS,WAAW,IAAoB;AACtC,QAAM,IAAI,GAAG,QAAQ,GAAG;AACxB,SAAO,MAAM,KAAK,KAAK,GAAG,MAAM,GAAG,CAAC;AACtC;AAEA,SAAS,aAAa,IAAqB;AACzC,SAAO,WAAW,EAAE,EAAE,SAAS,SAAS;AAC1C;AAEA,SAAS,oBAAoB,IAAoB;AAC/C,QAAM,OAAO,KAAK,SAAS,WAAW,EAAE,CAAC,EAAE,QAAQ,YAAY,EAAE;AACjE,SAAO,GAAG,KAAK,QAAQ,mBAAmB,EAAE,CAAC;AAC/C;AAEA,SAAS,iBAAiB,IAAY,YAAgC;AACpE,QAAM,OAAO,WAAW,QAAQ,WAAW,EAAE;AAC7C,QAAM,QAAQ,WAAW,OAAO,GAAG,WAAW,KAAK,MAAM,IAAI,IAAI,WAAW,KAAK,MAAM,GAAG,KAAK;AAC/F,QAAM,WAAW,QAAQ,GAAG,IAAI,IAAI,KAAK,KAAK;AAC9C,QAAM,OAAO,WAAW,OAAO,WAAW,OAAO;AACjD,SAAO,GAAG,QAAQ,KAAK,IAAI,KAAK,WAAW,OAAO;AACpD;AAEe,SAAR,aAA8B,UAA+B,CAAC,GAAW;AAC9E,MAAI,kBAA8B,QAAQ,cAAc;AAExD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,iBAAiB;AACf,wBAAkB,QAAQ,cAAc;AAAA,IAC1C;AAAA,IAEA,MAAM,KAAK,IAAI;AACb,UAAI,CAAC,aAAa,EAAE,EAAG,QAAO;AAE9B,YAAM,WAAW,WAAW,EAAE;AAC9B,YAAM,SAAS,MAAM,GAAG,SAAS,UAAU,OAAO;AAElD,YAAM,SAAS,aAAa,QAAQ;AAAA,QAClC,UAAU;AAAA,QACV,mBAAmB,oBAAoB,QAAQ;AAAA,QAC/C,YAAY;AAAA,MACd,CAAC;AAED,YAAM,SAAS,OAAO,YAAY,OAAO,CAAC,MAAM,EAAE,aAAa,OAAO;AACtE,UAAI,OAAO,QAAQ;AACjB,cAAM,YAAY,OAAO,IAAI,CAAC,SAAS,iBAAiB,UAAU,IAAI,CAAC,EAAE,KAAK,IAAI;AAClF,aAAK,MAAM,IAAI,MAAM;AAAA,EAAa,SAAS,EAAE,CAAC;AAAA,MAChD;AAGA,YAAM,cAAc,MAAM,qBAAqB,OAAO,MAAM,UAAU;AAAA,QACpE,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,iBAAiB;AAAA,MACnB,CAAC;AAED,aAAO;AAAA,QACL,MAAM,YAAY;AAAA,QAClB,KAAK,YAAY,OAAO;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import path from \"node:path\";\nimport fs from \"node:fs/promises\";\nimport fg from \"fast-glob\";\nimport type { HmrContext, ModuleNode, Plugin, ResolvedConfig } from \"vite\";\nimport { normalizePath, transformWithEsbuild } from \"vite\";\nimport type { Diagnostic, TemplateUnit } from \"@collie-lang/compiler\";\nimport { compileTemplate, parseCollie } from \"@collie-lang/compiler\";\n\ntype JsxRuntime = \"automatic\" | \"classic\";\n\nexport interface ColliePluginOptions {\n jsxRuntime?: JsxRuntime;\n}\n\ninterface TemplateLocation {\n file: string;\n line?: number;\n col?: number;\n}\n\ninterface TemplateRecord {\n id: string;\n encodedId: string;\n filePath: string;\n template: TemplateUnit;\n location: TemplateLocation;\n}\n\nconst VIRTUAL_REGISTRY_ID = \"virtual:collie/registry\";\nconst VIRTUAL_REGISTRY_RESOLVED = \"\\0collie:registry\";\nconst VIRTUAL_IDS_ID = \"virtual:collie/ids\";\nconst VIRTUAL_IDS_RESOLVED = \"\\0collie:ids\";\nconst VIRTUAL_TEMPLATE_PREFIX = \"virtual:collie/template/\";\nconst VIRTUAL_TEMPLATE_RESOLVED_PREFIX = \"\\0collie:template:\";\nconst COLLIE_GLOB = \"**/*.collie\";\nconst DEFAULT_IGNORE_GLOBS = [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\", \"**/build/**\", \"**/.vite/**\"];\n\nfunction stripQuery(id: string): string {\n const q = id.indexOf(\"?\");\n return q === -1 ? id : id.slice(0, q);\n}\n\nfunction isCollieFile(id: string): boolean {\n return stripQuery(id).endsWith(\".collie\");\n}\n\nfunction toDisplayPath(filePath: string, root?: string): string {\n const normalized = normalizePath(filePath);\n if (!root || !path.isAbsolute(filePath)) {\n return normalized;\n }\n const relative = path.relative(root, filePath);\n if (!relative || relative.startsWith(\"..\")) {\n return normalized;\n }\n return normalizePath(relative);\n}\n\nfunction formatDiagnostic(id: string, diagnostic: Diagnostic, root?: string): string {\n const file = diagnostic.filePath ?? diagnostic.file ?? stripQuery(id);\n const displayFile = toDisplayPath(file, root);\n const range = diagnostic.range ?? diagnostic.span;\n const where = range ? `${range.start.line}:${range.start.col}` : \"\";\n const location = where ? `${displayFile}:${where}` : displayFile;\n const code = diagnostic.code ? diagnostic.code : \"COLLIE\";\n return `${location} [${code}] ${diagnostic.message}`;\n}\n\nfunction isVirtualCollieId(id: string): boolean {\n return (\n id === VIRTUAL_REGISTRY_ID ||\n id === VIRTUAL_REGISTRY_RESOLVED ||\n id === VIRTUAL_IDS_ID ||\n id === VIRTUAL_IDS_RESOLVED ||\n id.startsWith(VIRTUAL_TEMPLATE_PREFIX) ||\n id.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX)\n );\n}\n\nfunction buildDirectImportError(importedId: string, importer?: string, root?: string): Error {\n const importLine = stripQuery(importedId);\n const importerLabel = importer ? toDisplayPath(importer, root) : \"<unknown>\";\n const lines = [\n \"Direct .collie imports are not supported.\",\n `Importer: ${importerLabel}`,\n `Import: ${importLine}`,\n \"Use the registry runtime instead:\",\n \"import { Collie } from '@collie-lang/react'\",\n '<Collie id=\"Your.TemplateId\" />',\n \"Templates are discovered automatically by @collie-lang/vite.\"\n ];\n return new Error(lines.join(\"\\n\"));\n}\n\nfunction encodeTemplateId(id: string): string {\n return Buffer.from(id, \"utf8\")\n .toString(\"base64\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/g, \"\");\n}\n\nfunction decodeTemplateId(encoded: string): string {\n const normalized = encoded.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padLength = normalized.length % 4;\n const padded = padLength === 0 ? normalized : normalized + \"=\".repeat(4 - padLength);\n return Buffer.from(padded, \"base64\").toString(\"utf8\");\n}\n\nfunction formatLocation(location: TemplateLocation, root?: string): string {\n const file = toDisplayPath(location.file, root);\n if (typeof location.line === \"number\" && typeof location.col === \"number\") {\n return `${file}:${location.line}:${location.col}`;\n }\n return file;\n}\n\nfunction formatDuplicateIdError(duplicates: Map<string, TemplateLocation[]>, root?: string): string {\n const lines = [\"[collie] Duplicate template ids detected:\"];\n const entries = Array.from(duplicates.entries()).sort((a, b) => a[0].localeCompare(b[0]));\n for (const [id, locations] of entries) {\n const formatted = locations.map((location) => formatLocation(location, root)).join(\", \");\n lines.push(`- ${id}: ${formatted}`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction buildIgnoreGlobs(config?: ResolvedConfig): string[] {\n const ignore = new Set(DEFAULT_IGNORE_GLOBS);\n if (!config) {\n return Array.from(ignore);\n }\n\n const addRelativeDir = (dir?: string): void => {\n if (!dir) {\n return;\n }\n const absolute = path.isAbsolute(dir) ? dir : path.join(config.root, dir);\n const relative = normalizePath(path.relative(config.root, absolute));\n if (!relative || relative.startsWith(\"..\")) {\n return;\n }\n ignore.add(`${relative}/**`);\n };\n\n addRelativeDir(config.build?.outDir);\n addRelativeDir(config.cacheDir);\n addRelativeDir(config.publicDir);\n\n return Array.from(ignore);\n}\n\nexport default function colliePlugin(options: ColliePluginOptions = {}): Plugin {\n let resolvedRuntime: JsxRuntime = options.jsxRuntime ?? \"automatic\";\n let resolvedConfig: ResolvedConfig | undefined;\n let needsScan = true;\n const templatesById = new Map<string, TemplateRecord>();\n const templatesByEncodedId = new Map<string, TemplateRecord>();\n const fileToTemplateIds = new Map<string, Set<string>>();\n const templateIdToVirtualId = new Map<string, string>();\n\n const resetTemplates = (): void => {\n needsScan = true;\n templatesById.clear();\n templatesByEncodedId.clear();\n fileToTemplateIds.clear();\n templateIdToVirtualId.clear();\n };\n\n const trackTemplateRecord = (record: TemplateRecord): void => {\n templatesById.set(record.id, record);\n templatesByEncodedId.set(record.encodedId, record);\n templateIdToVirtualId.set(record.id, `${VIRTUAL_TEMPLATE_RESOLVED_PREFIX}${record.encodedId}`);\n const ids = fileToTemplateIds.get(record.filePath) ?? new Set<string>();\n ids.add(record.id);\n fileToTemplateIds.set(record.filePath, ids);\n };\n\n const removeFileTemplates = (filePath: string): Set<string> => {\n const ids = fileToTemplateIds.get(filePath) ?? new Set<string>();\n for (const id of ids) {\n const record = templatesById.get(id);\n if (record && record.filePath === filePath) {\n templatesById.delete(id);\n templatesByEncodedId.delete(record.encodedId);\n templateIdToVirtualId.delete(id);\n }\n }\n fileToTemplateIds.delete(filePath);\n return ids;\n };\n\n const collectModuleIds = (ids: Iterable<string>): Set<string> => {\n const moduleIds = new Set<string>();\n for (const id of ids) {\n const moduleId = templateIdToVirtualId.get(id);\n if (moduleId) {\n moduleIds.add(moduleId);\n }\n }\n return moduleIds;\n };\n\n const reportHmrError = (ctx: HmrContext, error: unknown): void => {\n const err = error instanceof Error ? error : new Error(String(error));\n ctx.server.config.logger.error(err.message);\n ctx.server.ws.send({\n type: \"error\",\n err: {\n message: err.message,\n stack: err.stack ?? \"\"\n }\n });\n };\n\n const ensureTemplates = async (watcher?: { addWatchFile: (id: string) => void }): Promise<void> => {\n if (!needsScan) {\n return;\n }\n\n if (!resolvedConfig) {\n throw new Error(\"[collie] Vite config was not resolved before scanning templates.\");\n }\n\n templatesById.clear();\n templatesByEncodedId.clear();\n fileToTemplateIds.clear();\n templateIdToVirtualId.clear();\n\n const root = resolvedConfig.root ?? process.cwd();\n const ignore = buildIgnoreGlobs(resolvedConfig);\n const filePaths = await fg(COLLIE_GLOB, {\n cwd: root,\n absolute: true,\n onlyFiles: true,\n ignore\n });\n\n const diagnostics: Diagnostic[] = [];\n const locationsById = new Map<string, TemplateLocation[]>();\n\n for (const filePath of filePaths) {\n if (watcher) {\n watcher.addWatchFile(filePath);\n }\n const source = await fs.readFile(filePath, \"utf-8\");\n const document = parseCollie(source, { filename: filePath });\n diagnostics.push(...document.diagnostics);\n\n for (const template of document.templates) {\n const location: TemplateLocation = {\n file: filePath,\n line: template.span?.start.line,\n col: template.span?.start.col\n };\n const encodedId = encodeTemplateId(template.id);\n const record: TemplateRecord = {\n id: template.id,\n encodedId,\n filePath,\n template,\n location\n };\n trackTemplateRecord(record);\n const locations = locationsById.get(template.id) ?? [];\n locations.push(location);\n locationsById.set(template.id, locations);\n }\n }\n\n const errors = diagnostics.filter((diag) => diag.severity === \"error\");\n if (errors.length) {\n const formatted = errors\n .map((diag) => formatDiagnostic(root, diag, root))\n .join(\"\\n\");\n throw new Error(`[collie]\\n${formatted}`);\n }\n\n const duplicates = new Map(\n Array.from(locationsById.entries()).filter(([, locations]) => locations.length > 1)\n );\n if (duplicates.size) {\n throw new Error(formatDuplicateIdError(duplicates, root));\n }\n\n needsScan = false;\n };\n\n const updateFileTemplates = async (ctx: HmrContext): Promise<ModuleNode[]> => {\n if (needsScan) {\n try {\n await ensureTemplates();\n } catch (error) {\n reportHmrError(ctx, error);\n return [];\n }\n }\n\n const filePath = ctx.file;\n const root = resolvedConfig?.root ?? process.cwd();\n const previousIds = fileToTemplateIds.get(filePath) ?? new Set<string>();\n const previousModuleIds = collectModuleIds(previousIds);\n\n let source: string | null = null;\n try {\n source = await fs.readFile(filePath, \"utf-8\");\n } catch (error) {\n if ((error as NodeJS.ErrnoException)?.code === \"ENOENT\") {\n removeFileTemplates(filePath);\n return invalidateModules(ctx, previousModuleIds);\n }\n reportHmrError(ctx, error);\n return [];\n }\n\n const document = parseCollie(source, { filename: filePath });\n const errors = document.diagnostics.filter((diag) => diag.severity === \"error\");\n if (errors.length) {\n const formatted = errors.map((diag) => formatDiagnostic(filePath, diag, root)).join(\"\\n\");\n reportHmrError(ctx, new Error(`[collie]\\n${formatted}`));\n return [];\n }\n\n const duplicates = new Map<string, TemplateLocation[]>();\n for (const template of document.templates) {\n const existing = templatesById.get(template.id);\n if (existing && existing.filePath !== filePath) {\n const locations = duplicates.get(template.id) ?? [existing.location];\n locations.push({\n file: filePath,\n line: template.span?.start.line,\n col: template.span?.start.col\n });\n duplicates.set(template.id, locations);\n }\n }\n if (duplicates.size) {\n reportHmrError(ctx, new Error(formatDuplicateIdError(duplicates, root)));\n return [];\n }\n\n removeFileTemplates(filePath);\n for (const template of document.templates) {\n const record: TemplateRecord = {\n id: template.id,\n encodedId: encodeTemplateId(template.id),\n filePath,\n template,\n location: {\n file: filePath,\n line: template.span?.start.line,\n col: template.span?.start.col\n }\n };\n trackTemplateRecord(record);\n }\n\n const nextIds = fileToTemplateIds.get(filePath) ?? new Set<string>();\n const nextModuleIds = collectModuleIds(nextIds);\n const moduleIds = new Set<string>([...previousModuleIds, ...nextModuleIds]);\n return invalidateModules(ctx, moduleIds);\n };\n\n const invalidateModules = (ctx: HmrContext, moduleIds: Iterable<string>): ModuleNode[] => {\n const modules: ModuleNode[] = [];\n const registryModule = ctx.server.moduleGraph.getModuleById(VIRTUAL_REGISTRY_RESOLVED);\n if (registryModule) {\n ctx.server.moduleGraph.invalidateModule(registryModule);\n modules.push(registryModule);\n }\n for (const moduleId of moduleIds) {\n const mod = ctx.server.moduleGraph.getModuleById(moduleId);\n if (mod) {\n ctx.server.moduleGraph.invalidateModule(mod);\n modules.push(mod);\n }\n }\n return modules;\n };\n\n return {\n name: \"collie\",\n enforce: \"pre\",\n\n configResolved(config) {\n resolvedRuntime = options.jsxRuntime ?? \"automatic\";\n resolvedConfig = config;\n resetTemplates();\n },\n\n resolveId(id, importer) {\n const cleanId = stripQuery(id);\n if (cleanId === VIRTUAL_REGISTRY_ID) {\n return VIRTUAL_REGISTRY_RESOLVED;\n }\n if (cleanId === VIRTUAL_IDS_ID) {\n return VIRTUAL_IDS_RESOLVED;\n }\n if (cleanId === VIRTUAL_REGISTRY_RESOLVED) {\n return cleanId;\n }\n if (cleanId === VIRTUAL_IDS_RESOLVED) {\n return cleanId;\n }\n if (cleanId.startsWith(VIRTUAL_TEMPLATE_PREFIX)) {\n return VIRTUAL_TEMPLATE_RESOLVED_PREFIX + cleanId.slice(VIRTUAL_TEMPLATE_PREFIX.length);\n }\n if (cleanId.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX)) {\n return cleanId;\n }\n if (!isVirtualCollieId(cleanId) && cleanId.endsWith(\".collie\")) {\n this.error(buildDirectImportError(cleanId, importer, resolvedConfig?.root));\n }\n return null;\n },\n\n async load(id) {\n const cleanId = stripQuery(id);\n if (cleanId === VIRTUAL_REGISTRY_RESOLVED) {\n try {\n await ensureTemplates(this);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error(err);\n }\n\n const entries = Array.from(templatesById.values()).sort((a, b) =>\n a.id.localeCompare(b.id)\n );\n const lines = entries.map(\n (record) =>\n ` ${JSON.stringify(record.id)}: () => import(${JSON.stringify(\n `${VIRTUAL_TEMPLATE_PREFIX}${record.encodedId}`\n )}),`\n );\n return {\n code: [\n \"/** @type {Record<string, () => Promise<{ render: (props: any) => any }>>} */\",\n `export const registry = {\\n${lines.join(\"\\n\")}\\n};`\n ].join(\"\\n\"),\n map: null\n };\n }\n\n if (cleanId === VIRTUAL_IDS_RESOLVED) {\n try {\n await ensureTemplates(this);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error(err);\n }\n\n const ids = Array.from(templatesById.keys()).sort((a, b) => a.localeCompare(b));\n return {\n code: [\n \"/** @type {readonly string[]} */\",\n `export const ids = ${JSON.stringify(ids)};`\n ].join(\"\\n\"),\n map: null\n };\n }\n\n if (cleanId.startsWith(VIRTUAL_TEMPLATE_RESOLVED_PREFIX)) {\n const encoded = cleanId.slice(VIRTUAL_TEMPLATE_RESOLVED_PREFIX.length);\n try {\n await ensureTemplates(this);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n this.error(err);\n }\n\n const record = templatesByEncodedId.get(encoded);\n if (!record) {\n let decoded = encoded;\n try {\n decoded = decodeTemplateId(encoded);\n } catch {\n // Keep encoded value for the error message.\n }\n this.error(new Error(`[collie] Unknown template id \"${decoded}\".`));\n }\n\n const result = compileTemplate(record.template, {\n filename: record.filePath,\n jsxRuntime: resolvedRuntime,\n flavor: \"tsx\"\n });\n\n const errors = result.diagnostics.filter((diag) => diag.severity === \"error\");\n if (errors.length) {\n const formatted = errors\n .map((diag) => formatDiagnostic(record.filePath, diag, resolvedConfig?.root))\n .join(\"\\n\");\n this.error(new Error(`[collie]\\n${formatted}`));\n }\n\n const transformed = await transformWithEsbuild(result.code, record.filePath, {\n loader: \"tsx\",\n jsx: resolvedRuntime === \"classic\" ? \"transform\" : \"automatic\",\n jsxImportSource: \"react\"\n });\n\n return {\n code: transformed.code,\n map: transformed.map ?? null\n };\n }\n if (isCollieFile(cleanId)) {\n const info = this.getModuleInfo(cleanId);\n const importer = info?.importers?.[0];\n this.error(buildDirectImportError(cleanId, importer, resolvedConfig?.root));\n }\n\n return null;\n },\n\n handleHotUpdate(ctx: HmrContext) {\n if (!isCollieFile(ctx.file)) {\n return;\n }\n\n return updateFileTemplates(ctx);\n }\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@collie-lang/vite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Vite plugin for Collie (.collie -> React component).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -21,14 +21,17 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@collie-lang/compiler": "1.
|
|
24
|
+
"@collie-lang/compiler": "^1.1.1",
|
|
25
|
+
"fast-glob": "^3.3.3"
|
|
25
26
|
},
|
|
26
27
|
"peerDependencies": {
|
|
27
28
|
"vite": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
|
-
"
|
|
31
|
-
"
|
|
31
|
+
"rimraf": "^6.0.1",
|
|
32
|
+
"tsup": "^8.3.5",
|
|
33
|
+
"typescript": "^5.7.2",
|
|
34
|
+
"vite": "^7.3.0"
|
|
32
35
|
},
|
|
33
36
|
"scripts": {
|
|
34
37
|
"build": "tsup",
|