typescriptify and cleanup
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -35,3 +35,4 @@ jspm_packages
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
/dist
|
||||
|
||||
51
.vscode/launch.json
vendored
Normal file
51
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"program": "${workspaceFolder}\\node_stream_zip.js",
|
||||
"preLaunchTask": "tsc: build - tsconfig.json",
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/dist/**/*.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Mocha All",
|
||||
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
|
||||
"args": [
|
||||
"--timeout",
|
||||
"999999",
|
||||
"--colors",
|
||||
"-r",
|
||||
"ts-node/register",
|
||||
"test/**/*.spec.ts"
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Mocha Current File",
|
||||
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
|
||||
"args": [
|
||||
"--timeout",
|
||||
"999999",
|
||||
"--colors",
|
||||
"-r",
|
||||
"ts-node/register",
|
||||
"${file}"
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
|
||||
]
|
||||
}
|
||||
614
package-lock.json
generated
Normal file
614
package-lock.json
generated
Normal file
@@ -0,0 +1,614 @@
|
||||
{
|
||||
"name": "xml-streamer",
|
||||
"version": "0.2.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
|
||||
"integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
|
||||
"integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.0.0",
|
||||
"esutils": "^2.0.2",
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.132",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.132.tgz",
|
||||
"integrity": "sha512-RNUU1rrh85NgUJcjOOr96YXr+RHwInGbaQCZmlitqOaCKXffj8bh+Zxwuq5rjDy5OgzFldDVoqk4pyLEDiwxIw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mocha": {
|
||||
"version": "5.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
|
||||
"integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "12.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.4.tgz",
|
||||
"integrity": "sha512-j8YL2C0fXq7IONwl/Ud5Kt0PeXw22zGERt+HSSnwbKOJVsAGkEz3sFCYwaF9IOuoG1HOtE0vKCj6sXF7Q0+Vaw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/should": {
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/should/-/should-13.0.0.tgz",
|
||||
"integrity": "sha512-Mi6YZ2ABnnGGFMuiBDP0a8s1ZDCDNHqP97UH8TyDmCWuGGavpsFMfJnAMYaaqmDlSCOCNbVLHBrSDEOpx/oLhw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"should": "*"
|
||||
}
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"arg": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz",
|
||||
"integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==",
|
||||
"dev": true
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"requires": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"buffer-from": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||
"dev": true
|
||||
},
|
||||
"builtin-modules": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
|
||||
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.0.0.tgz",
|
||||
"integrity": "sha1-ib2d9nMrUSVrxnBTQrugLtEhMe8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "0.6.2"
|
||||
}
|
||||
},
|
||||
"diff": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"dev": true
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
|
||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
|
||||
"dev": true
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
|
||||
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz",
|
||||
"integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=",
|
||||
"dev": true
|
||||
},
|
||||
"growl": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz",
|
||||
"integrity": "sha1-Sy3sjZB+k9szZiTc7AGDUC+MlCg=",
|
||||
"dev": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
},
|
||||
"jade": {
|
||||
"version": "0.26.3",
|
||||
"resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz",
|
||||
"integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "0.6.1",
|
||||
"mkdirp": "0.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz",
|
||||
"integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz",
|
||||
"integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.13.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
|
||||
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.5",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
|
||||
"integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw=="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "2.7.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
|
||||
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=",
|
||||
"dev": true
|
||||
},
|
||||
"make-error": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
|
||||
"integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
},
|
||||
"mocha": {
|
||||
"version": "1.21.5",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-1.21.5.tgz",
|
||||
"integrity": "sha1-fFiwkXTfl25DSiOx6NY5hz/FKek=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "2.3.0",
|
||||
"debug": "2.0.0",
|
||||
"diff": "1.0.8",
|
||||
"escape-string-regexp": "1.0.2",
|
||||
"glob": "3.2.3",
|
||||
"growl": "1.8.1",
|
||||
"jade": "0.26.3",
|
||||
"mkdirp": "0.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz",
|
||||
"integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=",
|
||||
"dev": true
|
||||
},
|
||||
"diff": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-1.0.8.tgz",
|
||||
"integrity": "sha1-NDJ2MI7Jkbe8giZ+1VvBQR+XFmY=",
|
||||
"dev": true
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz",
|
||||
"integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=",
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz",
|
||||
"integrity": "sha1-4xPusknHr/qlxHUoaw4RW1mDlGc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "~2.0.0",
|
||||
"inherits": "2",
|
||||
"minimatch": "~0.2.11"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "0.2.14",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
|
||||
"integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "2",
|
||||
"sigmund": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
|
||||
"integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz",
|
||||
"integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw=",
|
||||
"dev": true
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
|
||||
},
|
||||
"node-expat": {
|
||||
"version": "2.3.15",
|
||||
"resolved": "https://registry.npmjs.org/node-expat/-/node-expat-2.3.15.tgz",
|
||||
"integrity": "sha1-lqU6C8AGSdr3j0/AdKI+ZEwiO0w=",
|
||||
"requires": {
|
||||
"bindings": "^1.2.1",
|
||||
"nan": "^2.3.5"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||
"dev": true
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz",
|
||||
"integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
},
|
||||
"should": {
|
||||
"version": "13.2.3",
|
||||
"resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz",
|
||||
"integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"should-equal": "^2.0.0",
|
||||
"should-format": "^3.0.3",
|
||||
"should-type": "^1.4.0",
|
||||
"should-type-adaptors": "^1.0.1",
|
||||
"should-util": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"should-equal": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz",
|
||||
"integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"should-type": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"should-format": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz",
|
||||
"integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"should-type": "^1.3.0",
|
||||
"should-type-adaptors": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"should-type": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz",
|
||||
"integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=",
|
||||
"dev": true
|
||||
},
|
||||
"should-type-adaptors": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz",
|
||||
"integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"should-type": "^1.3.0",
|
||||
"should-util": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"should-util": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz",
|
||||
"integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=",
|
||||
"dev": true
|
||||
},
|
||||
"sigmund": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
|
||||
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.12",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz",
|
||||
"integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"ts-node": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.2.0.tgz",
|
||||
"integrity": "sha512-m8XQwUurkbYqXrKqr3WHCW310utRNvV5OnRVeISeea7LoCWVcdfeB/Ntl8JYWFh+WRoUAdBgESrzKochQt7sMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"arg": "^4.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"source-map-support": "^0.5.6",
|
||||
"yn": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"diff": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
|
||||
"integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
||||
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
|
||||
"dev": true
|
||||
},
|
||||
"tslint": {
|
||||
"version": "5.17.0",
|
||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.17.0.tgz",
|
||||
"integrity": "sha512-pflx87WfVoYepTet3xLfDOLDm9Jqi61UXIKePOuca0qoAZyrGWonDG9VTbji58Fy+8gciUn8Bt7y69+KEVjc/w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"builtin-modules": "^1.1.1",
|
||||
"chalk": "^2.3.0",
|
||||
"commander": "^2.12.1",
|
||||
"diff": "^3.2.0",
|
||||
"glob": "^7.1.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
"minimatch": "^3.0.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"resolve": "^1.3.2",
|
||||
"semver": "^5.3.0",
|
||||
"tslib": "^1.8.0",
|
||||
"tsutils": "^2.29.0"
|
||||
}
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "2.29.0",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
|
||||
"integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.8.1"
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.1.tgz",
|
||||
"integrity": "sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw==",
|
||||
"dev": true
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
},
|
||||
"yn": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.0.tgz",
|
||||
"integrity": "sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
32
package.json
32
package.json
@@ -24,19 +24,39 @@
|
||||
"url": "https://github.com/Sai1919/xml-streamer"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-expat": "2.3.15",
|
||||
"lodash": "4.17.5"
|
||||
"lodash": "4.17.5",
|
||||
"node-expat": "2.3.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "^1.21.4",
|
||||
"should": "11.1.1",
|
||||
"standard": "8.5.0"
|
||||
"should": "^13.2.3",
|
||||
"@types/lodash": "^4.14.132",
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^12.0.4",
|
||||
"@types/should": "^13.0.0",
|
||||
"ts-node": "^8.2.0",
|
||||
"tslint": "^5.17.0",
|
||||
"typescript": "^3.5.1"
|
||||
},
|
||||
"optionalDependencies": {},
|
||||
"main": "./parser",
|
||||
"main": "dist/parser.js",
|
||||
"types": "dist/parser.d.ts",
|
||||
"scripts": {
|
||||
"test": "mocha && standard"
|
||||
"performance-test": "node --prof node_modules/mocha/bin/_mocha -r ts-node/register test/**/*.spec.ts",
|
||||
"test-one": "mocha -r ts-node/register",
|
||||
"test": "mocha -r ts-node/register test/**/*.spec.ts",
|
||||
"lint": "tslint --project .",
|
||||
"dryrun": "tsc -noEmit",
|
||||
"build": "tsc",
|
||||
"prepublish": "npm run lint && npm run dryrun && npm run test",
|
||||
"install": "npm run build"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Dror Gluska",
|
||||
"email": "drorgl@gmail.com"
|
||||
}
|
||||
],
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Sai Teja",
|
||||
|
||||
281
parser.js
281
parser.js
@@ -1,281 +0,0 @@
|
||||
var expat = require('node-expat')
|
||||
var _ = require('lodash')
|
||||
var util = require('util')
|
||||
var stream = require('stream')
|
||||
|
||||
var ParserState = require('./parserState')
|
||||
var defaults = {
|
||||
resourcePath: '',
|
||||
emitOnNodeName: false,
|
||||
attrsKey: '$',
|
||||
textKey: '_',
|
||||
explicitArray: true,
|
||||
verbatimText: false
|
||||
}
|
||||
|
||||
function XmlParser (opts) {
|
||||
this.opts = _.defaults(opts, defaults)
|
||||
this.parserState = new ParserState()
|
||||
this.parser = new expat.Parser('UTF-8')
|
||||
stream.Transform.call(this)
|
||||
this._readableState.objectMode = true
|
||||
}
|
||||
util.inherits(XmlParser, stream.Transform)
|
||||
|
||||
XmlParser.prototype.checkForInterestedNodeListeners = function () {
|
||||
var ignore = [ 'end', 'prefinish', 'data', 'error' ]
|
||||
var eventNames = Object.keys(this._events)
|
||||
|
||||
for (var i = 0; i < eventNames.length; i++) {
|
||||
if (_.includes(ignore, eventNames[i], 0)) continue
|
||||
this.parserState.interestedNodes.push(eventNames[i])
|
||||
}
|
||||
}
|
||||
|
||||
XmlParser.prototype._transform = function (chunk, encoding, callback) {
|
||||
if (encoding !== 'buffer') this.emit('error', new Error('unsupported encoding'))
|
||||
|
||||
this.processChunk(chunk)
|
||||
callback()
|
||||
}
|
||||
|
||||
XmlParser.prototype.processChunk = function (chunk) {
|
||||
var parser = this.parser
|
||||
var state = this.parserState
|
||||
|
||||
if (state.isRootNode) {
|
||||
this.checkForInterestedNodeListeners()
|
||||
registerEvents.call(this)
|
||||
}
|
||||
|
||||
if (typeof chunk === 'string') {
|
||||
if (!parser.parse('', true)) processError.call(this)
|
||||
} else {
|
||||
if (!parser.parse(chunk.toString())) processError.call(this)
|
||||
}
|
||||
}
|
||||
|
||||
XmlParser.prototype.parse = function (chunk, cb) {
|
||||
var parser = this.parser
|
||||
var state = this.parserState
|
||||
var error
|
||||
|
||||
if (state.isRootNode) {
|
||||
this.checkForInterestedNodeListeners()
|
||||
registerEvents.call(this)
|
||||
}
|
||||
|
||||
if (typeof chunk === Buffer) chunk = chunk.toString()
|
||||
|
||||
this.on('error', function (err) {
|
||||
error = err
|
||||
})
|
||||
|
||||
if (!parser.parse(chunk)) {
|
||||
error = processError.call(this)
|
||||
}
|
||||
|
||||
if (error) return cb(error)
|
||||
|
||||
return cb(null, this._readableState.buffer)
|
||||
}
|
||||
|
||||
function registerEvents () {
|
||||
var scope = this
|
||||
var parser = this.parser
|
||||
var state = this.parserState
|
||||
var lastIndex
|
||||
var resourcePath = this.opts.resourcePath
|
||||
var attrsKey = this.opts.attrsKey
|
||||
var textKey = this.opts.textKey
|
||||
var interestedNodes = state.interestedNodes
|
||||
var explicitArray = this.opts.explicitArray
|
||||
var verbatimText = this.opts.verbatimText;
|
||||
|
||||
parser.on('startElement', function (name, attrs) {
|
||||
if (state.isRootNode) state.isRootNode = false;
|
||||
state.currentPath = state.currentPath + '/' + name
|
||||
checkForResourcePath(name)
|
||||
if (state.isPathfound) processStartElement(name, attrs)
|
||||
})
|
||||
|
||||
parser.on('endElement', function (name) {
|
||||
state.lastEndedNode = name
|
||||
lastIndex = state.currentPath.lastIndexOf('/' + name)
|
||||
state.currentPath = state.currentPath.substring(0, lastIndex)
|
||||
if (state.isPathfound) processEndElement(name)
|
||||
checkForResourcePath(name)
|
||||
})
|
||||
|
||||
parser.on('text', function (text) {
|
||||
if (state.isPathfound) processText(text)
|
||||
})
|
||||
|
||||
parser.on('error', function (err) {
|
||||
processError.call(this, err)
|
||||
})
|
||||
|
||||
function processStartElement (name, attrs) {
|
||||
if (!name) return
|
||||
|
||||
var obj = {}
|
||||
if (attrs && !_.isEmpty(attrs)) obj[attrsKey] = attrs
|
||||
var tempObj = state.object
|
||||
var path = getRelativePath(name)
|
||||
if (!path) {
|
||||
if (attrs && !_.isEmpty(attrs)) state.object[attrsKey] = attrs
|
||||
return
|
||||
}
|
||||
var tokens = path.split('.')
|
||||
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
if (tempObj[tokens[i]] && !(explicitArray === false && i === tokens.length - 1)) {
|
||||
tempObj = tempObj[tokens[i]]
|
||||
} else {
|
||||
// if explicitArray is true then create each node as array
|
||||
// irrespective of how many nodes are there with same name.
|
||||
tempObj[tokens[i]] = explicitArray ? [] : obj
|
||||
tempObj = tempObj[tokens[i]]
|
||||
}
|
||||
if (Array.isArray(tempObj) && i !== tokens.length - 1) tempObj = tempObj[tempObj.length - 1]
|
||||
}
|
||||
|
||||
if (Array.isArray(tempObj)) {
|
||||
tempObj.push(obj)
|
||||
}
|
||||
}
|
||||
|
||||
function processEndElement (name) {
|
||||
if (resourcePath) {
|
||||
var index = resourcePath.lastIndexOf('/')
|
||||
var rpath = resourcePath.substring(0, index)
|
||||
|
||||
if (rpath === state.currentPath) {
|
||||
scope.push(state.object)
|
||||
if (scope.opts.emitOnNodeName) scope.emit(name, state.object)
|
||||
state.object = {}
|
||||
}
|
||||
} else {
|
||||
if (_.includes(interestedNodes, name, 0)) {
|
||||
emitInterestedNode(name)
|
||||
if (state.firstFoundNode === name) {
|
||||
state.object = {}
|
||||
state.firstFoundNode = ''
|
||||
state.isPathfound = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitInterestedNode (name) {
|
||||
var index
|
||||
var xpath
|
||||
var pathTokens
|
||||
|
||||
xpath = state.currentPath.substring(1)
|
||||
pathTokens = xpath.split('/')
|
||||
pathTokens.push(name)
|
||||
index = pathTokens.indexOf(state.firstFoundNode)
|
||||
pathTokens = _.drop(pathTokens, index + 1)
|
||||
var tempObj = state.object
|
||||
for (var i = 0; i < pathTokens.length; i++) {
|
||||
tempObj = tempObj[pathTokens[i]]
|
||||
}
|
||||
if (Array.isArray(tempObj)) tempObj = tempObj[tempObj.length - 1]
|
||||
scope.emit(name, tempObj)
|
||||
scope.push(tempObj)
|
||||
}
|
||||
|
||||
function processText (text) {
|
||||
if ((!text) || ((!verbatimText) && !/\S/.test(text))) {
|
||||
return
|
||||
}
|
||||
var path = getRelativePath()
|
||||
var tempObj = state.object
|
||||
if (!path) {
|
||||
if (!state.object[textKey]) state.object[textKey] = ''
|
||||
state.object[textKey] = state.object[textKey] + text
|
||||
return
|
||||
}
|
||||
var tokens = path.split('.')
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
if (tempObj[tokens[i]]) {
|
||||
tempObj = tempObj[tokens[i]]
|
||||
} else {
|
||||
tempObj[tokens[i]] = explicitArray ? [] : {}
|
||||
tempObj = tempObj[tokens[i]]
|
||||
}
|
||||
if (Array.isArray(tempObj) && i !== tokens.length - 1) tempObj = tempObj[tempObj.length - 1]
|
||||
}
|
||||
|
||||
if (Array.isArray(tempObj)) {
|
||||
var obj = tempObj[tempObj.length - 1]
|
||||
if (!obj[textKey]) obj[textKey] = ''
|
||||
obj[textKey] = obj[textKey] + text
|
||||
} else {
|
||||
if (!tempObj[textKey]) tempObj[textKey] = ''
|
||||
tempObj[textKey] = tempObj[textKey] + text
|
||||
}
|
||||
}
|
||||
|
||||
function checkForResourcePath (name) {
|
||||
if (resourcePath) {
|
||||
if (state.currentPath.indexOf(resourcePath) === 0) {
|
||||
state.isPathfound = true
|
||||
} else {
|
||||
state.isPathfound = false
|
||||
}
|
||||
} else {
|
||||
if (_.includes(interestedNodes, name, 0)) {
|
||||
state.isPathfound = true
|
||||
if (!state.firstFoundNode) {
|
||||
state.firstFoundNode = name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getRelativePath () {
|
||||
var tokens
|
||||
var jsonPath
|
||||
var index
|
||||
|
||||
if (resourcePath) {
|
||||
var xpath = state.currentPath.substring(resourcePath.length)
|
||||
|
||||
if (!xpath) return
|
||||
if (xpath[0] === '/') xpath = xpath.substring(1)
|
||||
tokens = xpath.split('/')
|
||||
jsonPath = tokens.join('.')
|
||||
} else {
|
||||
xpath = state.currentPath.substring(1)
|
||||
tokens = xpath.split('/')
|
||||
index = tokens.indexOf(state.firstFoundNode)
|
||||
tokens = _.drop(tokens, index + 1)
|
||||
jsonPath = tokens.join('.')
|
||||
}
|
||||
return jsonPath
|
||||
}
|
||||
}
|
||||
|
||||
function processError (err) {
|
||||
var parser = this.parser
|
||||
var error = ''
|
||||
|
||||
if (err) {
|
||||
error = err
|
||||
} else {
|
||||
error = parser.getError()
|
||||
}
|
||||
error = new Error(error + ' at line no: ' + parser.getCurrentLineNumber())
|
||||
this.emit('error', error)
|
||||
return error
|
||||
}
|
||||
|
||||
XmlParser.prototype._flush = function (callback) {
|
||||
this.processChunk('')
|
||||
callback()
|
||||
}
|
||||
|
||||
module.exports = XmlParser
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
|
||||
function ParserState () {
|
||||
this.currentPath = ''
|
||||
this.lastEndedNode = ''
|
||||
this.isPathfound = false
|
||||
this.object = {}
|
||||
this.paused = false
|
||||
this.isRootNode = true
|
||||
this.firstFoundNode = ''
|
||||
this.interestedNodes = []
|
||||
}
|
||||
|
||||
module.exports = ParserState
|
||||
300
src/parser.ts
Normal file
300
src/parser.ts
Normal file
@@ -0,0 +1,300 @@
|
||||
/// <reference types="../typings/node-expat" />
|
||||
import _ from "lodash";
|
||||
import * as expat from "node-expat";
|
||||
import stream from "stream";
|
||||
import util from "util";
|
||||
|
||||
import { ParserState } from "./parserState";
|
||||
const defaults = {
|
||||
resourcePath: "",
|
||||
emitOnNodeName: false,
|
||||
attrsKey: "$",
|
||||
textKey: "_",
|
||||
explicitArray: true,
|
||||
verbatimText: false
|
||||
};
|
||||
|
||||
export interface IXmlParserOptions {
|
||||
resourcePath?: string;
|
||||
emitOnNodeName?: boolean;
|
||||
attrsKey?: string;
|
||||
textKey?: string;
|
||||
explicitArray?: boolean;
|
||||
verbatimText?: boolean;
|
||||
}
|
||||
|
||||
export class XmlParser extends stream.Transform {
|
||||
public parserState: ParserState;
|
||||
private opts: IXmlParserOptions;
|
||||
private _readableState: { objectMode: true, buffer: any };
|
||||
private parser: expat.Parser;
|
||||
constructor(opts?: IXmlParserOptions) {
|
||||
super();
|
||||
this.opts = _.defaults(opts, defaults);
|
||||
this.parserState = new ParserState();
|
||||
this.parser = new expat.Parser();
|
||||
this._readableState.objectMode = true;
|
||||
}
|
||||
|
||||
public checkForInterestedNodeListeners() {
|
||||
const ignore = ["end", "prefinish", "data", "error"];
|
||||
const eventNames = Object.keys((this as any)._events);
|
||||
|
||||
// tslint:disable-next-line:prefer-for-of
|
||||
for (let i = 0; i < eventNames.length; i++) {
|
||||
if (_.includes(ignore, eventNames[i], 0)) { continue; }
|
||||
this.parserState.interestedNodes.push(eventNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public _transform(chunk: Buffer | string, encoding: string, callback: () => void) {
|
||||
if (encoding !== "buffer") { this.emit("error", new Error("unsupported encoding")); }
|
||||
|
||||
this.processChunk(chunk);
|
||||
callback();
|
||||
}
|
||||
|
||||
public processChunk(chunk: string | Buffer) {
|
||||
const parser = this.parser;
|
||||
const state = this.parserState;
|
||||
|
||||
if (state.isRootNode) {
|
||||
this.checkForInterestedNodeListeners();
|
||||
registerEvents.call(this);
|
||||
}
|
||||
|
||||
if (typeof chunk === "string") {
|
||||
if (!parser.parse("", true)) { processError.call(this); }
|
||||
} else {
|
||||
if (!parser.parse(chunk.toString())) { processError.call(this); }
|
||||
}
|
||||
}
|
||||
|
||||
public parse(chunk: Buffer | string, cb: (error: Error, data?: Buffer) => void) {
|
||||
const parser = this.parser;
|
||||
const state = this.parserState;
|
||||
let error;
|
||||
|
||||
if (state.isRootNode) {
|
||||
this.checkForInterestedNodeListeners();
|
||||
registerEvents.call(this);
|
||||
}
|
||||
|
||||
if (chunk instanceof Buffer) { chunk = chunk.toString(); }
|
||||
|
||||
this.on("error", (err) => {
|
||||
error = err;
|
||||
});
|
||||
|
||||
if (!parser.parse(chunk)) {
|
||||
error = processError.call(this);
|
||||
}
|
||||
|
||||
if (error) { return cb(error); }
|
||||
|
||||
const result = [];
|
||||
while (this._readableState.buffer.length > 0) {
|
||||
result.push(this._readableState.buffer.consume());
|
||||
}
|
||||
return cb(null, result as any);
|
||||
}
|
||||
|
||||
public _flush(callback: () => void) {
|
||||
this.processChunk("");
|
||||
callback();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function registerEvents() {
|
||||
const scope = this;
|
||||
const parser: expat.Parser = this.parser;
|
||||
const state = this.parserState;
|
||||
let lastIndex;
|
||||
const resourcePath = this.opts.resourcePath;
|
||||
const attrsKey = this.opts.attrsKey;
|
||||
const textKey = this.opts.textKey;
|
||||
const interestedNodes = state.interestedNodes;
|
||||
const explicitArray = this.opts.explicitArray;
|
||||
const verbatimText = this.opts.verbatimText;
|
||||
|
||||
parser.on("startElement", (name, attrs) => {
|
||||
if (state.isRootNode) { state.isRootNode = false; }
|
||||
state.currentPath = state.currentPath + "/" + name;
|
||||
checkForResourcePath(name);
|
||||
if (state.isPathfound) { processStartElement(name, attrs); }
|
||||
});
|
||||
|
||||
parser.on("endElement", (name) => {
|
||||
state.lastEndedNode = name;
|
||||
lastIndex = state.currentPath.lastIndexOf("/" + name);
|
||||
state.currentPath = state.currentPath.substring(0, lastIndex);
|
||||
if (state.isPathfound) { processEndElement(name); }
|
||||
checkForResourcePath(name);
|
||||
});
|
||||
|
||||
parser.on("text", (text) => {
|
||||
if (state.isPathfound) { processText(text); }
|
||||
});
|
||||
|
||||
parser.on("error", function(err) {
|
||||
processError.call(this, err);
|
||||
});
|
||||
|
||||
function processStartElement(name: string, attrs: any) {
|
||||
if (!name) { return; }
|
||||
|
||||
const obj: any = {};
|
||||
if (attrs && !_.isEmpty(attrs)) { obj[attrsKey] = attrs; }
|
||||
let tempObj = state.object;
|
||||
const path = getRelativePath(/*name*/);
|
||||
if (!path) {
|
||||
if (attrs && !_.isEmpty(attrs)) { state.object[attrsKey] = attrs; }
|
||||
return;
|
||||
}
|
||||
const tokens = path.split(".");
|
||||
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
if (tempObj[tokens[i]] && !(explicitArray === false && i === tokens.length - 1)) {
|
||||
tempObj = tempObj[tokens[i]];
|
||||
} else {
|
||||
// if explicitArray is true then create each node as array
|
||||
// irrespective of how many nodes are there with same name.
|
||||
tempObj[tokens[i]] = explicitArray ? [] : obj;
|
||||
tempObj = tempObj[tokens[i]];
|
||||
}
|
||||
if (Array.isArray(tempObj) && i !== tokens.length - 1) { tempObj = tempObj[tempObj.length - 1]; }
|
||||
}
|
||||
|
||||
if (Array.isArray(tempObj)) {
|
||||
tempObj.push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
function processEndElement(name: string) {
|
||||
if (resourcePath) {
|
||||
const index = resourcePath.lastIndexOf("/");
|
||||
const rpath = resourcePath.substring(0, index);
|
||||
|
||||
if (rpath === state.currentPath) {
|
||||
scope.push(state.object);
|
||||
if (scope.opts.emitOnNodeName) { scope.emit(name, state.object); }
|
||||
state.object = {};
|
||||
}
|
||||
} else {
|
||||
if (_.includes(interestedNodes, name, 0)) {
|
||||
emitInterestedNode(name);
|
||||
if (state.firstFoundNode === name) {
|
||||
state.object = {};
|
||||
state.firstFoundNode = "";
|
||||
state.isPathfound = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitInterestedNode(name: string) {
|
||||
let index;
|
||||
let xpath;
|
||||
let pathTokens;
|
||||
|
||||
xpath = state.currentPath.substring(1);
|
||||
pathTokens = xpath.split("/");
|
||||
pathTokens.push(name);
|
||||
index = pathTokens.indexOf(state.firstFoundNode);
|
||||
pathTokens = _.drop(pathTokens, index + 1);
|
||||
let tempObj = state.object;
|
||||
// tslint:disable-next-line:prefer-for-of
|
||||
for (let i = 0; i < pathTokens.length; i++) {
|
||||
tempObj = tempObj[pathTokens[i] as any];
|
||||
}
|
||||
if (Array.isArray(tempObj)) { tempObj = tempObj[tempObj.length - 1]; }
|
||||
scope.emit(name, tempObj);
|
||||
scope.push(tempObj);
|
||||
}
|
||||
|
||||
function processText(text: string) {
|
||||
if ((!text) || ((!verbatimText) && !/\S/.test(text))) {
|
||||
return;
|
||||
}
|
||||
const path = getRelativePath();
|
||||
let tempObj = state.object;
|
||||
if (!path) {
|
||||
if (!state.object[textKey]) { state.object[textKey] = ""; }
|
||||
state.object[textKey] = state.object[textKey] + text;
|
||||
return;
|
||||
}
|
||||
const tokens = path.split(".");
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
if (tempObj[tokens[i]]) {
|
||||
tempObj = tempObj[tokens[i]];
|
||||
} else {
|
||||
tempObj[tokens[i]] = explicitArray ? [] : {};
|
||||
tempObj = tempObj[tokens[i]];
|
||||
}
|
||||
if (Array.isArray(tempObj) && i !== tokens.length - 1) { tempObj = tempObj[tempObj.length - 1]; }
|
||||
}
|
||||
|
||||
if (Array.isArray(tempObj)) {
|
||||
const obj = tempObj[tempObj.length - 1];
|
||||
if (!obj[textKey]) { obj[textKey] = ""; }
|
||||
obj[textKey] = obj[textKey] + text;
|
||||
} else {
|
||||
if (!tempObj[textKey]) { tempObj[textKey] = ""; }
|
||||
tempObj[textKey] = tempObj[textKey] + text;
|
||||
}
|
||||
}
|
||||
|
||||
function checkForResourcePath(name: string) {
|
||||
if (resourcePath) {
|
||||
if (state.currentPath.indexOf(resourcePath) === 0) {
|
||||
state.isPathfound = true;
|
||||
} else {
|
||||
state.isPathfound = false;
|
||||
}
|
||||
} else {
|
||||
if (_.includes(interestedNodes, name, 0)) {
|
||||
state.isPathfound = true;
|
||||
if (!state.firstFoundNode) {
|
||||
state.firstFoundNode = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getRelativePath() {
|
||||
let tokens;
|
||||
let jsonPath;
|
||||
let index;
|
||||
|
||||
if (resourcePath) {
|
||||
let xpath = state.currentPath.substring(resourcePath.length);
|
||||
|
||||
if (!xpath) { return; }
|
||||
if (xpath[0] === "/") { xpath = xpath.substring(1); }
|
||||
tokens = xpath.split("/");
|
||||
jsonPath = tokens.join(".");
|
||||
} else {
|
||||
const xpath = state.currentPath.substring(1);
|
||||
tokens = xpath.split("/");
|
||||
index = tokens.indexOf(state.firstFoundNode);
|
||||
tokens = _.drop(tokens, index + 1);
|
||||
jsonPath = tokens.join(".");
|
||||
}
|
||||
return jsonPath;
|
||||
}
|
||||
}
|
||||
|
||||
function processError(err: Error) {
|
||||
const parser = this.parser;
|
||||
let error: Error = null;
|
||||
|
||||
if (err) {
|
||||
error = err;
|
||||
} else {
|
||||
error = parser.getError();
|
||||
}
|
||||
error = new Error(error + " at line no: " + parser.getCurrentLineNumber());
|
||||
this.emit("error", error);
|
||||
return error;
|
||||
}
|
||||
11
src/parserState.ts
Normal file
11
src/parserState.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
export class ParserState {
|
||||
public currentPath = "";
|
||||
public lastEndedNode = "";
|
||||
public isPathfound = false;
|
||||
public object: any = {};
|
||||
public paused = false;
|
||||
public isRootNode = true;
|
||||
public firstFoundNode = "";
|
||||
public interestedNodes: string[] = [];
|
||||
}
|
||||
146
test/basic.spec.ts
Normal file
146
test/basic.spec.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
|
||||
describe("Basic behavior", () => {
|
||||
it("should properly parse a simple file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
const expectedData = [
|
||||
{
|
||||
$: { id: "1", test: "hello" },
|
||||
subitem:
|
||||
[{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" },
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}];
|
||||
const actualData: string[] = [];
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
should(err).not.be.ok();
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', actualData)
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(dataEventCount).equal(2);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a medium size file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/medium.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(10);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a file containing many nodes.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/manyItems.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(296);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a xml simple file in which nodes contain text values randomly.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/randomText.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
const expectedData = [{
|
||||
$: { id: "1", test: "hello" }, _: " item one two",
|
||||
subitem: [{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" }, _: " item one two three four",
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}
|
||||
];
|
||||
const actualData: string[] = [];
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', JSON.stringify(actualData, null, 1))
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(dataEventCount).equal(2);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a huge file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/hugeFile.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
// console.log(parser)
|
||||
let dataEventCount = 0;
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(2072);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
30
test/cdata_and_comments.spec.ts
Normal file
30
test/cdata_and_comments.spec.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
describe("CData and comments in xml", () => {
|
||||
it("should properly parse a simple file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/CData-comments.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(296);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
136
test/emit.spec.ts
Normal file
136
test/emit.spec.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
describe("emitOnNodeName", () => {
|
||||
it("should properly emit events on node names.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", emitOnNodeName: true });
|
||||
const expectedData = [
|
||||
{
|
||||
$: { id: "1", test: "hello" },
|
||||
subitem:
|
||||
[{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" },
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}];
|
||||
const actualData: string[] = [];
|
||||
const itemData : string[] = [];
|
||||
let dataEventCount = 0;
|
||||
let itemCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
itemData.push(item);
|
||||
itemCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', actualData)
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(dataEventCount).equal(2);
|
||||
should(itemData).deepEqual(expectedData);
|
||||
should(itemCount).equal(2);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly emit events on node names while parsing a medium size file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/medium.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", emitOnNodeName: true });
|
||||
|
||||
let dataEventCount = 0;
|
||||
let itemCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("item", (data) => {
|
||||
itemCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(10);
|
||||
should(itemCount).equal(10);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a file containing many nodes.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/manyItems.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", emitOnNodeName: true });
|
||||
|
||||
let dataEventCount = 0;
|
||||
let itemCount = 0;
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("item", (data) => {
|
||||
itemCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(296);
|
||||
should(itemCount).equal(296);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a huge file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/hugeFile.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", emitOnNodeName: true });
|
||||
|
||||
let dataEventCount = 0;
|
||||
let itemCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
itemCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(2072);
|
||||
should(itemCount).equal(2072);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
45
test/error.spec.ts
Normal file
45
test/error.spec.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
describe("Error Handling", () => {
|
||||
it("should properly return error if the xml file is corrupted.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/corrupted.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
// console.log(err)
|
||||
should(err.message).equal("mismatched tag at line no: 11");
|
||||
done();
|
||||
});
|
||||
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly return error if the large xml file is corrupted.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/largeCorruptedFile.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
// console.log(err)
|
||||
should(err.message).equal("mismatched tag at line no: 8346");
|
||||
done();
|
||||
});
|
||||
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
250
test/explicit_array.spec.ts
Normal file
250
test/explicit_array.spec.ts
Normal file
@@ -0,0 +1,250 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
describe("should respect explicitArray constructor option", () => {
|
||||
it("should properly parse a simple file with explicitArray set to false.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", explicitArray: false });
|
||||
const expectedData = [
|
||||
{
|
||||
$: { id: "1", test: "hello" },
|
||||
subitem: { $: { sub: "2" }, _: "two" }
|
||||
},
|
||||
{
|
||||
$: { id: "2" },
|
||||
subitem: { _: "five" }
|
||||
}];
|
||||
|
||||
parser.parse(xml.toString(), (err, data) => {
|
||||
if (err) { done(err); }
|
||||
// console.log('data=', JSON.stringify(data))
|
||||
should(data).deepEqual(expectedData);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly parse a medium size file with explicitArray set to false.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/medium.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", explicitArray: false });
|
||||
const expectedData = [
|
||||
{
|
||||
$: {
|
||||
id: "1",
|
||||
test: "hello"
|
||||
},
|
||||
subitem: {
|
||||
$: {
|
||||
sub: "2"
|
||||
},
|
||||
_: "two"
|
||||
}
|
||||
},
|
||||
{
|
||||
$: {
|
||||
id: "2"
|
||||
},
|
||||
subitem: {
|
||||
_: "five"
|
||||
}
|
||||
},
|
||||
{
|
||||
$: {
|
||||
id: "3",
|
||||
test: "hello"
|
||||
},
|
||||
subitem: {
|
||||
$: {
|
||||
sub: "2"
|
||||
},
|
||||
_: "two"
|
||||
}
|
||||
},
|
||||
{
|
||||
$: {
|
||||
id: "4",
|
||||
test: "hello"
|
||||
},
|
||||
subitem: {
|
||||
$: {
|
||||
sub: "2"
|
||||
},
|
||||
_: "two"
|
||||
}
|
||||
},
|
||||
{
|
||||
$: {
|
||||
id: "5",
|
||||
test: "hello"
|
||||
},
|
||||
subitem: {
|
||||
$: {
|
||||
sub: "2"
|
||||
},
|
||||
_: "two"
|
||||
}
|
||||
},
|
||||
{
|
||||
$: {
|
||||
id: "6",
|
||||
test: "hello"
|
||||
},
|
||||
subitem: {
|
||||
$: {
|
||||
sub: "2"
|
||||
},
|
||||
_: "two"
|
||||
}
|
||||
},
|
||||
{
|
||||
$: {
|
||||
id: "7",
|
||||
test: "hello"
|
||||
},
|
||||
subitem: {
|
||||
$: {
|
||||
sub: "2"
|
||||
},
|
||||
_: "two"
|
||||
}
|
||||
},
|
||||
{
|
||||
$: {
|
||||
id: "8",
|
||||
test: "hello"
|
||||
},
|
||||
subitem: {
|
||||
$: {
|
||||
sub: "2"
|
||||
},
|
||||
_: "two"
|
||||
}
|
||||
},
|
||||
{
|
||||
$: {
|
||||
id: "9",
|
||||
test: "hello"
|
||||
},
|
||||
subitem: {
|
||||
$: {
|
||||
sub: "2"
|
||||
},
|
||||
_: "two"
|
||||
}
|
||||
},
|
||||
{
|
||||
$: {
|
||||
id: "10",
|
||||
test: "hello"
|
||||
},
|
||||
subitem: {
|
||||
$: {
|
||||
sub: "2"
|
||||
},
|
||||
_: "two"
|
||||
}
|
||||
}
|
||||
];
|
||||
parser.parse(xml, (err, data) => {
|
||||
if (err) { done(err); }
|
||||
|
||||
should(data).deepEqual(expectedData);
|
||||
should(data.length).equal(10);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly parse a file containing many nodes when explicitArray set to false.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/manyItems.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", explicitArray: false });
|
||||
|
||||
parser.parse(xml, (err, data) => {
|
||||
if (err) { done(err); }
|
||||
|
||||
should(data.length).equal(296);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly parse a xml simple file in which nodes contain text values randomly when explicitArray set to false.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/randomText.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", explicitArray: false });
|
||||
const expectedData = [{
|
||||
$: { id: "1", test: "hello" }, _: " item one two",
|
||||
subitem: { $: { sub: "2" }, _: "two" }
|
||||
},
|
||||
{
|
||||
$: { id: "2" }, _: " item one two three four",
|
||||
subitem: { _: "five" }
|
||||
}
|
||||
];
|
||||
|
||||
parser.parse(xml, (err, data) => {
|
||||
if (err) { done(err); }
|
||||
|
||||
should(data).deepEqual(expectedData);
|
||||
should(data.length).equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly parse a huge file with explicitArray set to false.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/hugeFile.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", explicitArray: false });
|
||||
// console.log(parser)
|
||||
parser.parse(xml, (err, data) => {
|
||||
if (err) { done(err); }
|
||||
should(data.length).equal(2072);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly return error if the xml file is corrupted.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/corrupted.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", explicitArray: false });
|
||||
|
||||
parser.parse(xml, (err, data) => {
|
||||
// console.log(err)
|
||||
should(err.message).equal("mismatched tag at line no: 11");
|
||||
should(data).not.be.ok();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly generate objects when special symbols are passed as attrs and text keys and explicitArray is false in the options.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", attrsKey: "!", textKey: "%", explicitArray: false });
|
||||
const expectedData = [
|
||||
{
|
||||
"!": { id: "1", test: "hello" },
|
||||
"subitem": { "!": { sub: "2" }, "%": "two" }
|
||||
},
|
||||
{
|
||||
"!": { id: "2" },
|
||||
"subitem": { "%": "five" }
|
||||
}];
|
||||
const actualData : string[] = [];
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', JSON.stringify(actualData, null, 1))
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(dataEventCount).equal(2);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
321
test/interested.spec.ts
Normal file
321
test/interested.spec.ts
Normal file
@@ -0,0 +1,321 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
|
||||
describe("interested Nodes", () => {
|
||||
it("should properly parse a simple file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser();
|
||||
|
||||
const expectedData =
|
||||
[
|
||||
{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" },
|
||||
{
|
||||
$: { id: "1", test: "hello" },
|
||||
subitem: [{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{ _: "three" },
|
||||
{ _: "four" },
|
||||
{ _: "five" },
|
||||
{
|
||||
$: { id: "2" },
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}
|
||||
];
|
||||
|
||||
const actualData: string[] = [];
|
||||
let dataEventCount = 0;
|
||||
const expectedItems = [
|
||||
{
|
||||
$: { id: "1", test: "hello" },
|
||||
subitem:
|
||||
[{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" },
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}];
|
||||
const actualItems: string[] = [];
|
||||
const actualSubitems: string[] = [];
|
||||
const expectedSubitems = [
|
||||
{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" },
|
||||
{ _: "three" },
|
||||
{ _: "four" },
|
||||
{ _: "five" }
|
||||
];
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
should(err).not.be.ok();
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
actualItems.push(item);
|
||||
});
|
||||
|
||||
parser.on("subitem", (subitem) => {
|
||||
actualSubitems.push(subitem);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', JSON.stringify(actualData, null, 1))
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(actualItems).deepEqual(expectedItems);
|
||||
should(actualSubitems).deepEqual(expectedSubitems);
|
||||
should(actualSubitems.length).equal(5);
|
||||
should(actualItems.length).equal(2);
|
||||
should(dataEventCount).equal(7);
|
||||
done();
|
||||
});
|
||||
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a medium size file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/medium.xml");
|
||||
const parser = new XmlParser();
|
||||
|
||||
let dataEventCount = 0;
|
||||
let itemEventCount = 0;
|
||||
let subitemEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
itemEventCount++;
|
||||
});
|
||||
|
||||
parser.on("subitem", (subitem) => {
|
||||
subitemEventCount++;
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
// console.log('itemEventCount=', itemEventCount)
|
||||
// console.log('subitemEventCount=', subitemEventCount)
|
||||
should(dataEventCount).equal(31);
|
||||
should(itemEventCount).equal(10);
|
||||
should(subitemEventCount).equal(21);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a file containing many nodes.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/manyItems.xml");
|
||||
const parser = new XmlParser();
|
||||
|
||||
let dataEventCount = 0;
|
||||
let itemEventCount = 0;
|
||||
let subitemEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
itemEventCount++;
|
||||
});
|
||||
|
||||
parser.on("subitem", (subitem) => {
|
||||
subitemEventCount++;
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
// console.log('itemEventCount=', itemEventCount)
|
||||
// console.log('subitemEventCount=', subitemEventCount)
|
||||
should(itemEventCount).equal(296);
|
||||
should(subitemEventCount).equal(600);
|
||||
should(dataEventCount).equal(896);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a xml simple file in which nodes contain text values randomly.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/randomText.xml");
|
||||
const parser = new XmlParser();
|
||||
const expectedData =
|
||||
[
|
||||
{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" },
|
||||
{
|
||||
$: { id: "1", test: "hello" }, _: " item one two",
|
||||
subitem: [{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{ _: "three" },
|
||||
{ _: "four" },
|
||||
{ _: "five" },
|
||||
{
|
||||
$: { id: "2" }, _: " item one two three four",
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}
|
||||
];
|
||||
const expectedItems = [
|
||||
{
|
||||
$: { id: "1", test: "hello" }, _: " item one two",
|
||||
subitem:
|
||||
[{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" }, _: " item one two three four",
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}];
|
||||
const actualItems: string[] = [];
|
||||
const actualSubitems: string[] = [];
|
||||
const expectedSubitems = [
|
||||
{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" },
|
||||
{ _: "three" },
|
||||
{ _: "four" },
|
||||
{ _: "five" }
|
||||
];
|
||||
const actualData: string[] = [];
|
||||
let dataEventCount = 0;
|
||||
let itemEventCount = 0;
|
||||
let subitemEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
itemEventCount++;
|
||||
actualItems.push(item);
|
||||
});
|
||||
|
||||
parser.on("subitem", (subitem) => {
|
||||
subitemEventCount++;
|
||||
actualSubitems.push(subitem);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', JSON.stringify(actualData, null, 1))
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
// console.log('itemEventCount=', itemEventCount)
|
||||
// console.log('subitemEventCount=', subitemEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(actualItems).deepEqual(expectedItems);
|
||||
should(actualSubitems).deepEqual(expectedSubitems);
|
||||
should(dataEventCount).equal(7);
|
||||
should(itemEventCount).equal(2);
|
||||
should(subitemEventCount).equal(5);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a huge file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/hugeFile.xml");
|
||||
const parser = new XmlParser();
|
||||
|
||||
let dataEventCount = 0;
|
||||
let itemEventCount = 0;
|
||||
let subitemEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
itemEventCount++;
|
||||
});
|
||||
|
||||
parser.on("subitem", (subitem) => {
|
||||
subitemEventCount++;
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
// console.log('itemEventCount=', itemEventCount)
|
||||
// console.log('subitemEventCount=', subitemEventCount)
|
||||
should(dataEventCount).equal(6272);
|
||||
should(itemEventCount).equal(2072);
|
||||
should(subitemEventCount).equal(4200);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a simple file and return when root element when listening on it.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser();
|
||||
const expectedData =
|
||||
[{
|
||||
item: [{
|
||||
$: { id: "1", test: "hello" },
|
||||
subitem: [{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" }, subitem: [{ _: "three" }, { _: "four" },
|
||||
{ _: "five" }]
|
||||
}]
|
||||
}];
|
||||
|
||||
const actualData: string[] = [];
|
||||
let dataEventCount = 0;
|
||||
let itemsEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
should(err).not.be.ok();
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("items", (item) => {
|
||||
itemsEventCount++;
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', JSON.stringify(actualData, null, 1))
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
// console.log('itemEventCount=', itemsEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(itemsEventCount).equal(1);
|
||||
should(dataEventCount).equal(1);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
117
test/options.spec.ts
Normal file
117
test/options.spec.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
describe("should respect the options passed", () => {
|
||||
it("should properly generate objects with $ as key for attrs and _ as key for text value of node.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
const expectedData = [
|
||||
{
|
||||
$: { id: "1", test: "hello" },
|
||||
subitem:
|
||||
[{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" },
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}];
|
||||
const actualData: string[] = [];
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', actualData)
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(dataEventCount).equal(2);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly generate objects with passed attrs and text keys in the options.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", attrsKey: "attrs", textKey: "text" });
|
||||
const expectedData = [
|
||||
{
|
||||
attrs: { id: "1", test: "hello" },
|
||||
subitem:
|
||||
[{ attrs: { sub: "TESTING SUB" }, text: "one" },
|
||||
{ attrs: { sub: "2" }, text: "two" }]
|
||||
},
|
||||
{
|
||||
attrs: { id: "2" },
|
||||
subitem: [{ text: "three" }, { text: "four" }, { text: "five" }]
|
||||
}];
|
||||
const actualData: string[] = [];
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', JSON.stringify(actualData, null, 1))
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(dataEventCount).equal(2);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly generate objects when special symbols are passed as attrs and text keys in the options.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item", attrsKey: "!", textKey: "%" });
|
||||
const expectedData = [
|
||||
{
|
||||
"!": { id: "1", test: "hello" },
|
||||
"subitem":
|
||||
[{ "!": { sub: "TESTING SUB" }, "%": "one" },
|
||||
{ "!": { sub: "2" }, "%": "two" }]
|
||||
},
|
||||
{
|
||||
"!": { id: "2" },
|
||||
"subitem": [{ "%": "three" }, { "%": "four" }, { "%": "five" }]
|
||||
}];
|
||||
const actualData: string[] = [];
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', JSON.stringify(actualData, null, 1))
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(dataEventCount).equal(2);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
97
test/parse.spec.ts
Normal file
97
test/parse.spec.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
describe("Parse function should work properly", () => {
|
||||
it("should properly parse a simple file.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
const expectedData = [
|
||||
{
|
||||
$: { id: "1", test: "hello" },
|
||||
subitem:
|
||||
[{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" },
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}];
|
||||
|
||||
parser.parse(xml.toString(), (err, data) => {
|
||||
if (err) { done(err); }
|
||||
should(data).deepEqual(expectedData);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly parse a medium size file.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/medium.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
|
||||
parser.parse(xml, (err, data) => {
|
||||
if (err) { done(err); }
|
||||
should(data.length).equal(10);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly parse a file containing many nodes.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/manyItems.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
|
||||
parser.parse(xml, (err, data) => {
|
||||
if (err) { done(err); }
|
||||
should(data.length).equal(296);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly parse a xml simple file in which nodes contain text values randomly.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/randomText.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
const expectedData = [{
|
||||
$: { id: "1", test: "hello" }, _: " item one two",
|
||||
subitem: [{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" }, _: " item one two three four",
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}
|
||||
];
|
||||
|
||||
parser.parse(xml, (err, data) => {
|
||||
if (err) { done(err); }
|
||||
should(data).deepEqual(expectedData);
|
||||
should(data.length).equal(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly parse a huge file.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/hugeFile.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
// console.log(parser)
|
||||
parser.parse(xml, (err, data) => {
|
||||
if (err) { done(err); }
|
||||
should(data.length).equal(2072);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should properly return error if the xml file is corrupted.", (done) => {
|
||||
const xml = fs.readFileSync("./test/TestFiles/corrupted.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
|
||||
parser.parse(xml, (err, data) => {
|
||||
// console.log(err)
|
||||
should(err.message).equal("mismatched tag at line no: 11");
|
||||
should(data).not.be.ok();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
82
test/pause_and_resume.spec.ts
Normal file
82
test/pause_and_resume.spec.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
describe("pause and resume", () => {
|
||||
it("should properly parse a simple file.", function(done) {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
const expectedData = [
|
||||
{
|
||||
$: { id: "1", test: "hello" },
|
||||
subitem:
|
||||
[{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" },
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}];
|
||||
const actualData: string[] = [];
|
||||
let dataEventCount = 0;
|
||||
let isSetTimeoutHappened = true;
|
||||
this.timeout(4000);
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
parser.pause();
|
||||
should(isSetTimeoutHappened).equal(true);
|
||||
setTimeout(() => {
|
||||
parser.resume();
|
||||
isSetTimeoutHappened = true;
|
||||
}, 1000);
|
||||
dataEventCount++;
|
||||
isSetTimeoutHappened = false;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', actualData)
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(actualData).deepEqual(expectedData);
|
||||
should(dataEventCount).equal(2);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should emit data events with 1sec interval between each using pause and resume.", function(done) {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/medium.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
|
||||
let dataEventCount = 0;
|
||||
let isSetTimeoutHappened = true;
|
||||
this.timeout(20000);
|
||||
parser.on("data", (data) => {
|
||||
parser.pause();
|
||||
should(isSetTimeoutHappened).equal(true);
|
||||
setTimeout(() => {
|
||||
parser.resume();
|
||||
isSetTimeoutHappened = true;
|
||||
}, 1000);
|
||||
dataEventCount++;
|
||||
isSetTimeoutHappened = false;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(10);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
103
test/performance.spec.ts
Normal file
103
test/performance.spec.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
describe.skip("performance testing", () => {
|
||||
it("should properly parse more than 500 MB of file.", function(done) {
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
// var wsStream = fs.createWriteStream('./test/TestFiles/MB_and_GB_size_files/MBFile.xml')
|
||||
// var rsStream = fs.createReadStream('./test/TestFiles/MB_and_GB_size_files/MBFile.xml')
|
||||
let dataEventCount = 0;
|
||||
// var maxRSSMemoryTaken = 0
|
||||
// var rss
|
||||
const startTime = Date.now();
|
||||
const xmlStream = new stream.Readable();
|
||||
xmlStream._read = function noop() {
|
||||
// nop
|
||||
};
|
||||
let dataChunk;
|
||||
this.timeout(900000);
|
||||
const firstChunk = fs.readFileSync("./test/TestFiles/MB_and_GB_size_files/firstChunk.xml");
|
||||
xmlStream.push(firstChunk);
|
||||
for (let i = 0; i < 2200; i++) {
|
||||
dataChunk = fs.readFileSync("./test/TestFiles/MB_and_GB_size_files/repetitiveChunk.xml");
|
||||
xmlStream.push(dataChunk);
|
||||
}
|
||||
|
||||
const endingChunk = fs.readFileSync("./test/TestFiles/MB_and_GB_size_files/endingChunk.xml");
|
||||
xmlStream.push(endingChunk);
|
||||
xmlStream.push(null);
|
||||
parser.on("data", (data) => {
|
||||
// rss = process.memoryUsage().rss
|
||||
// if (rss > maxRSSMemoryTaken) maxRSSMemoryTaken = rss
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
should(err).not.be.ok();
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
// console.log('RSS memory=', rss)
|
||||
const TimeTaken = Date.now() - startTime;
|
||||
// console.log('time taken=', TimeTaken)
|
||||
should(TimeTaken).be.belowOrEqual(300000);
|
||||
should(dataEventCount).equal(4558400);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse more than 1 GB of file.", function(done) {
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
// var wsStream = fs.createWriteStream('./test/TestFiles/MB_and_GB_size_files/MBFile.xml')
|
||||
// var rsStream = fs.createReadStream('./test/TestFiles/MB_and_GB_size_files/MBFile.xml')
|
||||
let dataEventCount = 0;
|
||||
// var maxRSSMemoryTaken = 0
|
||||
// var rss
|
||||
const startTime = Date.now();
|
||||
const xmlStream = new stream.Readable();
|
||||
xmlStream._read = function noop() {
|
||||
// nop
|
||||
};
|
||||
let dataChunk;
|
||||
this.timeout(900000);
|
||||
const firstChunk = fs.readFileSync("./test/TestFiles/MB_and_GB_size_files/firstChunk.xml");
|
||||
xmlStream.push(firstChunk);
|
||||
for (let i = 0; i < 4400; i++) {
|
||||
dataChunk = fs.readFileSync("./test/TestFiles/MB_and_GB_size_files/repetitiveChunk.xml");
|
||||
xmlStream.push(dataChunk);
|
||||
}
|
||||
|
||||
const endingChunk = fs.readFileSync("./test/TestFiles/MB_and_GB_size_files/endingChunk.xml");
|
||||
xmlStream.push(endingChunk);
|
||||
xmlStream.push(null);
|
||||
parser.on("data", (data) => {
|
||||
// rss = process.memoryUsage().rss
|
||||
// if (rss > maxRSSMemoryTaken) maxRSSMemoryTaken = rss
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
should(err).not.be.ok();
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
// console.log('RSS memory=', rss)
|
||||
const TimeTaken = Date.now() - startTime;
|
||||
// console.log('time taken=', TimeTaken)
|
||||
should(TimeTaken).be.belowOrEqual(700000);
|
||||
should(dataEventCount).equal(9116800);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
105
test/read.spec.ts
Normal file
105
test/read.spec.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
|
||||
describe("read method", () => {
|
||||
it("should properly parse a simple file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
const expectedData = [
|
||||
{
|
||||
$: { id: "1", test: "hello" },
|
||||
subitem:
|
||||
[{ $: { sub: "TESTING SUB" }, _: "one" },
|
||||
{ $: { sub: "2" }, _: "two" }]
|
||||
},
|
||||
{
|
||||
$: { id: "2" },
|
||||
subitem: [{ _: "three" }, { _: "four" }, { _: "five" }]
|
||||
}];
|
||||
const actualData: string[] = [];
|
||||
let obj;
|
||||
let Timeout: any;
|
||||
|
||||
parser.on("readable", () => {
|
||||
Timeout = setInterval(() => {
|
||||
obj = parser.read();
|
||||
if (obj) {
|
||||
actualData.push(obj);
|
||||
}
|
||||
obj = null;
|
||||
}, 50);
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', actualData)
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
clearInterval(Timeout);
|
||||
should(actualData).deepEqual(expectedData);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a file containing many nodes.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/manyItems.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
let objCount = 0;
|
||||
const endEventOcurred = false;
|
||||
|
||||
parser.on("readable", () => {
|
||||
read();
|
||||
});
|
||||
|
||||
function read() {
|
||||
while (parser.read()) { objCount++; }
|
||||
if (!endEventOcurred) { setTimeout(read, 50); }
|
||||
}
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log(objCount)
|
||||
should(objCount).deepEqual(296);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a huge.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/hugeFile.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
let objCount = 0;
|
||||
const endEventOcurred = false;
|
||||
|
||||
parser.on("readable", () => {
|
||||
read();
|
||||
});
|
||||
|
||||
function read() {
|
||||
while (parser.read()) { objCount++; }
|
||||
if (!endEventOcurred) { setTimeout(read, 50); }
|
||||
}
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log(objCount)
|
||||
should(objCount).deepEqual(2072);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
111
test/same_name.spec.ts
Normal file
111
test/same_name.spec.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
|
||||
describe("nodes with same names", () => {
|
||||
it("should properly parse a simple file containing nodes with same names.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/nodesWithSameNames.xml");
|
||||
const parser = new XmlParser();
|
||||
|
||||
const actualData: string[] = [];
|
||||
const actualItems: string[] = [];
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
should(err).not.be.ok();
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
actualItems.push(item);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
should(actualItems.length).equal(18);
|
||||
should(dataEventCount).equal(18);
|
||||
done();
|
||||
});
|
||||
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a simple file containing nodes with same names and emit events on multiple nodes.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/nodesWithSameNames.xml");
|
||||
const parser = new XmlParser();
|
||||
|
||||
let dataEventCount = 0;
|
||||
let itemEventCount = 0;
|
||||
let subitemEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
should(err).not.be.ok();
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
itemEventCount++;
|
||||
});
|
||||
|
||||
parser.on("subitem", (subitem) => {
|
||||
subitemEventCount++;
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
should(itemEventCount).equal(18);
|
||||
should(subitemEventCount).equal(13);
|
||||
should(dataEventCount).equal(31);
|
||||
done();
|
||||
});
|
||||
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a medium size file with same names randomly.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/nodesWithSameNamesRandomly.xml");
|
||||
const parser = new XmlParser();
|
||||
|
||||
let dataEventCount = 0;
|
||||
let itemEventCount = 0;
|
||||
let subitemEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
itemEventCount++;
|
||||
});
|
||||
|
||||
parser.on("subitem", (subitem) => {
|
||||
subitemEventCount++;
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
// console.log('itemEventCount=', itemEventCount)
|
||||
// console.log('subitemEventCount=', subitemEventCount)
|
||||
should(dataEventCount).equal(32);
|
||||
should(itemEventCount).equal(19);
|
||||
should(subitemEventCount).equal(13);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
1545
test/test.js
1545
test/test.js
File diff suppressed because it is too large
Load Diff
64
test/uncompressed.spec.ts
Normal file
64
test/uncompressed.spec.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
|
||||
describe("should properly handle uncompressed files", () => {
|
||||
it("should properly parse a uncompressed xml file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/medium.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
const gzip = zlib.createGzip();
|
||||
const gunzip = zlib.createGunzip();
|
||||
let dataEventCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(10);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(gzip).pipe(gunzip).pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse uncompressed file and go fine with pause and resume.", function(done) {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/medium.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/items/item" });
|
||||
const gzip = zlib.createGzip();
|
||||
const gunzip = zlib.createGunzip();
|
||||
|
||||
let dataEventCount = 0;
|
||||
let isSetTimeoutHappened = true;
|
||||
this.timeout(20000);
|
||||
parser.on("data", (data) => {
|
||||
parser.pause();
|
||||
should(isSetTimeoutHappened).equal(true);
|
||||
setTimeout(() => {
|
||||
parser.resume();
|
||||
isSetTimeoutHappened = true;
|
||||
}, 2000);
|
||||
dataEventCount++;
|
||||
isSetTimeoutHappened = false;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(10);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(gzip).pipe(gunzip).pipe(parser);
|
||||
});
|
||||
});
|
||||
99
test/wrong_resourcepath.spec.ts
Normal file
99
test/wrong_resourcepath.spec.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import fs from "fs";
|
||||
import "mocha";
|
||||
import should from "should";
|
||||
import stream from "stream";
|
||||
import zlib from "zlib";
|
||||
|
||||
import { XmlParser } from "../src/parser";
|
||||
|
||||
describe("wrong resourcePath", () => {
|
||||
it("should be able to detect the wrong resourcePath at root level.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/item.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/wrong/noNodes", emitOnNodeName: true });
|
||||
|
||||
const actualData : string[] = [];
|
||||
const itemData : string[] = [];
|
||||
let dataEventCount = 0;
|
||||
let itemCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
actualData.push(data);
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
itemData.push(item);
|
||||
itemCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('actualData=', actualData)
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(actualData.length).equal(0);
|
||||
should(dataEventCount).equal(0);
|
||||
should(itemData.length).equal(0);
|
||||
should(itemCount).equal(0);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should be able to detect wrong resourcePath while parsing xml", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/manyItems.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/wrong/noNodes", emitOnNodeName: true });
|
||||
|
||||
let dataEventCount = 0;
|
||||
let itemCount = 0;
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("item", (data) => {
|
||||
itemCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(0);
|
||||
should(itemCount).equal(0);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
|
||||
it("should properly parse a huge file.", (done) => {
|
||||
const xmlStream = fs.createReadStream("./test/TestFiles/hugeFile.xml");
|
||||
const parser = new XmlParser({ resourcePath: "/wrong/path", emitOnNodeName: true });
|
||||
|
||||
let dataEventCount = 0;
|
||||
let itemCount = 0;
|
||||
|
||||
parser.on("data", (data) => {
|
||||
dataEventCount++;
|
||||
});
|
||||
|
||||
parser.on("item", (item) => {
|
||||
itemCount++;
|
||||
});
|
||||
|
||||
parser.on("error", (err) => {
|
||||
done(err);
|
||||
});
|
||||
|
||||
parser.on("end", () => {
|
||||
// console.log('dataEventCount=', dataEventCount)
|
||||
should(dataEventCount).equal(0);
|
||||
should(itemCount).equal(0);
|
||||
done();
|
||||
});
|
||||
xmlStream.pipe(parser);
|
||||
});
|
||||
});
|
||||
33
tsconfig.json
Normal file
33
tsconfig.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"outDir": "dist",
|
||||
"moduleResolution": "node",
|
||||
"module": "commonjs",
|
||||
"removeComments": true,
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports":true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"noImplicitAny": true,
|
||||
"declaration": true,
|
||||
"resolveJsonModule": true,
|
||||
"target":"es2017",
|
||||
"lib": ["es2017"],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./typings"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./typings/**/*.d.ts",
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
22
tslint.json
Normal file
22
tslint.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"rules": {
|
||||
"no-console": [false],
|
||||
"variable-name": false,
|
||||
"radix": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"trailing-comma":[false],
|
||||
"indent": [true,"tabs"],
|
||||
"max-line-length": [false],
|
||||
"no-string-literal": false,
|
||||
"class-name": false,
|
||||
"no-namespace": [false],
|
||||
"no-bitwise": false
|
||||
},
|
||||
"extends": "tslint:recommended",
|
||||
"linterOptions": {
|
||||
"exclude":[
|
||||
"*.json",
|
||||
"**/*.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
91
typings/node-expat/index.d.ts
vendored
Normal file
91
typings/node-expat/index.d.ts
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
// Type definitions for node-expat 2.3.x
|
||||
// Project: http://nodejs.org/
|
||||
// Definitions by: Microsoft TypeScript <http://typescriptlang.org>
|
||||
// Oleksandr Fedorchuk <https://github.com/kol-93>
|
||||
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
|
||||
|
||||
|
||||
declare module "node-expat" {
|
||||
import { Stream } from "stream";
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
interface NameSpace<ValueType = any> {
|
||||
[key: string]: ValueType;
|
||||
}
|
||||
|
||||
interface TypedEmitter<EventMapType extends NameSpace<any[]>> extends EventEmitter {
|
||||
addListener<Event extends keyof EventMapType> (event: Event, listener: (...args: EventMapType[Event]) => void): this;
|
||||
on<Event extends keyof EventMapType> (event: Event, listener: (...args: EventMapType[Event]) => void): this;
|
||||
once<Event extends keyof EventMapType> (event: Event, listener: (...args: EventMapType[Event]) => void): this;
|
||||
prependListener<Event extends keyof EventMapType> (event: Event, listener: (...args: EventMapType[Event]) => void): this;
|
||||
prependOnceListener<Event extends keyof EventMapType> (event: Event, listener: (...args: EventMapType[Event]) => void): this;
|
||||
removeListener<Event extends keyof EventMapType> (event: Event, listener: (...args: EventMapType[Event]) => void): this;
|
||||
emit<Event extends keyof EventMapType> (event: Event, ...args: EventMapType[Event]): boolean;
|
||||
|
||||
addListener (event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
on (event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
|
||||
once (event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
prependListener (event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
prependOnceListener (event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
removeListener (event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
emit (event: string | symbol, ...args: any[]): boolean;
|
||||
}
|
||||
|
||||
interface ParserEventsMap extends NameSpace<any[]> {
|
||||
startElement: [string, NameSpace<string>];
|
||||
endElement: [string];
|
||||
text: [string];
|
||||
comment: [string];
|
||||
processingInstruction: [string, string];
|
||||
xmlDecl: [string | null, string | null, boolean];
|
||||
startCdata: [];
|
||||
endCdata: [];
|
||||
entityDecl: [string | null, boolean, string | null, string | null, string | null, string | null, string | null];
|
||||
end: [];
|
||||
close: [];
|
||||
error: [string | Error];
|
||||
}
|
||||
|
||||
export class Parser extends Stream implements NodeJS.WritableStream, TypedEmitter<ParserEventsMap>
|
||||
{
|
||||
readonly writable: boolean;
|
||||
stop(): this;
|
||||
|
||||
pause(): this;
|
||||
resume(): this;
|
||||
|
||||
parse(buf: string | Buffer, isFinal?: boolean): boolean;
|
||||
setEncoding(value: string): this;
|
||||
/// @TODO setUnknownEncoding
|
||||
getError(): string | null;
|
||||
destroy(): this;
|
||||
destroySoon(): this;
|
||||
|
||||
write(buffer: Buffer | string, cb?: Function): boolean;
|
||||
write(str: string, encoding?: string, cb?: Function): boolean;
|
||||
end(cb?: Function): boolean;
|
||||
end(chunk: Buffer, cb?: Function): boolean;
|
||||
end(chunk: string, cb?: Function): boolean;
|
||||
end(chunk: string, encding?: string, cb?: Function): boolean;
|
||||
reset(this: Parser): this;
|
||||
getCurrentLineNumber(this: Parser): number;
|
||||
getCurrentColumnNumber(this: Parser): number;
|
||||
getCurrentByteIndex(this: Parser): number;
|
||||
|
||||
on (event: "startElement", listener:(name:string, attrs: any)=>void):this;
|
||||
on (event: "endElement", listener:(name:string)=>void):this;
|
||||
on (event: "text", listener:(text:string)=>void):this;
|
||||
on (event: "processingInstruction", listener:(target:any, data:any)=>void):this;
|
||||
on (event: "comment", listener:(s:string)=>void):this;
|
||||
on (event: "xmlDecl", listener:(version:string, encoding: string, standalone: boolean)=>void):this;
|
||||
on (event: "startCdata", listener:()=>void):this;
|
||||
on (event: "endCdata", listener:()=>void):this;
|
||||
on (event: "entityDecl", listener:(entityName:string, isParameterEntity:boolean, value:string, base:string, systemId:string, publicId:string, notationName:string)=>void):this;
|
||||
on (event: "error", listener:(e:Error)=>void):this;
|
||||
on (event: "close", listener:()=>void):this;
|
||||
}
|
||||
|
||||
export function createParser(callback?: (name: string, attributes: NameSpace<string>) => void): Parser;
|
||||
}
|
||||
3
typings/node-expat/project.json
Normal file
3
typings/node-expat/project.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user