- ✅ 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
105 lines
2.8 KiB
JavaScript
105 lines
2.8 KiB
JavaScript
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
function normalizeWindowsPath(input = "") {
|
|
if (!input) {
|
|
return input;
|
|
}
|
|
return input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
|
|
}
|
|
|
|
const _UNC_REGEX = /^[/\\]{2}/;
|
|
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
|
|
const _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
|
|
const normalize = function(path) {
|
|
if (path.length === 0) {
|
|
return ".";
|
|
}
|
|
path = normalizeWindowsPath(path);
|
|
const isUNCPath = path.match(_UNC_REGEX);
|
|
const isPathAbsolute = isAbsolute(path);
|
|
const trailingSeparator = path[path.length - 1] === "/";
|
|
path = normalizeString(path, !isPathAbsolute);
|
|
if (path.length === 0) {
|
|
if (isPathAbsolute) {
|
|
return "/";
|
|
}
|
|
return trailingSeparator ? "./" : ".";
|
|
}
|
|
if (trailingSeparator) {
|
|
path += "/";
|
|
}
|
|
if (_DRIVE_LETTER_RE.test(path)) {
|
|
path += "/";
|
|
}
|
|
if (isUNCPath) {
|
|
if (!isPathAbsolute) {
|
|
return `//./${path}`;
|
|
}
|
|
return `//${path}`;
|
|
}
|
|
return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;
|
|
};
|
|
function normalizeString(path, allowAboveRoot) {
|
|
let res = "";
|
|
let lastSegmentLength = 0;
|
|
let lastSlash = -1;
|
|
let dots = 0;
|
|
let char = null;
|
|
for (let index = 0; index <= path.length; ++index) {
|
|
if (index < path.length) {
|
|
char = path[index];
|
|
} else if (char === "/") {
|
|
break;
|
|
} else {
|
|
char = "/";
|
|
}
|
|
if (char === "/") {
|
|
if (lastSlash === index - 1 || dots === 1) ; else if (dots === 2) {
|
|
if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
|
|
if (res.length > 2) {
|
|
const lastSlashIndex = res.lastIndexOf("/");
|
|
if (lastSlashIndex === -1) {
|
|
res = "";
|
|
lastSegmentLength = 0;
|
|
} else {
|
|
res = res.slice(0, lastSlashIndex);
|
|
lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
|
|
}
|
|
lastSlash = index;
|
|
dots = 0;
|
|
continue;
|
|
} else if (res.length > 0) {
|
|
res = "";
|
|
lastSegmentLength = 0;
|
|
lastSlash = index;
|
|
dots = 0;
|
|
continue;
|
|
}
|
|
}
|
|
if (allowAboveRoot) {
|
|
res += res.length > 0 ? "/.." : "..";
|
|
lastSegmentLength = 2;
|
|
}
|
|
} else {
|
|
if (res.length > 0) {
|
|
res += `/${path.slice(lastSlash + 1, index)}`;
|
|
} else {
|
|
res = path.slice(lastSlash + 1, index);
|
|
}
|
|
lastSegmentLength = index - lastSlash - 1;
|
|
}
|
|
lastSlash = index;
|
|
dots = 0;
|
|
} else if (char === "." && dots !== -1) {
|
|
++dots;
|
|
} else {
|
|
dots = -1;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
const isAbsolute = function(p) {
|
|
return _IS_ABSOLUTE_RE.test(p);
|
|
};
|
|
|
|
export { normalize as n };
|