solid-tag-runtime 0.0.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/ARCHITECTURE.md +608 -0
- package/README.md +324 -0
- package/index.d.ts +119 -0
- package/package.json +55 -0
- package/src/compiler.js +77 -0
- package/src/errors.js +32 -0
- package/src/index.js +21 -0
- package/src/runtime.js +591 -0
- package/src/url-backend.js +33 -0
package/src/runtime.js
ADDED
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CircularDependencyError,
|
|
3
|
+
ModuleCompileError,
|
|
4
|
+
ModuleResolutionError,
|
|
5
|
+
SolidTagRuntimeError,
|
|
6
|
+
} from "./errors.js";
|
|
7
|
+
import { createDefaultModuleUrlBackend } from "./url-backend.js";
|
|
8
|
+
|
|
9
|
+
const HOST_REGISTRY_KEY = "__solidTagRuntimeHostModules__";
|
|
10
|
+
let runtimeSequence = 0;
|
|
11
|
+
|
|
12
|
+
export function createRuntime(options = {}) {
|
|
13
|
+
const {
|
|
14
|
+
compiler,
|
|
15
|
+
modules = {},
|
|
16
|
+
urls = {},
|
|
17
|
+
allowNativeImports = true,
|
|
18
|
+
resolve: customResolve,
|
|
19
|
+
moduleUrlBackend = createDefaultModuleUrlBackend(),
|
|
20
|
+
} = options;
|
|
21
|
+
|
|
22
|
+
if (!compiler || typeof compiler.analyze !== "function" || typeof compiler.transform !== "function") {
|
|
23
|
+
throw new TypeError("createRuntime() requires a compiler with analyze() and transform() methods.");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const runtimeId = `solid-tag-runtime-${++runtimeSequence}-${randomId()}`;
|
|
27
|
+
const records = new Map();
|
|
28
|
+
let anonymousSequence = 0;
|
|
29
|
+
let disposed = false;
|
|
30
|
+
|
|
31
|
+
const globalRegistry = getHostRegistry();
|
|
32
|
+
const hostNamespaces = new Map();
|
|
33
|
+
globalRegistry.set(runtimeId, hostNamespaces);
|
|
34
|
+
|
|
35
|
+
const api = {
|
|
36
|
+
define,
|
|
37
|
+
defineModule,
|
|
38
|
+
defineUrl,
|
|
39
|
+
update,
|
|
40
|
+
import: importModule,
|
|
41
|
+
compile,
|
|
42
|
+
toModule,
|
|
43
|
+
toComponent,
|
|
44
|
+
has,
|
|
45
|
+
invalidate,
|
|
46
|
+
modules: listModules,
|
|
47
|
+
dependencies,
|
|
48
|
+
dependents,
|
|
49
|
+
getModuleInfo,
|
|
50
|
+
dispose,
|
|
51
|
+
resolve: resolvePublic,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
for (const [id, namespace] of Object.entries(modules)) defineModule(id, namespace);
|
|
55
|
+
for (const [id, url] of Object.entries(urls)) defineUrl(id, url);
|
|
56
|
+
|
|
57
|
+
return api;
|
|
58
|
+
|
|
59
|
+
function assertActive() {
|
|
60
|
+
if (disposed) throw new SolidTagRuntimeError("This solid-tag-runtime instance has been disposed.");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function define(id, source, defineOptions = {}) {
|
|
64
|
+
assertActive();
|
|
65
|
+
const normalized = normalizeDefinedId(id);
|
|
66
|
+
const existing = records.get(normalized);
|
|
67
|
+
|
|
68
|
+
if (existing) invalidate(normalized, { dependents: true });
|
|
69
|
+
|
|
70
|
+
const record = {
|
|
71
|
+
id: normalized,
|
|
72
|
+
kind: "source",
|
|
73
|
+
source: String(source),
|
|
74
|
+
format: defineOptions.format ?? "jsx",
|
|
75
|
+
version: (existing?.version ?? 0) + 1,
|
|
76
|
+
state: "defined",
|
|
77
|
+
dependencies: new Set(),
|
|
78
|
+
dependents: existing?.dependents ?? new Set(),
|
|
79
|
+
compiledCode: undefined,
|
|
80
|
+
diagnostics: [],
|
|
81
|
+
url: undefined,
|
|
82
|
+
importPromise: undefined,
|
|
83
|
+
namespace: undefined,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
records.set(normalized, record);
|
|
87
|
+
return normalized;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function update(id, source, updateOptions = {}) {
|
|
91
|
+
return define(id, source, updateOptions);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function defineModule(id, namespace) {
|
|
95
|
+
assertActive();
|
|
96
|
+
const normalized = normalizeDefinedId(id);
|
|
97
|
+
const existing = records.get(normalized);
|
|
98
|
+
if (existing) invalidate(normalized, { dependents: true });
|
|
99
|
+
|
|
100
|
+
if ((typeof namespace !== "object" || namespace === null) && typeof namespace !== "function") {
|
|
101
|
+
throw new TypeError("defineModule(id, namespace) expects an object, function, or ES module namespace-like value.");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
hostNamespaces.set(normalized, namespace);
|
|
105
|
+
|
|
106
|
+
records.set(normalized, {
|
|
107
|
+
id: normalized,
|
|
108
|
+
kind: "host",
|
|
109
|
+
namespace,
|
|
110
|
+
version: (existing?.version ?? 0) + 1,
|
|
111
|
+
state: "ready",
|
|
112
|
+
dependencies: new Set(),
|
|
113
|
+
dependents: existing?.dependents ?? new Set(),
|
|
114
|
+
url: undefined,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return normalized;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function defineUrl(id, url) {
|
|
121
|
+
assertActive();
|
|
122
|
+
const normalized = normalizeDefinedId(id);
|
|
123
|
+
const existing = records.get(normalized);
|
|
124
|
+
if (existing) invalidate(normalized, { dependents: true });
|
|
125
|
+
|
|
126
|
+
const href = String(url);
|
|
127
|
+
records.set(normalized, {
|
|
128
|
+
id: normalized,
|
|
129
|
+
kind: "url",
|
|
130
|
+
externalUrl: href,
|
|
131
|
+
version: (existing?.version ?? 0) + 1,
|
|
132
|
+
state: "defined",
|
|
133
|
+
dependencies: new Set(),
|
|
134
|
+
dependents: existing?.dependents ?? new Set(),
|
|
135
|
+
importPromise: undefined,
|
|
136
|
+
namespace: undefined,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return normalized;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function importModule(id) {
|
|
143
|
+
assertActive();
|
|
144
|
+
const resolved = resolveSpecifier(String(id), null);
|
|
145
|
+
const record = records.get(resolved);
|
|
146
|
+
|
|
147
|
+
if (!record) {
|
|
148
|
+
if (!allowNativeImports && !isAbsoluteUrl(resolved)) {
|
|
149
|
+
throw new ModuleResolutionError(id, null);
|
|
150
|
+
}
|
|
151
|
+
return import(resolved);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (record.kind === "host") return record.namespace;
|
|
155
|
+
|
|
156
|
+
if (record.kind === "url") {
|
|
157
|
+
if (!record.importPromise) {
|
|
158
|
+
record.importPromise = import(record.externalUrl).then(namespace => {
|
|
159
|
+
record.namespace = namespace;
|
|
160
|
+
record.state = "ready";
|
|
161
|
+
return namespace;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
return record.importPromise;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!record.importPromise) {
|
|
168
|
+
record.importPromise = ensureSourceUrl(record, []).then(url => import(url)).then(namespace => {
|
|
169
|
+
record.namespace = namespace;
|
|
170
|
+
record.state = "ready";
|
|
171
|
+
return namespace;
|
|
172
|
+
}).catch(error => {
|
|
173
|
+
record.importPromise = undefined;
|
|
174
|
+
record.state = "error";
|
|
175
|
+
throw error;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return record.importPromise;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function compile(id) {
|
|
183
|
+
assertActive();
|
|
184
|
+
const resolved = resolveSpecifier(String(id), null);
|
|
185
|
+
const record = records.get(resolved);
|
|
186
|
+
if (!record) throw new ModuleResolutionError(id, null);
|
|
187
|
+
if (record.kind !== "source") {
|
|
188
|
+
return {
|
|
189
|
+
id: record.id,
|
|
190
|
+
kind: record.kind,
|
|
191
|
+
code: undefined,
|
|
192
|
+
url: record.kind === "url" ? record.externalUrl : await ensureHostUrl(record),
|
|
193
|
+
dependencies: [...record.dependencies],
|
|
194
|
+
diagnostics: [],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const url = await ensureSourceUrl(record, []);
|
|
199
|
+
return {
|
|
200
|
+
id: record.id,
|
|
201
|
+
kind: record.kind,
|
|
202
|
+
code: record.compiledCode,
|
|
203
|
+
url,
|
|
204
|
+
dependencies: [...record.dependencies],
|
|
205
|
+
diagnostics: [...(record.diagnostics ?? [])],
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function toModule(source, moduleOptions = {}) {
|
|
210
|
+
assertActive();
|
|
211
|
+
const id = moduleOptions.id ?? `/__solid_tag_runtime__/anonymous-${++anonymousSequence}.jsx`;
|
|
212
|
+
const normalized = define(id, source, { format: moduleOptions.format ?? "jsx" });
|
|
213
|
+
return importModule(normalized);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async function toComponent(source, componentOptions = {}) {
|
|
217
|
+
const namespace = await toModule(source, componentOptions);
|
|
218
|
+
const exportName = componentOptions.exportName ?? "default";
|
|
219
|
+
|
|
220
|
+
if (!(exportName in namespace)) {
|
|
221
|
+
throw new SolidTagRuntimeError(
|
|
222
|
+
`Module does not export ${JSON.stringify(exportName)}. Available exports: ${Object.keys(namespace).join(", ") || "(none)"}.`
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const component = namespace[exportName];
|
|
227
|
+
if (typeof component !== "function") {
|
|
228
|
+
throw new SolidTagRuntimeError(
|
|
229
|
+
`Export ${JSON.stringify(exportName)} is not callable and cannot be used as a Solid component.`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return component;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function has(id) {
|
|
237
|
+
return records.has(normalizeLookupId(id));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function invalidate(id, invalidateOptions = {}) {
|
|
241
|
+
assertActive();
|
|
242
|
+
const normalized = normalizeLookupId(id);
|
|
243
|
+
const includeDependents = invalidateOptions.dependents ?? true;
|
|
244
|
+
const seen = new Set();
|
|
245
|
+
|
|
246
|
+
invalidateOne(normalized);
|
|
247
|
+
return [...seen];
|
|
248
|
+
|
|
249
|
+
function invalidateOne(targetId) {
|
|
250
|
+
if (seen.has(targetId)) return;
|
|
251
|
+
seen.add(targetId);
|
|
252
|
+
const record = records.get(targetId);
|
|
253
|
+
if (!record) return;
|
|
254
|
+
|
|
255
|
+
if (includeDependents) {
|
|
256
|
+
for (const dependent of record.dependents) invalidateOne(dependent);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (record.kind === "source") {
|
|
260
|
+
revokeRecordUrl(record);
|
|
261
|
+
record.compiledCode = undefined;
|
|
262
|
+
record.diagnostics = [];
|
|
263
|
+
record.importPromise = undefined;
|
|
264
|
+
record.namespace = undefined;
|
|
265
|
+
record.state = "defined";
|
|
266
|
+
} else if (record.kind === "host") {
|
|
267
|
+
revokeRecordUrl(record);
|
|
268
|
+
record.state = "ready";
|
|
269
|
+
} else if (record.kind === "url") {
|
|
270
|
+
record.importPromise = undefined;
|
|
271
|
+
record.namespace = undefined;
|
|
272
|
+
record.state = "defined";
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function listModules() {
|
|
278
|
+
return [...records.values()].map(toModuleInfo);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function dependencies(id) {
|
|
282
|
+
const record = records.get(normalizeLookupId(id));
|
|
283
|
+
return record ? [...record.dependencies] : [];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function dependents(id) {
|
|
287
|
+
const record = records.get(normalizeLookupId(id));
|
|
288
|
+
return record ? [...record.dependents] : [];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function getModuleInfo(id) {
|
|
292
|
+
const record = records.get(normalizeLookupId(id));
|
|
293
|
+
return record ? toModuleInfo(record) : undefined;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function dispose() {
|
|
297
|
+
if (disposed) return;
|
|
298
|
+
disposed = true;
|
|
299
|
+
|
|
300
|
+
for (const record of records.values()) revokeRecordUrl(record);
|
|
301
|
+
records.clear();
|
|
302
|
+
hostNamespaces.clear();
|
|
303
|
+
globalRegistry.delete(runtimeId);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function resolvePublic(specifier, importer) {
|
|
307
|
+
return resolveSpecifier(specifier, importer ?? null);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async function ensureSourceUrl(record, stack) {
|
|
311
|
+
if (record.url) return record.url;
|
|
312
|
+
|
|
313
|
+
if (stack.includes(record.id)) {
|
|
314
|
+
const cycleStart = stack.indexOf(record.id);
|
|
315
|
+
throw new CircularDependencyError([...stack.slice(cycleStart), record.id]);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const nextStack = [...stack, record.id];
|
|
319
|
+
record.state = "linking";
|
|
320
|
+
|
|
321
|
+
let analysis;
|
|
322
|
+
try {
|
|
323
|
+
analysis = compiler.analyze(record.source, { id: record.id, format: record.format });
|
|
324
|
+
} catch (error) {
|
|
325
|
+
record.state = "error";
|
|
326
|
+
throw new ModuleCompileError(record.id, error);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const resolvedImports = [];
|
|
330
|
+
const nextDependencies = new Set();
|
|
331
|
+
|
|
332
|
+
for (const reference of analysis.imports ?? []) {
|
|
333
|
+
const resolved = resolveSpecifier(reference.specifier, record.id);
|
|
334
|
+
const dependencyRecord = records.get(resolved);
|
|
335
|
+
let replacement = resolved;
|
|
336
|
+
|
|
337
|
+
if (dependencyRecord) {
|
|
338
|
+
nextDependencies.add(dependencyRecord.id);
|
|
339
|
+
|
|
340
|
+
if (dependencyRecord.kind === "source") {
|
|
341
|
+
replacement = await ensureSourceUrl(dependencyRecord, nextStack);
|
|
342
|
+
} else if (dependencyRecord.kind === "host") {
|
|
343
|
+
replacement = await ensureHostUrl(dependencyRecord);
|
|
344
|
+
} else {
|
|
345
|
+
replacement = dependencyRecord.externalUrl;
|
|
346
|
+
}
|
|
347
|
+
} else if (isRelativeSpecifier(reference.specifier) || reference.specifier.startsWith("/")) {
|
|
348
|
+
throw new ModuleResolutionError(reference.specifier, record.id);
|
|
349
|
+
} else if (!allowNativeImports && !isAbsoluteUrl(resolved)) {
|
|
350
|
+
throw new ModuleResolutionError(reference.specifier, record.id);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
resolvedImports.push({ ...reference, replacement });
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
let linkedSource = applyImportReplacements(record.source, resolvedImports);
|
|
357
|
+
|
|
358
|
+
// JSX produced by solid-tag needs @solidjs/html. Resolve it through the
|
|
359
|
+
// same module system so host applications can share their existing runtime.
|
|
360
|
+
let htmlImportSource;
|
|
361
|
+
const needsHtmlRuntime = record.format !== "js" && analysis.needsHtmlRuntime !== false;
|
|
362
|
+
if (needsHtmlRuntime) {
|
|
363
|
+
const htmlResolved = resolveSpecifier("@solidjs/html", record.id);
|
|
364
|
+
const htmlRecord = records.get(htmlResolved);
|
|
365
|
+
|
|
366
|
+
if (htmlRecord) {
|
|
367
|
+
nextDependencies.add(htmlRecord.id);
|
|
368
|
+
htmlImportSource = htmlRecord.kind === "source"
|
|
369
|
+
? await ensureSourceUrl(htmlRecord, nextStack)
|
|
370
|
+
: htmlRecord.kind === "host"
|
|
371
|
+
? await ensureHostUrl(htmlRecord)
|
|
372
|
+
: htmlRecord.externalUrl;
|
|
373
|
+
} else if (allowNativeImports) {
|
|
374
|
+
htmlImportSource = htmlResolved;
|
|
375
|
+
} else {
|
|
376
|
+
throw new ModuleResolutionError("@solidjs/html", record.id);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
syncDependencyEdges(record, nextDependencies);
|
|
381
|
+
|
|
382
|
+
try {
|
|
383
|
+
if (record.format === "js") {
|
|
384
|
+
record.compiledCode = linkedSource;
|
|
385
|
+
record.diagnostics = [];
|
|
386
|
+
} else {
|
|
387
|
+
const transformed = compiler.transform(linkedSource, {
|
|
388
|
+
id: record.id,
|
|
389
|
+
format: record.format,
|
|
390
|
+
htmlImportSource,
|
|
391
|
+
});
|
|
392
|
+
record.compiledCode = transformed.code;
|
|
393
|
+
record.diagnostics = [...(transformed.diagnostics ?? [])];
|
|
394
|
+
}
|
|
395
|
+
} catch (error) {
|
|
396
|
+
record.state = "error";
|
|
397
|
+
throw new ModuleCompileError(record.id, error);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
record.url = moduleUrlBackend.create(appendSourceUrl(record.compiledCode, record.id));
|
|
401
|
+
record.state = "compiled";
|
|
402
|
+
return record.url;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
async function ensureHostUrl(record) {
|
|
406
|
+
if (record.url) return record.url;
|
|
407
|
+
|
|
408
|
+
const namespace = hostNamespaces.get(record.id);
|
|
409
|
+
const exportNames = Object.keys(namespace ?? {}).filter(name => name !== "default" && isIdentifierName(name));
|
|
410
|
+
const lines = [
|
|
411
|
+
`const __registry = globalThis[${JSON.stringify(HOST_REGISTRY_KEY)}];`,
|
|
412
|
+
`const __runtime = __registry && __registry.get(${JSON.stringify(runtimeId)});`,
|
|
413
|
+
`const __module = __runtime && __runtime.get(${JSON.stringify(record.id)});`,
|
|
414
|
+
`if (!__module) throw new Error(${JSON.stringify(`Host module ${record.id} is unavailable.`)});`,
|
|
415
|
+
];
|
|
416
|
+
|
|
417
|
+
exportNames.forEach((name, index) => {
|
|
418
|
+
lines.push(`const __export${index} = __module[${JSON.stringify(name)}];`);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
if (namespace && Object.prototype.hasOwnProperty.call(namespace, "default")) {
|
|
422
|
+
lines.push("export default __module.default;");
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (exportNames.length) {
|
|
426
|
+
lines.push(
|
|
427
|
+
`export { ${exportNames.map((name, index) => `__export${index} as ${name}`).join(", ")} };`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
record.url = moduleUrlBackend.create(appendSourceUrl(lines.join("\n"), `host:${record.id}`));
|
|
432
|
+
return record.url;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function resolveSpecifier(specifier, importer) {
|
|
436
|
+
const raw = String(specifier);
|
|
437
|
+
|
|
438
|
+
if (typeof customResolve === "function") {
|
|
439
|
+
const custom = customResolve(raw, importer, api);
|
|
440
|
+
if (typeof custom === "string" && custom) return normalizeResolved(custom, importer);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (records.has(raw)) return raw;
|
|
444
|
+
if (isAbsoluteUrl(raw)) return raw;
|
|
445
|
+
|
|
446
|
+
if (raw.startsWith("/")) return normalizePath(raw);
|
|
447
|
+
|
|
448
|
+
if (isRelativeSpecifier(raw)) {
|
|
449
|
+
if (!importer) return normalizePath(`/${raw}`);
|
|
450
|
+
if (isAbsoluteUrl(importer)) return new URL(raw, importer).href;
|
|
451
|
+
return normalizePath(`${dirname(importer)}/${raw}`);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return raw;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function syncDependencyEdges(record, nextDependencies) {
|
|
458
|
+
for (const previous of record.dependencies) {
|
|
459
|
+
if (!nextDependencies.has(previous)) records.get(previous)?.dependents.delete(record.id);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
for (const next of nextDependencies) records.get(next)?.dependents.add(record.id);
|
|
463
|
+
record.dependencies = nextDependencies;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function revokeRecordUrl(record) {
|
|
467
|
+
if (!record?.url) return;
|
|
468
|
+
try {
|
|
469
|
+
moduleUrlBackend.revoke?.(record.url);
|
|
470
|
+
} finally {
|
|
471
|
+
record.url = undefined;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function toModuleInfo(record) {
|
|
476
|
+
return {
|
|
477
|
+
id: record.id,
|
|
478
|
+
kind: record.kind,
|
|
479
|
+
state: record.state,
|
|
480
|
+
version: record.version,
|
|
481
|
+
format: record.format,
|
|
482
|
+
dependencies: [...record.dependencies],
|
|
483
|
+
dependents: [...record.dependents],
|
|
484
|
+
url: record.kind === "url" ? record.externalUrl : record.url,
|
|
485
|
+
diagnostics: [...(record.diagnostics ?? [])],
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function getHostRegistry() {
|
|
491
|
+
let registry = globalThis[HOST_REGISTRY_KEY];
|
|
492
|
+
if (!(registry instanceof Map)) {
|
|
493
|
+
registry = new Map();
|
|
494
|
+
Object.defineProperty(globalThis, HOST_REGISTRY_KEY, {
|
|
495
|
+
value: registry,
|
|
496
|
+
configurable: true,
|
|
497
|
+
writable: true,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
return registry;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function applyImportReplacements(source, references) {
|
|
504
|
+
const replacements = references
|
|
505
|
+
.map(reference => ({
|
|
506
|
+
start: reference.start,
|
|
507
|
+
end: reference.end,
|
|
508
|
+
text: JSON.stringify(reference.replacement),
|
|
509
|
+
}))
|
|
510
|
+
.sort((a, b) => b.start - a.start);
|
|
511
|
+
|
|
512
|
+
let output = source;
|
|
513
|
+
for (const replacement of replacements) {
|
|
514
|
+
output = output.slice(0, replacement.start) + replacement.text + output.slice(replacement.end);
|
|
515
|
+
}
|
|
516
|
+
return output;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function normalizeDefinedId(id) {
|
|
520
|
+
const value = String(id);
|
|
521
|
+
if (isAbsoluteUrl(value) || isBareSpecifier(value)) return value;
|
|
522
|
+
if (value.startsWith("/")) return normalizePath(value);
|
|
523
|
+
return normalizePath(`/${value}`);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function normalizeLookupId(id) {
|
|
527
|
+
const value = String(id);
|
|
528
|
+
if (isAbsoluteUrl(value) || isBareSpecifier(value)) return value;
|
|
529
|
+
if (value.startsWith("/")) return normalizePath(value);
|
|
530
|
+
return normalizePath(`/${value}`);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function normalizeResolved(value, importer) {
|
|
534
|
+
if (isAbsoluteUrl(value) || isBareSpecifier(value)) return value;
|
|
535
|
+
if (value.startsWith("/")) return normalizePath(value);
|
|
536
|
+
if (isRelativeSpecifier(value) && importer) {
|
|
537
|
+
if (isAbsoluteUrl(importer)) return new URL(value, importer).href;
|
|
538
|
+
return normalizePath(`${dirname(importer)}/${value}`);
|
|
539
|
+
}
|
|
540
|
+
return normalizePath(`/${value}`);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function isBareSpecifier(value) {
|
|
544
|
+
return !value.startsWith(".") && !value.startsWith("/") && !isAbsoluteUrl(value);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function isRelativeSpecifier(value) {
|
|
548
|
+
return value === "." || value === ".." || value.startsWith("./") || value.startsWith("../");
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function isAbsoluteUrl(value) {
|
|
552
|
+
return /^[A-Za-z][A-Za-z\d+.-]*:/.test(value);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function dirname(id) {
|
|
556
|
+
const index = id.lastIndexOf("/");
|
|
557
|
+
return index <= 0 ? "/" : id.slice(0, index);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function normalizePath(path) {
|
|
561
|
+
const absolute = path.startsWith("/");
|
|
562
|
+
const parts = [];
|
|
563
|
+
|
|
564
|
+
for (const part of path.split("/")) {
|
|
565
|
+
if (!part || part === ".") continue;
|
|
566
|
+
if (part === "..") {
|
|
567
|
+
parts.pop();
|
|
568
|
+
} else {
|
|
569
|
+
parts.push(part);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
return `${absolute ? "/" : ""}${parts.join("/")}` || "/";
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function isIdentifierName(name) {
|
|
577
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
function appendSourceUrl(code, id) {
|
|
581
|
+
return `${code}\n//# sourceURL=${sanitizeSourceUrl(id)}`;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function sanitizeSourceUrl(id) {
|
|
585
|
+
return `solid-tag-runtime:${String(id).replace(/[\r\n]/g, "")}`;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function randomId() {
|
|
589
|
+
if (globalThis.crypto?.randomUUID) return globalThis.crypto.randomUUID();
|
|
590
|
+
return Math.random().toString(36).slice(2);
|
|
591
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
function isNodeLike() {
|
|
2
|
+
return typeof process !== "undefined" && !!process.versions?.node;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function createDefaultModuleUrlBackend() {
|
|
6
|
+
if (!isNodeLike() && typeof Blob !== "undefined" && typeof URL?.createObjectURL === "function") {
|
|
7
|
+
return createBlobModuleUrlBackend();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return createDataModuleUrlBackend();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function createBlobModuleUrlBackend() {
|
|
14
|
+
return {
|
|
15
|
+
kind: "blob",
|
|
16
|
+
create(code) {
|
|
17
|
+
return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
|
|
18
|
+
},
|
|
19
|
+
revoke(url) {
|
|
20
|
+
URL.revokeObjectURL(url);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function createDataModuleUrlBackend() {
|
|
26
|
+
return {
|
|
27
|
+
kind: "data",
|
|
28
|
+
create(code) {
|
|
29
|
+
return `data:text/javascript;charset=utf-8,${encodeURIComponent(code)}`;
|
|
30
|
+
},
|
|
31
|
+
revoke() {},
|
|
32
|
+
};
|
|
33
|
+
}
|