feat: Reinitialize frontend with SvelteKit and TypeScript

- Delete old Vite+Svelte frontend
- Initialize new SvelteKit project with TypeScript
- Configure Tailwind CSS v4 + DaisyUI
- Implement JWT authentication with auto-refresh
- Create login page with form validation (Zod)
- Add protected route guards
- Update Docker configuration for single-stage build
- Add E2E tests with Playwright (6/11 passing)
- Fix Svelte 5 reactivity with $state() runes

Known issues:
- 5 E2E tests failing (timing/async issues)
- Token refresh implementation needs debugging
- Validation error display timing
This commit is contained in:
2026-02-17 16:19:59 -05:00
parent 54df6018f5
commit de2d83092e
28274 changed files with 3816354 additions and 90 deletions

View File

@@ -0,0 +1,34 @@
import BrowserWindow from '../window/BrowserWindow.js';
import { URL } from 'url';
import IModule from './IModule.js';
import CSSStyleSheet from '../css/CSSStyleSheet.js';
/**
* CSS module.
*/
export default class CSSModule implements IModule {
#private;
readonly url: URL;
/**
* Constructor.
*
* @param window Window.
* @param url Module URL.
* @param source Source code.
*/
constructor(window: BrowserWindow, url: URL, source: string);
/**
* Compiles and evaluates the module.
*
* @returns Module exports.
*/
evaluate(): Promise<{
default: CSSStyleSheet;
}>;
/**
* Compiles and preloads the module and its imports.
*
* @returns Promise.
*/
preload(): Promise<void>;
}
//# sourceMappingURL=CSSModule.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CSSModule.d.ts","sourceRoot":"","sources":["../../src/module/CSSModule.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,aAAa,MAAM,yBAAyB,CAAC;AAEpD;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,SAAU,YAAW,OAAO;;IAChD,SAAgB,GAAG,EAAE,GAAG,CAAC;IAKzB;;;;;;OAMG;gBACS,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM;IAM3D;;;;OAIG;IACU,QAAQ,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,aAAa,CAAA;KAAE,CAAC;IAa5D;;;;OAIG;IACU,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}

View File

