typesxml
Version:
Open source XML library written in TypeScript
289 lines • 11.7 kB
JavaScript
"use strict";
/*******************************************************************************
* Copyright (c) 2023 - 2024 Maxprograms.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse License 1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-v10.html
*
* Contributors:
* Maxprograms - initial API and implementation
*******************************************************************************/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Catalog = void 0;
const fs_1 = require("fs");
const path = __importStar(require("node:path"));
const DOMBuilder_1 = require("./DOMBuilder");
const SAXParser_1 = require("./SAXParser");
const XMLUtils_1 = require("./XMLUtils");
class Catalog {
systemCatalog;
publicCatalog;
uriCatalog;
dtdCatalog;
uriRewrites;
systemRewrites;
workDir;
base;
constructor(catalogFile) {
if (!path.isAbsolute(catalogFile)) {
throw new Error('Catalog file must be absolute: ' + catalogFile);
}
if (!(0, fs_1.existsSync)(catalogFile)) {
throw new Error('Catalog file ' + catalogFile + ' not found');
}
this.systemCatalog = new Map();
this.publicCatalog = new Map();
this.uriCatalog = new Map();
this.dtdCatalog = new Map();
this.uriRewrites = new Array();
this.systemRewrites = new Array();
this.workDir = path.dirname(catalogFile);
this.base = '';
let contentHandler = new DOMBuilder_1.DOMBuilder();
let parser = new SAXParser_1.SAXParser();
parser.setContentHandler(contentHandler);
parser.parseFile(catalogFile);
let catalogDocument = contentHandler.getDocument();
let catalogRoot = catalogDocument.getRoot();
if (catalogRoot.getName() !== 'catalog') {
throw new Error('Catalog root element must be <catalog>');
}
this.recurse(catalogRoot);
}
recurse(catalogRoot) {
for (let child of catalogRoot.getChildren()) {
let currentBase = this.base;
if (child.hasAttribute('xml:base') && child.getAttribute("xml:base").getValue() !== '') {
this.base = child.getAttribute("xml:base").getValue();
if (!this.base.endsWith('/')) {
this.base += '/';
}
if (!path.isAbsolute(this.base)) {
this.base = path.resolve(this.workDir, this.base);
}
if (!(0, fs_1.existsSync)(this.base)) {
throw new Error('Invalid xml:base: ' + this.base);
}
}
if (child.getName() === 'public') {
let publicId = child.getAttribute("publicId").getValue();
if (publicId.startsWith("urn:publicid:")) {
publicId = this.unwrapUrn(publicId);
}
if (!this.publicCatalog.has(publicId)) {
let uri = this.makeAbsolute(child.getAttribute("uri").getValue());
if ((0, fs_1.existsSync)(uri)) {
this.publicCatalog.set(publicId, uri);
if (uri.endsWith(".dtd") || uri.endsWith(".ent") || uri.endsWith(".mod")) {
let name = path.basename(uri);
if (!this.dtdCatalog.has(name)) {
this.dtdCatalog.set(name, uri);
}
}
}
}
}
if (child.getName() === 'system') {
let uri = this.makeAbsolute(child.getAttribute("uri").getValue());
if ((0, fs_1.existsSync)(uri)) {
this.systemCatalog.set(child.getAttribute("systemId").getValue(), uri);
if (uri.endsWith(".dtd")) {
let name = path.basename(uri);
if (!this.dtdCatalog.has(name)) {
this.dtdCatalog.set(name, uri);
}
}
}
}
if (child.getName() === 'uri') {
let uri = this.makeAbsolute(child.getAttribute("uri").getValue());
if ((0, fs_1.existsSync)(uri)) {
this.uriCatalog.set(child.getAttribute("name").getValue(), uri);
if (uri.endsWith(".dtd") || uri.endsWith(".ent") || uri.endsWith(".mod")) {
let name = path.basename(uri);
if (!this.dtdCatalog.has(name)) {
this.dtdCatalog.set(name, uri);
}
}
}
}
if (child.getName() === 'rewriteURI') {
let uri = this.makeAbsolute(child.getAttribute("rewritePrefix").getValue());
let pair = [child.getAttribute("uriStartString").getValue(), uri];
if (!this.uriRewrites.includes(pair)) {
this.uriRewrites.push(pair);
}
}
if (child.getName() === 'rewriteSystem') {
let uri = this.makeAbsolute(child.getAttribute("rewritePrefix").getValue());
let pair = [child.getAttribute("systemIdStartString").getValue(), uri];
if (!this.systemRewrites.includes(pair)) {
this.systemRewrites.push(pair);
}
}
if (child.getName() === 'nextCatalog') {
let nextCatalog = this.makeAbsolute(child.getAttribute("catalog").getValue());
let catalog = new Catalog(nextCatalog);
let map = catalog.getSystemCatalog();
map.forEach((value, key) => {
if (!this.systemCatalog.has(key)) {
this.systemCatalog.set(key, value);
}
});
map = catalog.getPublicCatalog();
map.forEach((value, key) => {
if (!this.publicCatalog.has(key)) {
this.publicCatalog.set(key, value);
}
});
map = catalog.getUriCatalog();
map.forEach((value, key) => {
if (!this.uriCatalog.has(key)) {
this.uriCatalog.set(key, value);
}
});
map = catalog.getDtdCatalog();
map.forEach((value, key) => {
if (!this.dtdCatalog.has(key)) {
this.dtdCatalog.set(key, value);
}
});
let array = catalog.getUriRewrites();
array.forEach((value) => {
if (!this.uriRewrites.includes(value)) {
this.uriRewrites.push(value);
}
});
array = catalog.getSystemRewrites();
array.forEach((value) => {
if (!this.systemRewrites.includes(value)) {
this.systemRewrites.push(value);
}
});
}
this.recurse(child);
this.base = currentBase;
}
}
makeAbsolute(uri) {
let file = this.base + uri;
if (!path.isAbsolute(file)) {
if (this.base !== '') {
return path.resolve(this.base, uri);
}
return path.resolve(this.workDir, uri);
}
return this.base + uri;
}
unwrapUrn(urn) {
if (!urn.startsWith('urn:publicid:')) {
return urn;
}
let publicId = urn.trim().substring('urn:publicid:'.length);
publicId = XMLUtils_1.XMLUtils.replaceAll(publicId, '+', ' ');
publicId = XMLUtils_1.XMLUtils.replaceAll(publicId, ':', '//');
publicId = XMLUtils_1.XMLUtils.replaceAll(publicId, ';', '::');
publicId = XMLUtils_1.XMLUtils.replaceAll(publicId, '%2B', '+');
publicId = XMLUtils_1.XMLUtils.replaceAll(publicId, '%3A', ':');
publicId = XMLUtils_1.XMLUtils.replaceAll(publicId, '%2F', '/');
publicId = XMLUtils_1.XMLUtils.replaceAll(publicId, '%3B', ';');
publicId = XMLUtils_1.XMLUtils.replaceAll(publicId, '%27', '\'');
publicId = XMLUtils_1.XMLUtils.replaceAll(publicId, '%3F', '?');
publicId = XMLUtils_1.XMLUtils.replaceAll(publicId, '%23', '#');
return XMLUtils_1.XMLUtils.replaceAll(publicId, '%25', '%');
}
getSystemCatalog() {
return this.systemCatalog;
}
getPublicCatalog() {
return this.publicCatalog;
}
getUriCatalog() {
return this.uriCatalog;
}
getDtdCatalog() {
return this.dtdCatalog;
}
getUriRewrites() {
return this.uriRewrites;
}
getSystemRewrites() {
return this.systemRewrites;
}
resolveEntity(publicId, systemId) {
if (publicId) {
let location = this.matchPublic(publicId);
if (location) {
return location;
}
}
let location = this.matchSystem(systemId);
if (location) {
return location;
}
return undefined;
}
matchSystem(systemId) {
if (systemId) {
for (let pair of this.systemRewrites) {
if (systemId.startsWith(pair[0])) {
systemId = pair[1] + systemId.substring(pair[0].length);
}
}
if (this.systemCatalog.has(systemId)) {
return this.systemCatalog.get(systemId);
}
let fileName = path.basename(systemId);
if (this.dtdCatalog.has(fileName)) {
return this.dtdCatalog.get(fileName);
}
}
return undefined;
}
matchPublic(publicId) {
if (publicId.startsWith("urn:publicid:")) {
publicId = this.unwrapUrn(publicId);
}
if (this.publicCatalog.has(publicId)) {
return this.publicCatalog.get(publicId);
}
return undefined;
}
}
exports.Catalog = Catalog;
//# sourceMappingURL=Catalog.js.map