codigo0/node_modules/happy-dom/lib/module/ModuleURLUtility.js
planetazuzu 5d7a6500fe refactor: Fase 1 - Clean Architecture, refactorización modular y eliminación de duplicidades
-  Ticket 1.1: Estructura Clean Architecture en backend
-  Ticket 1.2: Schemas Zod compartidos
-  Ticket 1.3: Refactorización drugs.ts (1362 → 8 archivos modulares)
-  Ticket 1.4: Refactorización procedures.ts (3583 → 6 archivos modulares)
-  Ticket 1.5: Eliminación de duplicidades (~50 líneas)

Cambios principales:
- Creada estructura Clean Architecture en backend/src/
- Schemas Zod compartidos en backend/src/shared/schemas/
- Refactorización modular de drugs y procedures
- Utilidades genéricas en src/utils/ (filter, validation)
- Eliminados scripts obsoletos y documentación antigua
- Corregidos errores: QueryClient, import test-error-handling
- Build verificado y funcionando correctamente
2026-01-25 21:09:47 +01:00

162 lines
6.4 KiB
JavaScript

import { URL } from 'url';
import * as PropertySymbol from '../PropertySymbol.js';
import WindowBrowserContext from '../window/WindowBrowserContext.js';
import Path from 'path';
import FS from 'fs';
const MAIN_FIELDS = ['module', 'main'];
const EXTENSIONS = ['.js', '.mjs'];
/**
* Module URL utility.
*/
export default class ModuleURLUtility {
static nodeModuleResolveCache = new Map();
static packageJsonCache = new Map();
/**
* 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];
const resolved = this.resolveURL(window, parentURLString, url);
if (!importMap) {
return new URL(resolved, parentURLString);
}
if (importMap.scopes.length) {
for (const scope of importMap.scopes) {
if (parentURLString.includes(scope.scope)) {
for (const rule of scope.rules) {
if (resolved.startsWith(rule.from)) {
return new URL(rule.to + resolved.replace(rule.from, ''), parentURLString);
}
}
}
}
}
if (importMap.imports.length) {
for (const rule of importMap.imports) {
if (resolved.startsWith(rule.from)) {
return new URL(rule.to + resolved.replace(rule.from, ''), parentURLString);
}
}
}
return new URL(resolved, parentURLString);
}
/**
* Clears the internal caches.
*/
static clearCache() {
this.nodeModuleResolveCache.clear();
this.packageJsonCache.clear();
}
/**
* Resolves the module URL using the settings.
*
* @param window Window.
* @param parentURL Parent URL.
* @param url Module URL.
*/
static resolveURL(window, parentURL, url) {
const settings = new WindowBrowserContext(window).getSettings();
if (!settings) {
return url;
}
let resolvedURL = url;
if (settings.module.resolveNodeModules) {
resolvedURL = this.resolveNodeModuleURL(settings.module.resolveNodeModules, url);
}
if (settings.module.urlResolver) {
resolvedURL = settings.module.urlResolver({ url: resolvedURL, parentURL, window });
}
return resolvedURL;
}
/**
* Resolves node module URL.
*
* @param resolveNodeModules Settings for resolving node modules.
* @param url Module URL.
*/
static resolveNodeModuleURL(resolveNodeModules, url) {
if (url[0] === '.' ||
url[0] === '/' ||
url.startsWith('http://') ||
url.startsWith('https://')) {
return url;
}
const slash = resolveNodeModules.url[resolveNodeModules.url.length - 1] === '/' ? '' : '/';
const baseURL = `${resolveNodeModules.url}${slash}`;
const nodeModulesDirectory = Path.resolve(resolveNodeModules.directory);
const parts = url.split('/');
const cached = this.nodeModuleResolveCache.get(url);
if (cached) {
return cached;
}
const packageName = url[0] === '@' ? `${parts[0]}/${parts[1]}` : parts[0];
let packageJson = this.packageJsonCache.get(packageName);
if (!packageJson) {
try {
packageJson = JSON.parse(FS.readFileSync(Path.join(nodeModulesDirectory, packageName, 'package.json'), 'utf-8'));
this.packageJsonCache.set(packageName, packageJson);
}
catch {
return url;
}
}
if ((url[0] === '@' && parts.length === 2) || parts.length === 1) {
if (packageJson.exports?.['.']?.import) {
const resolvedURL = `${baseURL}${packageName}/${packageJson.exports['.'].import.replace('./', '')}`;
this.nodeModuleResolveCache.set(url, resolvedURL);
return resolvedURL;
}
const mainFields = resolveNodeModules.mainFields || MAIN_FIELDS;
for (const field of mainFields) {
if (packageJson[field] &&
FS.existsSync(Path.join(nodeModulesDirectory, packageName, packageJson[field]))) {
const resolvedURL = `${baseURL}${url}/${packageJson[field]}`;
this.nodeModuleResolveCache.set(url, resolvedURL);
return resolvedURL;
}
}
return url;
}
const subPath = parts.slice(url[0] === '@' ? 2 : 1).join('/');
if (packageJson.exports) {
for (const key of Object.keys(packageJson.exports)) {
const importEntry = Array.isArray(packageJson.exports[key].import)
? packageJson.exports[key].import[0]
: packageJson.exports[key].import;
if (importEntry) {
const regExp = new RegExp(`^${key.replace('./', '').replace(/\./g, '\\.').replace(/\*/g, '(.*)')}$`);
const match = subPath.match(regExp);
if (match) {
const resolvedSubPath = importEntry.replace('./', '').replace('*', match[1]);
const resolvedURL = `${baseURL}${packageName}/${resolvedSubPath}`;
this.nodeModuleResolveCache.set(url, resolvedURL);
return resolvedURL;
}
}
}
}
if (!url.endsWith('.js') && !url.endsWith('.mjs')) {
for (const ext of EXTENSIONS) {
if (FS.existsSync(Path.join(nodeModulesDirectory, `${url}${ext}`))) {
const resolvedURL = `${baseURL}${url}${ext}`;
this.nodeModuleResolveCache.set(url, resolvedURL);
return resolvedURL;
}
}
}
else {
if (FS.existsSync(Path.join(nodeModulesDirectory, url))) {
const resolvedURL = `${baseURL}${url}`;
this.nodeModuleResolveCache.set(url, resolvedURL);
return resolvedURL;
}
}
return url;
}
}
//# sourceMappingURL=ModuleURLUtility.js.map