@@ -0,0 +1,44 @@
/**
* CSS module.
*/
export default class CSSModule {
url;
#window;
#source;
#exports = null;
/**
* Constructor.
*
* @param window Window.
* @param url Module URL.
* @param source Source code.
*/
constructor(window, url, source) {
this.#window = window;
this.url = url;
this.#source = source;
}
/**
* Compiles and evaluates the module.
*
* @returns Module exports.
*/
async evaluate() {
if (this.#exports) {
return this.#exports;
}
const styleSheet = new this.#window.CSSStyleSheet();
styleSheet.replaceSync(this.#source);
this.#exports = { default: styleSheet };
return this.#exports;
}
/**
* Compiles and preloads the module and its imports.
*
* @returns Promise.
*/
async preload() {
await this.evaluate();
}
}
//# sourceMappingURL=CSSModule.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"CSSModule.js","sourceRoot":"","sources":["../../src/module/CSSModule.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,SAAS;IACb,GAAG,CAAM;IAChB,OAAO,CAAgB;IACvB,OAAO,CAAS;IACzB,QAAQ,GAAsC,IAAI,CAAC;IAEnD;;;;;;OAMG;IACH,YAAY,MAAqB,EAAE,GAAQ,EAAE,MAAc;QAC1D,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,QAAQ;QACpB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,QAAQ,CAAC;QACtB,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;QACpD,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAErC,IAAI,CAAC,QAAQ,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;QAExC,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,OAAO;QACnB,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IACvB,CAAC;CACD"}

View File

@@ -0,0 +1,36 @@
import BrowserWindow from '../window/BrowserWindow.js';
import { URL } from 'url';
import IModule from './IModule.js';
import * as PropertySymbol from '../PropertySymbol.js';
import Location from '../location/Location.js';
/**
* ECMAScript module.
*/
export default class ECMAScriptModule implements IModule {
#private;
readonly url: URL;
readonly [PropertySymbol.window]: BrowserWindow;
/**
* Constructor.
*
* @param window Window.
* @param url Module URL.
* @param source Source code.
*/
constructor(window: BrowserWindow, url: URL | Location, source: string);
/**
* Compiles and evaluates the module.
*
* @returns Module exports.
*/
evaluate(): Promise<{
[key: string]: any;
} | null>;
/**
* Compiles and preloads the module and its imports.
*
* @returns Promise.
*/
preload(): Promise<void>;
}
//# sourceMappingURL=ECMAScriptModule.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ECMAScriptModule.d.ts","sourceRoot":"","sources":["../../src/module/ECMAScriptModule.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,KAAK,cAAc,MAAM,sBAAsB,CAAC;AACvD,OAAO,QAAQ,MAAM,yBAAyB,CAAC;AAO/C;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAiB,YAAW,OAAO;;IACvD,SAAgB,GAAG,EAAE,GAAG,CAAC;IACzB,SAAgB,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAMvD;;;;;;OAMG;gBACS,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,GAAG,QAAQ,EAAE,MAAM,EAAE,MAAM;IAMtE;;;;OAIG;IACU,QAAQ,IAAI,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,GAAG,IAAI,CAAC;IA4C/D;;;;OAIG;IACU,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAgFrC"}

View File

@@ -0,0 +1,128 @@
import ECMAScriptModuleCompiler from './ECMAScriptModuleCompiler.js';
import * as PropertySymbol from '../PropertySymbol.js';
import WindowBrowserContext from '../window/WindowBrowserContext.js';
import ModuleFactory from './ModuleFactory.js';
const EMPTY_COMPILED_RESULT = { imports: [], execute: () => { } };
/**
* ECMAScript module.
*/
export default class ECMAScriptModule {
url;
[PropertySymbol.window];
#source;
#preloaded = false;
#compiled = null;
#exports = null;
/**
* Constructor.
*
* @param window Window.
* @param url Module URL.
* @param source Source code.
*/
constructor(window, url, source) {
this[PropertySymbol.window] = window;
this.url = url;
this.#source = source;
}
/**
* Compiles and evaluates the module.
*
* @returns Module exports.
*/
async evaluate() {
if (this.#exports) {
return this.#exports;
}
const compiled = this.#compile();
const modulePromises = [];
const window = this[PropertySymbol.window];
const browserFrame = new WindowBrowserContext(window).getBrowserFrame();
if (!browserFrame) {
return {};
}
for (const moduleImport of compiled.imports) {
modulePromises.push(ModuleFactory.getModule(window, this.url, moduleImport.url, {
with: { type: moduleImport.type }
}));
}
const modules = await Promise.all(modulePromises);
const imports = new Map();
for (const module of modules) {
imports.set(module.url.href, await module.evaluate());
}
const exports = {};
this.#exports = exports;
compiled.execute({
dispatchError: window[PropertySymbol.dispatchError].bind(window),
dynamicImport: this.#import.bind(this),
imports,
exports
});
return exports;
}
/**
* Compiles and preloads the module and its imports.
*
* @returns Promise.
*/
async preload() {
if (this.#preloaded) {
return;
}
this.#preloaded = true;
const compiled = this.#compile();
const modulePromises = [];
const window = this[PropertySymbol.window];
const browserFrame = new WindowBrowserContext(window).getBrowserFrame();
if (!browserFrame) {
return;
}
for (const moduleImport of compiled.imports) {
modulePromises.push(ModuleFactory.getModule(window, this.url, moduleImport.url, {
with: { type: moduleImport.type }
}));
}
const modules = await Promise.all(modulePromises);
const promises = [];
for (const module of modules) {
promises.push(module.preload());
}
await Promise.all(promises);
}
/**
* Compiles the module.
*/
#compile() {
if (this.#compiled) {
return this.#compiled;
}
// In case of an error, the compiled module will be empty.
this.#compiled = EMPTY_COMPILED_RESULT;
const compiler = new ECMAScriptModuleCompiler(this[PropertySymbol.window]);
this.#compiled = compiler.compile(this.url.href, this.#source);
return this.#compiled;
}
/**
* Imports a module.
*
* @param url URL.
* @param [options] Options.
* @param [options.with] With.
* @param [options.with.type] Type.
*/
async #import(url, options) {
const window = this[PropertySymbol.window];
const browserFrame = new WindowBrowserContext(window).getBrowserFrame();
if (!browserFrame) {
return;
}
const asyncTaskManager = browserFrame[PropertySymbol.asyncTaskManager];
const taskID = asyncTaskManager?.startTask();
const module = await ModuleFactory.getModule(window, this.url, url, options);
const exports = await module.evaluate();
asyncTaskManager.endTask(taskID);
return exports;
}
}
//# sourceMappingURL=ECMAScriptModule.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ECMAScriptModule.js","sourceRoot":"","sources":["../../src/module/ECMAScriptModule.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,31 @@
import BrowserWindow from '../window/BrowserWindow.js';
import IECMAScriptModuleCompiledResult from './IECMAScriptModuleCompiledResult.js';
/**
* ECMAScript module compiler.
*/
export default class ECMAScriptModuleCompiler {
readonly window: BrowserWindow;
/**
* Constructor.
*
* @param window Window.
* @param url Module URL.
*/
constructor(window: BrowserWindow);
/**
* Compiles code and returns imports and compiled code.
*
* @param moduleURL Module URL.
* @param code Code.
* @returns Result.
*/
compile(moduleURL: string, code: string): IECMAScriptModuleCompiledResult;
/**
* Remove multiline comments.
*
* @param code Code.
* @returns Code without multiline comments.
*/
private removeMultilineComments;
}
//# sourceMappingURL=ECMAScriptModuleCompiler.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ECMAScriptModuleCompiler.d.ts","sourceRoot":"","sources":["../../src/module/ECMAScriptModuleCompiler.ts"],"names":[],"mappings":"AACA,OAAO,aAAa,MAAM,4BAA4B,CAAC;AAEvD,OAAO,+BAA+B,MAAM,sCAAsC,CAAC;AA4DnF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,wBAAwB;IAC5C,SAAgB,MAAM,EAAE,aAAa,CAAC;IAEtC;;;;;OAKG;gBACS,MAAM,EAAE,aAAa;IAIjC;;;;;;OAMG;IACI,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,+BAA+B;IAichF;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;CAyB/B"}

View File

