@remix-run/assets 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +325 -2
  3. package/dist/assets.d.ts +3 -0
  4. package/dist/assets.d.ts.map +1 -0
  5. package/dist/assets.js +1 -0
  6. package/dist/lib/access.d.ts +10 -0
  7. package/dist/lib/access.d.ts.map +1 -0
  8. package/dist/lib/access.js +14 -0
  9. package/dist/lib/asset-server.d.ts +139 -0
  10. package/dist/lib/asset-server.d.ts.map +1 -0
  11. package/dist/lib/asset-server.js +338 -0
  12. package/dist/lib/compilation-error.d.ts +33 -0
  13. package/dist/lib/compilation-error.d.ts.map +1 -0
  14. package/dist/lib/compilation-error.js +32 -0
  15. package/dist/lib/file-matcher.d.ts +6 -0
  16. package/dist/lib/file-matcher.d.ts.map +1 -0
  17. package/dist/lib/file-matcher.js +44 -0
  18. package/dist/lib/fingerprint.d.ts +12 -0
  19. package/dist/lib/fingerprint.d.ts.map +1 -0
  20. package/dist/lib/fingerprint.js +49 -0
  21. package/dist/lib/module-store.d.ts +41 -0
  22. package/dist/lib/module-store.d.ts.map +1 -0
  23. package/dist/lib/module-store.js +230 -0
  24. package/dist/lib/paths.d.ts +8 -0
  25. package/dist/lib/paths.d.ts.map +1 -0
  26. package/dist/lib/paths.js +50 -0
  27. package/dist/lib/routes.d.ts +13 -0
  28. package/dist/lib/routes.d.ts.map +1 -0
  29. package/dist/lib/routes.js +94 -0
  30. package/dist/lib/scripts/cjs-check.d.ts +3 -0
  31. package/dist/lib/scripts/cjs-check.d.ts.map +1 -0
  32. package/dist/lib/scripts/cjs-check.js +398 -0
  33. package/dist/lib/scripts/compiler.d.ts +62 -0
  34. package/dist/lib/scripts/compiler.d.ts.map +1 -0
  35. package/dist/lib/scripts/compiler.js +439 -0
  36. package/dist/lib/scripts/emit.d.ts +25 -0
  37. package/dist/lib/scripts/emit.d.ts.map +1 -0
  38. package/dist/lib/scripts/emit.js +63 -0
  39. package/dist/lib/scripts/resolve.d.ts +50 -0
  40. package/dist/lib/scripts/resolve.d.ts.map +1 -0
  41. package/dist/lib/scripts/resolve.js +236 -0
  42. package/dist/lib/scripts/transform.d.ts +64 -0
  43. package/dist/lib/scripts/transform.d.ts.map +1 -0
  44. package/dist/lib/scripts/transform.js +373 -0
  45. package/dist/lib/source-maps.d.ts +4 -0
  46. package/dist/lib/source-maps.d.ts.map +1 -0
  47. package/dist/lib/source-maps.js +62 -0
  48. package/dist/lib/styles/compiler.d.ts +52 -0
  49. package/dist/lib/styles/compiler.d.ts.map +1 -0
  50. package/dist/lib/styles/compiler.js +272 -0
  51. package/dist/lib/styles/emit.d.ts +25 -0
  52. package/dist/lib/styles/emit.d.ts.map +1 -0
  53. package/dist/lib/styles/emit.js +78 -0
  54. package/dist/lib/styles/resolve.d.ts +48 -0
  55. package/dist/lib/styles/resolve.d.ts.map +1 -0
  56. package/dist/lib/styles/resolve.js +188 -0
  57. package/dist/lib/styles/transform.d.ts +47 -0
  58. package/dist/lib/styles/transform.d.ts.map +1 -0
  59. package/dist/lib/styles/transform.js +131 -0
  60. package/dist/lib/target.d.ts +21 -0
  61. package/dist/lib/target.d.ts.map +1 -0
  62. package/dist/lib/target.js +127 -0
  63. package/dist/lib/watch.d.ts +22 -0
  64. package/dist/lib/watch.d.ts.map +1 -0
  65. package/dist/lib/watch.js +96 -0
  66. package/package.json +55 -12
  67. package/src/assets.ts +2 -0
  68. package/src/lib/access.ts +24 -0
  69. package/src/lib/asset-server.ts +537 -0
  70. package/src/lib/compilation-error.ts +61 -0
  71. package/src/lib/file-matcher.ts +63 -0
  72. package/src/lib/fingerprint.ts +65 -0
  73. package/src/lib/module-store.ts +340 -0
  74. package/src/lib/paths.ts +66 -0
  75. package/src/lib/routes.ts +164 -0
  76. package/src/lib/scripts/cjs-check.ts +476 -0
  77. package/src/lib/scripts/compiler.ts +640 -0
  78. package/src/lib/scripts/emit.ts +122 -0
  79. package/src/lib/scripts/resolve.ts +433 -0
  80. package/src/lib/scripts/transform.ts +609 -0
  81. package/src/lib/source-maps.ts +75 -0
  82. package/src/lib/styles/compiler.ts +400 -0
  83. package/src/lib/styles/emit.ts +137 -0
  84. package/src/lib/styles/resolve.ts +316 -0
  85. package/src/lib/styles/transform.ts +226 -0
  86. package/src/lib/target.ts +196 -0
  87. package/src/lib/watch.ts +136 -0
