Skip to content

Commit 5729844

Browse files
committed
Switched to strict mode
1 parent 8090286 commit 5729844

20 files changed

Lines changed: 232 additions & 167 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export class Test {
6969

7070
// build the document again, this time from a string
7171
xmlParser.parseString(doc.toString());
72-
let newDoc = (contentHandler as DOMBuilder).getDocument();
72+
let newDoc : XMLDocument = (contentHandler as DOMBuilder).getDocument();
7373
console.log(newDoc.toString());
7474

7575
} catch (error: any) {

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "typesxml",
33
"productName": "TypesXML",
4-
"version": "1.7.0",
4+
"version": "1.8.0",
55
"description": "Open source XML library written in TypeScript",
66
"keywords": [
77
"XML",
@@ -29,7 +29,7 @@
2929
"url": "https://github.com/rmraya/TypesXML.git"
3030
},
3131
"devDependencies": {
32-
"@types/node": "^22.13.5",
33-
"typescript": "^5.7.3"
32+
"@types/node": "^24.3.0",
33+
"typescript": "^5.9.2"
3434
}
3535
}

ts/Catalog.ts

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212

1313
import { existsSync } from "fs";
1414
import * as path from "node:path";
15-
import { ContentHandler } from "./ContentHandler";
1615
import { DOMBuilder } from "./DOMBuilder";
1716
import { SAXParser } from "./SAXParser";
17+
import { XMLAttribute } from "./XMLAttribute";
1818
import { XMLDocument } from "./XMLDocument";
1919
import { XMLElement } from "./XMLElement";
2020
import { XMLUtils } from "./XMLUtils";
@@ -48,12 +48,18 @@ export class Catalog {
4848
this.workDir = path.dirname(catalogFile);
4949
this.base = '';
5050

51-
let contentHandler: ContentHandler = new DOMBuilder();
51+
let contentHandler: DOMBuilder = new DOMBuilder();
5252
let parser: SAXParser = new SAXParser();
5353
parser.setContentHandler(contentHandler);
5454
parser.parseFile(catalogFile);
55-
let catalogDocument: XMLDocument = (contentHandler as DOMBuilder).getDocument();
56-
let catalogRoot: XMLElement = catalogDocument.getRoot();
55+
let catalogDocument: XMLDocument | undefined = contentHandler.getDocument();
56+
if (!catalogDocument) {
57+
throw new Error('Catalog file ' + catalogFile + ' is empty');
58+
}
59+
let catalogRoot: XMLElement | undefined = catalogDocument.getRoot();
60+
if (!catalogRoot) {
61+
throw new Error('Catalog file ' + catalogFile + ' is empty');
62+
}
5763
if (catalogRoot.getName() !== 'catalog') {
5864
throw new Error('Catalog root element must be <catalog>');
5965
}
@@ -63,8 +69,9 @@ export class Catalog {
6369
recurse(catalogRoot: XMLElement) {
6470
for (let child of catalogRoot.getChildren()) {
6571
let currentBase: string = this.base;
66-
if (child.hasAttribute('xml:base') && child.getAttribute("xml:base").getValue() !== '') {
67-
this.base = child.getAttribute("xml:base").getValue();
72+
let xmlBase: XMLAttribute | undefined = child.getAttribute("xml:base");
73+
if (xmlBase) {
74+
this.base = xmlBase.getValue();
6875
if (!this.base.endsWith('/')) {
6976
this.base += '/';
7077
}
@@ -76,12 +83,20 @@ export class Catalog {
7683
}
7784
}
7885
if (child.getName() === 'public') {
79-
let publicId: string = child.getAttribute("publicId").getValue();
86+
let publicIdAttribute: XMLAttribute | undefined = child.getAttribute("publicId");
87+
if (!publicIdAttribute) {
88+
throw new Error('publicId attribute is required for <public>');
89+
}
90+
let publicId: string = publicIdAttribute.getValue();
8091
if (publicId.startsWith("urn:publicid:")) {
8192
publicId = this.unwrapUrn(publicId);
8293
}
8394
if (!this.publicCatalog.has(publicId)) {
84-
let uri: string = this.makeAbsolute(child.getAttribute("uri").getValue());
95+
let uriAttribute: XMLAttribute | undefined = child.getAttribute("uri");
96+
if (!uriAttribute) {
97+
throw new Error('uri attribute is required for <public>');
98+
}
99+
let uri: string = this.makeAbsolute(uriAttribute.getValue());
85100
if (existsSync(uri)) {
86101
this.publicCatalog.set(publicId, uri);
87102
if (uri.endsWith(".dtd") || uri.endsWith(".ent") || uri.endsWith(".mod")) {
@@ -94,9 +109,17 @@ export class Catalog {
94109
}
95110
}
96111
if (child.getName() === 'system') {
97-
let uri: string = this.makeAbsolute(child.getAttribute("uri").getValue());
112+
let uriAttribute: XMLAttribute | undefined = child.getAttribute("uri");
113+
if (!uriAttribute) {
114+
throw new Error('uri attribute is required for <system>');
115+
}
116+
let uri: string = this.makeAbsolute(uriAttribute.getValue());
98117
if (existsSync(uri)) {
99-
this.systemCatalog.set(child.getAttribute("systemId").getValue(), uri);
118+
let systemId: XMLAttribute | undefined = child.getAttribute("systemId");
119+
if (!systemId) {
120+
throw new Error('systemId attribute is required for <system>');
121+
}
122+
this.systemCatalog.set(systemId.getValue(), uri);
100123
if (uri.endsWith(".dtd")) {
101124
let name: string = path.basename(uri);
102125
if (!this.dtdCatalog.has(name)) {
@@ -106,9 +129,17 @@ export class Catalog {
106129
}
107130
}
108131
if (child.getName() === 'uri') {
109-
let uri: string = this.makeAbsolute(child.getAttribute("uri").getValue());
132+
let uriAttribute: XMLAttribute | undefined = child.getAttribute("uri");
133+
if (!uriAttribute) {
134+
throw new Error('uri attribute is required for <uri>');
135+
}
136+
let uri: string = this.makeAbsolute(uriAttribute.getValue());
110137
if (existsSync(uri)) {
111-
this.uriCatalog.set(child.getAttribute("name").getValue(), uri);
138+
let nameAttribute: XMLAttribute | undefined = child.getAttribute("name");
139+
if (!nameAttribute) {
140+
throw new Error('name attribute is required for <uri>');
141+
}
142+
this.uriCatalog.set(nameAttribute.getValue(), uri);
112143
if (uri.endsWith(".dtd") || uri.endsWith(".ent") || uri.endsWith(".mod")) {
113144
let name: string = path.basename(uri);
114145
if (!this.dtdCatalog.has(name)) {
@@ -118,21 +149,41 @@ export class Catalog {
118149
}
119150
}
120151
if (child.getName() === 'rewriteURI') {
121-
let uri: string = this.makeAbsolute(child.getAttribute("rewritePrefix").getValue());
122-
let pair: string[] = [child.getAttribute("uriStartString").getValue(), uri];
152+
let rewritePrefix: XMLAttribute | undefined = child.getAttribute("rewritePrefix");
153+
if (!rewritePrefix) {
154+
throw new Error('rewritePrefix attribute is required for <rewriteURI>');
155+
}
156+
let uri: string = this.makeAbsolute(rewritePrefix.getValue());
157+
let uriStartString: XMLAttribute | undefined = child.getAttribute("uriStartString");
158+
if (!uriStartString) {
159+
throw new Error('uriStartString attribute is required for <rewriteURI>');
160+
}
161+
let pair: string[] = [uriStartString.getValue(), uri];
123162
if (!this.uriRewrites.includes(pair)) {
124163
this.uriRewrites.push(pair);
125164
}
126165
}
127166
if (child.getName() === 'rewriteSystem') {
128-
let uri: string = this.makeAbsolute(child.getAttribute("rewritePrefix").getValue());
129-
let pair: string[] = [child.getAttribute("systemIdStartString").getValue(), uri];
167+
let rewritePrefix: XMLAttribute | undefined = child.getAttribute("rewritePrefix");
168+
if (!rewritePrefix) {
169+
throw new Error('rewritePrefix attribute is required for <rewriteSystem>');
170+
}
171+
let uri: string = this.makeAbsolute(rewritePrefix.getValue());
172+
let systemIdStartString: XMLAttribute | undefined = child.getAttribute("systemIdStartString");
173+
if (!systemIdStartString) {
174+
throw new Error('systemIdStartString attribute is required for <rewriteSystem>');
175+
}
176+
let pair: string[] = [systemIdStartString.getValue(), uri];
130177
if (!this.systemRewrites.includes(pair)) {
131178
this.systemRewrites.push(pair);
132179
}
133180
}
134181
if (child.getName() === 'nextCatalog') {
135-
let nextCatalog: string = this.makeAbsolute(child.getAttribute("catalog").getValue());
182+
let catalogAttribute: XMLAttribute | undefined = child.getAttribute("catalog");
183+
if (!catalogAttribute) {
184+
throw new Error('catalog attribute is required for <nextCatalog>');
185+
}
186+
let nextCatalog: string = this.makeAbsolute(catalogAttribute.getValue());
136187
let catalog: Catalog = new Catalog(nextCatalog);
137188
let map: Map<string, string> = catalog.getSystemCatalog();
138189
map.forEach((value, key) => {
@@ -229,21 +280,17 @@ export class Catalog {
229280
return this.systemRewrites;
230281
}
231282

232-
resolveEntity(publicId: string, systemId: string): string {
283+
resolveEntity(publicId: string, systemId: string): string | undefined {
233284
if (publicId) {
234-
let location: string = this.matchPublic(publicId);
285+
let location: string | undefined = this.matchPublic(publicId);
235286
if (location) {
236287
return location;
237288
}
238289
}
239-
let location: string = this.matchSystem(systemId);
240-
if (location) {
241-
return location;
242-
}
243-
return undefined;
290+
return this.matchSystem(systemId);
244291
}
245292

246-
matchSystem(systemId: string): string {
293+
matchSystem(systemId: string): string | undefined {
247294
if (systemId) {
248295
for (let pair of this.systemRewrites) {
249296
if (systemId.startsWith(pair[0])) {
@@ -261,7 +308,7 @@ export class Catalog {
261308
return undefined;
262309
}
263310

264-
matchPublic(publicId: string): string {
311+
matchPublic(publicId: string): string | undefined {
265312
if (publicId.startsWith("urn:publicid:")) {
266313
publicId = this.unwrapUrn(publicId);
267314
}

ts/ContentHandler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface ContentHandler {
2121
startDocument(): void;
2222
endDocument(): void;
2323

24-
xmlDeclaration(version: string, encoding: string, standalone: string): void;
24+
xmlDeclaration(version: string, encoding: string, standalone: string | undefined): void;
2525

2626
startElement(name: string, atts: Array<XMLAttribute>): void;
2727
endElement(name: string): void;

ts/DOMBuilder.ts

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ import { Grammar } from "./grammar/Grammar";
1515

1616
export class DOMBuilder implements ContentHandler {
1717

18-
inCdData: boolean;
19-
currentCData: CData;
20-
document: XMLDocument;
21-
stack: Array<XMLElement>;
22-
catalog: Catalog;
23-
dtdParser: DTDParser;
24-
grammarUrl: string;
25-
grammar: Grammar;
18+
inCdData: boolean = false;
19+
currentCData: CData = new CData('');
20+
document: XMLDocument | undefined;
21+
stack: Array<XMLElement> = [];
22+
catalog: Catalog | undefined;
23+
dtdParser: DTDParser | undefined;
24+
grammarUrl: string | undefined;
25+
grammar: Grammar | undefined;
2626

2727
initialize(): void {
2828
this.document = new XMLDocument();
@@ -38,7 +38,7 @@ export class DOMBuilder implements ContentHandler {
3838
this.dtdParser = dtdParser;
3939
}
4040

41-
getDocument(): XMLDocument {
41+
getDocument(): XMLDocument | undefined {
4242
return this.document;
4343
}
4444

@@ -52,7 +52,7 @@ export class DOMBuilder implements ContentHandler {
5252

5353
xmlDeclaration(version: string, encoding: string, standalone: string): void {
5454
let xmlDclaration = new XMLDeclaration(version, encoding, standalone);
55-
this.document.setXmlDeclaration(xmlDclaration);
55+
this.document?.setXmlDeclaration(xmlDclaration);
5656
}
5757

5858
startElement(name: string, atts: XMLAttribute[]): void {
@@ -63,7 +63,7 @@ export class DOMBuilder implements ContentHandler {
6363
if (this.stack.length > 0) {
6464
this.stack[this.stack.length - 1].addElement(element);
6565
} else {
66-
this.document.setRoot(element);
66+
this.document?.setRoot(element);
6767
}
6868
this.stack.push(element);
6969
}
@@ -73,7 +73,7 @@ export class DOMBuilder implements ContentHandler {
7373
}
7474

7575
internalSubset(declaration: string): void {
76-
let docType: XMLDocumentType = this.document.getDocumentType();
76+
let docType: XMLDocumentType | undefined = this.document?.getDocumentType();
7777
if (docType) {
7878
docType.setInternalSubset(declaration);
7979
}
@@ -88,7 +88,7 @@ export class DOMBuilder implements ContentHandler {
8888
if (this.stack.length > 0) {
8989
this.stack[this.stack.length - 1].addTextNode(textNode);
9090
} else {
91-
this.document.addTextNode(textNode);
91+
this.document?.addTextNode(textNode);
9292
}
9393
}
9494

@@ -97,7 +97,7 @@ export class DOMBuilder implements ContentHandler {
9797
if (this.stack.length > 0) {
9898
this.stack[this.stack.length - 1].addTextNode(textNode);
9999
} else {
100-
this.document.addTextNode(textNode);
100+
this.document?.addTextNode(textNode);
101101
}
102102
}
103103

@@ -106,7 +106,7 @@ export class DOMBuilder implements ContentHandler {
106106
if (this.stack.length > 0) {
107107
this.stack[this.stack.length - 1].addComment(comment);
108108
} else {
109-
this.document.addComment(comment);
109+
this.document?.addComment(comment);
110110
}
111111
}
112112

@@ -115,12 +115,15 @@ export class DOMBuilder implements ContentHandler {
115115
if (this.stack.length > 0) {
116116
this.stack[this.stack.length - 1].addProcessingInstruction(pi);
117117
} else {
118-
this.document.addProcessingInstruction(pi);
118+
this.document?.addProcessingInstruction(pi);
119119
}
120120
if (target === 'xml-model' && this.catalog) {
121+
// TODO process the xml-model
122+
/*
121123
let atts: Map<string, string> = this.parseXmlModel(data);
122124
let href: string = atts.get('href');
123125
let schematypens: string = atts.get('schematypens');
126+
*/
124127
}
125128
}
126129

@@ -180,14 +183,17 @@ export class DOMBuilder implements ContentHandler {
180183

181184
startDTD(name: string, publicId: string, systemId: string): void {
182185
let docType: XMLDocumentType = new XMLDocumentType(name, publicId, systemId);
183-
this.document.setDocumentType(docType);
186+
this.document?.setDocumentType(docType);
184187
if (this.catalog) {
185-
this.grammarUrl = this.catalog.resolveEntity(publicId, systemId);
186-
// TODO check grammar type (DTD, XDS or RelaxNG) and use the ritght parser
187-
if (this.dtdParser && this.grammarUrl) {
188-
let dtdGrammar: Grammar = this.dtdParser.parseDTD(this.grammarUrl);
189-
if (dtdGrammar) {
190-
this.grammar = dtdGrammar;
188+
let url = this.catalog.resolveEntity(publicId, systemId);
189+
if (url) {
190+
this.grammarUrl = url;
191+
// TODO check grammar type (DTD, XSD or RelaxNG) and use the ritght parser
192+
if (this.dtdParser && this.grammarUrl) {
193+
let dtdGrammar: Grammar = this.dtdParser.parseDTD(this.grammarUrl);
194+
if (dtdGrammar) {
195+
this.grammar = dtdGrammar;
196+
}
191197
}
192198
}
193199
}

ts/FileReader.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class FileReader {
3737

3838
static detectEncoding(path: string): BufferEncoding {
3939
const fd = openSync(path, 'r');
40-
let buffer = Buffer.alloc(3);
40+
let buffer: Buffer = Buffer.alloc(3);
4141
let bytesRead: number = readSync(fd, buffer, 0, 3, 0);
4242
closeSync(fd);
4343

ts/Indenter.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import { Constants } from "./Constants";
1414
import { TextNode } from "./TextNode";
15+
import { XMLAttribute } from "./XMLAttribute";
1516
import { XMLElement } from "./XMLElement";
1617
import { XMLNode } from "./XMLNode";
1718
import { XMLUtils } from "./XMLUtils";
@@ -39,7 +40,8 @@ export class Indenter {
3940
}
4041

4142
indent(e: XMLElement): void {
42-
if (e.hasAttribute('xml:space') && 'preserve' === e.getAttribute('xml:space').getValue()) {
43+
let space: XMLAttribute | undefined = e.getAttribute('xml:space');
44+
if (space && 'preserve' === space.getValue()) {
4345
return;
4446
}
4547
if (!this.hasText(e)) {
@@ -56,10 +58,10 @@ export class Indenter {
5658
private indentElement(e: XMLElement) {
5759
let start: string = '\n';
5860
let end: string = '\n';
59-
for (let i = 0; i < (this.indentLevel * this.numSpaces); i++) {
61+
for (let i: number = 0; i < (this.indentLevel * this.numSpaces); i++) {
6062
start += ' ';
6163
}
62-
for (let i = 0; i < ((this.indentLevel - 1) * this.numSpaces); i++) {
64+
for (let i: number = 0; i < ((this.indentLevel - 1) * this.numSpaces); i++) {
6365
end += ' ';
6466
}
6567
let content: Array<XMLNode> = new Array<XMLNode>();

0 commit comments

Comments
 (0)