@@ -0,0 +1,521 @@
import BrowserErrorCaptureEnum from '../browser/enums/BrowserErrorCaptureEnum.js';
import WindowBrowserContext from '../window/WindowBrowserContext.js';
import ModuleURLUtility from './ModuleURLUtility.js';
import * as PropertySymbol from '../PropertySymbol.js';
/**
* Code regexp.
*
* Group 1: Import without exported properties.
* Group 2: Dynamic import function call.
* Group 3: Import exported variables.
* Group 4: Import exported url.
* Group 5: Import with group.
* Group 6: Import with type.
* Group 7: Modules in export from module statement.
* Group 8: Import in export from module statement.
* Group 9: Export default statement.
* Group 10: Export function or class type.
* Group 11: Export function or class name.
* Group 12: Export object.
* Group 13: Export variable type (var, let or const).
* Group 14: Export variable name.
* Group 15: Export variable name end character (= or ;).
* Group 16: Slash (RegExp or comment).
* Group 17: Parentheses.
* Group 18: Curly braces.
* Group 19: Square brackets.
* Group 20: Escape template string (${).
* Group 21: Template string apostrophe (`).
* Group 22: String apostrophe (').
* Group 23: String apostrophe (").
* Group 24: Line feed character.
*/
const CODE_REGEXP = /import\s*["']([^"']+)["'];{0,1}|import\s*\(([^)]+)\)|(import[\s{])|[\s}]from\s*["']([^"']+)["'](\s+with\s*{\s*type\s*:\s*["']([^"']+)["']\s*}){0,1}|export\s([a-zA-Z0-9-_$]+|\*|\*\s+as\s+["'a-zA-Z0-9-_$]+|{[^}]+})\s*from\s["']([^"']+)["']|(export\s*default\s*)|export\s*(function\*{0,1}|class)\s*([^({\s]+)|export\s*{([^}]+)}|export\s+(var|let|const)\s+([^=;]+)(=|;)|(\/)|(\(|\))|({|})|(\[|\])|(\${)|(`)|(')|(")|(\n)/gm;
/**
* Import regexp.
*
* Group 1: Import braces.
* Group 2: Import all as.
* Group 3: Import default.
*/
const IMPORT_REGEXP = /{([^}]+)}|\*\s+as\s+([a-zA-Z0-9-_$]+)|([a-zA-Z0-9-_$]+)/gm;
/**
* Valid preceding token before a statement.
*/
const PRECEDING_STATEMENT_TOKEN_REGEXP = /['"`(){}\s;=>]/;
/**
* Valid preceding token before a regexp.
*/
const PRECEDING_REGEXP_TOKEN_REGEXP = /[([=\{\},;"'+-]/;
/**
* Multiline comment regexp.
*/
const MULTILINE_COMMENT_REGEXP = /\/\*|\*\//gm;
/**
* ECMAScript module compiler.
*/
export default class ECMAScriptModuleCompiler {
window;
/**
* Constructor.
*
* @param window Window.
* @param url Module URL.
*/
constructor(window) {
this.window = window;
}
/**
* Compiles code and returns imports and compiled code.
*
* @param moduleURL Module URL.
* @param code Code.
* @returns Result.
*/
compile(moduleURL, code) {
const browserSettings = new WindowBrowserContext(this.window).getSettings();
const regExp = new RegExp(CODE_REGEXP);
const imports = [];
const count = {
comment: 0,
singleLineComment: 0,
parantheses: 0,
curlyBraces: 0,
squareBrackets: 0,
regExp: 0,
regExpSquareBrackets: 0,
escapeTemplateString: 0,
simpleString: 0,
doubleString: 0
};
const stack = {
templateString: { index: null, code: [] }
};
const templateString = [];
const exportSpreadVariables = [];
let newCode = `(async function anonymous($happy_dom) {\n//# sourceURL=${moduleURL}\n`;
let match;
let precedingToken;
let isEscaped;
let lastIndex = 0;
let importStartIndex = -1;
let skipMatchedCode = false;
if (!browserSettings.disableErrorCapturing &&
browserSettings.errorCapture === BrowserErrorCaptureEnum.tryAndCatch) {
newCode += 'try {\n';
}
while ((match = regExp.exec(code))) {
if (importStartIndex === -1) {
newCode += code.substring(lastIndex, match.index);
}
precedingToken = code[match.index - 1] || ' ';
isEscaped = precedingToken === '\\' && code[match.index - 2] !== '\\';
// Imports and exports are only valid outside any statement, string or comment at the top level
if (count.comment === 0 &&
count.singleLineComment === 0 &&
count.parantheses === 0 &&
count.curlyBraces === 0 &&
count.squareBrackets === 0 &&
count.regExp === 0 &&
count.simpleString === 0 &&
count.doubleString === 0 &&
templateString.length === 0) {
if (match[1] && PRECEDING_STATEMENT_TOKEN_REGEXP.test(precedingToken)) {
// Import without exported properties
imports.push({
url: ModuleURLUtility.getURL(this.window, moduleURL, match[1]).href,
type: 'esm'
});
skipMatchedCode = true;
}
else if (match[3] && PRECEDING_STATEMENT_TOKEN_REGEXP.test(precedingToken)) {
// Import statement start
if (importStartIndex !== -1) {
throw new this.window.TypeError(`Failed to parse module: Unexpected import statement in "${moduleURL}"`);
}
importStartIndex = match.index + match[0].length - 1;
skipMatchedCode = true;
}
else if (match[4]) {
// Import statement end
if (importStartIndex !== -1) {
const url = ModuleURLUtility.getURL(this.window, moduleURL, match[4]).href;
const variables = code.substring(importStartIndex, match.index + 1);
const importRegExp = new RegExp(IMPORT_REGEXP);
const importCode = [];
let importMatch;
while ((importMatch = importRegExp.exec(variables))) {
if (importMatch[1]) {
// Import braces
importCode.push(`const {${importMatch[1].replace(/\s+as\s+/gm, ': ')}} = $happy_dom.imports.get('${url}')`);
}
else if (importMatch[2]) {
// Import all as
importCode.push(`const ${importMatch[2]} = $happy_dom.imports.get('${url}')`);
}
else if (importMatch[3]) {
// Import default
importCode.push(`const ${importMatch[3]} = $happy_dom.imports.get('${url}').default`);
}
}
newCode += importCode.join(';\n');
importStartIndex = -1;
imports.push({ url, type: match[6] || 'esm' });
skipMatchedCode = true;
}
}
else if (match[7] && match[8] && PRECEDING_STATEMENT_TOKEN_REGEXP.test(precedingToken)) {
// Export from module statement
const url = ModuleURLUtility.getURL(this.window, moduleURL, match[8]).href;
const imported = match[7];
if (imported === '*') {
newCode += `Object.assign($happy_dom.exports, $happy_dom.imports.get('${url}'))`;
imports.push({ url, type: 'esm' });
}
else if (imported[0] === '*') {
const parts = imported.split(/\s+as\s+/);
if (parts.length === 2) {
const exportName = parts[1].replace(/["']/g, '');
newCode += `$happy_dom.exports['${exportName}'] = $happy_dom.imports.get('${url}')`;
imports.push({ url, type: 'esm' });
}
}
else if (imported[0] === '{') {
const parts = this.removeMultilineComments(imported)
.slice(1, -1)
.split(/\s*,\s*/);
const exportCode = [];
for (const part of parts) {
const nameParts = part.trim().split(/\s+as\s+/);
const exportName = (nameParts[1] || nameParts[0]).replace(/["']/g, '');
const importName = nameParts[0].replace(/["']/g, '');
if (exportName && importName) {
exportCode.push(`$happy_dom.exports['${exportName}'] = $happy_dom.imports.get('${url}')['${importName}']`);
}
}
newCode += exportCode.join(';\n');
imports.push({ url, type: 'esm' });
}
skipMatchedCode = true;
}
else if (match[9] && PRECEDING_STATEMENT_TOKEN_REGEXP.test(precedingToken)) {
// Export default statement
newCode += '$happy_dom.exports.default = ';
skipMatchedCode = true;
}
else if (match[10] &&
match[11] &&
PRECEDING_STATEMENT_TOKEN_REGEXP.test(precedingToken)) {
// Export function or class type
newCode += `$happy_dom.exports['${match[11]}'] = ${match[10]} ${match[11]}`;
skipMatchedCode = true;
}
else if (match[12] && PRECEDING_STATEMENT_TOKEN_REGEXP.test(precedingToken)) {
// Export object
const parts = this.removeMultilineComments(match[12]).split(/\s*,\s*/);
const exportCode = [];
for (const part of parts) {
const nameParts = part.trim().split(/\s+as\s+/);
const exportName = (nameParts[1] || nameParts[0]).replace(/["']/g, '');
const importName = nameParts[0].replace(/["']/g, '');
if (exportName && importName) {
exportCode.push(`$happy_dom.exports['${exportName}'] = ${importName}`);
}
}
newCode += exportCode.join(';\n');
skipMatchedCode = true;
}
else if (match[13] && PRECEDING_STATEMENT_TOKEN_REGEXP.test(precedingToken)) {
// Export variable
if (match[15] === '=') {
const exportName = this.removeMultilineComments(match[14]).trim();
if ((exportName[0] === '{' && exportName[exportName.length - 1] === '}') ||
(exportName[0] === '[' && exportName[exportName.length - 1] === ']')) {
const parts = exportName.slice(1, -1).split(/\s*,\s*/);
const variableObject = new Map();
for (const part of parts) {
const nameParts = part.trim().split(/\s*:\s*/);
const exportName = (nameParts[1] || nameParts[0]).replace(/["']/g, '');
const importName = nameParts[0].replace(/["']/g, '');
if (exportName && importName) {
variableObject.set(exportName, importName);
}
}
newCode += `const $happy_dom_export_${exportSpreadVariables.length} =`;
exportSpreadVariables.push(variableObject);
}
else {
newCode += `$happy_dom.exports['${exportName}'] =`;
}
}
else {
// TODO: If there is no =, we should ignore until we know what it is useful for
// Example: export let name1, name2, name3;
newCode += `/*Unknown export: ${match[0]}*/`;
this.window.console.warn(`Unknown export in "${moduleURL}": ${match[0]}`);
}
skipMatchedCode = true;
}
}
if (match[2]) {
// Dynamic import function call
if (count.simpleString === 0 &&
count.doubleString === 0 &&
count.comment === 0 &&
count.singleLineComment === 0 &&
count.regExp === 0 &&
(templateString.length === 0 || templateString[0] > 0) &&
PRECEDING_STATEMENT_TOKEN_REGEXP.test(precedingToken)) {
newCode += `$happy_dom.dynamicImport(${match[2]})`;
skipMatchedCode = true;
}
}
else if (match[16]) {
// Slash (RegExp or Comment)
if (count.simpleString === 0 &&
count.doubleString === 0 &&
count.singleLineComment === 0 &&
count.regExpSquareBrackets === 0 &&
(templateString.length === 0 || templateString[0] > 0)) {
if (count.comment === 1) {
if (precedingToken === '*') {
count.comment = 0;
}
}
else {
if (count.regExp === 0) {
if (code[match.index + 1] === '*') {
count.comment = 1;
}
else if (code[match.index + 1] === '/') {
count.singleLineComment = 1;
}
else {
if (!isEscaped) {
let index = match.index - 1;
let nonSpacePrecedingToken = code[index];
while (nonSpacePrecedingToken === ' ' || nonSpacePrecedingToken === '\n') {
index--;
nonSpacePrecedingToken = code[index];
}
if (PRECEDING_REGEXP_TOKEN_REGEXP.test(nonSpacePrecedingToken)) {
count.regExp = 1;
}
}
}
}
else if (!isEscaped) {
count.regExp = 0;
}
}
}
}
else if (match[17]) {
// Parentheses
if (count.simpleString === 0 &&
count.doubleString === 0 &&
count.regExp === 0 &&
count.comment === 0 &&
count.singleLineComment === 0 &&
(templateString.length === 0 || templateString[0] > 0)) {
if (match[17] === '(') {
count.parantheses++;
}
else if (match[17] === ')' && count.parantheses > 0) {
count.parantheses--;
}
}
}
else if (match[18]) {
// Curly braces
if (count.simpleString === 0 &&
count.doubleString === 0 &&
count.regExp === 0 &&
count.comment === 0 &&
count.singleLineComment === 0 &&
(templateString.length === 0 || templateString[0] > 0)) {
if (match[18] === '{') {
if (templateString.length) {
templateString[0]++;
}
count.curlyBraces++;
}
else if (match[18] === '}') {
if (templateString.length && templateString[0] > 0) {
templateString[0]--;
}
if (count.curlyBraces > 0) {
count.curlyBraces--;
}
}
}
}
else if (match[19]) {
// Square brackets
if (count.simpleString === 0 &&
count.doubleString === 0 &&
count.comment === 0 &&
count.singleLineComment === 0 &&
(templateString.length === 0 || templateString[0] > 0)) {
// We need to check for square brackets in RegExp as well to know when the RegExp ends
if (count.regExp === 1) {
if (!isEscaped) {
if (match[19] === '[' && count.regExpSquareBrackets === 0) {
count.regExpSquareBrackets = 1;
}
else if (match[19] === ']' && count.regExpSquareBrackets === 1) {
count.regExpSquareBrackets = 0;
}
}
}
else {
if (match[19] === '[') {
count.squareBrackets++;
}
else if (match[19] === ']' && count.squareBrackets > 0) {
count.squareBrackets--;
}
}
}
}
else if (match[20]) {
// Escape template string (${)
if (count.simpleString === 0 &&
count.doubleString === 0 &&
count.comment === 0 &&
count.singleLineComment === 0 &&
count.regExp === 0 &&
!isEscaped) {
if (templateString.length > 0) {
templateString[0]++;
}
count.curlyBraces++;
}
}
else if (match[21]) {
// Template string
if (count.simpleString === 0 &&
count.doubleString === 0 &&
count.comment === 0 &&
count.singleLineComment === 0 &&
count.regExp === 0 &&
!isEscaped) {
if (templateString?.[0] == 0) {
templateString.shift();
stack.templateString.code.push(code.substring(stack.templateString.index, match.index + 1));
}
else {
templateString.unshift(0);
stack.templateString.index = match.index;
}
}
}
else if (match[22]) {
// String apostrophe (')
if (count.doubleString === 0 &&
count.comment === 0 &&
count.singleLineComment === 0 &&
count.regExp === 0 &&
!isEscaped &&
(templateString.length === 0 || templateString[0] > 0)) {
if (count.simpleString === 0) {
count.simpleString = 1;
}
else {
count.simpleString = 0;
}
}
}
else if (match[23]) {
// String apostrophe (")
if (count.simpleString === 0 &&
count.comment === 0 &&
count.singleLineComment === 0 &&
count.regExp === 0 &&
!isEscaped &&
(templateString.length === 0 || templateString[0] > 0)) {
if (count.doubleString === 0) {
count.doubleString = 1;
}
else {
count.doubleString = 0;
}
}
}
else if (match[24]) {
// Line feed character
count.singleLineComment = 0;
}
// Unless the code has been handled by transforming imports or exports, we add it to the new code
if (!skipMatchedCode && importStartIndex === -1) {
newCode += match[0];
}
skipMatchedCode = false;
lastIndex = regExp.lastIndex;
}
if (importStartIndex !== -1) {
// We will end up here if there is an import statement without a valid "from" part
// E.g. "import defaultExport from invalid;" or just "import defaultExport;"
throw new this.window.TypeError(`Failed to parse module: Unexpected import statement in "${moduleURL}"`);
}
newCode += code.substring(lastIndex);
if (exportSpreadVariables.length > 0) {
newCode += '\n\n';
for (let i = 0; i < exportSpreadVariables.length; i++) {
for (const [exportName, importName] of exportSpreadVariables[i]) {
newCode += `$happy_dom.exports['${exportName}'] = $happy_dom_export_${i}['${importName}'];\n`;
}
}
}
if (!browserSettings.disableErrorCapturing &&
browserSettings.errorCapture === BrowserErrorCaptureEnum.tryAndCatch) {
newCode += `\n} catch(e) {\n $happy_dom.dispatchError(e);\n}`;
}
newCode += '\n})';
try {
return { imports, execute: this.window.eval(newCode) };
}
catch (e) {
const error = new this.window.SyntaxError(`Failed to parse module '${moduleURL}': ${e.message}`);
if (browserSettings.disableErrorCapturing ||
browserSettings.errorCapture !== BrowserErrorCaptureEnum.tryAndCatch) {
throw error;
}
else {
this.window[PropertySymbol.dispatchError](error);
return {
imports,
execute: () => { }
};
}
}
}
/**
* Remove multiline comments.
*
* @param code Code.
* @returns Code without multiline comments.
*/
removeMultilineComments(code) {
const regexp = new RegExp(MULTILINE_COMMENT_REGEXP);
let match;
let count = 0;
let lastIndex = 0;
let newCode = '';
while ((match = regexp.exec(code))) {
if (count === 0) {
newCode += code.substring(lastIndex, match.index);
}
if (match[0] === '/*') {
count++;
}
else if (match[0] === '*/' && count > 0) {
count--;
}
lastIndex = regexp.lastIndex;
}
newCode += code.substring(lastIndex);
return newCode;
}
}
//# sourceMappingURL=ECMAScriptModuleCompiler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,21 @@
import IECMAScriptModuleImport from './IECMAScriptModuleImport.js';
export default interface IECMAScriptModuleCompiledResult {
imports: IECMAScriptModuleImport[];
execute: (options: {
dispatchError: (error: Error) => void;
dynamicImport: (url: string, options?: {
with?: {
type?: string;
};
}) => Promise<{
[key: string]: any;
}>;
imports: Map<string, {
[key: string]: any;
}>;
exports: {
[key: string]: any;
};
}) => void;
}
//# sourceMappingURL=IECMAScriptModuleCompiledResult.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IECMAScriptModuleCompiledResult.d.ts","sourceRoot":"","sources":["../../src/module/IECMAScriptModuleCompiledResult.ts"],"names":[],"mappings":"AAAA,OAAO,uBAAuB,MAAM,8BAA8B,CAAC;AAEnE,MAAM,CAAC,OAAO,WAAW,+BAA+B;IACvD,OAAO,EAAE,uBAAuB,EAAE,CAAC;IACnC,OAAO,EAAE,CAAC,OAAO,EAAE;QAClB,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;QACtC,aAAa,EAAE,CACd,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE;gBAAE,IAAI,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,KAClC,OAAO,CAAC;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC,CAAC;QACrC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC,CAAC;QAC7C,OAAO,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC;KAChC,KAAK,IAAI,CAAC;CACX"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=IECMAScriptModuleCompiledResult.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IECMAScriptModuleCompiledResult.js","sourceRoot":"","sources":["../../src/module/IECMAScriptModuleCompiledResult.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,5 @@
export default interface IECMAScriptModuleImport {
url: string;
type: string;
}
//# sourceMappingURL=IECMAScriptModuleImport.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IECMAScriptModuleImport.d.ts","sourceRoot":"","sources":["../../src/module/IECMAScriptModuleImport.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,WAAW,uBAAuB;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACb"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=IECMAScriptModuleImport.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IECMAScriptModuleImport.js","sourceRoot":"","sources":["../../src/module/IECMAScriptModuleImport.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,21 @@
/**
* Module interface.
*/
export default interface IModule {
url: URL;
/**
* Compiles and evaluates the module.
*
* @returns Module exports.
*/
evaluate(): Promise<{
[key: string]: any;
}>;
/**
* Compiles and preloads the module and its imports.
*
* @returns Promise.
*/
preload(): Promise<void>;
}
//# sourceMappingURL=IModule.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IModule.d.ts","sourceRoot":"","sources":["../../src/module/IModule.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,OAAO,WAAW,OAAO;IAC/B,GAAG,EAAE,GAAG,CAAC;IAET;;;;OAIG;IACH,QAAQ,IAAI,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC,CAAC;IAE5C;;;;OAIG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=IModule.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IModule.js","sourceRoot":"","sources":["../../src/module/IModule.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,10 @@
import IModuleImportMapRule from './IModuleImportMapRule.js';
import IModuleImportMapScope from './IModuleImportMapScope.js';
/**
* @see https://html.spec.whatwg.org/multipage/webappapis.html#import-map
*/
export default interface IModuleImportMap {
imports: IModuleImportMapRule[];
scopes: IModuleImportMapScope[];
}
//# sourceMappingURL=IModuleImportMap.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IModuleImportMap.d.ts","sourceRoot":"","sources":["../../src/module/IModuleImportMap.ts"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,MAAM,2BAA2B,CAAC;AAC7D,OAAO,qBAAqB,MAAM,4BAA4B,CAAC;AAE/D;;GAEG;AACH,MAAM,CAAC,OAAO,WAAW,gBAAgB;IACxC,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,MAAM,EAAE,qBAAqB,EAAE,CAAC;CAChC"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=IModuleImportMap.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IModuleImportMap.js","sourceRoot":"","sources":["../../src/module/IModuleImportMap.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,5 @@
export default interface IModuleImportMapRule {
from: string;
to: string;
}
//# sourceMappingURL=IModuleImportMapRule.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IModuleImportMapRule.d.ts","sourceRoot":"","sources":["../../src/module/IModuleImportMapRule.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,WAAW,oBAAoB;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACX"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=IModuleImportMapRule.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IModuleImportMapRule.js","sourceRoot":"","sources":["../../src/module/IModuleImportMapRule.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,6 @@
import IModuleImportMapRule from './IModuleImportMapRule.js';
export default interface IModuleImportMapScope {
scope: string;
rules: IModuleImportMapRule[];
}
//# sourceMappingURL=IModuleImportMapScope.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IModuleImportMapScope.d.ts","sourceRoot":"","sources":["../../src/module/IModuleImportMapScope.ts"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,MAAM,2BAA2B,CAAC;AAE7D,MAAM,CAAC,OAAO,WAAW,qBAAqB;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,oBAAoB,EAAE,CAAC;CAC9B"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=IModuleImportMapScope.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IModuleImportMapScope.js","sourceRoot":"","sources":["../../src/module/IModuleImportMapScope.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,33 @@
import BrowserWindow from '../window/BrowserWindow.js';
import { URL } from 'url';
import IModule from './IModule.js';
/**
* JSON module.
*/
export default class JSONModule implements IModule {
#private;
readonly url: URL;
/**
* Constructor.
*
* @param window Window.
* @param url Module URL.
* @param source Source code.
*/
constructor(window: BrowserWindow, url: URL, source: string);
/**
* Compiles and evaluates the module.
*
* @returns Module exports.
*/
evaluate(): Promise<{
default: object;
}>;
/**
* Compiles and preloads the module and its imports.
*
* @returns Promise.
*/
preload(): Promise<void>;
}
//# sourceMappingURL=JSONModule.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"JSONModule.d.ts","sourceRoot":"","sources":["../../src/module/JSONModule.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,UAAW,YAAW,OAAO;;IACjD,SAAgB,GAAG,EAAE,GAAG,CAAC;IAKzB;;;;;;OAMG;gBACS,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM;IAM3D;;;;OAIG;IACU,QAAQ,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAmBrD;;;;OAIG;IACU,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}

View File

@@ -0,0 +1,49 @@
/**
* JSON module.
*/
export default class JSONModule {
url;
#window;
#source;
#exports = null;
/**
* Constructor.
*
* @param window Window.
* @param url Module URL.
* @param source Source code.
*/
constructor(window, url, source) {
this.#window = window;
this.url = url;
this.#source = source;
}
/**
* Compiles and evaluates the module.
*
* @returns Module exports.
*/
async evaluate() {
if (this.#exports) {
return this.#exports;
}
let result;
try {
result = JSON.parse(this.#source);
}
catch (error) {
throw new this.#window.TypeError(`Failed to parse module "${this.url.href}": ${error.message}`);
}
this.#exports = { default: result };
return this.#exports;
}
/**
* Compiles and preloads the module and its imports.
*
* @returns Promise.
*/
async preload() {
await this.evaluate();
}
}
//# sourceMappingURL=JSONModule.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"JSONModule.js","sourceRoot":"","sources":["../../src/module/JSONModule.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,UAAU;IACd,GAAG,CAAM;IAChB,OAAO,CAAgB;IACvB,OAAO,CAAS;IACzB,QAAQ,GAA+B,IAAI,CAAC;IAE5C;;;;;;OAMG;IACH,YAAY,MAAqB,EAAE,GAAQ,EAAE,MAAc;QAC1D,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,QAAQ;QACpB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,QAAQ,CAAC;QACtB,CAAC;QAED,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAC/B,2BAA2B,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE,CAC7D,CAAC;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAEpC,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,OAAO;QACnB,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IACvB,CAAC;CACD"}

View File

@@ -0,0 +1,33 @@
import { URL } from 'url';
import IModule from './IModule.js';
import BrowserWindow from '../window/BrowserWindow.js';
import Location from '../location/Location.js';
/**
* Module factory.
*/
export default class ModuleFactory {
/**
* Fetches the source code of the module from the given URL and creates a new module instance.
*
* @param window Window.
* @param parentURL Parent URL.
* @param url Module URL.
* @param [options] Options.
* @param [options.with] Options.
* @param [options.with.type] Module type.
*/
static getModule(window: BrowserWindow, parentURL: URL | Location, url: string, options?: {
with?: {
type?: string;
};
}): Promise<IModule>;
/**
* Returns module URL based on parent URL and the import map.
*
* @param window Window.
* @param parentURL Parent URL.
* @param url Module URL.
*/
private static getURL;
}
//# sourceMappingURL=ModuleFactory.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ModuleFactory.d.ts","sourceRoot":"","sources":["../../src/module/ModuleFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,OAAO,MAAM,cAAc,CAAC;AAQnC,OAAO,aAAa,MAAM,4BAA4B,CAAC;AACvD,OAAO,QAAQ,MAAM,yBAAyB,CAAC;AAE/C;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,aAAa;IACjC;;;;;;;;;OASG;WACiB,SAAS,CAC5B,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,GAAG,GAAG,QAAQ,EACzB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GACpC,OAAO,CAAC,OAAO,CAAC;IA+DnB;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,MAAM;CAgCrB"}

View File

@@ -0,0 +1,107 @@
import { URL } from 'url';
import * as PropertySymbol from '../PropertySymbol.js';
import CSSModule from './CSSModule.js';
import JSONModule from './JSONModule.js';
import UnresolvedModule from './UnresolvedModule.js';
import WindowBrowserContext from '../window/WindowBrowserContext.js';
import ResourceFetch from '../fetch/ResourceFetch.js';
import ECMAScriptModule from './ECMAScriptModule.js';
/**
* Module factory.
*/
export default class ModuleFactory {
/**
* Fetches the source code of the module from the given URL and creates a new module instance.
*
* @param window Window.
* @param parentURL Parent URL.
* @param url Module URL.
* @param [options] Options.
* @param [options.with] Options.
* @param [options.with.type] Module type.
*/
static async getModule(window, parentURL, url, options) {
const absoluteURL = this.getURL(window, parentURL, url);
const absoluteURLString = absoluteURL.href;
const type = options?.with?.type || 'esm';
if (type !== 'esm' && type !== 'css' && type !== 'json') {
throw new window.TypeError(`Failed to import module "${absoluteURL}" from "${parentURL}": Unkown type "${type}"`);
}
const cached = window[PropertySymbol.modules][type].get(absoluteURLString);
if (cached) {
if (cached instanceof UnresolvedModule) {
await new Promise((resolve, reject) => {
cached.addResolveListener(resolve, reject);
});
return window[PropertySymbol.modules][type].get(absoluteURLString);
}
return cached;
}
const browserFrame = new WindowBrowserContext(window).getBrowserFrame();
if (!browserFrame) {
throw new window.TypeError(`Failed to import module "${absoluteURL}" from "${parentURL}": Window is closed and is no longer attached to a frame`);
}
const unresolvedModule = new UnresolvedModule(window, absoluteURL);
window[PropertySymbol.modules][type].set(absoluteURLString, unresolvedModule);
const resourceFetch = new ResourceFetch(window);
let source;
try {
source = await resourceFetch.fetch(absoluteURL, 'module');
}
catch (error) {
unresolvedModule.resolve(error);
throw error;
}
let module;
switch (type) {
case 'json':
module = new JSONModule(window, absoluteURL, source);
break;
case 'css':
module = new CSSModule(window, absoluteURL, source);
break;
case 'esm':
module = new ECMAScriptModule(window, absoluteURL, source);
break;
}
window[PropertySymbol.modules][type].set(absoluteURLString, module);
unresolvedModule.resolve();
return module;
}
/**
* Returns module URL based on parent URL and the import map.
*
* @param window Window.
* @param parentURL Parent URL.
* @param url Module URL.
*/
static getURL(window, parentURL, url) {
const parentURLString = parentURL.href;
const absoluteURL = new URL(url, parentURLString);
const absoluteURLString = absoluteURL.href;
const importMap = window[PropertySymbol.moduleImportMap];
if (!importMap) {
return absoluteURL;
}
if (importMap.scopes) {
for (const scope of importMap.scopes) {
if (parentURLString.includes(scope.scope)) {
for (const rule of scope.rules) {
if (absoluteURLString.startsWith(rule.from)) {
return new URL(rule.to + absoluteURLString.replace(rule.from, ''));
}
}
}
}
}
if (importMap.imports) {
for (const rule of importMap.imports) {
if (absoluteURLString.startsWith(rule.from)) {
return new URL(rule.to + absoluteURLString.replace(rule.from, ''));
}
}
}
return absoluteURL;
}
}
//# sourceMappingURL=ModuleFactory.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ModuleFactory.js","sourceRoot":"","sources":["../../src/module/ModuleFactory.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,17 @@
import { URL } from 'url';
import BrowserWindow from '../window/BrowserWindow.js';
import Location from '../location/Location.js';
/**
* Module URL utility.
*/
export default class ModuleURLUtility {
/**
* Returns module URL based on parent URL and the import map.
*
* @param window Window.
* @param parentURL Parent URL.
* @param url Module URL.
*/
static getURL(window: BrowserWindow, parentURL: URL | Location | string, url: string): URL;
}
//# sourceMappingURL=ModuleURLUtility.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ModuleURLUtility.d.ts","sourceRoot":"","sources":["../../src/module/ModuleURLUtility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,OAAO,aAAa,MAAM,4BAA4B,CAAC;AACvD,OAAO,QAAQ,MAAM,yBAAyB,CAAC;AAE/C;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACpC;;;;;;OAMG;WACW,MAAM,CACnB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,GAAG,GAAG,QAAQ,GAAG,MAAM,EAClC,GAAG,EAAE,MAAM,GACT,GAAG;CA8BN"}

View File

@@ -0,0 +1,41 @@
import { URL } from 'url';
import * as PropertySymbol from '../PropertySymbol.js';
/**
* Module URL utility.
*/
export default class ModuleURLUtility {
/**
* Returns module URL based on parent URL and the import map.
*
* @param window Window.
* @param parentURL Parent URL.
* @param url Module URL.
*/
static getURL(window, parentURL, url) {
const parentURLString = typeof parentURL === 'string' ? parentURL : parentURL.href;
const importMap = window[PropertySymbol.moduleImportMap];
if (!importMap) {
return new URL(url, parentURLString);
}
if (importMap.scopes.length) {
for (const scope of importMap.scopes) {
if (parentURLString.includes(scope.scope)) {
for (const rule of scope.rules) {
if (url.startsWith(rule.from)) {
return new URL(rule.to + url.replace(rule.from, ''), parentURLString);
}
}
}
}
}
if (importMap.imports.length) {
for (const rule of importMap.imports) {
if (url.startsWith(rule.from)) {
return new URL(rule.to + url.replace(rule.from, ''), parentURLString);
}
}
}
return new URL(url, parentURLString);
}
}
//# sourceMappingURL=ModuleURLUtility.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ModuleURLUtility.js","sourceRoot":"","sources":["../../src/module/ModuleURLUtility.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,KAAK,cAAc,MAAM,sBAAsB,CAAC;AAIvD;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACpC;;;;;;OAMG;IACI,MAAM,CAAC,MAAM,CACnB,MAAqB,EACrB,SAAkC,EAClC,GAAW;QAEX,MAAM,eAAe,GAAG,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC;QACnF,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QAEzD,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,OAAO,IAAI,GAAG,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;QACtC,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YAC7B,KAAK,MAAM,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;gBACtC,IAAI,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;wBAChC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;4BAC/B,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC;wBACvE,CAAC;oBACF,CAAC;gBACF,CAAC;YACF,CAAC;QACF,CAAC;QAED,IAAI,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC9B,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;gBACtC,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/B,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC;gBACvE,CAAC;YACF,CAAC;QACF,CAAC;QAED,OAAO,IAAI,GAAG,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IACtC,CAAC;CACD"}

View File

@@ -0,0 +1,43 @@
import BrowserWindow from '../window/BrowserWindow.js';
import { URL } from 'url';
import IModule from './IModule.js';
/**
* CSS module.
*/
export default class UnresolvedModule implements IModule {
#private;
readonly url: URL;
/**
* Constructor.
*
* @param window Window.
* @param url Module URL.
*/
constructor(window: BrowserWindow, url: URL);
/**
* Compiles and evaluates the module.
*
* @returns Module exports.
*/
evaluate(): Promise<null>;
/**
* Compiles and preloads the module and its imports.
*
* @returns Promise.
*/
preload(): Promise<void>;
/**
* Add a hook to be called when the module is resolved.
*
* @param resolve Resolve.
* @param reject Reject.
*/
addResolveListener(resolve: (value: unknown) => void, reject: (error: Error) => void): void;
/**
* Resolves the module.
*
* @param [error] Error.
*/
resolve(error?: Error): void;
}
//# sourceMappingURL=UnresolvedModule.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"UnresolvedModule.d.ts","sourceRoot":"","sources":["../../src/module/UnresolvedModule.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAiB,YAAW,OAAO;;IACvD,SAAgB,GAAG,EAAE,GAAG,CAAC;IAKzB;;;;;OAKG;gBACS,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG;IAK3C;;;;OAIG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC;;;;OAIG;IACU,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrC;;;;;OAKG;IACI,kBAAkB,CACxB,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,EACjC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAC5B,IAAI;IAQP;;;;OAIG;IACI,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;CAYnC"}

View File

@@ -0,0 +1,67 @@
/**
* CSS module.
*/
export default class UnresolvedModule {
url;
#window;
#hooks = [];
#error = null;
/**
* Constructor.
*
* @param window Window.
* @param url Module URL.
*/
constructor(window, url) {
this.#window = window;
this.url = url;
}
/**
* Compiles and evaluates the module.
*
* @returns Module exports.
*/
async evaluate() {
throw new this.#window.TypeError('Unresolved module. We should never end up here.');
}
/**
* Compiles and preloads the module and its imports.
*
* @returns Promise.
*/
async preload() {
throw new this.#window.TypeError('Unresolved module. We should never end up here.');
}
/**
* Add a hook to be called when the module is resolved.
*
* @param resolve Resolve.
* @param reject Reject.
*/
addResolveListener(resolve, reject) {
if (this.#error) {
reject(this.#error);
return;
}
this.#hooks.push({ resolve, reject });
}
/**
* Resolves the module.
*
* @param [error] Error.
*/
resolve(error) {
if (error) {
this.#error = error;
}
for (const hook of this.#hooks) {
if (error) {
hook.reject(error);
}
else {
hook.resolve(null);
}
}
}
}
//# sourceMappingURL=UnresolvedModule.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"UnresolvedModule.js","sourceRoot":"","sources":["../../src/module/UnresolvedModule.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACpB,GAAG,CAAM;IAChB,OAAO,CAAgB;IAChC,MAAM,GAA4E,EAAE,CAAC;IACrF,MAAM,GAAiB,IAAI,CAAC;IAE5B;;;;;OAKG;IACH,YAAY,MAAqB,EAAE,GAAQ;QAC1C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,QAAQ;QACpB,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,iDAAiD,CAAC,CAAC;IACrF,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,OAAO;QACnB,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,iDAAiD,CAAC,CAAC;IACrF,CAAC;IAED;;;;;OAKG;IACI,kBAAkB,CACxB,OAAiC,EACjC,MAA8B;QAE9B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACpB,OAAO;QACR,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACvC,CAAC;IAED;;;;OAIG;IACI,OAAO,CAAC,KAAa;QAC3B,IAAI,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACrB,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChC,IAAI,KAAK,EAAE,CAAC;gBACX,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACP,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;QACF,CAAC;IACF,CAAC;CACD"}