@@ -0,0 +1,439 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { IfNoneMatch } from '@remix-run/headers';
6
+ import { createAssetServerCompilationError } from "../compilation-error.js";
7
+ import { createFileMatcher } from "../file-matcher.js";
8
+ import { formatFingerprintedPathname, getFingerprintRequestCacheControl, parseFingerprintSuffix, } from "../fingerprint.js";
9
+ import { emitResolvedModule } from "./emit.js";
10
+ import { normalizeFilePath, resolveFilePath } from "../paths.js";
11
+ import { resolveModule, resolverExtensionAlias, resolverExtensions, supportedScriptExtensions, } from "./resolve.js";
12
+ import { createModuleStore } from "../module-store.js";
13
+ import { createTsconfigTransformOptionsResolver, transformModule } from "./transform.js";
14
+ import { ResolverFactory } from 'oxc-resolver';
15
+ const supportedScriptExtensionSet = new Set(supportedScriptExtensions);
16
+ const preloadConcurrency = Math.max(1, Math.min(8, os.availableParallelism() - 1));
17
+ export function createScriptCompiler(options) {
18
+ let resolvedOptions = {
19
+ ...options,
20
+ externalSet: new Set(options.external),
21
+ watchIgnoreMatchers: (options.watchIgnore ?? []).map((pattern) => createFileMatcher(pattern, options.rootDir)),
22
+ };
23
+ let scriptStore = createModuleStore({
24
+ onWatchDirectoriesChange: options.onWatchDirectoriesChange,
25
+ });
26
+ let tsconfigTransformOptionsResolver = createTsconfigTransformOptionsResolver();
27
+ let resolverFactory = new ResolverFactory({
28
+ aliasFields: [['browser']],
29
+ conditionNames: ['browser', 'import', 'module', 'default'],
30
+ extensionAlias: resolverExtensionAlias,
31
+ extensions: resolverExtensions,
32
+ mainFields: ['browser', 'module', 'main'],
33
+ tsconfig: 'auto',
34
+ });
35
+ let resolveInFlightByCacheKey = new Map();
36
+ let emitInFlightByCacheKey = new Map();
37
+ let transformArgs = {
38
+ buildId: resolvedOptions.buildId ?? null,
39
+ define: resolvedOptions.define ?? null,
40
+ externalSet: resolvedOptions.externalSet,
41
+ isWatchIgnored,
42
+ minify: resolvedOptions.minify,
43
+ resolveActualPath,
44
+ routes: resolvedOptions.routes,
45
+ sourceMapSourcePaths: resolvedOptions.sourceMapSourcePaths,
46
+ sourceMaps: resolvedOptions.sourceMaps ?? null,
47
+ target: resolvedOptions.target ?? null,
48
+ tsconfigTransformOptionsResolver,
49
+ };
50
+ let resolveArgs = {
51
+ isAllowed: resolvedOptions.isAllowed,
52
+ isWatchIgnored,
53
+ resolveModulePath,
54
+ resolverFactory,
55
+ routes: resolvedOptions.routes,
56
+ };
57
+ return {
58
+ async getScript(filePath, getOptions) {
59
+ let resolvedModule = resolveServedScriptOrThrow(resolveInputFilePath(filePath));
60
+ let record = scriptStore.get(resolvedModule.identityPath);
61
+ let notModified = getNotModifiedScript(record, getOptions);
62
+ if (notModified)
63
+ return notModified;
64
+ let emitted = await getOrCreateEmittedScript(record);
65
+ return {
66
+ script: toScriptCompileResult(emitted),
67
+ type: 'script',
68
+ };
69
+ },
70
+ async getPreloadLayers(filePath) {
71
+ let resolvedEntries = [];
72
+ let seen = new Set();
73
+ for (let resolvedModule of (Array.isArray(filePath) ? filePath : [filePath]).map((nextPath) => resolveServedScriptOrThrow(resolveInputFilePath(nextPath)))) {
74
+ if (seen.has(resolvedModule.identityPath))
75
+ continue;
76
+ seen.add(resolvedModule.identityPath);
77
+ resolvedEntries.push(resolvedModule.identityPath);
78
+ }
79
+ let visited = new Set(resolvedEntries);
80
+ let queue = [...resolvedEntries];
81
+ let layers = [];
82
+ while (queue.length > 0) {
83
+ let frontier = queue;
84
+ queue = [];
85
+ let resolvedModules = await getOrCreateResolvedScripts(frontier.map((identityPath) => scriptStore.get(identityPath)));
86
+ let layer = [];
87
+ for (let resolvedModule of resolvedModules) {
88
+ layer.push(getServedUrlForResolvedScript(resolvedModule));
89
+ for (let dep of resolvedModule.deps) {
90
+ if (visited.has(dep))
91
+ continue;
92
+ visited.add(dep);
93
+ queue.push(dep);
94
+ }
95
+ }
96
+ layers.push(layer);
97
+ }
98
+ return layers;
99
+ },
100
+ async getHref(filePath) {
101
+ let resolvedModule = resolveServedScriptOrThrow(resolveInputFilePath(filePath));
102
+ return getServedUrl(resolvedModule.identityPath);
103
+ },
104
+ async handleFileEvent(filePath, event) {
105
+ let normalizedFilePath = normalizeFilePath(filePath);
106
+ if (isWatchIgnored(normalizedFilePath))
107
+ return;
108
+ if (shouldClearResolverCacheForFileEvent(normalizedFilePath, event)) {
109
+ resolverFactory.clearCache();
110
+ }
111
+ if (isTsconfigPath(normalizedFilePath)) {
112
+ tsconfigTransformOptionsResolver.clear();
113
+ scriptStore.invalidateAll();
114
+ return;
115
+ }
116
+ if (isPackageJsonPath(normalizedFilePath)) {
117
+ scriptStore.invalidateAll();
118
+ return;
119
+ }
120
+ scriptStore.invalidateForFileEvent(normalizedFilePath, event);
121
+ },
122
+ parseRequestPathname(pathname) {
123
+ let parsedPathname = parseServedPathname(pathname);
124
+ let filePath = resolvedOptions.routes.resolveUrlPathname(parsedPathname.stablePathname);
125
+ if (!filePath)
126
+ return null;
127
+ if (resolvedOptions.fingerprintAssets && parsedPathname.requestedFingerprint === null)
128
+ return null;
129
+ return {
130
+ cacheControl: getFingerprintRequestCacheControl(parsedPathname.requestedFingerprint),
131
+ filePath,
132
+ isSourceMapRequest: parsedPathname.isSourceMapRequest,
133
+ requestedFingerprint: parsedPathname.requestedFingerprint,
134
+ };
135
+ },
136
+ };
137
+ function resolveInputFilePath(filePath) {
138
+ if (filePath.startsWith('file://')) {
139
+ return normalizeFilePath(fileURLToPath(new URL(filePath)));
140
+ }
141
+ if (filePath.includes('://')) {
142
+ throw new TypeError(`Expected a file path or file:// URL, received "${filePath}"`);
143
+ }
144
+ return resolveFilePath(resolvedOptions.rootDir, filePath);
145
+ }
146
+ function resolveServedScriptOrThrow(absolutePath) {
147
+ let resolvedModule = resolveModulePath(absolutePath);
148
+ if (!resolvedModule) {
149
+ throw createAssetServerCompilationError(`File not found: ${absolutePath}`, {
150
+ code: 'FILE_NOT_FOUND',
151
+ });
152
+ }
153
+ if (!resolvedOptions.isAllowed(resolvedModule.identityPath)) {
154
+ throw createAssetServerCompilationError(`File is not allowed: ${resolvedModule.identityPath}`, {
155
+ code: 'FILE_NOT_ALLOWED',
156
+ });
157
+ }
158
+ return resolvedModule;
159
+ }
160
+ function getNotModifiedScript(record, options) {
161
+ let current = getNotModifiedResult(record.emitted, options);
162
+ if (current)
163
+ return current;
164
+ if (!record.staleEmittedSnapshot || !isModuleSnapshotFresh(record.staleEmittedSnapshot)) {
165
+ return null;
166
+ }
167
+ return getNotModifiedResult(record.staleEmitted, options);
168
+ }
169
+ async function getOrCreateResolvedScripts(records) {
170
+ return mapWithConcurrency(records, preloadConcurrency, (record) => getOrCreateResolvedScript(record));
171
+ }
172
+ async function getOrCreateResolvedScript(record) {
173
+ if (record.resolved)
174
+ return record.resolved;
175
+ let cacheKey = getRecordCacheKey(record);
176
+ let existing = resolveInFlightByCacheKey.get(cacheKey);
177
+ if (existing)
178
+ return existing;
179
+ let promise = (async () => {
180
+ let startedVersion = record.invalidationVersion;
181
+ let transformedModule = await getOrCreateTransformedScript(record);
182
+ if (resolvedOptions.watchMode &&
183
+ transformedModule.unresolvedImports.some((unresolved) => isBareImportSpecifier(unresolved.specifier))) {
184
+ resolverFactory.clearCache();
185
+ }
186
+ let resolveModuleResult = await resolveModule(record, transformedModule, resolveArgs);
187
+ if (!resolveModuleResult.ok) {
188
+ if (isFresh(record, startedVersion)) {
189
+ scriptStore.clearResolved(record.identityPath, [resolveModuleResult.tracking]);
190
+ }
191
+ throw resolveModuleResult.error;
192
+ }
193
+ if (isFresh(record, startedVersion)) {
194
+ scriptStore.setResolved(record.identityPath, resolveModuleResult.value, [
195
+ resolveModuleResult.tracking,
196
+ ]);
197
+ }
198
+ return resolveModuleResult.value;
199
+ })();
200
+ resolveInFlightByCacheKey.set(cacheKey, promise);
201
+ try {
202
+ return await promise;
203
+ }
204
+ finally {
205
+ if (resolveInFlightByCacheKey.get(cacheKey) === promise) {
206
+ resolveInFlightByCacheKey.delete(cacheKey);
207
+ }
208
+ }
209
+ }
210
+ async function getOrCreateTransformedScript(record) {
211
+ if (record.transformed)
212
+ return record.transformed;
213
+ let startedVersion = record.invalidationVersion;
214
+ let transformModuleResult = await transformModule(record, transformArgs);
215
+ if (!transformModuleResult.ok) {
216
+ if (isFresh(record, startedVersion)) {
217
+ scriptStore.clearTransformed(record.identityPath, [transformModuleResult.tracking]);
218
+ }
219
+ throw transformModuleResult.error;
220
+ }
221
+ if (isFresh(record, startedVersion)) {
222
+ scriptStore.setTransformed(record.identityPath, transformModuleResult.value, [
223
+ transformModuleResult.tracking,
224
+ ]);
225
+ }
226
+ return transformModuleResult.value;
227
+ }
228
+ async function getOrCreateEmittedScript(record) {
229
+ if (record.emitted)
230
+ return record.emitted;
231
+ let cacheKey = getRecordCacheKey(record);
232
+ let existing = emitInFlightByCacheKey.get(cacheKey);
233
+ if (existing)
234
+ return existing;
235
+ let promise = (async () => {
236
+ let startedVersion = record.invalidationVersion;
237
+ let resolvedModule = await getOrCreateResolvedScript(record);
238
+ let emitResolvedModuleResult = await emitResolvedModule(resolvedModule, {
239
+ getServedUrl,
240
+ sourceMaps: resolvedOptions.sourceMaps,
241
+ });
242
+ if (!emitResolvedModuleResult.ok) {
243
+ throw emitResolvedModuleResult.error;
244
+ }
245
+ if (isFresh(record, startedVersion)) {
246
+ scriptStore.setEmitted(record.identityPath, emitResolvedModuleResult.value, createModuleSnapshot(resolvedModule.trackedFiles));
247
+ }
248
+ return emitResolvedModuleResult.value;
249
+ })();
250
+ emitInFlightByCacheKey.set(cacheKey, promise);
251
+ try {
252
+ return await promise;
253
+ }
254
+ finally {
255
+ if (emitInFlightByCacheKey.get(cacheKey) === promise) {
256
+ emitInFlightByCacheKey.delete(cacheKey);
257
+ }
258
+ }
259
+ }
260
+ async function getServedUrl(identityPath) {
261
+ return getServedUrlForResolvedScript(await getOrCreateResolvedScript(scriptStore.get(identityPath)));
262
+ }
263
+ function getServedUrlForResolvedScript(resolvedModule) {
264
+ return formatFingerprintedPathname(resolvedModule.stableUrlPathname, resolvedOptions.fingerprintAssets ? resolvedModule.fingerprint : null);
265
+ }
266
+ function isWatchIgnored(filePath) {
267
+ return resolvedOptions.watchIgnoreMatchers.some((matcher) => matcher(filePath));
268
+ }
269
+ }
270
+ function getRecordCacheKey(record) {
271
+ return `${record.identityPath}\0${record.invalidationVersion}`;
272
+ }
273
+ function isFresh(record, version) {
274
+ return record.invalidationVersion === version;
275
+ }
276
+ function getNotModifiedResult(emittedModule, options) {
277
+ if (!emittedModule || options.ifNoneMatch === null)
278
+ return null;
279
+ if (options.requestedFingerprint !== null &&
280
+ emittedModule.fingerprint !== options.requestedFingerprint) {
281
+ return null;
282
+ }
283
+ let asset = getEmittedAssetForRequest(emittedModule, options.isSourceMapRequest);
284
+ if (!asset)
285
+ return null;
286
+ if (!IfNoneMatch.from(options.ifNoneMatch).matches(asset.etag))
287
+ return null;
288
+ return { type: 'not-modified', etag: asset.etag };
289
+ }
290
+ function getEmittedAssetForRequest(emittedModule, isSourceMapRequest) {
291
+ return isSourceMapRequest ? emittedModule.sourceMap : emittedModule.code;
292
+ }
293
+ function createModuleSnapshot(filePaths) {
294
+ let snapshot = new Map();
295
+ for (let filePath of filePaths) {
296
+ let fileSnapshot = getFileSnapshot(filePath);
297
+ if (!fileSnapshot)
298
+ return null;
299
+ snapshot.set(filePath, fileSnapshot);
300
+ }
301
+ return snapshot;
302
+ }
303
+ function isModuleSnapshotFresh(snapshot) {
304
+ for (let [filePath, previous] of snapshot) {
305
+ let current = getFileSnapshot(filePath);
306
+ if (!current)
307
+ return false;
308
+ if (current.mtimeNs !== previous.mtimeNs || current.size !== previous.size)
309
+ return false;
310
+ }
311
+ return true;
312
+ }
313
+ function getFileSnapshot(filePath) {
314
+ try {
315
+ let stats = fs.statSync(filePath, { bigint: true });
316
+ if (!stats.isFile())
317
+ return null;
318
+ return {
319
+ mtimeNs: stats.mtimeNs,
320
+ size: stats.size,
321
+ };
322
+ }
323
+ catch (error) {
324
+ if (isNoEntityError(error))
325
+ return null;
326
+ throw error;
327
+ }
328
+ }
329
+ function parseServedPathname(pathname) {
330
+ let isSourceMapRequest = pathname.endsWith('.map');
331
+ let pathWithoutMap = isSourceMapRequest ? pathname.slice(0, -4) : pathname;
332
+ let fingerprint = parseFingerprintSuffix(pathWithoutMap);
333
+ return {
334
+ isSourceMapRequest,
335
+ requestedFingerprint: fingerprint.requestedFingerprint,
336
+ stablePathname: fingerprint.pathname,
337
+ };
338
+ }
339
+ async function mapWithConcurrency(items, concurrency, mapper) {
340
+ if (items.length === 0)
341
+ return [];
342
+ let results = new Array(items.length);
343
+ let nextIndex = 0;
344
+ async function worker() {
345
+ while (nextIndex < items.length) {
346
+ let index = nextIndex++;
347
+ results[index] = await mapper(items[index], index);
348
+ }
349
+ }
350
+ await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
351
+ return results;
352
+ }
353
+ function toScriptCompileResult(emittedModule) {
354
+ return {
355
+ code: emittedModule.code,
356
+ fingerprint: emittedModule.fingerprint,
357
+ sourceMap: emittedModule.sourceMap,
358
+ };
359
+ }
360
+ function isPackageJsonPath(filePath) {
361
+ return filePath.endsWith('/package.json');
362
+ }
363
+ function isTsconfigPath(filePath) {
364
+ return /\/tsconfig(?:\..+)?\.json$/.test(filePath);
365
+ }
366
+ function shouldClearResolverCacheForFileEvent(filePath, event) {
367
+ return event !== 'change' || isPackageJsonPath(filePath) || isTsconfigPath(filePath);
368
+ }
369
+ function resolveModulePath(absolutePath) {
370
+ let resolvedPath;
371
+ try {
372
+ resolvedPath = normalizeFilePath(fs.realpathSync(normalizeFilePath(absolutePath)));
373
+ }
374
+ catch (error) {
375
+ if (isNoEntityError(error))
376
+ return null;
377
+ throw error;
378
+ }
379
+ if (!supportedScriptExtensionSet.has(path.extname(resolvedPath).toLowerCase())) {
380
+ return null;
381
+ }
382
+ return {
383
+ identityPath: resolvedPath,
384
+ resolvedPath,
385
+ };
386
+ }
387
+ function resolveActualPath(identityPath) {
388
+ try {
389
+ return normalizeFilePath(fs.realpathSync(identityPath));
390
+ }
391
+ catch (error) {
392
+ if (isNoEntityError(error))
393
+ return null;
394
+ throw error;
395
+ }
396
+ }
397
+ function isBareImportSpecifier(specifier) {
398
+ return (!specifier.startsWith('./') &&
399
+ !specifier.startsWith('../') &&
400
+ !specifier.startsWith('/') &&
401
+ !specifier.startsWith('file:') &&
402
+ !specifier.startsWith('data:') &&
403
+ !specifier.startsWith('http://') &&
404
+ !specifier.startsWith('https://'));
405
+ }
406
+ function isNoEntityError(error) {
407
+ return (error instanceof Error &&
408
+ 'code' in error &&
409
+ (error.code === 'ENOENT' ||
410
+ error.code === 'ENOTDIR'));
411
+ }
412
+ export function createResponseForScript(result, options) {
413
+ let body;
414
+ let etag;
415
+ let contentType;
416
+ if (options.isSourceMapRequest) {
417
+ if (!result.sourceMap) {
418
+ return new Response('Not found', { status: 404 });
419
+ }
420
+ body = options.method === 'HEAD' ? null : result.sourceMap.content;
421
+ etag = result.sourceMap.etag;
422
+ contentType = 'application/json; charset=utf-8';
423
+ }
424
+ else {
425
+ body = options.method === 'HEAD' ? null : result.code.content;
426
+ etag = result.code.etag;
427
+ contentType = 'application/javascript; charset=utf-8';
428
+ }
429
+ if (IfNoneMatch.from(options.ifNoneMatch).matches(etag)) {
430
+ return new Response(null, { status: 304, headers: { ETag: etag } });
431
+ }
432
+ return new Response(body, {
433
+ headers: {
434
+ 'Cache-Control': options.cacheControl,
435
+ 'Content-Type': contentType,
436
+ ETag: etag,
437
+ },
438
+ });
439
+ }
@@ -0,0 +1,25 @@
1
+ import type { ResolvedModule } from './resolve.ts';
2
+ import type { AssetServerCompilationError } from '../compilation-error.ts';
3
+ export type EmittedAsset = {
4
+ content: string;
5
+ etag: string;
6
+ };
7
+ export type EmittedModule = {
8
+ code: EmittedAsset;
9
+ fingerprint: string | null;
10
+ importUrls: string[];
11
+ sourceMap: EmittedAsset | null;
12
+ };
13
+ type EmitResult = {
14
+ ok: true;
15
+ value: EmittedModule;
16
+ } | {
17
+ ok: false;
18
+ error: AssetServerCompilationError;
19
+ };
20
+ export declare function emitResolvedModule(resolvedModule: ResolvedModule, options: {
21
+ getServedUrl(identityPath: string): Promise<string>;
22
+ sourceMaps?: 'external' | 'inline';
23
+ }): Promise<EmitResult>;
24
+ export {};
25
+ //# sourceMappingURL=emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/emit.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAE1E,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,YAAY,CAAA;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,SAAS,EAAE,YAAY,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED,KAAK,UAAU,GACX;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,aAAa,CAAA;CACrB,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,2BAA2B,CAAA;CACnC,CAAA;AAEL,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,cAAc,EAC9B,OAAO,EAAE;IACP,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACnD,UAAU,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;CACnC,GACA,OAAO,CAAC,UAAU,CAAC,CAkCrB"}
@@ -0,0 +1,63 @@
1
+ import MagicString from 'magic-string';
2
+ import { createAssetServerCompilationError, isAssetServerCompilationError, } from "../compilation-error.js";
3
+ import { hashContent } from "../fingerprint.js";
4
+ import { composeSourceMaps } from "../source-maps.js";
5
+ export async function emitResolvedModule(resolvedModule, options) {
6
+ try {
7
+ let importUrls = await Promise.all(resolvedModule.deps.map((depPath) => options.getServedUrl(depPath)));
8
+ let rewriteResult = await rewriteImports(resolvedModule, options);
9
+ let finalCode = rewriteResult.code;
10
+ if (rewriteResult.sourceMap) {
11
+ if (options.sourceMaps === 'inline') {
12
+ let encoded = Buffer.from(rewriteResult.sourceMap).toString('base64');
13
+ finalCode += `\n//# sourceMappingURL=data:application/json;base64,${encoded}`;
14
+ }
15
+ else if (options.sourceMaps === 'external') {
16
+ finalCode += `\n//# sourceMappingURL=${await options.getServedUrl(resolvedModule.identityPath)}.map`;
17
+ }
18
+ }
19
+ return {
20
+ ok: true,
21
+ value: {
22
+ code: await createEmittedAsset(finalCode),
23
+ fingerprint: resolvedModule.fingerprint,
24
+ importUrls,
25
+ sourceMap: rewriteResult.sourceMap
26
+ ? await createEmittedAsset(rewriteResult.sourceMap)
27
+ : null,
28
+ },
29
+ };
30
+ }
31
+ catch (error) {
32
+ return {
33
+ ok: false,
34
+ error: toEmitError(error, resolvedModule.identityPath),
35
+ };
36
+ }
37
+ }
38
+ async function rewriteImports(resolvedModule, options) {
39
+ let rewrittenSource = new MagicString(resolvedModule.rawCode);
40
+ for (let imported of resolvedModule.imports) {
41
+ let url = await options.getServedUrl(imported.depPath);
42
+ rewrittenSource.overwrite(imported.start, imported.end, imported.quote ? `${imported.quote}${url}${imported.quote}` : url);
43
+ }
44
+ let code = rewrittenSource.toString();
45
+ let sourceMap = resolvedModule.sourceMap && resolvedModule.imports.length > 0
46
+ ? composeSourceMaps(rewrittenSource.generateMap({ hires: true }).toString(), resolvedModule.sourceMap)
47
+ : resolvedModule.sourceMap;
48
+ return { code, sourceMap };
49
+ }
50
+ async function createEmittedAsset(content) {
51
+ return {
52
+ content,
53
+ etag: `W/"${await hashContent(content)}"`,
54
+ };
55
+ }
56
+ function toEmitError(error, identityPath) {
57
+ if (isAssetServerCompilationError(error))
58
+ return error;
59
+ return createAssetServerCompilationError(`Failed to emit script ${identityPath}. ${error instanceof Error ? error.message : String(error)}`, {
60
+ cause: error,
61
+ code: 'EMIT_FAILED',
62
+ });
63
+ }
@@ -0,0 +1,50 @@
1
+ import type { ResolverFactory } from 'oxc-resolver';
2
+ import type { AssetServerCompilationError } from '../compilation-error.ts';
3
+ import type { ModuleRecord, ModuleTracking } from '../module-store.ts';
4
+ import type { CompiledRoutes } from '../routes.ts';
5
+ import type { ResolveModuleResult, TransformedModule } from './transform.ts';
6
+ import type { EmittedModule } from './emit.ts';
7
+ type ScriptRecord = ModuleRecord<TransformedModule, ResolvedModule, EmittedModule>;
8
+ export declare const resolverExtensionAlias: {
9
+ '.js': string[];
10
+ '.jsx': string[];
11
+ '.mjs': string[];
12
+ };
13
+ export declare const resolverExtensions: string[];
14
+ export declare const supportedScriptExtensions: string[];
15
+ type ResolvedImport = {
16
+ depPath: string;
17
+ end: number;
18
+ quote?: '"' | "'" | '`';
19
+ start: number;
20
+ };
21
+ export type ResolvedModule = {
22
+ deps: string[];
23
+ fingerprint: string | null;
24
+ identityPath: string;
25
+ imports: ResolvedImport[];
26
+ trackedFiles: string[];
27
+ rawCode: string;
28
+ resolvedPath: string;
29
+ sourceMap: string | null;
30
+ stableUrlPathname: string;
31
+ };
32
+ type ResolveResult = {
33
+ tracking: ModuleTracking;
34
+ } & ({
35
+ ok: true;
36
+ value: ResolvedModule;
37
+ } | {
38
+ ok: false;
39
+ error: AssetServerCompilationError;
40
+ });
41
+ export type ResolveArgs = {
42
+ isAllowed(absolutePath: string): boolean;
43
+ isWatchIgnored(filePath: string): boolean;
44
+ resolveModulePath(absolutePath: string): ResolveModuleResult | null;
45
+ resolverFactory: ResolverFactory;
46
+ routes: CompiledRoutes;
47
+ };
48
+ export declare function resolveModule(record: ScriptRecord, transformed: TransformedModule, args: ResolveArgs): Promise<ResolveResult>;
49
+ export {};
50
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/lib/scripts/resolve.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAMnD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9C,KAAK,YAAY,GAAG,YAAY,CAAC,iBAAiB,EAAE,cAAc,EAAE,aAAa,CAAC,CAAA;AAElF,eAAO,MAAM,sBAAsB;;;;CAIC,CAAA;AAEpC,eAAO,MAAM,kBAAkB,UAAiD,CAAA;AAChF,eAAO,MAAM,yBAAyB,UAAiD,CAAA;AAGvF,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAYD,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,cAAc,CAAA;CACzB,GAAG,CACA;IACE,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,cAAc,CAAA;CACtB,GACD;IACE,EAAE,EAAE,KAAK,CAAA;IACT,KAAK,EAAE,2BAA2B,CAAA;CACnC,CACJ,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAA;IACxC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;IACzC,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAAA;IACnE,eAAe,EAAE,eAAe,CAAA;IAChC,MAAM,EAAE,cAAc,CAAA;CACvB,CAAA;AAQD,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,WAAW,EAAE,iBAAiB,EAC9B,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CAyIxB"}