create-dalila 1.2.14 → 1.2.16
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 +6 -2
- package/index.js +11 -0
- package/package.json +1 -1
- package/template/build.mjs +2192 -0
- package/template/index.html +7 -0
- package/template/package.json +3 -2
- package/template/src/app/page.ts +1 -1
- package/template/src/main.ts +17 -0
|
@@ -0,0 +1,2192 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const FOUC_PREVENTION_STYLE = ` <style>[d-loading]{visibility:hidden}</style>`;
|
|
9
|
+
const SCRIPT_SOURCE_EXTENSIONS = new Set(['.ts', '.mts', '.cts']);
|
|
10
|
+
const SCRIPT_REQUEST_SOURCE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs']);
|
|
11
|
+
const JAVASCRIPT_EXTENSIONS = new Set(['.js', '.mjs', '.cjs']);
|
|
12
|
+
const TYPE_ARTIFACT_EXTENSIONS = ['.d.ts', '.d.ts.map', '.js.map', '.mjs.map', '.cjs.map'];
|
|
13
|
+
const STATIC_DIR_EXCLUDES = new Set([
|
|
14
|
+
'src',
|
|
15
|
+
'public',
|
|
16
|
+
'node_modules',
|
|
17
|
+
'dist',
|
|
18
|
+
'coverage',
|
|
19
|
+
'playwright-report',
|
|
20
|
+
'test-results',
|
|
21
|
+
]);
|
|
22
|
+
const HTML_ENTRY_DIR_EXCLUDES = new Set([
|
|
23
|
+
'node_modules',
|
|
24
|
+
'dist',
|
|
25
|
+
'coverage',
|
|
26
|
+
'playwright-report',
|
|
27
|
+
'test-results',
|
|
28
|
+
]);
|
|
29
|
+
const STATIC_FILE_EXCLUDES = new Set([
|
|
30
|
+
'package.json',
|
|
31
|
+
'package-lock.json',
|
|
32
|
+
'bun.lock',
|
|
33
|
+
'bun.lockb',
|
|
34
|
+
'pnpm-lock.yaml',
|
|
35
|
+
'yarn.lock',
|
|
36
|
+
'tsconfig.json',
|
|
37
|
+
'build.mjs',
|
|
38
|
+
'dev.mjs',
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
function resolvePackageModule(moduleName, projectDir) {
|
|
42
|
+
try {
|
|
43
|
+
return require.resolve(moduleName, { paths: [projectDir] });
|
|
44
|
+
} catch {
|
|
45
|
+
return require.resolve(moduleName);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function isScriptSourceFile(filePath) {
|
|
50
|
+
return SCRIPT_SOURCE_EXTENSIONS.has(path.extname(filePath)) && !filePath.endsWith('.d.ts');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function walkFiles(dir, files = []) {
|
|
54
|
+
if (!fs.existsSync(dir)) return files;
|
|
55
|
+
|
|
56
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
const entryPath = path.join(dir, entry.name);
|
|
59
|
+
if (entry.isDirectory()) {
|
|
60
|
+
walkFiles(entryPath, files);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
files.push(entryPath);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return files;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function detectPreloadScripts(baseDir) {
|
|
71
|
+
const preloads = [];
|
|
72
|
+
|
|
73
|
+
for (const filePath of walkFiles(baseDir)) {
|
|
74
|
+
if (!isScriptSourceFile(filePath)) continue;
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const source = fs.readFileSync(filePath, 'utf8');
|
|
78
|
+
const persistRegex = /persist\s*\(\s*signal\s*(?:<[^>]+>)?\s*\(\s*['"]?([^'")]+)['"]?\s*\)\s*,\s*\{([^}]+)\}\s*\)/g;
|
|
79
|
+
|
|
80
|
+
let match;
|
|
81
|
+
while ((match = persistRegex.exec(source)) !== null) {
|
|
82
|
+
const defaultValue = match[1];
|
|
83
|
+
const options = match[2];
|
|
84
|
+
|
|
85
|
+
if (!options.includes('preload') || !options.match(/preload\s*:\s*true/)) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const nameMatch = options.match(/name\s*:\s*['"]([^'"]+)['"]/);
|
|
90
|
+
if (!nameMatch) continue;
|
|
91
|
+
|
|
92
|
+
let storageType = 'localStorage';
|
|
93
|
+
const storageMatch = options.match(/storage\s*:\s*(\w+)/);
|
|
94
|
+
if (storageMatch && storageMatch[1] === 'sessionStorage') {
|
|
95
|
+
storageType = 'sessionStorage';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
preloads.push({
|
|
99
|
+
name: nameMatch[1],
|
|
100
|
+
defaultValue,
|
|
101
|
+
storageType,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
// Ignore malformed files during packaging.
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return preloads;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function generatePreloadScript(name, defaultValue, storageType = 'localStorage') {
|
|
113
|
+
const k = JSON.stringify(name);
|
|
114
|
+
const d = JSON.stringify(defaultValue);
|
|
115
|
+
const script = `(function(){try{var v=${storageType}.getItem(${k});document.documentElement.setAttribute('data-theme',v?JSON.parse(v):${d})}catch(e){document.documentElement.setAttribute('data-theme',${d})}})();`;
|
|
116
|
+
|
|
117
|
+
return script
|
|
118
|
+
.replace(/</g, '\\x3C')
|
|
119
|
+
.replace(/-->/g, '--\\x3E')
|
|
120
|
+
.replace(/\u2028/g, '\\u2028')
|
|
121
|
+
.replace(/\u2029/g, '\\u2029');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function renderPreloadScriptTags(baseDir) {
|
|
125
|
+
const preloads = detectPreloadScripts(baseDir);
|
|
126
|
+
if (preloads.length === 0) return '';
|
|
127
|
+
|
|
128
|
+
return preloads
|
|
129
|
+
.map((preload) => ` <script>${generatePreloadScript(preload.name, preload.defaultValue, preload.storageType)}</script>`)
|
|
130
|
+
.join('\n');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function ensureFileExists(filePath, label) {
|
|
134
|
+
if (!fs.existsSync(filePath)) {
|
|
135
|
+
throw new Error(`Missing ${label}: ${filePath}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function copyDirectoryContents(sourceDir, destinationDir) {
|
|
140
|
+
if (!fs.existsSync(sourceDir)) return;
|
|
141
|
+
fs.mkdirSync(path.dirname(destinationDir), { recursive: true });
|
|
142
|
+
fs.cpSync(sourceDir, destinationDir, { recursive: true, force: true });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function copyStaticSourceAssets(sourceDir, destinationDir) {
|
|
146
|
+
if (!fs.existsSync(sourceDir)) return;
|
|
147
|
+
|
|
148
|
+
for (const filePath of walkFiles(sourceDir)) {
|
|
149
|
+
if (isScriptSourceFile(filePath) || filePath.endsWith('.d.ts')) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const relativePath = path.relative(sourceDir, filePath);
|
|
154
|
+
const targetPath = path.join(destinationDir, relativePath);
|
|
155
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
156
|
+
fs.copyFileSync(filePath, targetPath);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function resolveDalilaPackageRoot(projectDir) {
|
|
161
|
+
const dalilaEntry = require.resolve('dalila', { paths: [projectDir] });
|
|
162
|
+
return path.dirname(path.dirname(dalilaEntry));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function formatTypeScriptError(ts, diagnostic) {
|
|
166
|
+
return ts.formatDiagnostic(diagnostic, {
|
|
167
|
+
getCanonicalFileName: (value) => value,
|
|
168
|
+
getCurrentDirectory: () => process.cwd(),
|
|
169
|
+
getNewLine: () => '\n',
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function parseTypeScriptConfig(ts, configPath) {
|
|
174
|
+
let unrecoverableDiagnostic = null;
|
|
175
|
+
const parsed = ts.getParsedCommandLineOfConfigFile(
|
|
176
|
+
configPath,
|
|
177
|
+
{},
|
|
178
|
+
{
|
|
179
|
+
...ts.sys,
|
|
180
|
+
onUnRecoverableConfigFileDiagnostic(diagnostic) {
|
|
181
|
+
unrecoverableDiagnostic = diagnostic;
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
if (unrecoverableDiagnostic) {
|
|
187
|
+
throw new Error(formatTypeScriptError(ts, unrecoverableDiagnostic));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (!parsed) {
|
|
191
|
+
throw new Error(`Failed to parse TypeScript config: ${configPath}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (parsed.errors?.length) {
|
|
195
|
+
throw new Error(parsed.errors.map((diagnostic) => formatTypeScriptError(ts, diagnostic)).join('\n'));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return parsed;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function inferCommonSourceDir(fileNames, fallbackDir) {
|
|
202
|
+
const sourceDirs = fileNames
|
|
203
|
+
.filter((filePath) => !filePath.endsWith('.d.ts'))
|
|
204
|
+
.map((filePath) => path.dirname(path.resolve(filePath)));
|
|
205
|
+
|
|
206
|
+
if (sourceDirs.length === 0) {
|
|
207
|
+
return fallbackDir;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let commonDir = sourceDirs[0];
|
|
211
|
+
for (const nextDir of sourceDirs.slice(1)) {
|
|
212
|
+
while (commonDir !== path.dirname(commonDir)) {
|
|
213
|
+
const relativePath = path.relative(commonDir, nextDir);
|
|
214
|
+
if (relativePath === '' || isRelativePathInsideBase(relativePath)) {
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
commonDir = path.dirname(commonDir);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const relativePath = path.relative(commonDir, nextDir);
|
|
221
|
+
if (relativePath !== '' && !isRelativePathInsideBase(relativePath)) {
|
|
222
|
+
return fallbackDir;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return commonDir;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function loadTypeScriptBuildConfig(projectDir) {
|
|
230
|
+
const ts = require(resolvePackageModule('typescript', projectDir));
|
|
231
|
+
const configPath = ts.findConfigFile(projectDir, ts.sys.fileExists, 'tsconfig.json');
|
|
232
|
+
const packageOutDirAbs = path.join(projectDir, 'dist');
|
|
233
|
+
const defaultSourceDirAbs = fs.existsSync(path.join(projectDir, 'src'))
|
|
234
|
+
? path.join(projectDir, 'src')
|
|
235
|
+
: projectDir;
|
|
236
|
+
|
|
237
|
+
if (!configPath) {
|
|
238
|
+
const ts = require(resolvePackageModule('typescript', projectDir));
|
|
239
|
+
return {
|
|
240
|
+
projectDir,
|
|
241
|
+
configPath: null,
|
|
242
|
+
configDir: projectDir,
|
|
243
|
+
compileOutDirAbs: packageOutDirAbs,
|
|
244
|
+
packageOutDirAbs,
|
|
245
|
+
rootDirAbs: projectDir,
|
|
246
|
+
sourceDirAbs: defaultSourceDirAbs,
|
|
247
|
+
ts,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const configDir = path.dirname(configPath);
|
|
252
|
+
const parsed = parseTypeScriptConfig(ts, configPath);
|
|
253
|
+
const inferredRootDirAbs = inferCommonSourceDir(parsed.fileNames, projectDir);
|
|
254
|
+
const explicitRootDirAbs = typeof parsed.options.rootDir === 'string'
|
|
255
|
+
? path.resolve(configDir, parsed.options.rootDir)
|
|
256
|
+
: null;
|
|
257
|
+
const sourceDirAbs = explicitRootDirAbs
|
|
258
|
+
?? (defaultSourceDirAbs !== projectDir ? defaultSourceDirAbs : inferredRootDirAbs);
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
projectDir,
|
|
262
|
+
configPath,
|
|
263
|
+
configDir,
|
|
264
|
+
compileOutDirAbs: parsed.options.outDir
|
|
265
|
+
? path.resolve(configDir, parsed.options.outDir)
|
|
266
|
+
: packageOutDirAbs,
|
|
267
|
+
packageOutDirAbs,
|
|
268
|
+
rootDirAbs: explicitRootDirAbs ?? inferredRootDirAbs,
|
|
269
|
+
sourceDirAbs,
|
|
270
|
+
ts,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function resolveExportTarget(target) {
|
|
275
|
+
if (typeof target === 'string') return target;
|
|
276
|
+
if (!target || typeof target !== 'object') return null;
|
|
277
|
+
return target.default || target.import || null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function buildDalilaImportEntries(projectDir) {
|
|
281
|
+
const dalilaRoot = resolveDalilaPackageRoot(projectDir);
|
|
282
|
+
const dalilaPackageJson = JSON.parse(
|
|
283
|
+
fs.readFileSync(path.join(dalilaRoot, 'package.json'), 'utf8')
|
|
284
|
+
);
|
|
285
|
+
const distRoot = path.join(dalilaRoot, 'dist');
|
|
286
|
+
const distIndexPath = path.join(distRoot, 'index.js');
|
|
287
|
+
const imports = {};
|
|
288
|
+
|
|
289
|
+
for (const [subpath, target] of Object.entries(dalilaPackageJson.exports ?? {})) {
|
|
290
|
+
const exportTarget = resolveExportTarget(target);
|
|
291
|
+
if (!exportTarget || !exportTarget.endsWith('.js')) continue;
|
|
292
|
+
|
|
293
|
+
const absoluteTarget = path.resolve(dalilaRoot, exportTarget);
|
|
294
|
+
if (absoluteTarget !== distIndexPath && !absoluteTarget.startsWith(distRoot + path.sep)) {
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const relativeTarget = path.relative(distRoot, absoluteTarget).replace(/\\/g, '/');
|
|
299
|
+
const specifier = subpath === '.' ? 'dalila' : `dalila/${subpath.slice(2)}`;
|
|
300
|
+
imports[specifier] = `/vendor/dalila/${relativeTarget}`;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return imports;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function normalizeNodeModulesImportTarget(target, projectDir, baseDirAbs = projectDir) {
|
|
307
|
+
if (typeof target !== 'string') return null;
|
|
308
|
+
|
|
309
|
+
const { pathname, suffix } = splitUrlTarget(target);
|
|
310
|
+
if (isUrlWithScheme(pathname)) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (pathname.startsWith('/node_modules/')) {
|
|
315
|
+
return {
|
|
316
|
+
relativeTarget: pathname.slice('/node_modules/'.length),
|
|
317
|
+
suffix,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (pathname.startsWith('node_modules/')) {
|
|
322
|
+
return {
|
|
323
|
+
relativeTarget: pathname.slice('node_modules/'.length),
|
|
324
|
+
suffix,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (!pathname.startsWith('./') && !pathname.startsWith('../')) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const nodeModulesRoot = path.join(projectDir, 'node_modules');
|
|
333
|
+
const resolvedAbsPath = resolveLocalProjectPath(projectDir, pathname, baseDirAbs);
|
|
334
|
+
const relativeTarget = path.relative(nodeModulesRoot, resolvedAbsPath);
|
|
335
|
+
if (!isRelativePathInsideBase(relativeTarget)) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return {
|
|
340
|
+
relativeTarget: toPosixPath(relativeTarget),
|
|
341
|
+
suffix,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function splitUrlTarget(target) {
|
|
346
|
+
const match = String(target).match(/^([^?#]*)([?#].*)?$/);
|
|
347
|
+
return {
|
|
348
|
+
pathname: match?.[1] ?? String(target),
|
|
349
|
+
suffix: match?.[2] ?? '',
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function isUrlWithScheme(pathname) {
|
|
354
|
+
return /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(pathname) || pathname.startsWith('//');
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function isLocalUrlPath(pathname) {
|
|
358
|
+
return pathname.startsWith('/') || pathname.startsWith('./') || pathname.startsWith('../');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function resolveLocalProjectPath(projectDir, pathname, baseDirAbs = projectDir) {
|
|
362
|
+
if (pathname.startsWith('/')) {
|
|
363
|
+
return path.resolve(projectDir, pathname.slice(1));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return path.resolve(baseDirAbs, pathname);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function emittedExtensionCandidates(sourceExt) {
|
|
370
|
+
switch (sourceExt) {
|
|
371
|
+
case '.mts':
|
|
372
|
+
return ['.mjs', '.js'];
|
|
373
|
+
case '.cts':
|
|
374
|
+
return ['.cjs', '.js'];
|
|
375
|
+
case '.ts':
|
|
376
|
+
return ['.js'];
|
|
377
|
+
default:
|
|
378
|
+
return [];
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function replaceExtension(filePath, nextExt) {
|
|
383
|
+
return `${filePath.slice(0, -path.extname(filePath).length)}${nextExt}`;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function toPosixPath(value) {
|
|
387
|
+
return value.replace(/\\/g, '/');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function isRelativePathInsideBase(relativePath) {
|
|
391
|
+
return !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function getProjectRelativeCandidates(targetAbsPath, buildConfig) {
|
|
395
|
+
const relativeCandidates = [];
|
|
396
|
+
const relativeToRootDir = path.relative(buildConfig.rootDirAbs, targetAbsPath);
|
|
397
|
+
if (isRelativePathInsideBase(relativeToRootDir)) {
|
|
398
|
+
relativeCandidates.push(relativeToRootDir);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const relativeToProject = path.relative(buildConfig.projectDir, targetAbsPath);
|
|
402
|
+
if (isRelativePathInsideBase(relativeToProject)) {
|
|
403
|
+
relativeCandidates.push(relativeToProject);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return [...new Set(relativeCandidates)];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function resolveCompiledSourceOutputPath(sourceAbsPath, buildConfig) {
|
|
410
|
+
const sourceExt = path.extname(sourceAbsPath);
|
|
411
|
+
const candidateExts = emittedExtensionCandidates(sourceExt);
|
|
412
|
+
if (candidateExts.length === 0) return null;
|
|
413
|
+
|
|
414
|
+
for (const relativeCandidate of getProjectRelativeCandidates(sourceAbsPath, buildConfig)) {
|
|
415
|
+
for (const candidateExt of candidateExts) {
|
|
416
|
+
const compiledAbsPath = path.join(
|
|
417
|
+
buildConfig.compileOutDirAbs,
|
|
418
|
+
replaceExtension(relativeCandidate, candidateExt)
|
|
419
|
+
);
|
|
420
|
+
if (fs.existsSync(compiledAbsPath)) {
|
|
421
|
+
return compiledAbsPath;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function toPackagedUrlFromCompiledOutput(compiledAbsPath, buildConfig) {
|
|
430
|
+
return `/${toPosixPath(path.relative(buildConfig.compileOutDirAbs, compiledAbsPath))}`;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function resolvePackagedProjectUrlPath(targetAbsPath, buildConfig) {
|
|
434
|
+
const [relativeCandidate] = getProjectRelativeCandidates(targetAbsPath, buildConfig);
|
|
435
|
+
if (relativeCandidate == null) {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (!relativeCandidate) {
|
|
440
|
+
return '/';
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return `/${toPosixPath(relativeCandidate)}`;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function ensureTrailingSlash(urlPath) {
|
|
447
|
+
return urlPath.endsWith('/') ? urlPath : `${urlPath}/`;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function buildUserProjectImportEntries(buildConfig) {
|
|
451
|
+
const sourceDirUrl = resolvePackagedProjectUrlPath(buildConfig.sourceDirAbs, buildConfig) ?? '/src/';
|
|
452
|
+
return {
|
|
453
|
+
'@/': ensureTrailingSlash(sourceDirUrl),
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function getScriptSourceRequestCandidates(requestAbsPath) {
|
|
458
|
+
const requestExt = path.extname(requestAbsPath);
|
|
459
|
+
if (SCRIPT_SOURCE_EXTENSIONS.has(requestExt)) {
|
|
460
|
+
return {
|
|
461
|
+
candidates: [requestAbsPath],
|
|
462
|
+
requireExistingFile: false,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (!SCRIPT_REQUEST_SOURCE_EXTENSIONS.has(requestExt)) {
|
|
467
|
+
return {
|
|
468
|
+
candidates: [],
|
|
469
|
+
requireExistingFile: true,
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
switch (requestExt) {
|
|
474
|
+
case '.mjs':
|
|
475
|
+
return {
|
|
476
|
+
candidates: [replaceExtension(requestAbsPath, '.mts'), replaceExtension(requestAbsPath, '.ts')],
|
|
477
|
+
requireExistingFile: true,
|
|
478
|
+
};
|
|
479
|
+
case '.cjs':
|
|
480
|
+
return {
|
|
481
|
+
candidates: [replaceExtension(requestAbsPath, '.cts'), replaceExtension(requestAbsPath, '.ts')],
|
|
482
|
+
requireExistingFile: true,
|
|
483
|
+
};
|
|
484
|
+
case '.js':
|
|
485
|
+
default:
|
|
486
|
+
return {
|
|
487
|
+
candidates: [
|
|
488
|
+
replaceExtension(requestAbsPath, '.ts'),
|
|
489
|
+
replaceExtension(requestAbsPath, '.mts'),
|
|
490
|
+
replaceExtension(requestAbsPath, '.cts'),
|
|
491
|
+
],
|
|
492
|
+
requireExistingFile: true,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function resolveLocalSourceScriptPath(target, buildConfig, baseDirAbs = buildConfig.projectDir) {
|
|
498
|
+
const { pathname } = splitUrlTarget(target);
|
|
499
|
+
if (!isLocalUrlPath(pathname) || isUrlWithScheme(pathname)) {
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const requestAbsPath = resolveLocalProjectPath(buildConfig.projectDir, pathname, baseDirAbs);
|
|
504
|
+
const { candidates, requireExistingFile } = getScriptSourceRequestCandidates(requestAbsPath);
|
|
505
|
+
for (const candidateAbsPath of candidates) {
|
|
506
|
+
if (!requireExistingFile || fs.existsSync(candidateAbsPath)) {
|
|
507
|
+
return candidateAbsPath;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function rewriteLocalSourceTarget(target, buildConfig, baseDirAbs = buildConfig.projectDir) {
|
|
515
|
+
const { suffix } = splitUrlTarget(target);
|
|
516
|
+
const sourceAbsPath = resolveLocalSourceScriptPath(target, buildConfig, baseDirAbs);
|
|
517
|
+
if (!sourceAbsPath) {
|
|
518
|
+
return null;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const compiledAbsPath = resolveCompiledSourceOutputPath(sourceAbsPath, buildConfig);
|
|
522
|
+
if (!compiledAbsPath) {
|
|
523
|
+
throw new Error(`Compiled output not found for source target "${target}"`);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return `${toPackagedUrlFromCompiledOutput(compiledAbsPath, buildConfig)}${suffix}`;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function rewriteImportMapScopeName(scopeName, buildConfig, baseDirAbs = buildConfig.projectDir) {
|
|
530
|
+
const rewrittenSourceTarget = rewriteLocalSourceTarget(scopeName, buildConfig, baseDirAbs);
|
|
531
|
+
if (rewrittenSourceTarget) {
|
|
532
|
+
return rewrittenSourceTarget;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const { pathname, suffix } = splitUrlTarget(scopeName);
|
|
536
|
+
if (!isLocalUrlPath(pathname) || isUrlWithScheme(pathname)) {
|
|
537
|
+
return scopeName;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
const packagedUrlPath = resolvePackagedProjectUrlPath(
|
|
541
|
+
resolveLocalProjectPath(buildConfig.projectDir, pathname, baseDirAbs),
|
|
542
|
+
buildConfig
|
|
543
|
+
);
|
|
544
|
+
if (!packagedUrlPath) {
|
|
545
|
+
return scopeName;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const needsTrailingSlash = pathname.endsWith('/') && packagedUrlPath !== '/' && !packagedUrlPath.endsWith('/');
|
|
549
|
+
return `${packagedUrlPath}${needsTrailingSlash ? '/' : ''}${suffix}`;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function getPackagePathParts(relativeTarget) {
|
|
553
|
+
const segments = relativeTarget.split('/').filter(Boolean);
|
|
554
|
+
if (segments.length === 0) {
|
|
555
|
+
throw new Error(`Invalid node_modules import target: "${relativeTarget}"`);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (segments[0].startsWith('@')) {
|
|
559
|
+
if (segments.length < 2) {
|
|
560
|
+
throw new Error(`Invalid scoped package import target: "${relativeTarget}"`);
|
|
561
|
+
}
|
|
562
|
+
return segments.slice(0, 2);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return segments.slice(0, 1);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function rewriteImportMapTarget(projectDir, vendorDir, target, buildConfig, copiedPackages, baseDirAbs = projectDir) {
|
|
569
|
+
const normalizedTarget = normalizeNodeModulesImportTarget(target, projectDir, baseDirAbs);
|
|
570
|
+
if (normalizedTarget) {
|
|
571
|
+
const relativeTarget = normalizedTarget.relativeTarget;
|
|
572
|
+
const packagePathParts = getPackagePathParts(relativeTarget);
|
|
573
|
+
const packagePath = path.join(...packagePathParts);
|
|
574
|
+
const sourcePackageDir = path.join(projectDir, 'node_modules', packagePath);
|
|
575
|
+
const destinationPackageDir = path.join(vendorDir, 'node_modules', packagePath);
|
|
576
|
+
ensureFileExists(sourcePackageDir, `import-map package for target "${target}"`);
|
|
577
|
+
|
|
578
|
+
if (!copiedPackages.has(packagePath)) {
|
|
579
|
+
copyDirectoryContents(sourcePackageDir, destinationPackageDir);
|
|
580
|
+
copiedPackages.add(packagePath);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return `/vendor/node_modules/${relativeTarget}${normalizedTarget.suffix}`;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const rewrittenSourceTarget = rewriteLocalSourceTarget(target, buildConfig, baseDirAbs);
|
|
587
|
+
if (rewrittenSourceTarget) {
|
|
588
|
+
return rewrittenSourceTarget;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
return target;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function packageExistingImportMapImports(projectDir, vendorDir, imports, buildConfig, copiedPackages = new Set(), baseDirAbs = projectDir) {
|
|
595
|
+
const rewrittenImports = {};
|
|
596
|
+
|
|
597
|
+
for (const [specifier, target] of Object.entries(imports ?? {})) {
|
|
598
|
+
rewrittenImports[specifier] = rewriteImportMapTarget(projectDir, vendorDir, target, buildConfig, copiedPackages, baseDirAbs);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
return rewrittenImports;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function packageExistingImportMapScopes(projectDir, vendorDir, scopes, buildConfig, copiedPackages = new Set(), baseDirAbs = projectDir) {
|
|
605
|
+
const rewrittenScopes = {};
|
|
606
|
+
|
|
607
|
+
for (const [scopeName, scopeImports] of Object.entries(scopes ?? {})) {
|
|
608
|
+
const rewrittenScopeName = rewriteImportMapScopeName(scopeName, buildConfig, baseDirAbs);
|
|
609
|
+
if (!scopeImports || typeof scopeImports !== 'object' || Array.isArray(scopeImports)) {
|
|
610
|
+
rewrittenScopes[rewrittenScopeName] = scopeImports;
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
const rewrittenScopeImports = packageExistingImportMapImports(
|
|
615
|
+
projectDir,
|
|
616
|
+
vendorDir,
|
|
617
|
+
scopeImports,
|
|
618
|
+
buildConfig,
|
|
619
|
+
copiedPackages,
|
|
620
|
+
baseDirAbs
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
rewrittenScopes[rewrittenScopeName] = {
|
|
624
|
+
...(rewrittenScopes[rewrittenScopeName] ?? {}),
|
|
625
|
+
...rewrittenScopeImports,
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
return rewrittenScopes;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
function extractImportMap(html) {
|
|
633
|
+
const importMapPattern = /<script[^>]*type=["']importmap["'][^>]*>([\s\S]*?)<\/script>/i;
|
|
634
|
+
const match = html.match(importMapPattern);
|
|
635
|
+
if (!match) {
|
|
636
|
+
return {
|
|
637
|
+
html,
|
|
638
|
+
importMap: { imports: {} },
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
let importMap = { imports: {} };
|
|
643
|
+
try {
|
|
644
|
+
const parsed = JSON.parse(match[1]);
|
|
645
|
+
if (parsed && typeof parsed === 'object') {
|
|
646
|
+
importMap = parsed;
|
|
647
|
+
}
|
|
648
|
+
} catch {
|
|
649
|
+
// Ignore invalid import maps and replace them with the packaged version.
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
return {
|
|
653
|
+
html: html.replace(match[0], '').trimEnd() + '\n',
|
|
654
|
+
importMap,
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function renderImportMapScript(importMap) {
|
|
659
|
+
const payload = JSON.stringify(importMap, null, 2)
|
|
660
|
+
.split('\n')
|
|
661
|
+
.map(line => ` ${line}`)
|
|
662
|
+
.join('\n');
|
|
663
|
+
|
|
664
|
+
return ` <script type="importmap">\n${payload}\n </script>`;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function renderModulePreloadLinks(moduleUrls) {
|
|
668
|
+
return [...new Set(moduleUrls)]
|
|
669
|
+
.sort()
|
|
670
|
+
.map((moduleUrl) => ` <link rel="modulepreload" href="${moduleUrl}">`)
|
|
671
|
+
.join('\n');
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function collectModuleSpecifierKinds(source, ts) {
|
|
675
|
+
const staticSpecifiers = new Set();
|
|
676
|
+
const dynamicSpecifiers = new Set();
|
|
677
|
+
const runtimeUrlSpecifiers = new Set();
|
|
678
|
+
const bindingExpressions = new Map();
|
|
679
|
+
const resolvedBindings = new Map();
|
|
680
|
+
const serviceWorkerAliases = new Set();
|
|
681
|
+
const navigatorAliases = new Set();
|
|
682
|
+
const serviceWorkerRegisterAliases = new Set();
|
|
683
|
+
const workerConstructorAliases = new Set();
|
|
684
|
+
let hasUnresolvedDalilaDynamicImport = false;
|
|
685
|
+
let hasUnresolvedDynamicImport = false;
|
|
686
|
+
let hasUnresolvedRuntimeUrl = false;
|
|
687
|
+
const sourceFile = ts.createSourceFile(
|
|
688
|
+
'module.js',
|
|
689
|
+
source,
|
|
690
|
+
ts.ScriptTarget.Latest,
|
|
691
|
+
true,
|
|
692
|
+
ts.ScriptKind.JS
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
const isImportMetaUrl = (node) =>
|
|
696
|
+
ts.isPropertyAccessExpression(node)
|
|
697
|
+
&& ts.isMetaProperty(node.expression)
|
|
698
|
+
&& node.expression.keywordToken === ts.SyntaxKind.ImportKeyword
|
|
699
|
+
&& node.expression.name.text === 'meta'
|
|
700
|
+
&& node.name.text === 'url';
|
|
701
|
+
|
|
702
|
+
const isImportMetaUrlAlias = (node) =>
|
|
703
|
+
ts.isIdentifier(node)
|
|
704
|
+
&& bindingExpressions.get(node.text)?.length === 1
|
|
705
|
+
&& isImportMetaUrl(bindingExpressions.get(node.text)[0]);
|
|
706
|
+
|
|
707
|
+
const isNavigatorReference = (node) =>
|
|
708
|
+
ts.isIdentifier(node)
|
|
709
|
+
&& (node.text === 'navigator' || navigatorAliases.has(node.text));
|
|
710
|
+
|
|
711
|
+
const isServiceWorkerReference = (node) =>
|
|
712
|
+
(
|
|
713
|
+
ts.isPropertyAccessExpression(node)
|
|
714
|
+
&& ts.isIdentifier(node.name)
|
|
715
|
+
&& node.name.text === 'serviceWorker'
|
|
716
|
+
&& isNavigatorReference(node.expression)
|
|
717
|
+
)
|
|
718
|
+
|| (ts.isIdentifier(node) && serviceWorkerAliases.has(node.text));
|
|
719
|
+
|
|
720
|
+
const isScopeBoundaryNode = (node) =>
|
|
721
|
+
node !== sourceFile
|
|
722
|
+
&& (
|
|
723
|
+
ts.isBlock(node)
|
|
724
|
+
|| ts.isFunctionLike(node)
|
|
725
|
+
|| ts.isClassLike(node)
|
|
726
|
+
|| ts.isModuleBlock(node)
|
|
727
|
+
);
|
|
728
|
+
|
|
729
|
+
const collectScopeDeclaredNames = (scopeNode) => {
|
|
730
|
+
const names = new Set();
|
|
731
|
+
|
|
732
|
+
const visitScopeNode = (node) => {
|
|
733
|
+
if (node !== scopeNode && isScopeBoundaryNode(node)) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
738
|
+
names.add(node.name.text);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if ((ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) && node.name && ts.isIdentifier(node.name)) {
|
|
742
|
+
names.add(node.name.text);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (ts.isParameter(node) && ts.isIdentifier(node.name)) {
|
|
746
|
+
names.add(node.name.text);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
ts.forEachChild(node, visitScopeNode);
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
visitScopeNode(scopeNode);
|
|
753
|
+
return names;
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
const resolveStringExpression = (node, options = {}) => {
|
|
757
|
+
const allowBindings = options.allowBindings !== false;
|
|
758
|
+
if (!node) {
|
|
759
|
+
return { value: null, referencesDalila: false };
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (ts.isStringLiteralLike(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
763
|
+
return {
|
|
764
|
+
value: node.text,
|
|
765
|
+
referencesDalila: node.text.includes('dalila'),
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (ts.isIdentifier(node)) {
|
|
770
|
+
const resolvedLiteral = allowBindings
|
|
771
|
+
? (resolvedBindings.get(node.text) ?? resolveBinding(node.text))
|
|
772
|
+
: null;
|
|
773
|
+
if (typeof resolvedLiteral === 'string') {
|
|
774
|
+
return {
|
|
775
|
+
value: resolvedLiteral,
|
|
776
|
+
referencesDalila: resolvedLiteral.includes('dalila'),
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
return {
|
|
781
|
+
value: null,
|
|
782
|
+
referencesDalila: node.text.toLowerCase().includes('dalila'),
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
787
|
+
return allowBindings
|
|
788
|
+
? resolveObjectProperty(node.expression, node.name.text, options)
|
|
789
|
+
: { value: null, referencesDalila: false };
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
|
|
793
|
+
const left = resolveStringExpression(node.left, options);
|
|
794
|
+
const right = resolveStringExpression(node.right, options);
|
|
795
|
+
return {
|
|
796
|
+
value: typeof left.value === 'string' && typeof right.value === 'string'
|
|
797
|
+
? `${left.value}${right.value}`
|
|
798
|
+
: null,
|
|
799
|
+
referencesDalila: left.referencesDalila || right.referencesDalila,
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
if (ts.isTemplateExpression(node)) {
|
|
804
|
+
let value = node.head.text;
|
|
805
|
+
let isFullyResolved = true;
|
|
806
|
+
let referencesDalila = node.head.text.includes('dalila');
|
|
807
|
+
|
|
808
|
+
for (const span of node.templateSpans) {
|
|
809
|
+
const expressionResult = resolveStringExpression(span.expression, options);
|
|
810
|
+
if (typeof expressionResult.value !== 'string') {
|
|
811
|
+
isFullyResolved = false;
|
|
812
|
+
} else {
|
|
813
|
+
value += expressionResult.value;
|
|
814
|
+
}
|
|
815
|
+
referencesDalila = referencesDalila || expressionResult.referencesDalila;
|
|
816
|
+
value += span.literal.text;
|
|
817
|
+
referencesDalila = referencesDalila || span.literal.text.includes('dalila');
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
return {
|
|
821
|
+
value: isFullyResolved ? value : null,
|
|
822
|
+
referencesDalila,
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
return {
|
|
827
|
+
value: null,
|
|
828
|
+
referencesDalila: node.getText(sourceFile).includes('dalila'),
|
|
829
|
+
};
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
const resolveObjectProperty = (node, propertyName, options = {}) => {
|
|
833
|
+
if (!node) {
|
|
834
|
+
return { value: null, referencesDalila: false };
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
if (ts.isParenthesizedExpression(node)) {
|
|
838
|
+
return resolveObjectProperty(node.expression, propertyName, options);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
if (ts.isIdentifier(node)) {
|
|
842
|
+
const bindingCandidates = options.allowBindings === false ? null : bindingExpressions.get(node.text);
|
|
843
|
+
if (bindingCandidates?.length === 1) {
|
|
844
|
+
return resolveObjectProperty(bindingCandidates[0], propertyName, options);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
return { value: null, referencesDalila: false };
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (!ts.isObjectLiteralExpression(node)) {
|
|
851
|
+
return { value: null, referencesDalila: false };
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
for (const property of node.properties) {
|
|
855
|
+
if (!ts.isPropertyAssignment(property) || property.name == null) {
|
|
856
|
+
continue;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
let candidateName = null;
|
|
860
|
+
if (ts.isIdentifier(property.name) || ts.isStringLiteralLike(property.name) || ts.isNumericLiteral(property.name)) {
|
|
861
|
+
candidateName = property.name.text;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if (candidateName !== propertyName) {
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
return resolveStringExpression(property.initializer, options);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
return { value: null, referencesDalila: false };
|
|
872
|
+
};
|
|
873
|
+
|
|
874
|
+
const resolveRuntimeUrlExpression = (node, options = {}) => {
|
|
875
|
+
if (!node) {
|
|
876
|
+
return { value: null, isRemote: false };
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
if (ts.isIdentifier(node)) {
|
|
880
|
+
const bindingCandidates = options.allowBindings === false ? null : bindingExpressions.get(node.text);
|
|
881
|
+
if (bindingCandidates?.length === 1) {
|
|
882
|
+
return resolveRuntimeUrlExpression(bindingCandidates[0], options);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
887
|
+
const propertyValue = resolveObjectProperty(node.expression, node.name.text, options);
|
|
888
|
+
if (typeof propertyValue.value === 'string') {
|
|
889
|
+
return { value: propertyValue.value, isRemote: false };
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
const direct = resolveStringExpression(node, options);
|
|
894
|
+
if (typeof direct.value === 'string') {
|
|
895
|
+
return { value: direct.value, isRemote: false };
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
if (ts.isNewExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === 'URL') {
|
|
899
|
+
const [firstArgument, secondArgument] = node.arguments ?? [];
|
|
900
|
+
const importMetaUrlAlias = ts.isIdentifier(secondArgument)
|
|
901
|
+
? isImportMetaUrlAlias(secondArgument)
|
|
902
|
+
: false;
|
|
903
|
+
if (!secondArgument || isImportMetaUrl(secondArgument) || importMetaUrlAlias) {
|
|
904
|
+
const resolvedArgument = resolveStringExpression(firstArgument, options);
|
|
905
|
+
if (typeof resolvedArgument.value === 'string') {
|
|
906
|
+
return { value: resolvedArgument.value, isRemote: false };
|
|
907
|
+
}
|
|
908
|
+
} else {
|
|
909
|
+
return { value: null, isRemote: true };
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
return { value: null, isRemote: false };
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
const collectBindings = (node, scopeDepth = 0) => {
|
|
917
|
+
const isScopeBoundary = node !== sourceFile && (
|
|
918
|
+
ts.isBlock(node)
|
|
919
|
+
|| ts.isFunctionLike(node)
|
|
920
|
+
|| ts.isClassLike(node)
|
|
921
|
+
|| ts.isModuleBlock(node)
|
|
922
|
+
|| ts.isSourceFile(node)
|
|
923
|
+
);
|
|
924
|
+
const nextScopeDepth = isScopeBoundary ? scopeDepth + 1 : scopeDepth;
|
|
925
|
+
|
|
926
|
+
if (scopeDepth === 0) {
|
|
927
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {
|
|
928
|
+
const expressions = bindingExpressions.get(node.name.text) ?? [];
|
|
929
|
+
expressions.push(node.initializer);
|
|
930
|
+
bindingExpressions.set(node.name.text, expressions);
|
|
931
|
+
|
|
932
|
+
if (ts.isIdentifier(node.initializer) && node.initializer.text === 'navigator') {
|
|
933
|
+
navigatorAliases.add(node.name.text);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
if (isServiceWorkerReference(node.initializer)) {
|
|
937
|
+
serviceWorkerAliases.add(node.name.text);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
if (
|
|
941
|
+
ts.isPropertyAccessExpression(node.initializer)
|
|
942
|
+
&& ts.isIdentifier(node.initializer.name)
|
|
943
|
+
&& node.initializer.name.text === 'register'
|
|
944
|
+
&& isServiceWorkerReference(node.initializer.expression)
|
|
945
|
+
) {
|
|
946
|
+
serviceWorkerRegisterAliases.add(node.name.text);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
if (
|
|
950
|
+
ts.isPropertyAccessExpression(node.initializer)
|
|
951
|
+
&& ts.isIdentifier(node.initializer.expression)
|
|
952
|
+
&& ['window', 'globalThis', 'self'].includes(node.initializer.expression.text)
|
|
953
|
+
&& ['Worker', 'SharedWorker'].includes(node.initializer.name.text)
|
|
954
|
+
) {
|
|
955
|
+
workerConstructorAliases.add(node.name.text);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
if (ts.isVariableDeclaration(node) && ts.isObjectBindingPattern(node.name) && node.initializer && ts.isIdentifier(node.initializer) && node.initializer.text === 'navigator') {
|
|
960
|
+
for (const element of node.name.elements) {
|
|
961
|
+
if (!ts.isBindingElement(element)) continue;
|
|
962
|
+
const propertyName = element.propertyName && ts.isIdentifier(element.propertyName)
|
|
963
|
+
? element.propertyName.text
|
|
964
|
+
: ts.isIdentifier(element.name)
|
|
965
|
+
? element.name.text
|
|
966
|
+
: null;
|
|
967
|
+
const aliasName = ts.isIdentifier(element.name) ? element.name.text : null;
|
|
968
|
+
if (propertyName === 'serviceWorker' && aliasName) {
|
|
969
|
+
serviceWorkerAliases.add(aliasName);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
if (ts.isVariableDeclaration(node) && ts.isObjectBindingPattern(node.name) && node.initializer && isServiceWorkerReference(node.initializer)) {
|
|
975
|
+
for (const element of node.name.elements) {
|
|
976
|
+
if (!ts.isBindingElement(element)) continue;
|
|
977
|
+
const propertyName = element.propertyName && ts.isIdentifier(element.propertyName)
|
|
978
|
+
? element.propertyName.text
|
|
979
|
+
: ts.isIdentifier(element.name)
|
|
980
|
+
? element.name.text
|
|
981
|
+
: null;
|
|
982
|
+
const aliasName = ts.isIdentifier(element.name) ? element.name.text : null;
|
|
983
|
+
if (propertyName === 'register' && aliasName) {
|
|
984
|
+
serviceWorkerRegisterAliases.add(aliasName);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
if (
|
|
990
|
+
ts.isVariableDeclaration(node)
|
|
991
|
+
&& ts.isObjectBindingPattern(node.name)
|
|
992
|
+
&& node.initializer
|
|
993
|
+
&& ts.isIdentifier(node.initializer)
|
|
994
|
+
&& navigatorAliases.has(node.initializer.text)
|
|
995
|
+
) {
|
|
996
|
+
for (const element of node.name.elements) {
|
|
997
|
+
if (!ts.isBindingElement(element)) continue;
|
|
998
|
+
const propertyName = element.propertyName && ts.isIdentifier(element.propertyName)
|
|
999
|
+
? element.propertyName.text
|
|
1000
|
+
: ts.isIdentifier(element.name)
|
|
1001
|
+
? element.name.text
|
|
1002
|
+
: null;
|
|
1003
|
+
const aliasName = ts.isIdentifier(element.name) ? element.name.text : null;
|
|
1004
|
+
if (propertyName === 'serviceWorker' && aliasName) {
|
|
1005
|
+
serviceWorkerAliases.add(aliasName);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
if (
|
|
1011
|
+
ts.isVariableDeclaration(node)
|
|
1012
|
+
&& ts.isObjectBindingPattern(node.name)
|
|
1013
|
+
&& node.initializer
|
|
1014
|
+
&& ts.isIdentifier(node.initializer)
|
|
1015
|
+
&& ['window', 'globalThis', 'self'].includes(node.initializer.text)
|
|
1016
|
+
) {
|
|
1017
|
+
for (const element of node.name.elements) {
|
|
1018
|
+
if (!ts.isBindingElement(element)) continue;
|
|
1019
|
+
const propertyName = element.propertyName && ts.isIdentifier(element.propertyName)
|
|
1020
|
+
? element.propertyName.text
|
|
1021
|
+
: ts.isIdentifier(element.name)
|
|
1022
|
+
? element.name.text
|
|
1023
|
+
: null;
|
|
1024
|
+
const aliasName = ts.isIdentifier(element.name) ? element.name.text : null;
|
|
1025
|
+
if (aliasName && ['Worker', 'SharedWorker'].includes(propertyName)) {
|
|
1026
|
+
workerConstructorAliases.add(aliasName);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isIdentifier(node.left)) {
|
|
1032
|
+
const expressions = bindingExpressions.get(node.left.text) ?? [];
|
|
1033
|
+
expressions.push(node.right);
|
|
1034
|
+
bindingExpressions.set(node.left.text, expressions);
|
|
1035
|
+
|
|
1036
|
+
if (ts.isIdentifier(node.right) && node.right.text === 'navigator') {
|
|
1037
|
+
navigatorAliases.add(node.left.text);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
ts.forEachChild(node, (child) => collectBindings(child, nextScopeDepth));
|
|
1043
|
+
};
|
|
1044
|
+
|
|
1045
|
+
const resolutionStack = new Set();
|
|
1046
|
+
const bindingReferencesDalila = (name) => {
|
|
1047
|
+
const bindingCandidates = bindingExpressions.get(name);
|
|
1048
|
+
if (!bindingCandidates || bindingCandidates.length === 0) {
|
|
1049
|
+
return false;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
return bindingCandidates.some((bindingExpression) => resolveStringExpression(bindingExpression).referencesDalila);
|
|
1053
|
+
};
|
|
1054
|
+
|
|
1055
|
+
const resolveBinding = (name) => {
|
|
1056
|
+
if (resolvedBindings.has(name)) {
|
|
1057
|
+
return resolvedBindings.get(name) ?? null;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
if (resolutionStack.has(name)) {
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
const bindingCandidates = bindingExpressions.get(name);
|
|
1065
|
+
if (!bindingCandidates || bindingCandidates.length === 0) {
|
|
1066
|
+
return null;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
resolutionStack.add(name);
|
|
1070
|
+
const resolvedValues = new Set();
|
|
1071
|
+
let hasAmbiguity = false;
|
|
1072
|
+
|
|
1073
|
+
for (const bindingExpression of bindingCandidates) {
|
|
1074
|
+
const resolved = resolveStringExpression(bindingExpression);
|
|
1075
|
+
if (typeof resolved.value === 'string') {
|
|
1076
|
+
resolvedValues.add(resolved.value);
|
|
1077
|
+
} else {
|
|
1078
|
+
hasAmbiguity = true;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
resolutionStack.delete(name);
|
|
1082
|
+
|
|
1083
|
+
if (!hasAmbiguity && resolvedValues.size === 1) {
|
|
1084
|
+
const [resolvedValue] = resolvedValues;
|
|
1085
|
+
resolvedBindings.set(name, resolvedValue);
|
|
1086
|
+
return resolvedValue;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
return null;
|
|
1090
|
+
};
|
|
1091
|
+
|
|
1092
|
+
const visit = (node, scopeDepth = 0, scopeDeclarations = []) => {
|
|
1093
|
+
const nestedScope = isScopeBoundaryNode(node);
|
|
1094
|
+
const nextScopeDepth = nestedScope ? scopeDepth + 1 : scopeDepth;
|
|
1095
|
+
const nextScopeDeclarations = nestedScope
|
|
1096
|
+
? [...scopeDeclarations, collectScopeDeclaredNames(node)]
|
|
1097
|
+
: scopeDeclarations;
|
|
1098
|
+
|
|
1099
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {
|
|
1100
|
+
const resolvedLiteral = resolveBinding(node.name.text);
|
|
1101
|
+
if (typeof resolvedLiteral === 'string') {
|
|
1102
|
+
resolvedBindings.set(node.name.text, resolvedLiteral);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && node.moduleSpecifier && ts.isStringLiteralLike(node.moduleSpecifier)) {
|
|
1107
|
+
staticSpecifiers.add(node.moduleSpecifier.text);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
|
1111
|
+
const [firstArgument] = node.arguments;
|
|
1112
|
+
if (firstArgument) {
|
|
1113
|
+
const localShadowed = ts.isIdentifier(firstArgument)
|
|
1114
|
+
&& nextScopeDeclarations.some((declaredNames) => declaredNames.has(firstArgument.text));
|
|
1115
|
+
const importArg = resolveStringExpression(firstArgument, {
|
|
1116
|
+
allowBindings: scopeDepth === 0 && !localShadowed,
|
|
1117
|
+
});
|
|
1118
|
+
if (typeof importArg.value === 'string') {
|
|
1119
|
+
dynamicSpecifiers.add(importArg.value);
|
|
1120
|
+
} else if (importArg.referencesDalila) {
|
|
1121
|
+
hasUnresolvedDalilaDynamicImport = true;
|
|
1122
|
+
hasUnresolvedDynamicImport = true;
|
|
1123
|
+
} else {
|
|
1124
|
+
if (!localShadowed && ts.isIdentifier(firstArgument)) {
|
|
1125
|
+
const resolvedTopLevel = resolveBinding(firstArgument.text);
|
|
1126
|
+
if (typeof resolvedTopLevel === 'string' && resolvedTopLevel.startsWith('dalila')) {
|
|
1127
|
+
hasUnresolvedDalilaDynamicImport = true;
|
|
1128
|
+
} else if (bindingReferencesDalila(firstArgument.text)) {
|
|
1129
|
+
hasUnresolvedDalilaDynamicImport = true;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
hasUnresolvedDynamicImport = true;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
if (
|
|
1138
|
+
ts.isCallExpression(node)
|
|
1139
|
+
&& ts.isPropertyAccessExpression(node.expression)
|
|
1140
|
+
&& node.expression.name.text === 'register'
|
|
1141
|
+
&& (
|
|
1142
|
+
(
|
|
1143
|
+
ts.isPropertyAccessExpression(node.expression.expression)
|
|
1144
|
+
&& ts.isIdentifier(node.expression.expression.name)
|
|
1145
|
+
&& node.expression.expression.name.text === 'serviceWorker'
|
|
1146
|
+
&& ts.isIdentifier(node.expression.expression.expression)
|
|
1147
|
+
&& (
|
|
1148
|
+
node.expression.expression.expression.text === 'navigator'
|
|
1149
|
+
|| navigatorAliases.has(node.expression.expression.expression.text)
|
|
1150
|
+
)
|
|
1151
|
+
)
|
|
1152
|
+
|| (ts.isIdentifier(node.expression.expression) && serviceWorkerAliases.has(node.expression.expression.text))
|
|
1153
|
+
)
|
|
1154
|
+
) {
|
|
1155
|
+
const localShadowed = ts.isIdentifier(node.arguments[0])
|
|
1156
|
+
&& nextScopeDeclarations.some((declaredNames) => declaredNames.has(node.arguments[0].text));
|
|
1157
|
+
const runtimeUrl = resolveRuntimeUrlExpression(node.arguments[0], {
|
|
1158
|
+
allowBindings: scopeDepth === 0 && !localShadowed,
|
|
1159
|
+
});
|
|
1160
|
+
if (runtimeUrl.value) {
|
|
1161
|
+
runtimeUrlSpecifiers.add(runtimeUrl.value);
|
|
1162
|
+
} else if (node.arguments[0] && !runtimeUrl.isRemote) {
|
|
1163
|
+
hasUnresolvedRuntimeUrl = true;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
if (
|
|
1168
|
+
ts.isCallExpression(node)
|
|
1169
|
+
&& ts.isIdentifier(node.expression)
|
|
1170
|
+
&& serviceWorkerRegisterAliases.has(node.expression.text)
|
|
1171
|
+
) {
|
|
1172
|
+
const localShadowed = ts.isIdentifier(node.arguments[0])
|
|
1173
|
+
&& nextScopeDeclarations.some((declaredNames) => declaredNames.has(node.arguments[0].text));
|
|
1174
|
+
const runtimeUrl = resolveRuntimeUrlExpression(node.arguments[0], {
|
|
1175
|
+
allowBindings: scopeDepth === 0 && !localShadowed,
|
|
1176
|
+
});
|
|
1177
|
+
if (runtimeUrl.value) {
|
|
1178
|
+
runtimeUrlSpecifiers.add(runtimeUrl.value);
|
|
1179
|
+
} else if (node.arguments[0] && !runtimeUrl.isRemote) {
|
|
1180
|
+
hasUnresolvedRuntimeUrl = true;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
if (
|
|
1185
|
+
ts.isCallExpression(node)
|
|
1186
|
+
&& (
|
|
1187
|
+
(ts.isIdentifier(node.expression) && node.expression.text === 'importScripts')
|
|
1188
|
+
|| (
|
|
1189
|
+
ts.isPropertyAccessExpression(node.expression)
|
|
1190
|
+
&& ts.isIdentifier(node.expression.expression)
|
|
1191
|
+
&& node.expression.expression.text === 'self'
|
|
1192
|
+
&& node.expression.name.text === 'importScripts'
|
|
1193
|
+
)
|
|
1194
|
+
)
|
|
1195
|
+
) {
|
|
1196
|
+
for (const argument of node.arguments) {
|
|
1197
|
+
const localShadowed = ts.isIdentifier(argument)
|
|
1198
|
+
&& nextScopeDeclarations.some((declaredNames) => declaredNames.has(argument.text));
|
|
1199
|
+
const runtimeUrl = resolveRuntimeUrlExpression(argument, {
|
|
1200
|
+
allowBindings: scopeDepth === 0 && !localShadowed,
|
|
1201
|
+
});
|
|
1202
|
+
if (runtimeUrl.value) {
|
|
1203
|
+
runtimeUrlSpecifiers.add(runtimeUrl.value);
|
|
1204
|
+
} else if (!runtimeUrl.isRemote) {
|
|
1205
|
+
hasUnresolvedRuntimeUrl = true;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
const isWorkerConstructor = ts.isNewExpression(node) && (
|
|
1211
|
+
(ts.isIdentifier(node.expression) && ['Worker', 'SharedWorker'].includes(node.expression.text))
|
|
1212
|
+
|| (ts.isIdentifier(node.expression) && workerConstructorAliases.has(node.expression.text))
|
|
1213
|
+
|| (
|
|
1214
|
+
ts.isPropertyAccessExpression(node.expression)
|
|
1215
|
+
&& ts.isIdentifier(node.expression.expression)
|
|
1216
|
+
&& ['window', 'globalThis', 'self'].includes(node.expression.expression.text)
|
|
1217
|
+
&& ['Worker', 'SharedWorker'].includes(node.expression.name.text)
|
|
1218
|
+
)
|
|
1219
|
+
);
|
|
1220
|
+
|
|
1221
|
+
if (isWorkerConstructor) {
|
|
1222
|
+
const localShadowed = ts.isIdentifier(node.arguments?.[0])
|
|
1223
|
+
&& nextScopeDeclarations.some((declaredNames) => declaredNames.has(node.arguments[0].text));
|
|
1224
|
+
const runtimeUrl = resolveRuntimeUrlExpression(node.arguments?.[0], {
|
|
1225
|
+
allowBindings: scopeDepth === 0 && !localShadowed,
|
|
1226
|
+
});
|
|
1227
|
+
if (runtimeUrl.value) {
|
|
1228
|
+
runtimeUrlSpecifiers.add(runtimeUrl.value);
|
|
1229
|
+
} else if (node.arguments?.[0] && !runtimeUrl.isRemote) {
|
|
1230
|
+
hasUnresolvedRuntimeUrl = true;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
ts.forEachChild(node, (child) => visit(child, nextScopeDepth, nextScopeDeclarations));
|
|
1235
|
+
};
|
|
1236
|
+
|
|
1237
|
+
ts.forEachChild(sourceFile, (child) => collectBindings(child, 0));
|
|
1238
|
+
ts.forEachChild(sourceFile, (child) => visit(child, 0, []));
|
|
1239
|
+
return {
|
|
1240
|
+
staticSpecifiers: [...staticSpecifiers],
|
|
1241
|
+
dynamicSpecifiers: [...dynamicSpecifiers],
|
|
1242
|
+
runtimeUrlSpecifiers: [...runtimeUrlSpecifiers],
|
|
1243
|
+
allSpecifiers: [...new Set([...staticSpecifiers, ...dynamicSpecifiers])],
|
|
1244
|
+
hasUnresolvedDalilaDynamicImport,
|
|
1245
|
+
hasUnresolvedDynamicImport,
|
|
1246
|
+
hasUnresolvedRuntimeUrl,
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
function resolveRelativeUrl(specifier, referrerUrl) {
|
|
1251
|
+
const resolvedUrl = new URL(specifier, new URL(referrerUrl, 'https://dalila.local'));
|
|
1252
|
+
return `${resolvedUrl.pathname}${resolvedUrl.search}${resolvedUrl.hash}`;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
function resolveImportMapMatch(specifier, imports = {}) {
|
|
1256
|
+
if (typeof imports[specifier] === 'string') {
|
|
1257
|
+
return imports[specifier];
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
let bestPrefix = null;
|
|
1261
|
+
for (const [prefix, target] of Object.entries(imports)) {
|
|
1262
|
+
if (typeof target !== 'string' || !prefix.endsWith('/')) {
|
|
1263
|
+
continue;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
if (!specifier.startsWith(prefix)) {
|
|
1267
|
+
continue;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
if (!bestPrefix || prefix.length > bestPrefix.length) {
|
|
1271
|
+
bestPrefix = prefix;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
if (!bestPrefix) {
|
|
1276
|
+
return null;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
const target = imports[bestPrefix];
|
|
1280
|
+
if (typeof target !== 'string') {
|
|
1281
|
+
return null;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
return `${target}${specifier.slice(bestPrefix.length)}`;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
function resolveImportMapSpecifier(specifier, importMap, referrerUrl) {
|
|
1288
|
+
const scopes = importMap?.scopes ?? {};
|
|
1289
|
+
let bestScope = null;
|
|
1290
|
+
|
|
1291
|
+
for (const scopeName of Object.keys(scopes)) {
|
|
1292
|
+
if (!referrerUrl.startsWith(scopeName)) {
|
|
1293
|
+
continue;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
if (!bestScope || scopeName.length > bestScope.length) {
|
|
1297
|
+
bestScope = scopeName;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
if (bestScope) {
|
|
1302
|
+
const scopedMatch = resolveImportMapMatch(specifier, scopes[bestScope]);
|
|
1303
|
+
if (scopedMatch) {
|
|
1304
|
+
return scopedMatch;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
return resolveImportMapMatch(specifier, importMap?.imports ?? {});
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
function resolveSpecifierToPackagedUrl(specifier, referrerUrl, importMap, importMapBaseUrl = referrerUrl) {
|
|
1312
|
+
if (isUrlWithScheme(specifier) || specifier.startsWith('//')) {
|
|
1313
|
+
return null;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
if (specifier.startsWith('/') || specifier.startsWith('./') || specifier.startsWith('../')) {
|
|
1317
|
+
return resolveRelativeUrl(specifier, referrerUrl);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
const mappedTarget = resolveImportMapSpecifier(specifier, importMap, referrerUrl);
|
|
1321
|
+
if (!mappedTarget) {
|
|
1322
|
+
return null;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
if (isUrlWithScheme(mappedTarget) || mappedTarget.startsWith('//')) {
|
|
1326
|
+
return null;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
if (mappedTarget.startsWith('/') || mappedTarget.startsWith('./') || mappedTarget.startsWith('../')) {
|
|
1330
|
+
return resolveRelativeUrl(mappedTarget, importMapBaseUrl);
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
return mappedTarget;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
function isJavaScriptModuleUrl(moduleUrl) {
|
|
1337
|
+
return JAVASCRIPT_EXTENSIONS.has(path.extname(splitUrlTarget(moduleUrl).pathname));
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
function collectHtmlModuleEntries(html, htmlUrl, ts) {
|
|
1341
|
+
const entryModuleUrls = new Set();
|
|
1342
|
+
const classicScriptUrls = new Set();
|
|
1343
|
+
const inlineModuleSpecifiers = new Set();
|
|
1344
|
+
const inlineStaticModuleSpecifiers = new Set();
|
|
1345
|
+
const inlineRuntimeUrlSpecifiers = new Set();
|
|
1346
|
+
let requiresFullDalilaImportMap = false;
|
|
1347
|
+
let hasUnresolvedDynamicImport = false;
|
|
1348
|
+
let hasUnresolvedRuntimeUrl = false;
|
|
1349
|
+
|
|
1350
|
+
html.replace(/<script\b([^>]*)>([\s\S]*?)<\/script>/gi, (fullMatch, attrs, content) => {
|
|
1351
|
+
const typeMatch = attrs.match(/\btype=["']([^"']+)["']/i);
|
|
1352
|
+
const srcMatch = attrs.match(/\bsrc=["']([^"']+)["']/i);
|
|
1353
|
+
if (!typeMatch || typeMatch[1] !== 'module') {
|
|
1354
|
+
if (srcMatch) {
|
|
1355
|
+
const classicScriptUrl = resolveSpecifierToPackagedUrl(srcMatch[1], htmlUrl, { imports: {}, scopes: {} });
|
|
1356
|
+
if (classicScriptUrl && isJavaScriptModuleUrl(classicScriptUrl)) {
|
|
1357
|
+
classicScriptUrls.add(classicScriptUrl);
|
|
1358
|
+
}
|
|
1359
|
+
} else if (content.trim()) {
|
|
1360
|
+
const collectedClassicSpecifiers = collectModuleSpecifierKinds(content, ts);
|
|
1361
|
+
for (const specifier of collectedClassicSpecifiers.allSpecifiers) {
|
|
1362
|
+
inlineModuleSpecifiers.add(specifier);
|
|
1363
|
+
}
|
|
1364
|
+
for (const runtimeUrlSpecifier of collectedClassicSpecifiers.runtimeUrlSpecifiers ?? []) {
|
|
1365
|
+
inlineRuntimeUrlSpecifiers.add(runtimeUrlSpecifier);
|
|
1366
|
+
}
|
|
1367
|
+
if (collectedClassicSpecifiers.hasUnresolvedDalilaDynamicImport) {
|
|
1368
|
+
requiresFullDalilaImportMap = true;
|
|
1369
|
+
}
|
|
1370
|
+
if (collectedClassicSpecifiers.hasUnresolvedDynamicImport) {
|
|
1371
|
+
hasUnresolvedDynamicImport = true;
|
|
1372
|
+
}
|
|
1373
|
+
if (collectedClassicSpecifiers.hasUnresolvedRuntimeUrl) {
|
|
1374
|
+
hasUnresolvedRuntimeUrl = true;
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
return fullMatch;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
if (srcMatch) {
|
|
1381
|
+
const entryModuleUrl = resolveSpecifierToPackagedUrl(srcMatch[1], htmlUrl, { imports: {}, scopes: {} });
|
|
1382
|
+
if (entryModuleUrl) {
|
|
1383
|
+
entryModuleUrls.add(entryModuleUrl);
|
|
1384
|
+
}
|
|
1385
|
+
return fullMatch;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
const collectedSpecifiers = collectModuleSpecifierKinds(content, ts);
|
|
1389
|
+
for (const specifier of collectedSpecifiers.allSpecifiers) {
|
|
1390
|
+
inlineModuleSpecifiers.add(specifier);
|
|
1391
|
+
}
|
|
1392
|
+
for (const specifier of collectedSpecifiers.staticSpecifiers) {
|
|
1393
|
+
inlineStaticModuleSpecifiers.add(specifier);
|
|
1394
|
+
}
|
|
1395
|
+
for (const runtimeUrlSpecifier of collectedSpecifiers.runtimeUrlSpecifiers ?? []) {
|
|
1396
|
+
inlineRuntimeUrlSpecifiers.add(runtimeUrlSpecifier);
|
|
1397
|
+
}
|
|
1398
|
+
if (collectedSpecifiers.hasUnresolvedDalilaDynamicImport) {
|
|
1399
|
+
requiresFullDalilaImportMap = true;
|
|
1400
|
+
}
|
|
1401
|
+
if (collectedSpecifiers.hasUnresolvedDynamicImport) {
|
|
1402
|
+
hasUnresolvedDynamicImport = true;
|
|
1403
|
+
}
|
|
1404
|
+
if (collectedSpecifiers.hasUnresolvedRuntimeUrl) {
|
|
1405
|
+
hasUnresolvedRuntimeUrl = true;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
return fullMatch;
|
|
1409
|
+
});
|
|
1410
|
+
|
|
1411
|
+
return {
|
|
1412
|
+
classicScriptUrls: [...classicScriptUrls],
|
|
1413
|
+
entryModuleUrls: [...entryModuleUrls],
|
|
1414
|
+
inlineModuleSpecifiers: [...inlineModuleSpecifiers],
|
|
1415
|
+
inlineStaticModuleSpecifiers: [...inlineStaticModuleSpecifiers],
|
|
1416
|
+
inlineRuntimeUrlSpecifiers: [...inlineRuntimeUrlSpecifiers],
|
|
1417
|
+
requiresFullDalilaImportMap,
|
|
1418
|
+
hasUnresolvedDynamicImport,
|
|
1419
|
+
hasUnresolvedRuntimeUrl,
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
function collectImportMapModuleUrls(importMap, htmlUrl) {
|
|
1424
|
+
const moduleUrls = new Set();
|
|
1425
|
+
|
|
1426
|
+
const addTarget = (target) => {
|
|
1427
|
+
if (typeof target !== 'string') {
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
const moduleUrl = resolveSpecifierToPackagedUrl(target, htmlUrl, { imports: {}, scopes: {} });
|
|
1432
|
+
if (moduleUrl && isJavaScriptModuleUrl(moduleUrl)) {
|
|
1433
|
+
moduleUrls.add(moduleUrl);
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1437
|
+
for (const target of Object.values(importMap?.imports ?? {})) {
|
|
1438
|
+
addTarget(target);
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
for (const scopeImports of Object.values(importMap?.scopes ?? {})) {
|
|
1442
|
+
if (!scopeImports || typeof scopeImports !== 'object' || Array.isArray(scopeImports)) {
|
|
1443
|
+
continue;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
for (const target of Object.values(scopeImports)) {
|
|
1447
|
+
addTarget(target);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
return [...moduleUrls];
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
function resolvePackagedModuleSourcePath(moduleUrl, buildConfig, dalilaRoot) {
|
|
1455
|
+
const { pathname } = splitUrlTarget(moduleUrl);
|
|
1456
|
+
|
|
1457
|
+
if (pathname.startsWith('/vendor/dalila/')) {
|
|
1458
|
+
return path.join(dalilaRoot, 'dist', pathname.slice('/vendor/dalila/'.length));
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
if (pathname.startsWith('/vendor/node_modules/')) {
|
|
1462
|
+
return path.join(buildConfig.projectDir, 'node_modules', pathname.slice('/vendor/node_modules/'.length));
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
const packagedPath = path.join(buildConfig.packageOutDirAbs, pathname.slice(1));
|
|
1466
|
+
if (fs.existsSync(packagedPath)) {
|
|
1467
|
+
return packagedPath;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
return path.join(buildConfig.projectDir, pathname.slice(1));
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
function traceReachableModules(page, importMap, buildConfig, dalilaRoot) {
|
|
1474
|
+
const reachableModuleUrls = new Set();
|
|
1475
|
+
const staticReachableModuleUrls = new Set();
|
|
1476
|
+
const usedDalilaSpecifiers = new Set();
|
|
1477
|
+
const classicScriptUrlSet = new Set(page.classicScriptUrls ?? []);
|
|
1478
|
+
const pendingUrls = [];
|
|
1479
|
+
const pendingKeys = new Set();
|
|
1480
|
+
const processedKeys = new Set();
|
|
1481
|
+
let requiresFullDalilaImportMap = page.requiresFullDalilaImportMap === true;
|
|
1482
|
+
let hasUnresolvedDynamicImport = page.hasUnresolvedDynamicImport === true;
|
|
1483
|
+
let hasUnresolvedRuntimeUrl = page.hasUnresolvedRuntimeUrl === true;
|
|
1484
|
+
|
|
1485
|
+
const enqueueResolvedUrl = (moduleUrl, isStatic = false) => {
|
|
1486
|
+
if (!moduleUrl || !isJavaScriptModuleUrl(moduleUrl)) {
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
const queueKey = `${moduleUrl}::${isStatic ? 'static' : 'dynamic'}`;
|
|
1491
|
+
if (processedKeys.has(queueKey) || pendingKeys.has(queueKey)) {
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
if (reachableModuleUrls.has(moduleUrl) && isStatic) {
|
|
1496
|
+
staticReachableModuleUrls.add(moduleUrl);
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
pendingUrls.push({ moduleUrl, isStatic });
|
|
1500
|
+
pendingKeys.add(queueKey);
|
|
1501
|
+
};
|
|
1502
|
+
|
|
1503
|
+
for (const entryModuleUrl of page.entryModuleUrls) {
|
|
1504
|
+
enqueueResolvedUrl(entryModuleUrl, true);
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
for (const classicScriptUrl of page.classicScriptUrls ?? []) {
|
|
1508
|
+
enqueueResolvedUrl(classicScriptUrl, false);
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
for (const specifier of page.inlineModuleSpecifiers) {
|
|
1512
|
+
if (specifier === 'dalila' || specifier.startsWith('dalila/')) {
|
|
1513
|
+
usedDalilaSpecifiers.add(specifier);
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
const isStatic = page.inlineStaticModuleSpecifiers?.includes(specifier) ?? false;
|
|
1517
|
+
enqueueResolvedUrl(resolveSpecifierToPackagedUrl(specifier, page.htmlUrl, importMap, page.htmlUrl), isStatic);
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
for (const runtimeUrlSpecifier of page.inlineRuntimeUrlSpecifiers ?? []) {
|
|
1521
|
+
enqueueResolvedUrl(resolveSpecifierToPackagedUrl(runtimeUrlSpecifier, page.htmlUrl, importMap, page.htmlUrl), false);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
while (pendingUrls.length > 0) {
|
|
1525
|
+
const pending = pendingUrls.pop();
|
|
1526
|
+
const moduleUrl = pending?.moduleUrl;
|
|
1527
|
+
const isStaticRoot = pending?.isStatic === true;
|
|
1528
|
+
const queueKey = moduleUrl ? `${moduleUrl}::${isStaticRoot ? 'static' : 'dynamic'}` : null;
|
|
1529
|
+
if (queueKey) {
|
|
1530
|
+
pendingKeys.delete(queueKey);
|
|
1531
|
+
}
|
|
1532
|
+
if (!moduleUrl) {
|
|
1533
|
+
continue;
|
|
1534
|
+
}
|
|
1535
|
+
if (queueKey && processedKeys.has(queueKey)) {
|
|
1536
|
+
continue;
|
|
1537
|
+
}
|
|
1538
|
+
if (queueKey) {
|
|
1539
|
+
processedKeys.add(queueKey);
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
const sourcePath = resolvePackagedModuleSourcePath(moduleUrl, buildConfig, dalilaRoot);
|
|
1543
|
+
ensureFileExists(sourcePath, `module dependency "${moduleUrl}"`);
|
|
1544
|
+
reachableModuleUrls.add(moduleUrl);
|
|
1545
|
+
if (isStaticRoot) {
|
|
1546
|
+
staticReachableModuleUrls.add(moduleUrl);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
const source = fs.readFileSync(sourcePath, 'utf8');
|
|
1550
|
+
const collectedSpecifiers = collectModuleSpecifierKinds(source, buildConfig.ts);
|
|
1551
|
+
if (collectedSpecifiers.hasUnresolvedDalilaDynamicImport) {
|
|
1552
|
+
requiresFullDalilaImportMap = true;
|
|
1553
|
+
}
|
|
1554
|
+
if (collectedSpecifiers.hasUnresolvedDynamicImport) {
|
|
1555
|
+
hasUnresolvedDynamicImport = true;
|
|
1556
|
+
}
|
|
1557
|
+
if (collectedSpecifiers.hasUnresolvedRuntimeUrl) {
|
|
1558
|
+
hasUnresolvedRuntimeUrl = true;
|
|
1559
|
+
}
|
|
1560
|
+
for (const specifier of collectedSpecifiers.allSpecifiers) {
|
|
1561
|
+
if (specifier === 'dalila' || specifier.startsWith('dalila/')) {
|
|
1562
|
+
usedDalilaSpecifiers.add(specifier);
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
const isStaticDependency = isStaticRoot && collectedSpecifiers.staticSpecifiers.includes(specifier);
|
|
1566
|
+
enqueueResolvedUrl(resolveSpecifierToPackagedUrl(specifier, moduleUrl, importMap, page.htmlUrl), isStaticDependency);
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
const runtimeSpecifierBaseUrl = classicScriptUrlSet.has(moduleUrl) ? page.htmlUrl : moduleUrl;
|
|
1570
|
+
for (const runtimeUrlSpecifier of collectedSpecifiers.runtimeUrlSpecifiers ?? []) {
|
|
1571
|
+
enqueueResolvedUrl(resolveSpecifierToPackagedUrl(runtimeUrlSpecifier, runtimeSpecifierBaseUrl, importMap, page.htmlUrl), false);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
return {
|
|
1576
|
+
reachableModuleUrls,
|
|
1577
|
+
staticReachableModuleUrls,
|
|
1578
|
+
usedDalilaSpecifiers,
|
|
1579
|
+
requiresFullDalilaImportMap,
|
|
1580
|
+
hasUnresolvedDynamicImport,
|
|
1581
|
+
hasUnresolvedRuntimeUrl,
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
function copyReachableDalilaModules(reachableModuleUrls, packageOutDirAbs, dalilaRoot) {
|
|
1586
|
+
for (const moduleUrl of reachableModuleUrls) {
|
|
1587
|
+
const { pathname } = splitUrlTarget(moduleUrl);
|
|
1588
|
+
if (!pathname.startsWith('/vendor/dalila/')) {
|
|
1589
|
+
continue;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
const sourcePath = path.join(dalilaRoot, 'dist', pathname.slice('/vendor/dalila/'.length));
|
|
1593
|
+
const destinationPath = path.join(packageOutDirAbs, pathname.slice(1));
|
|
1594
|
+
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
|
|
1595
|
+
fs.copyFileSync(sourcePath, destinationPath);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
function copyDalilaModuleClosure(moduleUrls, packageOutDirAbs, dalilaRoot, ts) {
|
|
1600
|
+
const pendingUrls = [...moduleUrls];
|
|
1601
|
+
const copiedUrls = new Set();
|
|
1602
|
+
|
|
1603
|
+
while (pendingUrls.length > 0) {
|
|
1604
|
+
const moduleUrl = pendingUrls.pop();
|
|
1605
|
+
const { pathname } = splitUrlTarget(moduleUrl);
|
|
1606
|
+
if (!pathname.startsWith('/vendor/dalila/') || copiedUrls.has(moduleUrl)) {
|
|
1607
|
+
continue;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
copiedUrls.add(moduleUrl);
|
|
1611
|
+
const sourcePath = path.join(dalilaRoot, 'dist', pathname.slice('/vendor/dalila/'.length));
|
|
1612
|
+
ensureFileExists(sourcePath, `dalila module "${moduleUrl}"`);
|
|
1613
|
+
const destinationPath = path.join(packageOutDirAbs, pathname.slice(1));
|
|
1614
|
+
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
|
|
1615
|
+
fs.copyFileSync(sourcePath, destinationPath);
|
|
1616
|
+
|
|
1617
|
+
const source = fs.readFileSync(sourcePath, 'utf8');
|
|
1618
|
+
const collectedSpecifiers = collectModuleSpecifierKinds(source, ts);
|
|
1619
|
+
for (const specifier of collectedSpecifiers.allSpecifiers) {
|
|
1620
|
+
const resolvedUrl = resolveSpecifierToPackagedUrl(specifier, moduleUrl, { imports: {}, scopes: {} });
|
|
1621
|
+
if (resolvedUrl?.startsWith('/vendor/dalila/')) {
|
|
1622
|
+
pendingUrls.push(resolvedUrl);
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
function prunePackagedCompiledArtifacts(
|
|
1629
|
+
buildConfig,
|
|
1630
|
+
_reachableModuleUrls,
|
|
1631
|
+
copiedSourceAssetPaths = new Set(),
|
|
1632
|
+
_preserveCompiledJavaScript = false
|
|
1633
|
+
) {
|
|
1634
|
+
for (const filePath of walkFiles(buildConfig.packageOutDirAbs)) {
|
|
1635
|
+
const relativePath = path.relative(buildConfig.packageOutDirAbs, filePath);
|
|
1636
|
+
if (!isRelativePathInsideBase(relativePath)) {
|
|
1637
|
+
continue;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
if (relativePath.startsWith(`vendor${path.sep}`) || relativePath === 'vendor') {
|
|
1641
|
+
continue;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
if (copiedSourceAssetPaths.has(filePath)) {
|
|
1645
|
+
continue;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
if (TYPE_ARTIFACT_EXTENSIONS.some((extension) => filePath.endsWith(extension))) {
|
|
1649
|
+
fs.rmSync(filePath, { force: true });
|
|
1650
|
+
continue;
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
function pickDalilaImportEntries(dalilaImportEntries, usedDalilaSpecifiers, requiresFullDalilaImportMap = false) {
|
|
1656
|
+
if (requiresFullDalilaImportMap) {
|
|
1657
|
+
return { ...dalilaImportEntries };
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
if (usedDalilaSpecifiers.size === 0) {
|
|
1661
|
+
return {};
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
const selectedEntries = {};
|
|
1665
|
+
for (const specifier of usedDalilaSpecifiers) {
|
|
1666
|
+
if (dalilaImportEntries[specifier]) {
|
|
1667
|
+
selectedEntries[specifier] = dalilaImportEntries[specifier];
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
return selectedEntries;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
function copyDalilaImportEntryTargets(importEntries, packageOutDirAbs, dalilaRoot, ts) {
|
|
1675
|
+
const dalilaModuleUrls = Object.values(importEntries)
|
|
1676
|
+
.filter((target) => typeof target === 'string' && target.startsWith('/vendor/dalila/'));
|
|
1677
|
+
copyDalilaModuleClosure(dalilaModuleUrls, packageOutDirAbs, dalilaRoot, ts);
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
function shouldPackageHtmlEntry(source) {
|
|
1681
|
+
return /<script[^>]*type=["']module["'][^>]*>/i.test(source)
|
|
1682
|
+
|| /<script[^>]*\bsrc=["'][^"']+\.(?:js|mjs|cjs)(?:[?#][^"']*)?["'][^>]*>/i.test(source)
|
|
1683
|
+
|| /<script\b(?![^>]*type=["'](?:module|importmap)["'])[^>]*>[\s\S]*?\bimport\s*\(/i.test(source)
|
|
1684
|
+
|| /<script\b(?![^>]*type=["']importmap["'])[^>]*>[\s\S]*?(?:\bimportScripts\s*\(|\bnew\s+(?:SharedWorker|Worker)\s*\(|\.serviceWorker\s*\.\s*register\s*\()/i.test(source)
|
|
1685
|
+
|| /<script[^>]*type=["']importmap["'][^>]*>/i.test(source);
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
function injectHeadContent(html, fragments) {
|
|
1689
|
+
const content = fragments.filter(Boolean).join('\n');
|
|
1690
|
+
if (!content) return html;
|
|
1691
|
+
|
|
1692
|
+
const headOpenMatch = html.match(/<head\b[^>]*>/i);
|
|
1693
|
+
const headCloseMatch = html.match(/<\/head>/i);
|
|
1694
|
+
if (!headOpenMatch || headOpenMatch.index == null || !headCloseMatch || headCloseMatch.index == null) {
|
|
1695
|
+
return `${content}\n${html}`;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
const headStart = headOpenMatch.index + headOpenMatch[0].length;
|
|
1699
|
+
const headEnd = headCloseMatch.index;
|
|
1700
|
+
const headContent = html.slice(headStart, headEnd);
|
|
1701
|
+
const anyScriptMatch = headContent.match(/<script\b[^>]*>/i);
|
|
1702
|
+
const moduleScriptMatch = headContent.match(/<script\b[^>]*\btype=["']module["'][^>]*>/i);
|
|
1703
|
+
const stylesheetMatch = headContent.match(/<link\b[^>]*\brel=["']stylesheet["'][^>]*>/i);
|
|
1704
|
+
const insertionOffset = anyScriptMatch?.index
|
|
1705
|
+
?? moduleScriptMatch?.index
|
|
1706
|
+
?? stylesheetMatch?.index
|
|
1707
|
+
?? headContent.length;
|
|
1708
|
+
const insertionIndex = headStart + insertionOffset;
|
|
1709
|
+
|
|
1710
|
+
return `${html.slice(0, insertionIndex)}\n${content}\n${html.slice(insertionIndex)}`;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
function rewriteInlineModuleSpecifiers(source, buildConfig, baseDirAbs = buildConfig.projectDir) {
|
|
1714
|
+
const rewriteStaticSpecifierMatch = (fullMatch, prefix, quote, specifier) => {
|
|
1715
|
+
const rewrittenSpecifier = rewriteLocalSourceTarget(specifier, buildConfig, baseDirAbs);
|
|
1716
|
+
if (!rewrittenSpecifier) {
|
|
1717
|
+
return fullMatch;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
return `${prefix}${quote}${rewrittenSpecifier}${quote}`;
|
|
1721
|
+
};
|
|
1722
|
+
|
|
1723
|
+
const rewriteDynamicSpecifierMatch = (fullMatch, prefix, quote, specifier, suffix) => {
|
|
1724
|
+
const rewrittenSpecifier = rewriteLocalSourceTarget(specifier, buildConfig, baseDirAbs);
|
|
1725
|
+
if (!rewrittenSpecifier) {
|
|
1726
|
+
return fullMatch;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
return `${prefix}${quote}${rewrittenSpecifier}${quote}${suffix}`;
|
|
1730
|
+
};
|
|
1731
|
+
|
|
1732
|
+
let rewrittenSource = source.replace(
|
|
1733
|
+
/(\bimport\s*\(\s*)(['"])([^'"]+)\2(\s*\))/g,
|
|
1734
|
+
rewriteDynamicSpecifierMatch
|
|
1735
|
+
);
|
|
1736
|
+
|
|
1737
|
+
rewrittenSource = rewrittenSource.replace(
|
|
1738
|
+
/(\bfrom\s*)(['"])([^'"]+)\2/g,
|
|
1739
|
+
rewriteStaticSpecifierMatch
|
|
1740
|
+
);
|
|
1741
|
+
|
|
1742
|
+
rewrittenSource = rewrittenSource.replace(
|
|
1743
|
+
/(\bimport\s+)(['"])([^'"]+)\2/g,
|
|
1744
|
+
rewriteStaticSpecifierMatch
|
|
1745
|
+
);
|
|
1746
|
+
|
|
1747
|
+
return rewrittenSource;
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
function rewritePackagedModuleSpecifiers(buildConfig) {
|
|
1751
|
+
for (const filePath of walkFiles(buildConfig.packageOutDirAbs)) {
|
|
1752
|
+
if (!SCRIPT_REQUEST_SOURCE_EXTENSIONS.has(path.extname(filePath))) {
|
|
1753
|
+
continue;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
const source = fs.readFileSync(filePath, 'utf8');
|
|
1757
|
+
const rewrittenSource = rewriteInlineModuleSpecifiers(source, buildConfig);
|
|
1758
|
+
if (rewrittenSource !== source) {
|
|
1759
|
+
fs.writeFileSync(filePath, rewrittenSource);
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
function rewriteHtmlModuleScripts(html, buildConfig, baseDirAbs = buildConfig.projectDir) {
|
|
1765
|
+
return html.replace(/<script\b([^>]*)>([\s\S]*?)<\/script>/gi, (fullMatch, attrs, content) => {
|
|
1766
|
+
const typeMatch = attrs.match(/\btype=["']([^"']+)["']/i);
|
|
1767
|
+
if (!typeMatch || typeMatch[1] !== 'module') {
|
|
1768
|
+
return fullMatch;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
const srcMatch = attrs.match(/\bsrc=["']([^"']+)["']/i);
|
|
1772
|
+
if (srcMatch) {
|
|
1773
|
+
const rewrittenSrc = rewriteLocalSourceTarget(srcMatch[1], buildConfig, baseDirAbs);
|
|
1774
|
+
if (!rewrittenSrc) {
|
|
1775
|
+
return fullMatch;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
return fullMatch.replace(srcMatch[0], `src="${rewrittenSrc}"`);
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
const rewrittenContent = rewriteInlineModuleSpecifiers(content, buildConfig, baseDirAbs);
|
|
1782
|
+
if (rewrittenContent === content) {
|
|
1783
|
+
return fullMatch;
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
return `<script${attrs}>${rewrittenContent}</script>`;
|
|
1787
|
+
});
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
function buildHtmlDocument(html, importEntries, buildConfig, modulePreloadUrls = []) {
|
|
1791
|
+
return injectHeadContent(html, [
|
|
1792
|
+
FOUC_PREVENTION_STYLE,
|
|
1793
|
+
renderPreloadScriptTags(buildConfig.sourceDirAbs),
|
|
1794
|
+
renderModulePreloadLinks(modulePreloadUrls),
|
|
1795
|
+
renderImportMapScript(importEntries),
|
|
1796
|
+
]);
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
function pathsOverlap(leftPath, rightPath) {
|
|
1800
|
+
const normalizedLeft = path.resolve(leftPath);
|
|
1801
|
+
const normalizedRight = path.resolve(rightPath);
|
|
1802
|
+
|
|
1803
|
+
return normalizedLeft === normalizedRight
|
|
1804
|
+
|| normalizedLeft.startsWith(`${normalizedRight}${path.sep}`)
|
|
1805
|
+
|| normalizedRight.startsWith(`${normalizedLeft}${path.sep}`);
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
function copyCompiledOutputTree(buildConfig) {
|
|
1809
|
+
if (buildConfig.compileOutDirAbs === buildConfig.packageOutDirAbs) {
|
|
1810
|
+
ensureFileExists(buildConfig.packageOutDirAbs, 'compiled output directory');
|
|
1811
|
+
return {
|
|
1812
|
+
buildConfig,
|
|
1813
|
+
cleanup() {},
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
ensureFileExists(buildConfig.compileOutDirAbs, 'compiled output directory');
|
|
1818
|
+
let snapshotRoot = null;
|
|
1819
|
+
let compileOutDirAbs = buildConfig.compileOutDirAbs;
|
|
1820
|
+
|
|
1821
|
+
try {
|
|
1822
|
+
if (pathsOverlap(buildConfig.compileOutDirAbs, buildConfig.packageOutDirAbs)) {
|
|
1823
|
+
snapshotRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'dalila-build-'));
|
|
1824
|
+
compileOutDirAbs = path.join(snapshotRoot, 'compiled');
|
|
1825
|
+
copyDirectoryContents(buildConfig.compileOutDirAbs, compileOutDirAbs);
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
fs.rmSync(buildConfig.packageOutDirAbs, { recursive: true, force: true });
|
|
1829
|
+
copyDirectoryContents(compileOutDirAbs, buildConfig.packageOutDirAbs);
|
|
1830
|
+
|
|
1831
|
+
return {
|
|
1832
|
+
buildConfig: compileOutDirAbs === buildConfig.compileOutDirAbs
|
|
1833
|
+
? buildConfig
|
|
1834
|
+
: { ...buildConfig, compileOutDirAbs },
|
|
1835
|
+
cleanup() {
|
|
1836
|
+
if (snapshotRoot) {
|
|
1837
|
+
fs.rmSync(snapshotRoot, { recursive: true, force: true });
|
|
1838
|
+
}
|
|
1839
|
+
},
|
|
1840
|
+
};
|
|
1841
|
+
} catch (error) {
|
|
1842
|
+
if (snapshotRoot) {
|
|
1843
|
+
fs.rmSync(snapshotRoot, { recursive: true, force: true });
|
|
1844
|
+
}
|
|
1845
|
+
throw error;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
function getTopLevelProjectDirName(projectDir, targetDirAbs) {
|
|
1850
|
+
const relativePath = path.relative(projectDir, targetDirAbs);
|
|
1851
|
+
if (!relativePath || relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
1852
|
+
return null;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
const [topLevelName] = relativePath.split(path.sep);
|
|
1856
|
+
return topLevelName || null;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
function collectTopLevelStaticDirs(projectDir, buildConfig) {
|
|
1860
|
+
const excludedNames = new Set(STATIC_DIR_EXCLUDES);
|
|
1861
|
+
const sourceTopLevelDir = getTopLevelProjectDirName(projectDir, buildConfig.rootDirAbs);
|
|
1862
|
+
const compileTopLevelDir = getTopLevelProjectDirName(projectDir, buildConfig.compileOutDirAbs);
|
|
1863
|
+
const packageTopLevelDir = getTopLevelProjectDirName(projectDir, buildConfig.packageOutDirAbs);
|
|
1864
|
+
|
|
1865
|
+
if (sourceTopLevelDir && buildConfig.rootDirAbs !== buildConfig.projectDir) {
|
|
1866
|
+
excludedNames.add(sourceTopLevelDir);
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
if (compileTopLevelDir) {
|
|
1870
|
+
excludedNames.add(compileTopLevelDir);
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
if (packageTopLevelDir) {
|
|
1874
|
+
excludedNames.add(packageTopLevelDir);
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
return fs.readdirSync(projectDir, { withFileTypes: true })
|
|
1878
|
+
.filter((entry) => entry.isDirectory() && !entry.name.startsWith('.') && !excludedNames.has(entry.name))
|
|
1879
|
+
.map((entry) => entry.name);
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
function copyTopLevelStaticDirs(projectDir, packageOutDirAbs, buildConfig, copiedAssetPaths = new Set()) {
|
|
1883
|
+
for (const dirName of collectTopLevelStaticDirs(projectDir, buildConfig)) {
|
|
1884
|
+
const sourceDir = path.join(projectDir, dirName);
|
|
1885
|
+
const destinationDir = path.join(packageOutDirAbs, dirName);
|
|
1886
|
+
copyDirectoryContents(sourceDir, destinationDir);
|
|
1887
|
+
for (const copiedPath of walkFiles(destinationDir)) {
|
|
1888
|
+
copiedAssetPaths.add(copiedPath);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
function copyTopLevelStaticFiles(projectDir, packageOutDirAbs, copiedAssetPaths = new Set()) {
|
|
1894
|
+
for (const entry of fs.readdirSync(projectDir, { withFileTypes: true })) {
|
|
1895
|
+
if (!entry.isFile() || entry.name.startsWith('.') || STATIC_FILE_EXCLUDES.has(entry.name)) {
|
|
1896
|
+
continue;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
const sourcePath = path.join(projectDir, entry.name);
|
|
1900
|
+
const destinationPath = path.join(packageOutDirAbs, entry.name);
|
|
1901
|
+
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
|
|
1902
|
+
fs.copyFileSync(sourcePath, destinationPath);
|
|
1903
|
+
copiedAssetPaths.add(destinationPath);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
function resolveSourceAssetRoots(projectDir, buildConfig) {
|
|
1908
|
+
const sourceRoots = [];
|
|
1909
|
+
const srcDir = path.join(projectDir, 'src');
|
|
1910
|
+
|
|
1911
|
+
if (buildConfig.rootDirAbs !== projectDir && fs.existsSync(buildConfig.rootDirAbs)) {
|
|
1912
|
+
sourceRoots.push(buildConfig.rootDirAbs);
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
if (fs.existsSync(srcDir)) {
|
|
1916
|
+
sourceRoots.push(srcDir);
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
return [...new Set(sourceRoots)];
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
function copyPackagedSourceAssets(projectDir, buildConfig) {
|
|
1923
|
+
const copiedAssetPaths = new Set();
|
|
1924
|
+
for (const sourceDir of resolveSourceAssetRoots(projectDir, buildConfig)) {
|
|
1925
|
+
for (const filePath of walkFiles(sourceDir)) {
|
|
1926
|
+
if (isScriptSourceFile(filePath) || filePath.endsWith('.d.ts')) {
|
|
1927
|
+
continue;
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
const destinationPaths = new Set();
|
|
1931
|
+
const projectRelativePath = path.relative(projectDir, filePath);
|
|
1932
|
+
if (isRelativePathInsideBase(projectRelativePath)) {
|
|
1933
|
+
destinationPaths.add(path.join(buildConfig.packageOutDirAbs, projectRelativePath));
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
const packagedUrlPath = resolvePackagedProjectUrlPath(filePath, buildConfig);
|
|
1937
|
+
if (packagedUrlPath && packagedUrlPath !== '/') {
|
|
1938
|
+
destinationPaths.add(path.join(buildConfig.packageOutDirAbs, packagedUrlPath.slice(1)));
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
for (const destinationPath of destinationPaths) {
|
|
1942
|
+
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
|
|
1943
|
+
fs.copyFileSync(filePath, destinationPath);
|
|
1944
|
+
copiedAssetPaths.add(destinationPath);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
const publicDir = path.join(projectDir, 'public');
|
|
1950
|
+
if (fs.existsSync(publicDir)) {
|
|
1951
|
+
const publicOutDir = path.join(buildConfig.packageOutDirAbs, 'public');
|
|
1952
|
+
copyDirectoryContents(publicDir, publicOutDir);
|
|
1953
|
+
for (const copiedPath of walkFiles(publicOutDir)) {
|
|
1954
|
+
const relativePath = path.relative(publicOutDir, copiedPath);
|
|
1955
|
+
const sourcePath = path.join(publicDir, relativePath);
|
|
1956
|
+
if (fs.existsSync(sourcePath) && fs.statSync(sourcePath).isFile()) {
|
|
1957
|
+
copiedAssetPaths.add(copiedPath);
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
copyTopLevelStaticDirs(projectDir, buildConfig.packageOutDirAbs, buildConfig, copiedAssetPaths);
|
|
1963
|
+
copyTopLevelStaticFiles(projectDir, buildConfig.packageOutDirAbs, copiedAssetPaths);
|
|
1964
|
+
|
|
1965
|
+
return copiedAssetPaths;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
function walkProjectHtmlFiles(dir, files = []) {
|
|
1969
|
+
if (!fs.existsSync(dir)) return files;
|
|
1970
|
+
|
|
1971
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
1972
|
+
for (const entry of entries) {
|
|
1973
|
+
if (entry.name.startsWith('.')) {
|
|
1974
|
+
continue;
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
const entryPath = path.join(dir, entry.name);
|
|
1978
|
+
if (entry.isDirectory()) {
|
|
1979
|
+
if (HTML_ENTRY_DIR_EXCLUDES.has(entry.name)) {
|
|
1980
|
+
continue;
|
|
1981
|
+
}
|
|
1982
|
+
walkProjectHtmlFiles(entryPath, files);
|
|
1983
|
+
continue;
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
if (entry.isFile() && entry.name.endsWith('.html')) {
|
|
1987
|
+
files.push(entryPath);
|
|
1988
|
+
}
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
return files;
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
function collectHtmlEntryPoints(projectDir, vendorDir, buildConfig, copiedPackages, dalilaImportEntries, dalilaRoot) {
|
|
1995
|
+
const pages = [];
|
|
1996
|
+
|
|
1997
|
+
for (const sourceHtmlPath of walkProjectHtmlFiles(projectDir)) {
|
|
1998
|
+
const source = fs.readFileSync(sourceHtmlPath, 'utf8');
|
|
1999
|
+
if (!shouldPackageHtmlEntry(source)) {
|
|
2000
|
+
continue;
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
const { importMap: existingImportMap } = extractImportMap(source);
|
|
2004
|
+
const existingImports = existingImportMap && typeof existingImportMap.imports === 'object'
|
|
2005
|
+
? existingImportMap.imports
|
|
2006
|
+
: {};
|
|
2007
|
+
const existingScopes = existingImportMap && typeof existingImportMap.scopes === 'object'
|
|
2008
|
+
? existingImportMap.scopes
|
|
2009
|
+
: {};
|
|
2010
|
+
const baseDirAbs = path.dirname(sourceHtmlPath);
|
|
2011
|
+
const rewrittenImports = packageExistingImportMapImports(
|
|
2012
|
+
projectDir,
|
|
2013
|
+
vendorDir,
|
|
2014
|
+
existingImports,
|
|
2015
|
+
buildConfig,
|
|
2016
|
+
copiedPackages,
|
|
2017
|
+
baseDirAbs
|
|
2018
|
+
);
|
|
2019
|
+
const rewrittenScopes = packageExistingImportMapScopes(
|
|
2020
|
+
projectDir,
|
|
2021
|
+
vendorDir,
|
|
2022
|
+
existingScopes,
|
|
2023
|
+
buildConfig,
|
|
2024
|
+
copiedPackages,
|
|
2025
|
+
baseDirAbs
|
|
2026
|
+
);
|
|
2027
|
+
|
|
2028
|
+
const { html: htmlWithoutImportMap } = extractImportMap(source);
|
|
2029
|
+
const rewrittenHtml = rewriteHtmlModuleScripts(htmlWithoutImportMap, buildConfig, baseDirAbs);
|
|
2030
|
+
const packagedHtmlPath = path.join(buildConfig.packageOutDirAbs, path.relative(projectDir, sourceHtmlPath));
|
|
2031
|
+
const htmlUrl = `/${toPosixPath(path.relative(projectDir, sourceHtmlPath))}`;
|
|
2032
|
+
const htmlModuleEntries = collectHtmlModuleEntries(rewrittenHtml, htmlUrl, buildConfig.ts);
|
|
2033
|
+
const publicImportMapModuleUrls = collectImportMapModuleUrls(
|
|
2034
|
+
{
|
|
2035
|
+
imports: rewrittenImports,
|
|
2036
|
+
scopes: rewrittenScopes,
|
|
2037
|
+
},
|
|
2038
|
+
htmlUrl
|
|
2039
|
+
);
|
|
2040
|
+
const traceImportMap = {
|
|
2041
|
+
...existingImportMap,
|
|
2042
|
+
imports: {
|
|
2043
|
+
...rewrittenImports,
|
|
2044
|
+
...buildUserProjectImportEntries(buildConfig),
|
|
2045
|
+
...dalilaImportEntries,
|
|
2046
|
+
},
|
|
2047
|
+
scopes: rewrittenScopes,
|
|
2048
|
+
};
|
|
2049
|
+
const {
|
|
2050
|
+
reachableModuleUrls,
|
|
2051
|
+
staticReachableModuleUrls,
|
|
2052
|
+
usedDalilaSpecifiers,
|
|
2053
|
+
requiresFullDalilaImportMap,
|
|
2054
|
+
hasUnresolvedDynamicImport,
|
|
2055
|
+
hasUnresolvedRuntimeUrl,
|
|
2056
|
+
} = traceReachableModules(
|
|
2057
|
+
{
|
|
2058
|
+
htmlUrl,
|
|
2059
|
+
...htmlModuleEntries,
|
|
2060
|
+
},
|
|
2061
|
+
traceImportMap,
|
|
2062
|
+
buildConfig,
|
|
2063
|
+
dalilaRoot
|
|
2064
|
+
);
|
|
2065
|
+
const publicImportMapTrace = traceReachableModules(
|
|
2066
|
+
{
|
|
2067
|
+
htmlUrl,
|
|
2068
|
+
entryModuleUrls: publicImportMapModuleUrls,
|
|
2069
|
+
inlineModuleSpecifiers: [],
|
|
2070
|
+
},
|
|
2071
|
+
traceImportMap,
|
|
2072
|
+
buildConfig,
|
|
2073
|
+
dalilaRoot
|
|
2074
|
+
);
|
|
2075
|
+
|
|
2076
|
+
pages.push({
|
|
2077
|
+
htmlUrl,
|
|
2078
|
+
packagedHtmlPath,
|
|
2079
|
+
rewrittenHtml,
|
|
2080
|
+
rewrittenImports,
|
|
2081
|
+
rewrittenScopes,
|
|
2082
|
+
existingImportMap,
|
|
2083
|
+
entryModuleUrls: htmlModuleEntries.entryModuleUrls,
|
|
2084
|
+
reachableModuleUrls,
|
|
2085
|
+
staticReachableModuleUrls,
|
|
2086
|
+
preservedModuleUrls: publicImportMapTrace.reachableModuleUrls,
|
|
2087
|
+
usedDalilaSpecifiers: new Set([
|
|
2088
|
+
...usedDalilaSpecifiers,
|
|
2089
|
+
...publicImportMapTrace.usedDalilaSpecifiers,
|
|
2090
|
+
]),
|
|
2091
|
+
requiresFullDalilaImportMap: requiresFullDalilaImportMap || publicImportMapTrace.requiresFullDalilaImportMap,
|
|
2092
|
+
hasUnresolvedDynamicImport: hasUnresolvedDynamicImport || publicImportMapTrace.hasUnresolvedDynamicImport,
|
|
2093
|
+
hasUnresolvedRuntimeUrl: hasUnresolvedRuntimeUrl || publicImportMapTrace.hasUnresolvedRuntimeUrl,
|
|
2094
|
+
});
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
return pages;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
function writePackagedHtmlEntryPoints(pages, buildConfig, dalilaImportEntries) {
|
|
2101
|
+
for (const page of pages) {
|
|
2102
|
+
const importMap = {
|
|
2103
|
+
...page.existingImportMap,
|
|
2104
|
+
imports: {
|
|
2105
|
+
...page.rewrittenImports,
|
|
2106
|
+
...buildUserProjectImportEntries(buildConfig),
|
|
2107
|
+
...pickDalilaImportEntries(dalilaImportEntries, page.usedDalilaSpecifiers, page.requiresFullDalilaImportMap),
|
|
2108
|
+
},
|
|
2109
|
+
scopes: page.rewrittenScopes,
|
|
2110
|
+
};
|
|
2111
|
+
const modulePreloadUrls = [...page.staticReachableModuleUrls]
|
|
2112
|
+
.filter((moduleUrl) => !page.entryModuleUrls.includes(moduleUrl));
|
|
2113
|
+
const packagedHtml = buildHtmlDocument(page.rewrittenHtml, importMap, buildConfig, modulePreloadUrls);
|
|
2114
|
+
fs.mkdirSync(path.dirname(page.packagedHtmlPath), { recursive: true });
|
|
2115
|
+
fs.writeFileSync(page.packagedHtmlPath, packagedHtml);
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
export async function buildProject(projectDir = process.cwd()) {
|
|
2120
|
+
const rootDir = path.resolve(projectDir);
|
|
2121
|
+
const initialBuildConfig = loadTypeScriptBuildConfig(rootDir);
|
|
2122
|
+
const distDir = initialBuildConfig.packageOutDirAbs;
|
|
2123
|
+
const vendorDir = path.join(distDir, 'vendor');
|
|
2124
|
+
const dalilaRoot = resolveDalilaPackageRoot(rootDir);
|
|
2125
|
+
const indexHtmlPath = path.join(rootDir, 'index.html');
|
|
2126
|
+
|
|
2127
|
+
ensureFileExists(indexHtmlPath, 'index.html');
|
|
2128
|
+
const compiledOutput = copyCompiledOutputTree(initialBuildConfig);
|
|
2129
|
+
const buildConfig = compiledOutput.buildConfig;
|
|
2130
|
+
|
|
2131
|
+
try {
|
|
2132
|
+
fs.rmSync(vendorDir, { recursive: true, force: true });
|
|
2133
|
+
rewritePackagedModuleSpecifiers(buildConfig);
|
|
2134
|
+
const copiedSourceAssetPaths = copyPackagedSourceAssets(rootDir, buildConfig);
|
|
2135
|
+
const dalilaImportEntries = buildDalilaImportEntries(rootDir);
|
|
2136
|
+
const copiedPackages = new Set();
|
|
2137
|
+
const pages = collectHtmlEntryPoints(
|
|
2138
|
+
rootDir,
|
|
2139
|
+
vendorDir,
|
|
2140
|
+
buildConfig,
|
|
2141
|
+
copiedPackages,
|
|
2142
|
+
dalilaImportEntries,
|
|
2143
|
+
dalilaRoot
|
|
2144
|
+
);
|
|
2145
|
+
const reachableModuleUrls = new Set(
|
|
2146
|
+
pages.flatMap((page) => [...page.reachableModuleUrls, ...page.preservedModuleUrls])
|
|
2147
|
+
);
|
|
2148
|
+
const preserveCompiledJavaScript = pages.some(
|
|
2149
|
+
(page) => page.hasUnresolvedDynamicImport === true || page.hasUnresolvedRuntimeUrl === true
|
|
2150
|
+
);
|
|
2151
|
+
prunePackagedCompiledArtifacts(
|
|
2152
|
+
buildConfig,
|
|
2153
|
+
reachableModuleUrls,
|
|
2154
|
+
copiedSourceAssetPaths,
|
|
2155
|
+
preserveCompiledJavaScript
|
|
2156
|
+
);
|
|
2157
|
+
copyReachableDalilaModules(reachableModuleUrls, distDir, dalilaRoot);
|
|
2158
|
+
for (const page of pages) {
|
|
2159
|
+
const selectedDalilaEntries = pickDalilaImportEntries(
|
|
2160
|
+
dalilaImportEntries,
|
|
2161
|
+
page.usedDalilaSpecifiers,
|
|
2162
|
+
page.requiresFullDalilaImportMap
|
|
2163
|
+
);
|
|
2164
|
+
copyDalilaImportEntryTargets(selectedDalilaEntries, distDir, dalilaRoot, buildConfig.ts);
|
|
2165
|
+
}
|
|
2166
|
+
copyDirectoryContents(path.join(rootDir, 'public'), path.join(distDir, 'public'));
|
|
2167
|
+
copyTopLevelStaticDirs(rootDir, distDir, buildConfig);
|
|
2168
|
+
copyTopLevelStaticFiles(rootDir, distDir);
|
|
2169
|
+
writePackagedHtmlEntryPoints(pages, buildConfig, dalilaImportEntries);
|
|
2170
|
+
|
|
2171
|
+
return {
|
|
2172
|
+
distDir,
|
|
2173
|
+
importEntries: {
|
|
2174
|
+
imports: {
|
|
2175
|
+
...buildUserProjectImportEntries(buildConfig),
|
|
2176
|
+
...dalilaImportEntries,
|
|
2177
|
+
},
|
|
2178
|
+
},
|
|
2179
|
+
};
|
|
2180
|
+
} finally {
|
|
2181
|
+
compiledOutput.cleanup();
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
2186
|
+
|
|
2187
|
+
if (isMain) {
|
|
2188
|
+
buildProject().catch((error) => {
|
|
2189
|
+
console.error('[Dalila] build packaging failed:', error);
|
|
2190
|
+
process.exit(1);
|
|
2191
|
+
});
|
|
2192
|
+
}
|