- ✅ 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
162 lines
6.4 KiB
JavaScript
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
|