Skip to content
This repository was archived by the owner on Aug 7, 2021. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 98bc543

Browse files
author
vakrilov
committedSep 17, 2019
refactor: use sax xml parser instead of tns
1 parent d786a04 commit 98bc543

File tree

3 files changed

+61
-16
lines changed

3 files changed

+61
-16
lines changed
 

‎package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"request": "2.88.0",
6464
"resolve-url-loader": "~3.0.0",
6565
"sass-loader": "~7.1.0",
66+
"sax": "^1.2.4",
6667
"schema-utils": "0.4.5",
6768
"semver": "^6.0.0",
6869
"shelljs": "0.6.0",
@@ -84,6 +85,7 @@
8485
"@types/loader-utils": "^1.1.3",
8586
"@types/node": "^10.12.12",
8687
"@types/proxyquire": "1.3.28",
88+
"@types/sax": "^1.2.0",
8789
"@types/semver": "^6.0.0",
8890
"@types/webpack": "^4.4.34",
8991
"conventional-changelog-cli": "^1.3.22",

‎xml-namespace-loader.spec.ts

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ interface TestSetup {
1818
expectedDeps: string[],
1919
expectedRegs: { name: string, path: string }[],
2020
ignore?: RegExp,
21-
assureNoDeps?: boolean;
21+
assureNoDeps?: boolean,
22+
expectError?: boolean
2223
}
2324

2425
function getContext(
2526
done: DoneFn,
26-
{ resolveMap, expectedDeps, expectedRegs, assureNoDeps, ignore }: TestSetup) {
27+
{ resolveMap, expectedDeps, expectedRegs, assureNoDeps, ignore, expectError }: TestSetup) {
2728
const actualDeps: string[] = [];
2829

2930
const loaderContext = {
@@ -42,7 +43,13 @@ function getContext(
4243
expect(source).not.toContain("global.registerModule");
4344
}
4445

45-
done();
46+
if (error && !expectError) {
47+
done.fail(error)
48+
} else if (!error && expectError) {
49+
done.fail("Error expected here")
50+
} else {
51+
done();
52+
}
4653
},
4754
resolve: (context: string, request: string, callback: (err: Error, result: string) => void) => {
4855
// console.log(`Resolve request: ${request}, result: ${resolveMap[request]}`);
@@ -61,7 +68,7 @@ function getContext(
6168
return loaderContext;
6269
}
6370

64-
fdescribe("XmlNamespaceLoader", () => {
71+
describe("XmlNamespaceLoader", () => {
6572
it("with namespace pointing to files", (done) => {
6673
const resolveMap = {
6774
"app/nativescript-ui-chart": "app/nativescript-ui-chart.js",
@@ -186,4 +193,31 @@ fdescribe("XmlNamespaceLoader", () => {
186193

187194
xmlNsLoader.call(loaderContext, CODE_FILE);
188195
})
196+
197+
it("with XML declaration and Doctype does not fail", (done) => {
198+
const resolveMap = {};
199+
const expectedDeps = [];
200+
const expectedRegs = [];
201+
202+
const testXml = `
203+
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
204+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
205+
<!-- comment.xml -->
206+
<Page xmlns="http://www.nativescript.org/tns.xsd"></Page>`;
207+
208+
const loaderContext = getContext(done, { resolveMap, expectedDeps, expectedRegs, assureNoDeps: true });
209+
210+
xmlNsLoader.call(loaderContext, testXml);
211+
})
212+
it("with invalid XML fails", (done) => {
213+
const resolveMap = {};
214+
const expectedDeps = [];
215+
const expectedRegs = [];
216+
217+
const testXml = `<Page xmlns="http://www.nativescript.org/tns.xsd"></PageOpsWrongTagHere>`;
218+
219+
const loaderContext = getContext(done, { resolveMap, expectedDeps, expectedRegs, expectError: true });
220+
221+
xmlNsLoader.call(loaderContext, testXml);
222+
})
189223
});

‎xml-namespace-loader.ts

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,27 @@
11
import { parse, join } from "path";
22
import { promisify } from "util";
33
import { loader } from "webpack";
4+
import { parser, QualifiedTag } from "sax";
5+
46
import { convertSlashesInPath } from "./projectHelpers";
57

68
interface NamespaceEntry {
79
name: string;
810
path: string
911
}
1012

11-
const loader: loader.Loader = function (source, map) {
13+
const loader: loader.Loader = function (source: string, map) {
1214
this.value = source;
1315
const { ignore } = this.query;
1416
const callback = this.async();
1517

16-
const { XmlParser } = require("tns-core-modules/xml");
17-
1818
const resolvePromise = promisify(this.resolve);
1919
const promises: Promise<any>[] = [];
20-
2120
const namespaces: NamespaceEntry[] = [];
22-
const parser = new XmlParser((event) => {
23-
const { namespace, elementName } = event;
24-
const moduleName = `${namespace}/${elementName}`;
21+
let parsingError = false;
2522

23+
const handleOpenTag = (namespace: string, elementName: string) => {
24+
const moduleName = `${namespace}/${elementName}`;
2625
if (
2726
namespace &&
2827
!namespace.startsWith("http") &&
@@ -87,9 +86,16 @@ const loader: loader.Loader = function (source, map) {
8786
})
8887
);
8988
}
90-
}, undefined, true);
89+
}
9190

92-
parser.parse(source);
91+
const saxParser = parser(true, { xmlns: true });
92+
saxParser.onopentag = (node: QualifiedTag) => { handleOpenTag(node.uri, node.local); };
93+
saxParser.onerror = (err) => {
94+
saxParser.error = null;
95+
parsingError = true;
96+
callback(err);
97+
};
98+
saxParser.write(source).close();
9399

94100
Promise.all(promises).then(() => {
95101
const distinctNamespaces = new Map<string, string>();
@@ -108,11 +114,14 @@ const loader: loader.Loader = function (source, map) {
108114

109115
const wrapped = `${moduleRegisters.join("")}\nmodule.exports = ${json}`;
110116

111-
callback(null, wrapped, map);
117+
if (!parsingError) {
118+
callback(null, wrapped, map);
119+
}
112120
}).catch((err) => {
113-
callback(err);
121+
if (!parsingError) {
122+
callback(err);
123+
}
114124
})
115-
116125
}
117126

118127
export default loader;

0 commit comments

Comments
 (0)
This repository has been archived.