依赖文件
This commit is contained in:
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../semver/bin/semver" "$@"
|
||||
else
|
||||
exec node "$basedir/../semver/bin/semver" "$@"
|
||||
fi
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\semver\bin\semver" %*
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../semver/bin/semver" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../semver/bin/semver" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../semver/bin/semver" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../semver/bin/semver" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
case `uname` in
|
||||
*CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;;
|
||||
esac
|
||||
|
||||
if [ -x "$basedir/node" ]; then
|
||||
exec "$basedir/node" "$basedir/../which/bin/which" "$@"
|
||||
else
|
||||
exec node "$basedir/../which/bin/which" "$@"
|
||||
fi
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
@ECHO off
|
||||
GOTO start
|
||||
:find_dp0
|
||||
SET dp0=%~dp0
|
||||
EXIT /b
|
||||
:start
|
||||
SETLOCAL
|
||||
CALL :find_dp0
|
||||
|
||||
IF EXIST "%dp0%\node.exe" (
|
||||
SET "_prog=%dp0%\node.exe"
|
||||
) ELSE (
|
||||
SET "_prog=node"
|
||||
SET PATHEXT=%PATHEXT:;.JS;=;%
|
||||
)
|
||||
|
||||
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\which\bin\which" %*
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env pwsh
|
||||
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
|
||||
|
||||
$exe=""
|
||||
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
|
||||
# Fix case when both the Windows and Linux builds of Node
|
||||
# are installed in the same directory
|
||||
$exe=".exe"
|
||||
}
|
||||
$ret=0
|
||||
if (Test-Path "$basedir/node$exe") {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "$basedir/node$exe" "$basedir/../which/bin/which" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../which/bin/which" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../which/bin/which" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../which/bin/which" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
+383
@@ -50,6 +50,11 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@googlemaps/js-api-loader": {
|
||||
"version": "1.16.8",
|
||||
"resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.16.8.tgz",
|
||||
"integrity": "sha512-CROqqwfKotdO6EBjZO/gQGVTbeDps5V7Mt9+8+5Q+jTg5CRMi3Ii/L9PmV3USROrt2uWxtGzJHORmByxyo9pSQ=="
|
||||
},
|
||||
"node_modules/@intlify/core-base": {
|
||||
"version": "9.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.9.tgz",
|
||||
@@ -243,12 +248,169 @@
|
||||
"integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@xmldom/xmldom": {
|
||||
"version": "0.8.10",
|
||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
||||
"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz",
|
||||
"integrity": "sha512-iFY7JCgHbepc0b82yLaw4IMortylNb6wG4kL+4R0C3iv6i+RHGHux/yUX5BTiRvSX/shMnngjR1YyNMnXEFh5A=="
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/big-integer": {
|
||||
"version": "1.6.52",
|
||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz",
|
||||
"integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/bplist-parser": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz",
|
||||
"integrity": "sha512-2AEM0FXy8ZxVLBuqX0hqt1gDwcnz2zygEkQ6zaD5Wko/sB9paUNwlpawrFtKeHUAQUOzjVy9AO4oeonqIHKA9Q==",
|
||||
"dependencies": {
|
||||
"big-integer": "^1.6.7"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/cordova-common": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-3.2.1.tgz",
|
||||
"integrity": "sha512-xg0EnjnA6EipxXG8cupdlYQYeDA6+ghbN+Pjq88xN1LInwP6Bo7IyGBdSV5QnfjOvzShF9BBwSxBAv0FOO0C2Q==",
|
||||
"dependencies": {
|
||||
"ansi": "^0.3.1",
|
||||
"bplist-parser": "^0.1.0",
|
||||
"cross-spawn": "^6.0.5",
|
||||
"elementtree": "0.1.7",
|
||||
"endent": "^1.1.1",
|
||||
"fs-extra": "^8.0.0",
|
||||
"glob": "^7.1.2",
|
||||
"minimatch": "^3.0.0",
|
||||
"plist": "^3.0.1",
|
||||
"q": "^1.4.1",
|
||||
"strip-bom": "^3.0.0",
|
||||
"underscore": "^1.8.3",
|
||||
"which": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cordova-plugin-googlemaps": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/cordova-plugin-googlemaps/-/cordova-plugin-googlemaps-2.7.1.tgz",
|
||||
"integrity": "sha512-CPqLTc+Pmf/8sL4+lJazQR0ESNTSLaHIp+37yLe49dRg+qF3KNvtGX/l01SoJilgAwDkZjFNtOORhHlzlbmEdA==",
|
||||
"engines": [
|
||||
{
|
||||
"name": "cordova-android",
|
||||
"version": ">=5.1.0"
|
||||
},
|
||||
{
|
||||
"name": "cordova-ios",
|
||||
"version": ">=5.1.1"
|
||||
},
|
||||
{
|
||||
"name": "apple-xcode",
|
||||
"version": ">=10.0.0"
|
||||
},
|
||||
{
|
||||
"name": "apple-ios",
|
||||
"version": ">=10.0.0"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"cordova-common": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "6.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz",
|
||||
"integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==",
|
||||
"dependencies": {
|
||||
"nice-try": "^1.0.4",
|
||||
"path-key": "^2.0.1",
|
||||
"semver": "^5.5.0",
|
||||
"shebang-command": "^1.2.0",
|
||||
"which": "^1.2.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.8"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/dedent": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
|
||||
"integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA=="
|
||||
},
|
||||
"node_modules/elementtree": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.7.tgz",
|
||||
"integrity": "sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==",
|
||||
"dependencies": {
|
||||
"sax": "1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/endent": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/endent/-/endent-1.4.1.tgz",
|
||||
"integrity": "sha512-buHTb5c8AC9NshtP6dgmNLYkiT+olskbq1z6cEGvfGCF3Qphbu/1zz5Xu+yjTDln8RbxNhPoUyJ5H8MSrp1olQ==",
|
||||
"dependencies": {
|
||||
"dedent": "^0.7.0",
|
||||
"fast-json-parse": "^1.0.3",
|
||||
"objectorarray": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
@@ -267,6 +429,82 @@
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/fast-json-parse": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz",
|
||||
"integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw=="
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6 <7 || >=8"
|
||||
}
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.1.1",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
|
||||
},
|
||||
"node_modules/inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
|
||||
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
|
||||
"dependencies": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.17",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
|
||||
@@ -276,6 +514,17 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.9",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.9.tgz",
|
||||
@@ -294,12 +543,59 @@
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/nice-try": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
|
||||
},
|
||||
"node_modules/objectorarray": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz",
|
||||
"integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg=="
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
|
||||
"integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/plist": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
|
||||
"integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==",
|
||||
"dependencies": {
|
||||
"@xmldom/xmldom": "^0.8.8",
|
||||
"base64-js": "^1.5.1",
|
||||
"xmlbuilder": "^15.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||
@@ -328,6 +624,48 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/q": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
|
||||
"integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
|
||||
"deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)",
|
||||
"engines": {
|
||||
"node": ">=0.6.0",
|
||||
"teleport": ">=0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz",
|
||||
"integrity": "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg=="
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
|
||||
"integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
|
||||
"dependencies": {
|
||||
"shebang-regex": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-regex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
|
||||
"integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
@@ -345,6 +683,27 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/underscore": {
|
||||
"version": "1.13.7",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
|
||||
"integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g=="
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.5.13",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz",
|
||||
@@ -382,6 +741,30 @@
|
||||
"peerDependencies": {
|
||||
"vue": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
|
||||
"dependencies": {
|
||||
"isexe": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"which": "bin/which"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"node_modules/xmlbuilder": {
|
||||
"version": "15.1.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
|
||||
"integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
# Google Maps JavaScript API Loader
|
||||
|
||||
[](https://www.npmjs.com/package/@googlemaps/js-api-loader)
|
||||

|
||||

|
||||
[](https://codecov.io/gh/googlemaps/js-api-loader)
|
||||

|
||||
[](https://github.com/semantic-release/semantic-release)
|
||||
[](https://discord.gg/jRteCzP)
|
||||
|
||||
## Description
|
||||
Load the Google Maps JavaScript API script dynamically. This takes inspiration from the [google-maps](https://www.npmjs.com/package/google-maps) npm package but updates it with ES6, Promises, and TypeScript.
|
||||
|
||||
## Install
|
||||
|
||||
Available via npm as the package [@googlemaps/js-api-loader](https://www.npmjs.com/package/@googlemaps/js-api-loader).
|
||||
|
||||
```sh
|
||||
npm i @googlemaps/js-api-loader
|
||||
```
|
||||
|
||||
Alternatively you may add the umd package directly to the html document using the unpkg link.
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/@googlemaps/js-api-loader@1.x/dist/index.min.js"></script>
|
||||
```
|
||||
|
||||
When adding via unpkg, the loader can be accessed at `google.maps.plugins.loader.Loader`.
|
||||
|
||||
### TypeScript
|
||||
|
||||
TypeScript users need to install the following types package.
|
||||
|
||||
```sh
|
||||
npm i -D @types/google.maps
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
The reference documentation can be found at this [link](https://googlemaps.github.io/js-api-loader/index.html). The Google Maps JavaScript API [documentation](https://developers.google.com/maps/documentation/javascript/tutorial) is the authoritative source for the loader options.
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
```javascript
|
||||
import { Loader } from '@googlemaps/js-api-loader';
|
||||
|
||||
const loader = new Loader({
|
||||
apiKey: "",
|
||||
version: "weekly",
|
||||
libraries: ["places"]
|
||||
});
|
||||
|
||||
const mapOptions = {
|
||||
center: {
|
||||
lat: 0,
|
||||
lng: 0
|
||||
},
|
||||
zoom: 4
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
Using a promise for a specific library.
|
||||
|
||||
```javascript
|
||||
// Promise for a specific library
|
||||
loader
|
||||
.importLibrary('maps')
|
||||
.then(({Map}) => {
|
||||
new Map(document.getElementById("map"), mapOptions);
|
||||
})
|
||||
.catch((e) => {
|
||||
// do something
|
||||
});
|
||||
```
|
||||
|
||||
Using a promise for when the script has loaded.
|
||||
|
||||
```javascript
|
||||
// Promise
|
||||
loader
|
||||
.load()
|
||||
.then((google) => {
|
||||
new google.maps.Map(document.getElementById("map"), mapOptions);
|
||||
})
|
||||
.catch(e => {
|
||||
// do something
|
||||
});
|
||||
```
|
||||
|
||||
Alternatively, if you want to use a callback.
|
||||
|
||||
```javascript
|
||||
// Callback
|
||||
loader.loadCallback(e => {
|
||||
if (e) {
|
||||
console.log(e);
|
||||
} else {
|
||||
new google.maps.Map(document.getElementById("map"), mapOptions);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
View the package in action [here](https://googlemaps.github.io/js-api-loader/examples/index.html).
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
This library is community supported. We're comfortable enough with the stability and features of
|
||||
the library that we want you to build real production applications on it.
|
||||
|
||||
If you find a bug, or have a feature suggestion, please [log an issue][issues]. If you'd like to
|
||||
contribute, please read [How to Contribute][contrib].
|
||||
|
||||
[issues]: https://github.com/googlemaps/js-api-loader/issues
|
||||
[contrib]: https://github.com/googlemaps/js-api-loader/blob/main/CONTRIBUTING.md
|
||||
+315
@@ -0,0 +1,315 @@
|
||||
/**
|
||||
* Copyright 2019 Google LLC. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at.
|
||||
*
|
||||
* Http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/// <reference types="google.maps" />
|
||||
export declare const DEFAULT_ID = "__googleMapsScriptId";
|
||||
export type Library = "core" | "maps" | "places" | "geocoding" | "routes" | "marker" | "geometry" | "elevation" | "streetView" | "journeySharing" | "drawing" | "visualization";
|
||||
export type Libraries = Library[];
|
||||
/**
|
||||
* The Google Maps JavaScript API
|
||||
* [documentation](https://developers.google.com/maps/documentation/javascript/tutorial)
|
||||
* is the authoritative source for [[LoaderOptions]].
|
||||
/**
|
||||
* Loader options
|
||||
*/
|
||||
export interface LoaderOptions {
|
||||
/**
|
||||
* See https://developers.google.com/maps/documentation/javascript/get-api-key.
|
||||
*/
|
||||
apiKey: string;
|
||||
/**
|
||||
* @deprecated See https://developers.google.com/maps/premium/overview.
|
||||
*/
|
||||
channel?: string;
|
||||
/**
|
||||
* @deprecated See https://developers.google.com/maps/premium/overview, use `apiKey` instead.
|
||||
*/
|
||||
client?: string;
|
||||
/**
|
||||
* In your application you can specify release channels or version numbers:
|
||||
*
|
||||
* The weekly version is specified with `version=weekly`. This version is
|
||||
* updated once per week, and is the most current.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, version: 'weekly'});
|
||||
* ```
|
||||
*
|
||||
* The quarterly version is specified with `version=quarterly`. This version
|
||||
* is updated once per quarter, and is the most predictable.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, version: 'quarterly'});
|
||||
* ```
|
||||
*
|
||||
* The version number is specified with `version=n.nn`. You can choose
|
||||
* `version=3.40`, `version=3.39`, or `version=3.38`. Version numbers are
|
||||
* updated once per quarter.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, version: '3.40'});
|
||||
* ```
|
||||
*
|
||||
* If you do not explicitly specify a version, you will receive the
|
||||
* weekly version by default.
|
||||
*/
|
||||
version?: string;
|
||||
/**
|
||||
* The id of the script tag. Before adding a new script, the Loader will check for an existing one.
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* When loading the Maps JavaScript API via the URL you may optionally load
|
||||
* additional libraries through use of the libraries URL parameter. Libraries
|
||||
* are modules of code that provide additional functionality to the main Maps
|
||||
* JavaScript API but are not loaded unless you specifically request them.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({
|
||||
* apiKey,
|
||||
* libraries: ['drawing', 'geometry', 'places', 'visualization'],
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Set the [list of libraries](https://developers.google.com/maps/documentation/javascript/libraries) for more options.
|
||||
*/
|
||||
libraries?: Libraries;
|
||||
/**
|
||||
* By default, the Maps JavaScript API uses the user's preferred language
|
||||
* setting as specified in the browser, when displaying textual information
|
||||
* such as the names for controls, copyright notices, driving directions and
|
||||
* labels on maps. In most cases, it's preferable to respect the browser
|
||||
* setting. However, if you want the Maps JavaScript API to ignore the
|
||||
* browser's language setting, you can force it to display information in a
|
||||
* particular language when loading the Maps JavaScript API code.
|
||||
*
|
||||
* For example, the following example localizes the language to Japan:
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, language: 'ja', region: 'JP'});
|
||||
* ```
|
||||
*
|
||||
* See the [list of supported
|
||||
* languages](https://developers.google.com/maps/faq#languagesupport). Note
|
||||
* that new languages are added often, so this list may not be exhaustive.
|
||||
*
|
||||
*/
|
||||
language?: string;
|
||||
/**
|
||||
* When you load the Maps JavaScript API from maps.googleapis.com it applies a
|
||||
* default bias for application behavior towards the United States. If you
|
||||
* want to alter your application to serve different map tiles or bias the
|
||||
* application (such as biasing geocoding results towards the region), you can
|
||||
* override this default behavior by adding a region parameter when loading
|
||||
* the Maps JavaScript API code.
|
||||
*
|
||||
* The region parameter accepts Unicode region subtag identifiers which
|
||||
* (generally) have a one-to-one mapping to country code Top-Level Domains
|
||||
* (ccTLDs). Most Unicode region identifiers are identical to ISO 3166-1
|
||||
* codes, with some notable exceptions. For example, Great Britain's ccTLD is
|
||||
* "uk" (corresponding to the domain .co.uk) while its region identifier is
|
||||
* "GB."
|
||||
*
|
||||
* For example, the following example localizes the map to the United Kingdom:
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, region: 'GB'});
|
||||
* ```
|
||||
*/
|
||||
region?: string;
|
||||
/**
|
||||
* @deprecated Passing `mapIds` is no longer required in the script tag.
|
||||
*/
|
||||
mapIds?: string[];
|
||||
/**
|
||||
* Use a custom url and path to load the Google Maps API script.
|
||||
*/
|
||||
url?: string;
|
||||
/**
|
||||
* Use a cryptographic nonce attribute.
|
||||
*/
|
||||
nonce?: string;
|
||||
/**
|
||||
* The number of script load retries.
|
||||
*/
|
||||
retries?: number;
|
||||
/**
|
||||
* Maps JS customers can configure HTTP Referrer Restrictions in the Cloud
|
||||
* Console to limit which URLs are allowed to use a particular API Key. By
|
||||
* default, these restrictions can be configured to allow only certain paths
|
||||
* to use an API Key. If any URL on the same domain or origin may use the API
|
||||
* Key, you can set `auth_referrer_policy=origin` to limit the amount of data
|
||||
* sent when authorizing requests from the Maps JavaScript API. This is
|
||||
* available starting in version 3.46. When this parameter is specified and
|
||||
* HTTP Referrer Restrictions are enabled on Cloud Console, Maps JavaScript
|
||||
* API will only be able to load if there is an HTTP Referrer Restriction that
|
||||
* matches the current website's domain without a path specified.
|
||||
*/
|
||||
authReferrerPolicy?: "origin";
|
||||
}
|
||||
/**
|
||||
* The status of the [[Loader]].
|
||||
*/
|
||||
export declare enum LoaderStatus {
|
||||
INITIALIZED = 0,
|
||||
LOADING = 1,
|
||||
SUCCESS = 2,
|
||||
FAILURE = 3
|
||||
}
|
||||
/**
|
||||
* [[Loader]] makes it easier to add Google Maps JavaScript API to your application
|
||||
* dynamically using
|
||||
* [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
|
||||
* It works by dynamically creating and appending a script node to the the
|
||||
* document head and wrapping the callback function so as to return a promise.
|
||||
*
|
||||
* ```
|
||||
* const loader = new Loader({
|
||||
* apiKey: "",
|
||||
* version: "weekly",
|
||||
* libraries: ["places"]
|
||||
* });
|
||||
*
|
||||
* loader.load().then((google) => {
|
||||
* const map = new google.maps.Map(...)
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export declare class Loader {
|
||||
private static instance;
|
||||
/**
|
||||
* See [[LoaderOptions.version]]
|
||||
*/
|
||||
readonly version: string;
|
||||
/**
|
||||
* See [[LoaderOptions.apiKey]]
|
||||
*/
|
||||
readonly apiKey: string;
|
||||
/**
|
||||
* See [[LoaderOptions.channel]]
|
||||
*/
|
||||
readonly channel: string;
|
||||
/**
|
||||
* See [[LoaderOptions.client]]
|
||||
*/
|
||||
readonly client: string;
|
||||
/**
|
||||
* See [[LoaderOptions.id]]
|
||||
*/
|
||||
readonly id: string;
|
||||
/**
|
||||
* See [[LoaderOptions.libraries]]
|
||||
*/
|
||||
readonly libraries: Libraries;
|
||||
/**
|
||||
* See [[LoaderOptions.language]]
|
||||
*/
|
||||
readonly language: string;
|
||||
/**
|
||||
* See [[LoaderOptions.region]]
|
||||
*/
|
||||
readonly region: string;
|
||||
/**
|
||||
* See [[LoaderOptions.mapIds]]
|
||||
*/
|
||||
readonly mapIds: string[];
|
||||
/**
|
||||
* See [[LoaderOptions.nonce]]
|
||||
*/
|
||||
readonly nonce: string | null;
|
||||
/**
|
||||
* See [[LoaderOptions.retries]]
|
||||
*/
|
||||
readonly retries: number;
|
||||
/**
|
||||
* See [[LoaderOptions.url]]
|
||||
*/
|
||||
readonly url: string;
|
||||
/**
|
||||
* See [[LoaderOptions.authReferrerPolicy]]
|
||||
*/
|
||||
readonly authReferrerPolicy: "origin";
|
||||
private callbacks;
|
||||
private done;
|
||||
private loading;
|
||||
private onerrorEvent;
|
||||
private errors;
|
||||
/**
|
||||
* Creates an instance of Loader using [[LoaderOptions]]. No defaults are set
|
||||
* using this library, instead the defaults are set by the Google Maps
|
||||
* JavaScript API server.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, version: 'weekly', libraries: ['places']});
|
||||
* ```
|
||||
*/
|
||||
constructor({ apiKey, authReferrerPolicy, channel, client, id, language, libraries, mapIds, nonce, region, retries, url, version, }: LoaderOptions);
|
||||
get options(): LoaderOptions;
|
||||
get status(): LoaderStatus;
|
||||
private get failed();
|
||||
/**
|
||||
* CreateUrl returns the Google Maps JavaScript API script url given the [[LoaderOptions]].
|
||||
*
|
||||
* @ignore
|
||||
* @deprecated
|
||||
*/
|
||||
createUrl(): string;
|
||||
deleteScript(): void;
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script and return a Promise.
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
load(): Promise<typeof google>;
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script and return a Promise.
|
||||
*
|
||||
* @ignore
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
loadPromise(): Promise<typeof google>;
|
||||
/**
|
||||
* See https://developers.google.com/maps/documentation/javascript/reference/top-level#google.maps.importLibrary
|
||||
*/
|
||||
importLibrary(name: "core"): Promise<google.maps.CoreLibrary>;
|
||||
importLibrary(name: "maps"): Promise<google.maps.MapsLibrary>;
|
||||
importLibrary(name: "places"): Promise<google.maps.PlacesLibrary>;
|
||||
importLibrary(name: "geocoding"): Promise<google.maps.GeocodingLibrary>;
|
||||
importLibrary(name: "routes"): Promise<google.maps.RoutesLibrary>;
|
||||
importLibrary(name: "marker"): Promise<google.maps.MarkerLibrary>;
|
||||
importLibrary(name: "geometry"): Promise<google.maps.GeometryLibrary>;
|
||||
importLibrary(name: "elevation"): Promise<google.maps.ElevationLibrary>;
|
||||
importLibrary(name: "streetView"): Promise<google.maps.StreetViewLibrary>;
|
||||
importLibrary(name: "journeySharing"): Promise<google.maps.JourneySharingLibrary>;
|
||||
importLibrary(name: "drawing"): Promise<google.maps.DrawingLibrary>;
|
||||
importLibrary(name: "visualization"): Promise<google.maps.VisualizationLibrary>;
|
||||
importLibrary(name: Library): Promise<unknown>;
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script with a callback.
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
loadCallback(fn: (e: ErrorEvent) => void): void;
|
||||
/**
|
||||
* Set the script on document.
|
||||
*/
|
||||
private setScript;
|
||||
/**
|
||||
* Reset the loader state.
|
||||
*/
|
||||
private reset;
|
||||
private resetIfRetryingFailed;
|
||||
private loadErrorCallback;
|
||||
private callback;
|
||||
private execute;
|
||||
}
|
||||
+450
@@ -0,0 +1,450 @@
|
||||
this.google = this.google || {};
|
||||
this.google.maps = this.google.maps || {};
|
||||
this.google.maps.plugins = this.google.maps.plugins || {};
|
||||
this.google.maps.plugins.loader = (function (exports) {
|
||||
'use strict';
|
||||
|
||||
/******************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
/* global Reflect, Promise, SuppressedError, Symbol */
|
||||
|
||||
function __awaiter(thisArg, _arguments, P, generator) {
|
||||
function adopt(value) {
|
||||
return value instanceof P ? value : new P(function (resolve) {
|
||||
resolve(value);
|
||||
});
|
||||
}
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) {
|
||||
try {
|
||||
step(generator.next(value));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}
|
||||
function rejected(value) {
|
||||
try {
|
||||
step(generator["throw"](value));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}
|
||||
function step(result) {
|
||||
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
|
||||
}
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
}
|
||||
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
||||
var e = new Error(message);
|
||||
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
||||
};
|
||||
|
||||
function getDefaultExportFromCjs (x) {
|
||||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
||||
}
|
||||
|
||||
// do not edit .js files directly - edit src/index.jst
|
||||
|
||||
var fastDeepEqual = function equal(a, b) {
|
||||
if (a === b) return true;
|
||||
if (a && b && typeof a == 'object' && typeof b == 'object') {
|
||||
if (a.constructor !== b.constructor) return false;
|
||||
var length, i, keys;
|
||||
if (Array.isArray(a)) {
|
||||
length = a.length;
|
||||
if (length != b.length) return false;
|
||||
for (i = length; i-- !== 0;) if (!equal(a[i], b[i])) return false;
|
||||
return true;
|
||||
}
|
||||
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
||||
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
||||
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
||||
keys = Object.keys(a);
|
||||
length = keys.length;
|
||||
if (length !== Object.keys(b).length) return false;
|
||||
for (i = length; i-- !== 0;) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
||||
for (i = length; i-- !== 0;) {
|
||||
var key = keys[i];
|
||||
if (!equal(a[key], b[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// true if both NaN, false otherwise
|
||||
return a !== a && b !== b;
|
||||
};
|
||||
var isEqual = /*@__PURE__*/getDefaultExportFromCjs(fastDeepEqual);
|
||||
|
||||
/**
|
||||
* Copyright 2019 Google LLC. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at.
|
||||
*
|
||||
* Http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const DEFAULT_ID = "__googleMapsScriptId";
|
||||
/**
|
||||
* The status of the [[Loader]].
|
||||
*/
|
||||
exports.LoaderStatus = void 0;
|
||||
(function (LoaderStatus) {
|
||||
LoaderStatus[LoaderStatus["INITIALIZED"] = 0] = "INITIALIZED";
|
||||
LoaderStatus[LoaderStatus["LOADING"] = 1] = "LOADING";
|
||||
LoaderStatus[LoaderStatus["SUCCESS"] = 2] = "SUCCESS";
|
||||
LoaderStatus[LoaderStatus["FAILURE"] = 3] = "FAILURE";
|
||||
})(exports.LoaderStatus || (exports.LoaderStatus = {}));
|
||||
/**
|
||||
* [[Loader]] makes it easier to add Google Maps JavaScript API to your application
|
||||
* dynamically using
|
||||
* [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
|
||||
* It works by dynamically creating and appending a script node to the the
|
||||
* document head and wrapping the callback function so as to return a promise.
|
||||
*
|
||||
* ```
|
||||
* const loader = new Loader({
|
||||
* apiKey: "",
|
||||
* version: "weekly",
|
||||
* libraries: ["places"]
|
||||
* });
|
||||
*
|
||||
* loader.load().then((google) => {
|
||||
* const map = new google.maps.Map(...)
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
class Loader {
|
||||
/**
|
||||
* Creates an instance of Loader using [[LoaderOptions]]. No defaults are set
|
||||
* using this library, instead the defaults are set by the Google Maps
|
||||
* JavaScript API server.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, version: 'weekly', libraries: ['places']});
|
||||
* ```
|
||||
*/
|
||||
constructor(_ref) {
|
||||
let {
|
||||
apiKey,
|
||||
authReferrerPolicy,
|
||||
channel,
|
||||
client,
|
||||
id = DEFAULT_ID,
|
||||
language,
|
||||
libraries = [],
|
||||
mapIds,
|
||||
nonce,
|
||||
region,
|
||||
retries = 3,
|
||||
url = "https://maps.googleapis.com/maps/api/js",
|
||||
version
|
||||
} = _ref;
|
||||
this.callbacks = [];
|
||||
this.done = false;
|
||||
this.loading = false;
|
||||
this.errors = [];
|
||||
this.apiKey = apiKey;
|
||||
this.authReferrerPolicy = authReferrerPolicy;
|
||||
this.channel = channel;
|
||||
this.client = client;
|
||||
this.id = id || DEFAULT_ID; // Do not allow empty string
|
||||
this.language = language;
|
||||
this.libraries = libraries;
|
||||
this.mapIds = mapIds;
|
||||
this.nonce = nonce;
|
||||
this.region = region;
|
||||
this.retries = retries;
|
||||
this.url = url;
|
||||
this.version = version;
|
||||
if (Loader.instance) {
|
||||
if (!isEqual(this.options, Loader.instance.options)) {
|
||||
throw new Error(`Loader must not be called again with different options. ${JSON.stringify(this.options)} !== ${JSON.stringify(Loader.instance.options)}`);
|
||||
}
|
||||
return Loader.instance;
|
||||
}
|
||||
Loader.instance = this;
|
||||
}
|
||||
get options() {
|
||||
return {
|
||||
version: this.version,
|
||||
apiKey: this.apiKey,
|
||||
channel: this.channel,
|
||||
client: this.client,
|
||||
id: this.id,
|
||||
libraries: this.libraries,
|
||||
language: this.language,
|
||||
region: this.region,
|
||||
mapIds: this.mapIds,
|
||||
nonce: this.nonce,
|
||||
url: this.url,
|
||||
authReferrerPolicy: this.authReferrerPolicy
|
||||
};
|
||||
}
|
||||
get status() {
|
||||
if (this.errors.length) {
|
||||
return exports.LoaderStatus.FAILURE;
|
||||
}
|
||||
if (this.done) {
|
||||
return exports.LoaderStatus.SUCCESS;
|
||||
}
|
||||
if (this.loading) {
|
||||
return exports.LoaderStatus.LOADING;
|
||||
}
|
||||
return exports.LoaderStatus.INITIALIZED;
|
||||
}
|
||||
get failed() {
|
||||
return this.done && !this.loading && this.errors.length >= this.retries + 1;
|
||||
}
|
||||
/**
|
||||
* CreateUrl returns the Google Maps JavaScript API script url given the [[LoaderOptions]].
|
||||
*
|
||||
* @ignore
|
||||
* @deprecated
|
||||
*/
|
||||
createUrl() {
|
||||
let url = this.url;
|
||||
url += `?callback=__googleMapsCallback&loading=async`;
|
||||
if (this.apiKey) {
|
||||
url += `&key=${this.apiKey}`;
|
||||
}
|
||||
if (this.channel) {
|
||||
url += `&channel=${this.channel}`;
|
||||
}
|
||||
if (this.client) {
|
||||
url += `&client=${this.client}`;
|
||||
}
|
||||
if (this.libraries.length > 0) {
|
||||
url += `&libraries=${this.libraries.join(",")}`;
|
||||
}
|
||||
if (this.language) {
|
||||
url += `&language=${this.language}`;
|
||||
}
|
||||
if (this.region) {
|
||||
url += `®ion=${this.region}`;
|
||||
}
|
||||
if (this.version) {
|
||||
url += `&v=${this.version}`;
|
||||
}
|
||||
if (this.mapIds) {
|
||||
url += `&map_ids=${this.mapIds.join(",")}`;
|
||||
}
|
||||
if (this.authReferrerPolicy) {
|
||||
url += `&auth_referrer_policy=${this.authReferrerPolicy}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
deleteScript() {
|
||||
const script = document.getElementById(this.id);
|
||||
if (script) {
|
||||
script.remove();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script and return a Promise.
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
load() {
|
||||
return this.loadPromise();
|
||||
}
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script and return a Promise.
|
||||
*
|
||||
* @ignore
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
loadPromise() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.loadCallback(err => {
|
||||
if (!err) {
|
||||
resolve(window.google);
|
||||
} else {
|
||||
reject(err.error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
importLibrary(name) {
|
||||
this.execute();
|
||||
return google.maps.importLibrary(name);
|
||||
}
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script with a callback.
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
loadCallback(fn) {
|
||||
this.callbacks.push(fn);
|
||||
this.execute();
|
||||
}
|
||||
/**
|
||||
* Set the script on document.
|
||||
*/
|
||||
setScript() {
|
||||
var _a, _b;
|
||||
if (document.getElementById(this.id)) {
|
||||
// TODO wrap onerror callback for cases where the script was loaded elsewhere
|
||||
this.callback();
|
||||
return;
|
||||
}
|
||||
const params = {
|
||||
key: this.apiKey,
|
||||
channel: this.channel,
|
||||
client: this.client,
|
||||
libraries: this.libraries.length && this.libraries,
|
||||
v: this.version,
|
||||
mapIds: this.mapIds,
|
||||
language: this.language,
|
||||
region: this.region,
|
||||
authReferrerPolicy: this.authReferrerPolicy
|
||||
};
|
||||
// keep the URL minimal:
|
||||
Object.keys(params).forEach(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
key => !params[key] && delete params[key]);
|
||||
if (!((_b = (_a = window === null || window === void 0 ? void 0 : window.google) === null || _a === void 0 ? void 0 : _a.maps) === null || _b === void 0 ? void 0 : _b.importLibrary)) {
|
||||
// tweaked copy of https://developers.google.com/maps/documentation/javascript/load-maps-js-api#dynamic-library-import
|
||||
// which also sets the base url, the id, and the nonce
|
||||
/* eslint-disable */
|
||||
(g => {
|
||||
// @ts-ignore
|
||||
let h,
|
||||
a,
|
||||
k,
|
||||
p = "The Google Maps JavaScript API",
|
||||
c = "google",
|
||||
l = "importLibrary",
|
||||
q = "__ib__",
|
||||
m = document,
|
||||
b = window;
|
||||
// @ts-ignore
|
||||
b = b[c] || (b[c] = {});
|
||||
// @ts-ignore
|
||||
const d = b.maps || (b.maps = {}),
|
||||
r = new Set(),
|
||||
e = new URLSearchParams(),
|
||||
u = () =>
|
||||
// @ts-ignore
|
||||
h || (h = new Promise((f, n) => __awaiter(this, void 0, void 0, function* () {
|
||||
var _a;
|
||||
yield a = m.createElement("script");
|
||||
a.id = this.id;
|
||||
e.set("libraries", [...r] + "");
|
||||
// @ts-ignore
|
||||
for (k in g) e.set(k.replace(/[A-Z]/g, t => "_" + t[0].toLowerCase()), g[k]);
|
||||
e.set("callback", c + ".maps." + q);
|
||||
a.src = this.url + `?` + e;
|
||||
d[q] = f;
|
||||
a.onerror = () => h = n(Error(p + " could not load."));
|
||||
// @ts-ignore
|
||||
a.nonce = this.nonce || ((_a = m.querySelector("script[nonce]")) === null || _a === void 0 ? void 0 : _a.nonce) || "";
|
||||
m.head.append(a);
|
||||
})));
|
||||
// @ts-ignore
|
||||
d[l] ? console.warn(p + " only loads once. Ignoring:", g) : d[l] = function (f) {
|
||||
for (var _len = arguments.length, n = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
n[_key - 1] = arguments[_key];
|
||||
}
|
||||
return r.add(f) && u().then(() => d[l](f, ...n));
|
||||
};
|
||||
})(params);
|
||||
/* eslint-enable */
|
||||
}
|
||||
// While most libraries populate the global namespace when loaded via bootstrap params,
|
||||
// this is not the case for "marker" when used with the inline bootstrap loader
|
||||
// (and maybe others in the future). So ensure there is an importLibrary for each:
|
||||
const libraryPromises = this.libraries.map(library => this.importLibrary(library));
|
||||
// ensure at least one library, to kick off loading...
|
||||
if (!libraryPromises.length) {
|
||||
libraryPromises.push(this.importLibrary("core"));
|
||||
}
|
||||
Promise.all(libraryPromises).then(() => this.callback(), error => {
|
||||
const event = new ErrorEvent("error", {
|
||||
error
|
||||
}); // for backwards compat
|
||||
this.loadErrorCallback(event);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Reset the loader state.
|
||||
*/
|
||||
reset() {
|
||||
this.deleteScript();
|
||||
this.done = false;
|
||||
this.loading = false;
|
||||
this.errors = [];
|
||||
this.onerrorEvent = null;
|
||||
}
|
||||
resetIfRetryingFailed() {
|
||||
if (this.failed) {
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
loadErrorCallback(e) {
|
||||
this.errors.push(e);
|
||||
if (this.errors.length <= this.retries) {
|
||||
const delay = this.errors.length * Math.pow(2, this.errors.length);
|
||||
console.error(`Failed to load Google Maps script, retrying in ${delay} ms.`);
|
||||
setTimeout(() => {
|
||||
this.deleteScript();
|
||||
this.setScript();
|
||||
}, delay);
|
||||
} else {
|
||||
this.onerrorEvent = e;
|
||||
this.callback();
|
||||
}
|
||||
}
|
||||
callback() {
|
||||
this.done = true;
|
||||
this.loading = false;
|
||||
this.callbacks.forEach(cb => {
|
||||
cb(this.onerrorEvent);
|
||||
});
|
||||
this.callbacks = [];
|
||||
}
|
||||
execute() {
|
||||
this.resetIfRetryingFailed();
|
||||
if (this.loading) {
|
||||
// do nothing but wait
|
||||
return;
|
||||
}
|
||||
if (this.done) {
|
||||
this.callback();
|
||||
} else {
|
||||
// short circuit and warn if google.maps is already loaded
|
||||
if (window.google && window.google.maps && window.google.maps.version) {
|
||||
console.warn("Google Maps already loaded outside @googlemaps/js-api-loader. " + "This may result in undesirable behavior as options and script parameters may not match.");
|
||||
this.callback();
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.setScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.DEFAULT_ID = DEFAULT_ID;
|
||||
exports.Loader = Loader;
|
||||
|
||||
return exports;
|
||||
|
||||
})({});
|
||||
//# sourceMappingURL=index.dev.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+2
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+410
@@ -0,0 +1,410 @@
|
||||
/******************************************************************************
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
***************************************************************************** */
|
||||
/* global Reflect, Promise, SuppressedError, Symbol */
|
||||
|
||||
|
||||
function __awaiter(thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
}
|
||||
|
||||
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
||||
var e = new Error(message);
|
||||
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
||||
};
|
||||
|
||||
function getDefaultExportFromCjs (x) {
|
||||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
||||
}
|
||||
|
||||
// do not edit .js files directly - edit src/index.jst
|
||||
|
||||
|
||||
|
||||
var fastDeepEqual = function equal(a, b) {
|
||||
if (a === b) return true;
|
||||
|
||||
if (a && b && typeof a == 'object' && typeof b == 'object') {
|
||||
if (a.constructor !== b.constructor) return false;
|
||||
|
||||
var length, i, keys;
|
||||
if (Array.isArray(a)) {
|
||||
length = a.length;
|
||||
if (length != b.length) return false;
|
||||
for (i = length; i-- !== 0;)
|
||||
if (!equal(a[i], b[i])) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
||||
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
||||
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
||||
|
||||
keys = Object.keys(a);
|
||||
length = keys.length;
|
||||
if (length !== Object.keys(b).length) return false;
|
||||
|
||||
for (i = length; i-- !== 0;)
|
||||
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
||||
|
||||
for (i = length; i-- !== 0;) {
|
||||
var key = keys[i];
|
||||
|
||||
if (!equal(a[key], b[key])) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// true if both NaN, false otherwise
|
||||
return a!==a && b!==b;
|
||||
};
|
||||
|
||||
var isEqual = /*@__PURE__*/getDefaultExportFromCjs(fastDeepEqual);
|
||||
|
||||
/**
|
||||
* Copyright 2019 Google LLC. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at.
|
||||
*
|
||||
* Http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const DEFAULT_ID = "__googleMapsScriptId";
|
||||
/**
|
||||
* The status of the [[Loader]].
|
||||
*/
|
||||
var LoaderStatus;
|
||||
(function (LoaderStatus) {
|
||||
LoaderStatus[LoaderStatus["INITIALIZED"] = 0] = "INITIALIZED";
|
||||
LoaderStatus[LoaderStatus["LOADING"] = 1] = "LOADING";
|
||||
LoaderStatus[LoaderStatus["SUCCESS"] = 2] = "SUCCESS";
|
||||
LoaderStatus[LoaderStatus["FAILURE"] = 3] = "FAILURE";
|
||||
})(LoaderStatus || (LoaderStatus = {}));
|
||||
/**
|
||||
* [[Loader]] makes it easier to add Google Maps JavaScript API to your application
|
||||
* dynamically using
|
||||
* [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
|
||||
* It works by dynamically creating and appending a script node to the the
|
||||
* document head and wrapping the callback function so as to return a promise.
|
||||
*
|
||||
* ```
|
||||
* const loader = new Loader({
|
||||
* apiKey: "",
|
||||
* version: "weekly",
|
||||
* libraries: ["places"]
|
||||
* });
|
||||
*
|
||||
* loader.load().then((google) => {
|
||||
* const map = new google.maps.Map(...)
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
class Loader {
|
||||
/**
|
||||
* Creates an instance of Loader using [[LoaderOptions]]. No defaults are set
|
||||
* using this library, instead the defaults are set by the Google Maps
|
||||
* JavaScript API server.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, version: 'weekly', libraries: ['places']});
|
||||
* ```
|
||||
*/
|
||||
constructor({ apiKey, authReferrerPolicy, channel, client, id = DEFAULT_ID, language, libraries = [], mapIds, nonce, region, retries = 3, url = "https://maps.googleapis.com/maps/api/js", version, }) {
|
||||
this.callbacks = [];
|
||||
this.done = false;
|
||||
this.loading = false;
|
||||
this.errors = [];
|
||||
this.apiKey = apiKey;
|
||||
this.authReferrerPolicy = authReferrerPolicy;
|
||||
this.channel = channel;
|
||||
this.client = client;
|
||||
this.id = id || DEFAULT_ID; // Do not allow empty string
|
||||
this.language = language;
|
||||
this.libraries = libraries;
|
||||
this.mapIds = mapIds;
|
||||
this.nonce = nonce;
|
||||
this.region = region;
|
||||
this.retries = retries;
|
||||
this.url = url;
|
||||
this.version = version;
|
||||
if (Loader.instance) {
|
||||
if (!isEqual(this.options, Loader.instance.options)) {
|
||||
throw new Error(`Loader must not be called again with different options. ${JSON.stringify(this.options)} !== ${JSON.stringify(Loader.instance.options)}`);
|
||||
}
|
||||
return Loader.instance;
|
||||
}
|
||||
Loader.instance = this;
|
||||
}
|
||||
get options() {
|
||||
return {
|
||||
version: this.version,
|
||||
apiKey: this.apiKey,
|
||||
channel: this.channel,
|
||||
client: this.client,
|
||||
id: this.id,
|
||||
libraries: this.libraries,
|
||||
language: this.language,
|
||||
region: this.region,
|
||||
mapIds: this.mapIds,
|
||||
nonce: this.nonce,
|
||||
url: this.url,
|
||||
authReferrerPolicy: this.authReferrerPolicy,
|
||||
};
|
||||
}
|
||||
get status() {
|
||||
if (this.errors.length) {
|
||||
return LoaderStatus.FAILURE;
|
||||
}
|
||||
if (this.done) {
|
||||
return LoaderStatus.SUCCESS;
|
||||
}
|
||||
if (this.loading) {
|
||||
return LoaderStatus.LOADING;
|
||||
}
|
||||
return LoaderStatus.INITIALIZED;
|
||||
}
|
||||
get failed() {
|
||||
return this.done && !this.loading && this.errors.length >= this.retries + 1;
|
||||
}
|
||||
/**
|
||||
* CreateUrl returns the Google Maps JavaScript API script url given the [[LoaderOptions]].
|
||||
*
|
||||
* @ignore
|
||||
* @deprecated
|
||||
*/
|
||||
createUrl() {
|
||||
let url = this.url;
|
||||
url += `?callback=__googleMapsCallback&loading=async`;
|
||||
if (this.apiKey) {
|
||||
url += `&key=${this.apiKey}`;
|
||||
}
|
||||
if (this.channel) {
|
||||
url += `&channel=${this.channel}`;
|
||||
}
|
||||
if (this.client) {
|
||||
url += `&client=${this.client}`;
|
||||
}
|
||||
if (this.libraries.length > 0) {
|
||||
url += `&libraries=${this.libraries.join(",")}`;
|
||||
}
|
||||
if (this.language) {
|
||||
url += `&language=${this.language}`;
|
||||
}
|
||||
if (this.region) {
|
||||
url += `®ion=${this.region}`;
|
||||
}
|
||||
if (this.version) {
|
||||
url += `&v=${this.version}`;
|
||||
}
|
||||
if (this.mapIds) {
|
||||
url += `&map_ids=${this.mapIds.join(",")}`;
|
||||
}
|
||||
if (this.authReferrerPolicy) {
|
||||
url += `&auth_referrer_policy=${this.authReferrerPolicy}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
deleteScript() {
|
||||
const script = document.getElementById(this.id);
|
||||
if (script) {
|
||||
script.remove();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script and return a Promise.
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
load() {
|
||||
return this.loadPromise();
|
||||
}
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script and return a Promise.
|
||||
*
|
||||
* @ignore
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
loadPromise() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.loadCallback((err) => {
|
||||
if (!err) {
|
||||
resolve(window.google);
|
||||
}
|
||||
else {
|
||||
reject(err.error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
importLibrary(name) {
|
||||
this.execute();
|
||||
return google.maps.importLibrary(name);
|
||||
}
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script with a callback.
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
loadCallback(fn) {
|
||||
this.callbacks.push(fn);
|
||||
this.execute();
|
||||
}
|
||||
/**
|
||||
* Set the script on document.
|
||||
*/
|
||||
setScript() {
|
||||
var _a, _b;
|
||||
if (document.getElementById(this.id)) {
|
||||
// TODO wrap onerror callback for cases where the script was loaded elsewhere
|
||||
this.callback();
|
||||
return;
|
||||
}
|
||||
const params = {
|
||||
key: this.apiKey,
|
||||
channel: this.channel,
|
||||
client: this.client,
|
||||
libraries: this.libraries.length && this.libraries,
|
||||
v: this.version,
|
||||
mapIds: this.mapIds,
|
||||
language: this.language,
|
||||
region: this.region,
|
||||
authReferrerPolicy: this.authReferrerPolicy,
|
||||
};
|
||||
// keep the URL minimal:
|
||||
Object.keys(params).forEach(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(key) => !params[key] && delete params[key]);
|
||||
if (!((_b = (_a = window === null || window === void 0 ? void 0 : window.google) === null || _a === void 0 ? void 0 : _a.maps) === null || _b === void 0 ? void 0 : _b.importLibrary)) {
|
||||
// tweaked copy of https://developers.google.com/maps/documentation/javascript/load-maps-js-api#dynamic-library-import
|
||||
// which also sets the base url, the id, and the nonce
|
||||
/* eslint-disable */
|
||||
((g) => {
|
||||
// @ts-ignore
|
||||
let h, a, k, p = "The Google Maps JavaScript API", c = "google", l = "importLibrary", q = "__ib__", m = document, b = window;
|
||||
// @ts-ignore
|
||||
b = b[c] || (b[c] = {});
|
||||
// @ts-ignore
|
||||
const d = b.maps || (b.maps = {}), r = new Set(), e = new URLSearchParams(), u = () =>
|
||||
// @ts-ignore
|
||||
h || (h = new Promise((f, n) => __awaiter(this, void 0, void 0, function* () {
|
||||
var _a;
|
||||
yield (a = m.createElement("script"));
|
||||
a.id = this.id;
|
||||
e.set("libraries", [...r] + "");
|
||||
// @ts-ignore
|
||||
for (k in g)
|
||||
e.set(k.replace(/[A-Z]/g, (t) => "_" + t[0].toLowerCase()), g[k]);
|
||||
e.set("callback", c + ".maps." + q);
|
||||
a.src = this.url + `?` + e;
|
||||
d[q] = f;
|
||||
a.onerror = () => (h = n(Error(p + " could not load.")));
|
||||
// @ts-ignore
|
||||
a.nonce = this.nonce || ((_a = m.querySelector("script[nonce]")) === null || _a === void 0 ? void 0 : _a.nonce) || "";
|
||||
m.head.append(a);
|
||||
})));
|
||||
// @ts-ignore
|
||||
d[l] ? console.warn(p + " only loads once. Ignoring:", g) : (d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)));
|
||||
})(params);
|
||||
/* eslint-enable */
|
||||
}
|
||||
// While most libraries populate the global namespace when loaded via bootstrap params,
|
||||
// this is not the case for "marker" when used with the inline bootstrap loader
|
||||
// (and maybe others in the future). So ensure there is an importLibrary for each:
|
||||
const libraryPromises = this.libraries.map((library) => this.importLibrary(library));
|
||||
// ensure at least one library, to kick off loading...
|
||||
if (!libraryPromises.length) {
|
||||
libraryPromises.push(this.importLibrary("core"));
|
||||
}
|
||||
Promise.all(libraryPromises).then(() => this.callback(), (error) => {
|
||||
const event = new ErrorEvent("error", { error }); // for backwards compat
|
||||
this.loadErrorCallback(event);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Reset the loader state.
|
||||
*/
|
||||
reset() {
|
||||
this.deleteScript();
|
||||
this.done = false;
|
||||
this.loading = false;
|
||||
this.errors = [];
|
||||
this.onerrorEvent = null;
|
||||
}
|
||||
resetIfRetryingFailed() {
|
||||
if (this.failed) {
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
loadErrorCallback(e) {
|
||||
this.errors.push(e);
|
||||
if (this.errors.length <= this.retries) {
|
||||
const delay = this.errors.length * Math.pow(2, this.errors.length);
|
||||
console.error(`Failed to load Google Maps script, retrying in ${delay} ms.`);
|
||||
setTimeout(() => {
|
||||
this.deleteScript();
|
||||
this.setScript();
|
||||
}, delay);
|
||||
}
|
||||
else {
|
||||
this.onerrorEvent = e;
|
||||
this.callback();
|
||||
}
|
||||
}
|
||||
callback() {
|
||||
this.done = true;
|
||||
this.loading = false;
|
||||
this.callbacks.forEach((cb) => {
|
||||
cb(this.onerrorEvent);
|
||||
});
|
||||
this.callbacks = [];
|
||||
}
|
||||
execute() {
|
||||
this.resetIfRetryingFailed();
|
||||
if (this.loading) {
|
||||
// do nothing but wait
|
||||
return;
|
||||
}
|
||||
if (this.done) {
|
||||
this.callback();
|
||||
}
|
||||
else {
|
||||
// short circuit and warn if google.maps is already loaded
|
||||
if (window.google && window.google.maps && window.google.maps.version) {
|
||||
console.warn("Google Maps already loaded outside @googlemaps/js-api-loader. " +
|
||||
"This may result in undesirable behavior as options and script parameters may not match.");
|
||||
this.callback();
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.setScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { DEFAULT_ID, Loader, LoaderStatus };
|
||||
//# sourceMappingURL=index.mjs.map
|
||||
+1
File diff suppressed because one or more lines are too long
+2
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+73
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "@googlemaps/js-api-loader",
|
||||
"type": "commonjs",
|
||||
"version": "1.16.8",
|
||||
"description": "Wrapper for the loading of Google Maps JavaScript API script in the browser",
|
||||
"keywords": [
|
||||
"google",
|
||||
"maps"
|
||||
],
|
||||
"homepage": "https://github.com/googlemaps/js-api-loader",
|
||||
"bugs": {
|
||||
"url": "https://github.com/googlemaps/js-api-loader/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/googlemaps/js-api-loader.git"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"author": "Justin Poehnelt",
|
||||
"main": "dist/index.umd.js",
|
||||
"unpkg": "dist/index.min.js",
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist/",
|
||||
"src/"
|
||||
],
|
||||
"scripts": {
|
||||
"docs": "typedoc src/index.ts && cp -r dist docs/dist && cp -r examples docs/examples",
|
||||
"format": "eslint . --fix",
|
||||
"lint": "eslint .",
|
||||
"prepare": "rm -rf dist && rollup -c",
|
||||
"test": "jest src/*",
|
||||
"test:e2e": "jest e2e/*"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.9.5",
|
||||
"@babel/runtime-corejs3": "^7.9.2",
|
||||
"@rollup/plugin-babel": "^6.0.3",
|
||||
"@rollup/plugin-commonjs": "^25.0.4",
|
||||
"@rollup/plugin-node-resolve": "^15.2.1",
|
||||
"@rollup/plugin-terser": "^0.4.3",
|
||||
"@rollup/plugin-typescript": "^11.1.4",
|
||||
"@types/google.maps": "^3.53.1",
|
||||
"@types/jest": "^29.5.5",
|
||||
"@types/selenium-webdriver": "^4.0.9",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.3",
|
||||
"@typescript-eslint/parser": "^6.7.3",
|
||||
"core-js": "^3.6.4",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-jest": "^27.4.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"geckodriver": "^4.2.1",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"prettier": "^3.0.3",
|
||||
"rollup": "^4.6.1",
|
||||
"selenium-webdriver": "^4.0.0-alpha.7",
|
||||
"ts-jest": "^29.1.1",
|
||||
"typedoc": "^0.25.1",
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://wombat-dressing-room.appspot.com"
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "es5"
|
||||
}
|
||||
}
|
||||
+469
@@ -0,0 +1,469 @@
|
||||
/**
|
||||
* Copyright 2019 Google LLC. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at.
|
||||
*
|
||||
* Http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint @typescript-eslint/no-explicit-any: 0 */
|
||||
import { DEFAULT_ID, Loader, LoaderOptions, LoaderStatus } from ".";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
afterEach(() => {
|
||||
document.getElementsByTagName("html")[0].innerHTML = "";
|
||||
delete Loader["instance"];
|
||||
if (window.google) delete window.google;
|
||||
});
|
||||
|
||||
test.each([
|
||||
[
|
||||
{},
|
||||
"https://maps.googleapis.com/maps/api/js?callback=__googleMapsCallback&loading=async",
|
||||
],
|
||||
[
|
||||
{ apiKey: "foo" },
|
||||
"https://maps.googleapis.com/maps/api/js?callback=__googleMapsCallback&loading=async&key=foo",
|
||||
],
|
||||
[
|
||||
{
|
||||
apiKey: "foo",
|
||||
version: "weekly",
|
||||
libraries: ["marker", "places"],
|
||||
language: "language",
|
||||
region: "region",
|
||||
},
|
||||
"https://maps.googleapis.com/maps/api/js?callback=__googleMapsCallback&loading=async&key=foo&libraries=marker,places&language=language®ion=region&v=weekly",
|
||||
],
|
||||
[
|
||||
{ mapIds: ["foo", "bar"] },
|
||||
"https://maps.googleapis.com/maps/api/js?callback=__googleMapsCallback&loading=async&map_ids=foo,bar",
|
||||
],
|
||||
[
|
||||
{ url: "https://example.com/js" },
|
||||
"https://example.com/js?callback=__googleMapsCallback&loading=async",
|
||||
],
|
||||
[
|
||||
{ client: "bar", channel: "foo" },
|
||||
"https://maps.googleapis.com/maps/api/js?callback=__googleMapsCallback&loading=async&channel=foo&client=bar",
|
||||
],
|
||||
[
|
||||
{ authReferrerPolicy: "origin" },
|
||||
"https://maps.googleapis.com/maps/api/js?callback=__googleMapsCallback&loading=async&auth_referrer_policy=origin",
|
||||
],
|
||||
])("createUrl is correct", (options: LoaderOptions, expected: string) => {
|
||||
const loader = new Loader(options);
|
||||
expect(loader.createUrl()).toEqual(expected);
|
||||
expect(loader.status).toBe(LoaderStatus.INITIALIZED);
|
||||
});
|
||||
|
||||
test("uses default id if empty string", () => {
|
||||
expect(new Loader({ apiKey: "foo", id: "" }).id).toBe(DEFAULT_ID);
|
||||
});
|
||||
|
||||
test("setScript adds a script to head with correct attributes", async () => {
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
|
||||
loader["setScript"]();
|
||||
await 0;
|
||||
|
||||
const script = document.head.childNodes[0] as HTMLScriptElement;
|
||||
|
||||
expect(script.id).toEqual(loader.id);
|
||||
});
|
||||
|
||||
test("setScript adds a script with id", async () => {
|
||||
const loader = new Loader({ apiKey: "foo", id: "bar" });
|
||||
loader["setScript"]();
|
||||
await 0;
|
||||
|
||||
const script = document.head.childNodes[0] as HTMLScriptElement;
|
||||
expect(script.localName).toEqual("script");
|
||||
expect(loader.id).toEqual("bar");
|
||||
expect(script.id).toEqual("bar");
|
||||
});
|
||||
|
||||
test("setScript does not add second script with same id", async () => {
|
||||
new Loader({ apiKey: "foo", id: "bar" })["setScript"]();
|
||||
new Loader({ apiKey: "foo", id: "bar" })["setScript"]();
|
||||
await 0;
|
||||
new Loader({ apiKey: "foo", id: "bar" })["setScript"]();
|
||||
await 0;
|
||||
|
||||
expect(document.head.childNodes.length).toBe(1);
|
||||
});
|
||||
|
||||
test("setScript adds a script to head with valid src", async () => {
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
|
||||
loader["setScript"]();
|
||||
await 0;
|
||||
|
||||
const script = document.head.childNodes[0] as HTMLScriptElement;
|
||||
|
||||
expect(script.src).toEqual(
|
||||
"https://maps.googleapis.com/maps/api/js?libraries=core&key=foo&callback=google.maps.__ib__"
|
||||
);
|
||||
});
|
||||
|
||||
test("setScript adds a script to head with valid src with libraries", async () => {
|
||||
const loader = new Loader({ apiKey: "foo", libraries: ["marker", "places"] });
|
||||
|
||||
loader["setScript"]();
|
||||
await 0;
|
||||
|
||||
const script = document.head.childNodes[0] as HTMLScriptElement;
|
||||
|
||||
expect(script.src).toEqual(
|
||||
"https://maps.googleapis.com/maps/api/js?libraries=marker%2Cplaces&key=foo&callback=google.maps.__ib__"
|
||||
);
|
||||
});
|
||||
|
||||
test("load should return a promise that resolves even if called twice", () => {
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
loader.importLibrary = (() => Promise.resolve()) as any;
|
||||
|
||||
expect.assertions(1);
|
||||
const promise = Promise.all([loader.load(), loader.load()]).then(() => {
|
||||
expect(loader["done"]).toBeTruthy();
|
||||
});
|
||||
|
||||
return promise;
|
||||
});
|
||||
|
||||
test("loadCallback callback should fire", () => {
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
loader.importLibrary = (() => Promise.resolve()) as any;
|
||||
|
||||
expect.assertions(2);
|
||||
loader.loadCallback((e: Event) => {
|
||||
expect(loader["done"]).toBeTruthy();
|
||||
expect(e).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
test("script onerror should reject promise", async () => {
|
||||
const loader = new Loader({ apiKey: "foo", retries: 0 });
|
||||
|
||||
const rejection = expect(loader.load()).rejects.toBeInstanceOf(Error);
|
||||
|
||||
loader["loadErrorCallback"](
|
||||
new ErrorEvent("ErrorEvent(", { error: new Error("") })
|
||||
);
|
||||
|
||||
await rejection;
|
||||
expect(loader["done"]).toBeTruthy();
|
||||
expect(loader["loading"]).toBeFalsy();
|
||||
expect(loader["errors"].length).toBe(1);
|
||||
expect(loader.status).toBe(LoaderStatus.FAILURE);
|
||||
});
|
||||
|
||||
test("script onerror should reject promise with multiple loaders", async () => {
|
||||
const loader = new Loader({ apiKey: "foo", retries: 0 });
|
||||
const extraLoader = new Loader({ apiKey: "foo", retries: 0 });
|
||||
|
||||
let rejection = expect(loader.load()).rejects.toBeInstanceOf(Error);
|
||||
loader["loadErrorCallback"](
|
||||
new ErrorEvent("ErrorEvent(", { error: new Error("") })
|
||||
);
|
||||
|
||||
await rejection;
|
||||
expect(loader["done"]).toBeTruthy();
|
||||
expect(loader["loading"]).toBeFalsy();
|
||||
expect(loader["onerrorEvent"]).toBeInstanceOf(ErrorEvent);
|
||||
|
||||
rejection = expect(extraLoader.load()).rejects.toBeInstanceOf(Error);
|
||||
loader["loadErrorCallback"](
|
||||
new ErrorEvent("ErrorEvent(", { error: new Error("") })
|
||||
);
|
||||
|
||||
await rejection;
|
||||
expect(extraLoader["done"]).toBeTruthy();
|
||||
expect(extraLoader["loading"]).toBeFalsy();
|
||||
});
|
||||
|
||||
test("script onerror should retry", async () => {
|
||||
const loader = new Loader({ apiKey: "foo", retries: 1 });
|
||||
const deleteScript = jest.spyOn(loader, "deleteScript");
|
||||
loader.importLibrary = (() => Promise.reject(new Error("fake error"))) as any;
|
||||
const rejection = expect(loader.load()).rejects.toBeInstanceOf(Error);
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
console.error = jest.fn();
|
||||
|
||||
// wait for the first failure
|
||||
await 0;
|
||||
await 0;
|
||||
expect(loader["errors"].length).toBe(1);
|
||||
// trigger the retry delay:
|
||||
jest.runAllTimers();
|
||||
|
||||
await rejection;
|
||||
expect(loader["errors"].length).toBe(2);
|
||||
expect(loader["done"]).toBeTruthy();
|
||||
expect(loader["failed"]).toBeTruthy();
|
||||
expect(loader["loading"]).toBeFalsy();
|
||||
expect(deleteScript).toHaveBeenCalledTimes(1);
|
||||
expect(console.error).toHaveBeenCalledTimes(loader.retries);
|
||||
});
|
||||
|
||||
test("script onerror should reset retry mechanism with next loader", async () => {
|
||||
const loader = new Loader({ apiKey: "foo", retries: 1 });
|
||||
const deleteScript = jest.spyOn(loader, "deleteScript");
|
||||
loader.importLibrary = (() => Promise.reject(new Error("fake error"))) as any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
console.error = jest.fn();
|
||||
|
||||
let rejection = expect(loader.load()).rejects.toBeInstanceOf(Error);
|
||||
// wait for the first first failure
|
||||
await 0;
|
||||
await 0;
|
||||
expect(loader["errors"].length).toBe(1);
|
||||
// trigger the retry delay:
|
||||
jest.runAllTimers();
|
||||
await rejection;
|
||||
|
||||
// try again...
|
||||
rejection = expect(loader.load()).rejects.toBeInstanceOf(Error);
|
||||
expect(loader["done"]).toBeFalsy();
|
||||
expect(loader["failed"]).toBeFalsy();
|
||||
expect(loader["loading"]).toBeTruthy();
|
||||
expect(loader["errors"].length).toBe(0);
|
||||
|
||||
// wait for the second first failure
|
||||
await 0;
|
||||
await 0;
|
||||
expect(loader["errors"].length).toBe(1);
|
||||
// trigger the retry delay:
|
||||
jest.runAllTimers();
|
||||
|
||||
await rejection;
|
||||
expect(deleteScript).toHaveBeenCalledTimes(3);
|
||||
expect(console.error).toHaveBeenCalledTimes(loader.retries * 2);
|
||||
});
|
||||
|
||||
test("script onerror should not reset retry mechanism with parallel loaders", async () => {
|
||||
const loader = new Loader({ apiKey: "foo", retries: 1 });
|
||||
const deleteScript = jest.spyOn(loader, "deleteScript");
|
||||
loader.importLibrary = (() => Promise.reject(new Error("fake error"))) as any;
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
console.error = jest.fn();
|
||||
|
||||
const rejection1 = expect(loader.load()).rejects.toBeInstanceOf(Error);
|
||||
const rejection2 = expect(loader.load()).rejects.toBeInstanceOf(Error);
|
||||
// wait for the first first failure
|
||||
await 0;
|
||||
await 0;
|
||||
jest.runAllTimers();
|
||||
|
||||
await Promise.all([rejection1, rejection2]);
|
||||
expect(loader["done"]).toBeTruthy();
|
||||
expect(loader["loading"]).toBeFalsy();
|
||||
expect(loader["errors"].length).toBe(2);
|
||||
expect(deleteScript).toHaveBeenCalledTimes(1);
|
||||
expect(console.error).toHaveBeenCalledTimes(loader.retries);
|
||||
});
|
||||
|
||||
test("reset should clear state", () => {
|
||||
const loader = new Loader({ apiKey: "foo", retries: 0 });
|
||||
const deleteScript = jest.spyOn(loader, "deleteScript");
|
||||
|
||||
loader["done"] = true;
|
||||
loader["loading"] = false;
|
||||
loader["errors"] = [new ErrorEvent("foo")];
|
||||
|
||||
loader["reset"]();
|
||||
|
||||
expect(loader["done"]).toBeFalsy();
|
||||
expect(loader["loading"]).toBeFalsy();
|
||||
expect(loader["onerrorEvent"]).toBe(null);
|
||||
expect(deleteScript).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("failed getter should be correct", () => {
|
||||
const loader = new Loader({ apiKey: "foo", retries: 0 });
|
||||
|
||||
// initial
|
||||
expect(loader["failed"]).toBeFalsy();
|
||||
|
||||
// not done
|
||||
loader["done"] = false;
|
||||
loader["loading"] = false;
|
||||
loader["errors"] = [new ErrorEvent("foo")];
|
||||
expect(loader["failed"]).toBeFalsy();
|
||||
|
||||
// still loading
|
||||
loader["done"] = false;
|
||||
loader["loading"] = true;
|
||||
loader["errors"] = [new ErrorEvent("foo")];
|
||||
expect(loader["failed"]).toBeFalsy();
|
||||
|
||||
// no errors
|
||||
loader["done"] = true;
|
||||
loader["loading"] = false;
|
||||
loader["errors"] = [];
|
||||
expect(loader["failed"]).toBeFalsy();
|
||||
|
||||
// done with errors
|
||||
loader["done"] = true;
|
||||
loader["loading"] = false;
|
||||
loader["errors"] = [new ErrorEvent("foo")];
|
||||
expect(loader["failed"]).toBeTruthy();
|
||||
});
|
||||
|
||||
test("loader should not reset retry mechanism if successfully loaded", async () => {
|
||||
const loader = new Loader({ apiKey: "foo", retries: 0 });
|
||||
const deleteScript = jest.spyOn(loader, "deleteScript");
|
||||
loader.importLibrary = (() => Promise.resolve()) as any;
|
||||
|
||||
await expect(loader.load()).resolves.not.toBeUndefined();
|
||||
|
||||
expect(loader["done"]).toBeTruthy();
|
||||
expect(loader["loading"]).toBeFalsy();
|
||||
expect(deleteScript).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test("singleton should be used", () => {
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
const extraLoader = new Loader({ apiKey: "foo" });
|
||||
expect(extraLoader).toBe(loader);
|
||||
|
||||
loader["done"] = true;
|
||||
expect(extraLoader["done"]).toBe(loader["done"]);
|
||||
expect(loader.status).toBe(LoaderStatus.SUCCESS);
|
||||
});
|
||||
|
||||
test("singleton should throw with different options", () => {
|
||||
new Loader({ apiKey: "foo" });
|
||||
expect(() => {
|
||||
new Loader({ apiKey: "bar" });
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
test("loader should resolve immediately when successfully loaded", async () => {
|
||||
// use await/async pattern since the promise resolves without trigger
|
||||
const loader = new Loader({ apiKey: "foo", retries: 0 });
|
||||
loader["done"] = true;
|
||||
// TODO causes warning
|
||||
window.google = { maps: { version: "3.*.*" } as any };
|
||||
await expect(loader.loadPromise()).resolves.toBeDefined();
|
||||
});
|
||||
|
||||
test("loader should resolve immediately when failed loading", async () => {
|
||||
// use await/async pattern since the promise rejects without trigger
|
||||
const loader = new Loader({ apiKey: "foo", retries: 0 });
|
||||
loader["done"] = true;
|
||||
loader["onerrorEvent"] = new ErrorEvent("ErrorEvent(", {
|
||||
error: new Error(""),
|
||||
});
|
||||
|
||||
await expect(loader.loadPromise()).rejects.toBeDefined();
|
||||
});
|
||||
|
||||
test("loader should wait if already loading", () => {
|
||||
const loader = new Loader({ apiKey: "foo", retries: 0 });
|
||||
loader["loading"] = true;
|
||||
expect(loader.status).toBe(LoaderStatus.LOADING);
|
||||
loader.load();
|
||||
});
|
||||
|
||||
test("setScript adds a nonce", async () => {
|
||||
const nonce = "bar";
|
||||
const loader = new Loader({ apiKey: "foo", nonce });
|
||||
loader["setScript"]();
|
||||
await 0;
|
||||
const script = document.head.childNodes[0] as HTMLScriptElement;
|
||||
expect(script.nonce).toBe(nonce);
|
||||
});
|
||||
|
||||
test("loader should resolve immediately when google.maps defined", async () => {
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
window.google = { maps: { version: "3.*.*" } as any };
|
||||
console.warn = jest.fn();
|
||||
await expect(loader.loadPromise()).resolves.toBeDefined();
|
||||
delete window.google;
|
||||
expect(console.warn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("loader should not warn if done and google.maps is defined", async () => {
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
loader["done"] = true;
|
||||
window.google = { maps: { version: "3.*.*" } as any };
|
||||
console.warn = jest.fn();
|
||||
await expect(loader.loadPromise()).resolves.toBeDefined();
|
||||
delete window.google;
|
||||
expect(console.warn).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test("deleteScript removes script tag from head", async () => {
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
loader["setScript"]();
|
||||
await 0;
|
||||
expect(document.head.childNodes.length).toBe(1);
|
||||
loader.deleteScript();
|
||||
expect(document.head.childNodes.length).toBe(0);
|
||||
// should work without script existing
|
||||
loader.deleteScript();
|
||||
expect(document.head.childNodes.length).toBe(0);
|
||||
});
|
||||
|
||||
test("importLibrary resolves correctly", async () => {
|
||||
window.google = { maps: {} } as any;
|
||||
google.maps.importLibrary = async (name) => ({ [name]: "fake" }) as any;
|
||||
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
const corePromise = loader.importLibrary("core");
|
||||
|
||||
const core = await corePromise;
|
||||
expect(core).toEqual({ core: "fake" });
|
||||
});
|
||||
|
||||
test("importLibrary resolves correctly without warning with sequential await", async () => {
|
||||
console.warn = jest.fn();
|
||||
window.google = { maps: {} } as any;
|
||||
google.maps.importLibrary = async (name) => {
|
||||
google.maps.version = "3.*.*";
|
||||
return { [name]: "fake" } as any;
|
||||
};
|
||||
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
const core = await loader.importLibrary("core");
|
||||
const marker = await loader.importLibrary("marker");
|
||||
|
||||
expect(console.warn).toHaveBeenCalledTimes(0);
|
||||
expect(core).toEqual({ core: "fake" });
|
||||
expect(marker).toEqual({ marker: "fake" });
|
||||
});
|
||||
|
||||
test("importLibrary can also set up bootstrap libraries (if bootstrap libraries empty)", async () => {
|
||||
const loader = new Loader({ apiKey: "foo" });
|
||||
loader.importLibrary("marker");
|
||||
loader.importLibrary("places");
|
||||
|
||||
await 0;
|
||||
|
||||
const script = document.head.childNodes[0] as HTMLScriptElement;
|
||||
|
||||
expect(script.src).toEqual(
|
||||
"https://maps.googleapis.com/maps/api/js?libraries=core%2Cmarker%2Cplaces&key=foo&callback=google.maps.__ib__"
|
||||
);
|
||||
});
|
||||
|
||||
test("importLibrary resolves correctly even with different bootstrap libraries", async () => {
|
||||
window.google = { maps: {} } as any;
|
||||
google.maps.importLibrary = async (name) => ({ [name]: "fake" }) as any;
|
||||
|
||||
const loader = new Loader({ apiKey: "foo", libraries: ["places"] });
|
||||
const corePromise = loader.importLibrary("core");
|
||||
|
||||
const core = await corePromise;
|
||||
expect(core).toEqual({ core: "fake" });
|
||||
expect(await loader.importLibrary("places")).toEqual({ places: "fake" });
|
||||
});
|
||||
+648
@@ -0,0 +1,648 @@
|
||||
/**
|
||||
* Copyright 2019 Google LLC. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at.
|
||||
*
|
||||
* Http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import isEqual from "fast-deep-equal";
|
||||
|
||||
export const DEFAULT_ID = "__googleMapsScriptId";
|
||||
|
||||
// https://developers.google.com/maps/documentation/javascript/libraries#libraries-for-dynamic-library-import
|
||||
export type Library =
|
||||
| "core"
|
||||
| "maps"
|
||||
| "places"
|
||||
| "geocoding"
|
||||
| "routes"
|
||||
| "marker"
|
||||
| "geometry"
|
||||
| "elevation"
|
||||
| "streetView"
|
||||
| "journeySharing"
|
||||
| "drawing"
|
||||
| "visualization";
|
||||
|
||||
export type Libraries = Library[];
|
||||
|
||||
/**
|
||||
* The Google Maps JavaScript API
|
||||
* [documentation](https://developers.google.com/maps/documentation/javascript/tutorial)
|
||||
* is the authoritative source for [[LoaderOptions]].
|
||||
/**
|
||||
* Loader options
|
||||
*/
|
||||
export interface LoaderOptions {
|
||||
/**
|
||||
* See https://developers.google.com/maps/documentation/javascript/get-api-key.
|
||||
*/
|
||||
apiKey: string;
|
||||
/**
|
||||
* @deprecated See https://developers.google.com/maps/premium/overview.
|
||||
*/
|
||||
channel?: string;
|
||||
/**
|
||||
* @deprecated See https://developers.google.com/maps/premium/overview, use `apiKey` instead.
|
||||
*/
|
||||
client?: string;
|
||||
/**
|
||||
* In your application you can specify release channels or version numbers:
|
||||
*
|
||||
* The weekly version is specified with `version=weekly`. This version is
|
||||
* updated once per week, and is the most current.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, version: 'weekly'});
|
||||
* ```
|
||||
*
|
||||
* The quarterly version is specified with `version=quarterly`. This version
|
||||
* is updated once per quarter, and is the most predictable.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, version: 'quarterly'});
|
||||
* ```
|
||||
*
|
||||
* The version number is specified with `version=n.nn`. You can choose
|
||||
* `version=3.40`, `version=3.39`, or `version=3.38`. Version numbers are
|
||||
* updated once per quarter.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, version: '3.40'});
|
||||
* ```
|
||||
*
|
||||
* If you do not explicitly specify a version, you will receive the
|
||||
* weekly version by default.
|
||||
*/
|
||||
version?: string;
|
||||
/**
|
||||
* The id of the script tag. Before adding a new script, the Loader will check for an existing one.
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* When loading the Maps JavaScript API via the URL you may optionally load
|
||||
* additional libraries through use of the libraries URL parameter. Libraries
|
||||
* are modules of code that provide additional functionality to the main Maps
|
||||
* JavaScript API but are not loaded unless you specifically request them.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({
|
||||
* apiKey,
|
||||
* libraries: ['drawing', 'geometry', 'places', 'visualization'],
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* Set the [list of libraries](https://developers.google.com/maps/documentation/javascript/libraries) for more options.
|
||||
*/
|
||||
libraries?: Libraries;
|
||||
/**
|
||||
* By default, the Maps JavaScript API uses the user's preferred language
|
||||
* setting as specified in the browser, when displaying textual information
|
||||
* such as the names for controls, copyright notices, driving directions and
|
||||
* labels on maps. In most cases, it's preferable to respect the browser
|
||||
* setting. However, if you want the Maps JavaScript API to ignore the
|
||||
* browser's language setting, you can force it to display information in a
|
||||
* particular language when loading the Maps JavaScript API code.
|
||||
*
|
||||
* For example, the following example localizes the language to Japan:
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, language: 'ja', region: 'JP'});
|
||||
* ```
|
||||
*
|
||||
* See the [list of supported
|
||||
* languages](https://developers.google.com/maps/faq#languagesupport). Note
|
||||
* that new languages are added often, so this list may not be exhaustive.
|
||||
*
|
||||
*/
|
||||
language?: string;
|
||||
/**
|
||||
* When you load the Maps JavaScript API from maps.googleapis.com it applies a
|
||||
* default bias for application behavior towards the United States. If you
|
||||
* want to alter your application to serve different map tiles or bias the
|
||||
* application (such as biasing geocoding results towards the region), you can
|
||||
* override this default behavior by adding a region parameter when loading
|
||||
* the Maps JavaScript API code.
|
||||
*
|
||||
* The region parameter accepts Unicode region subtag identifiers which
|
||||
* (generally) have a one-to-one mapping to country code Top-Level Domains
|
||||
* (ccTLDs). Most Unicode region identifiers are identical to ISO 3166-1
|
||||
* codes, with some notable exceptions. For example, Great Britain's ccTLD is
|
||||
* "uk" (corresponding to the domain .co.uk) while its region identifier is
|
||||
* "GB."
|
||||
*
|
||||
* For example, the following example localizes the map to the United Kingdom:
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, region: 'GB'});
|
||||
* ```
|
||||
*/
|
||||
region?: string;
|
||||
/**
|
||||
* @deprecated Passing `mapIds` is no longer required in the script tag.
|
||||
*/
|
||||
mapIds?: string[];
|
||||
/**
|
||||
* Use a custom url and path to load the Google Maps API script.
|
||||
*/
|
||||
url?: string;
|
||||
/**
|
||||
* Use a cryptographic nonce attribute.
|
||||
*/
|
||||
nonce?: string;
|
||||
/**
|
||||
* The number of script load retries.
|
||||
*/
|
||||
retries?: number;
|
||||
/**
|
||||
* Maps JS customers can configure HTTP Referrer Restrictions in the Cloud
|
||||
* Console to limit which URLs are allowed to use a particular API Key. By
|
||||
* default, these restrictions can be configured to allow only certain paths
|
||||
* to use an API Key. If any URL on the same domain or origin may use the API
|
||||
* Key, you can set `auth_referrer_policy=origin` to limit the amount of data
|
||||
* sent when authorizing requests from the Maps JavaScript API. This is
|
||||
* available starting in version 3.46. When this parameter is specified and
|
||||
* HTTP Referrer Restrictions are enabled on Cloud Console, Maps JavaScript
|
||||
* API will only be able to load if there is an HTTP Referrer Restriction that
|
||||
* matches the current website's domain without a path specified.
|
||||
*/
|
||||
authReferrerPolicy?: "origin";
|
||||
}
|
||||
|
||||
/**
|
||||
* The status of the [[Loader]].
|
||||
*/
|
||||
export enum LoaderStatus {
|
||||
INITIALIZED,
|
||||
LOADING,
|
||||
SUCCESS,
|
||||
FAILURE,
|
||||
}
|
||||
|
||||
/**
|
||||
* [[Loader]] makes it easier to add Google Maps JavaScript API to your application
|
||||
* dynamically using
|
||||
* [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
|
||||
* It works by dynamically creating and appending a script node to the the
|
||||
* document head and wrapping the callback function so as to return a promise.
|
||||
*
|
||||
* ```
|
||||
* const loader = new Loader({
|
||||
* apiKey: "",
|
||||
* version: "weekly",
|
||||
* libraries: ["places"]
|
||||
* });
|
||||
*
|
||||
* loader.load().then((google) => {
|
||||
* const map = new google.maps.Map(...)
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export class Loader {
|
||||
private static instance: Loader;
|
||||
/**
|
||||
* See [[LoaderOptions.version]]
|
||||
*/
|
||||
public readonly version: string;
|
||||
/**
|
||||
* See [[LoaderOptions.apiKey]]
|
||||
*/
|
||||
public readonly apiKey: string;
|
||||
/**
|
||||
* See [[LoaderOptions.channel]]
|
||||
*/
|
||||
public readonly channel: string;
|
||||
/**
|
||||
* See [[LoaderOptions.client]]
|
||||
*/
|
||||
public readonly client: string;
|
||||
/**
|
||||
* See [[LoaderOptions.id]]
|
||||
*/
|
||||
public readonly id: string;
|
||||
/**
|
||||
* See [[LoaderOptions.libraries]]
|
||||
*/
|
||||
public readonly libraries: Libraries;
|
||||
/**
|
||||
* See [[LoaderOptions.language]]
|
||||
*/
|
||||
public readonly language: string;
|
||||
|
||||
/**
|
||||
* See [[LoaderOptions.region]]
|
||||
*/
|
||||
public readonly region: string;
|
||||
|
||||
/**
|
||||
* See [[LoaderOptions.mapIds]]
|
||||
*/
|
||||
public readonly mapIds: string[];
|
||||
|
||||
/**
|
||||
* See [[LoaderOptions.nonce]]
|
||||
*/
|
||||
public readonly nonce: string | null;
|
||||
|
||||
/**
|
||||
* See [[LoaderOptions.retries]]
|
||||
*/
|
||||
public readonly retries: number;
|
||||
|
||||
/**
|
||||
* See [[LoaderOptions.url]]
|
||||
*/
|
||||
public readonly url: string;
|
||||
/**
|
||||
* See [[LoaderOptions.authReferrerPolicy]]
|
||||
*/
|
||||
public readonly authReferrerPolicy: "origin";
|
||||
|
||||
private callbacks: ((e: ErrorEvent) => void)[] = [];
|
||||
private done = false;
|
||||
private loading = false;
|
||||
private onerrorEvent: ErrorEvent;
|
||||
private errors: ErrorEvent[] = [];
|
||||
|
||||
/**
|
||||
* Creates an instance of Loader using [[LoaderOptions]]. No defaults are set
|
||||
* using this library, instead the defaults are set by the Google Maps
|
||||
* JavaScript API server.
|
||||
*
|
||||
* ```
|
||||
* const loader = Loader({apiKey, version: 'weekly', libraries: ['places']});
|
||||
* ```
|
||||
*/
|
||||
constructor({
|
||||
apiKey,
|
||||
authReferrerPolicy,
|
||||
channel,
|
||||
client,
|
||||
id = DEFAULT_ID,
|
||||
language,
|
||||
libraries = [],
|
||||
mapIds,
|
||||
nonce,
|
||||
region,
|
||||
retries = 3,
|
||||
url = "https://maps.googleapis.com/maps/api/js",
|
||||
version,
|
||||
}: LoaderOptions) {
|
||||
this.apiKey = apiKey;
|
||||
this.authReferrerPolicy = authReferrerPolicy;
|
||||
this.channel = channel;
|
||||
this.client = client;
|
||||
this.id = id || DEFAULT_ID; // Do not allow empty string
|
||||
this.language = language;
|
||||
this.libraries = libraries;
|
||||
this.mapIds = mapIds;
|
||||
this.nonce = nonce;
|
||||
this.region = region;
|
||||
this.retries = retries;
|
||||
this.url = url;
|
||||
this.version = version;
|
||||
|
||||
if (Loader.instance) {
|
||||
if (!isEqual(this.options, Loader.instance.options)) {
|
||||
throw new Error(
|
||||
`Loader must not be called again with different options. ${JSON.stringify(
|
||||
this.options
|
||||
)} !== ${JSON.stringify(Loader.instance.options)}`
|
||||
);
|
||||
}
|
||||
|
||||
return Loader.instance;
|
||||
}
|
||||
|
||||
Loader.instance = this;
|
||||
}
|
||||
|
||||
public get options(): LoaderOptions {
|
||||
return {
|
||||
version: this.version,
|
||||
apiKey: this.apiKey,
|
||||
channel: this.channel,
|
||||
client: this.client,
|
||||
id: this.id,
|
||||
libraries: this.libraries,
|
||||
language: this.language,
|
||||
region: this.region,
|
||||
mapIds: this.mapIds,
|
||||
nonce: this.nonce,
|
||||
url: this.url,
|
||||
authReferrerPolicy: this.authReferrerPolicy,
|
||||
};
|
||||
}
|
||||
|
||||
public get status(): LoaderStatus {
|
||||
if (this.errors.length) {
|
||||
return LoaderStatus.FAILURE;
|
||||
}
|
||||
if (this.done) {
|
||||
return LoaderStatus.SUCCESS;
|
||||
}
|
||||
if (this.loading) {
|
||||
return LoaderStatus.LOADING;
|
||||
}
|
||||
return LoaderStatus.INITIALIZED;
|
||||
}
|
||||
|
||||
private get failed(): boolean {
|
||||
return this.done && !this.loading && this.errors.length >= this.retries + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateUrl returns the Google Maps JavaScript API script url given the [[LoaderOptions]].
|
||||
*
|
||||
* @ignore
|
||||
* @deprecated
|
||||
*/
|
||||
public createUrl(): string {
|
||||
let url = this.url;
|
||||
|
||||
url += `?callback=__googleMapsCallback&loading=async`;
|
||||
|
||||
if (this.apiKey) {
|
||||
url += `&key=${this.apiKey}`;
|
||||
}
|
||||
|
||||
if (this.channel) {
|
||||
url += `&channel=${this.channel}`;
|
||||
}
|
||||
|
||||
if (this.client) {
|
||||
url += `&client=${this.client}`;
|
||||
}
|
||||
|
||||
if (this.libraries.length > 0) {
|
||||
url += `&libraries=${this.libraries.join(",")}`;
|
||||
}
|
||||
|
||||
if (this.language) {
|
||||
url += `&language=${this.language}`;
|
||||
}
|
||||
|
||||
if (this.region) {
|
||||
url += `®ion=${this.region}`;
|
||||
}
|
||||
|
||||
if (this.version) {
|
||||
url += `&v=${this.version}`;
|
||||
}
|
||||
|
||||
if (this.mapIds) {
|
||||
url += `&map_ids=${this.mapIds.join(",")}`;
|
||||
}
|
||||
|
||||
if (this.authReferrerPolicy) {
|
||||
url += `&auth_referrer_policy=${this.authReferrerPolicy}`;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
public deleteScript(): void {
|
||||
const script = document.getElementById(this.id);
|
||||
if (script) {
|
||||
script.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script and return a Promise.
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
public load(): Promise<typeof google> {
|
||||
return this.loadPromise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script and return a Promise.
|
||||
*
|
||||
* @ignore
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
public loadPromise(): Promise<typeof google> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.loadCallback((err: ErrorEvent) => {
|
||||
if (!err) {
|
||||
resolve(window.google);
|
||||
} else {
|
||||
reject(err.error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://developers.google.com/maps/documentation/javascript/reference/top-level#google.maps.importLibrary
|
||||
*/
|
||||
public importLibrary(name: "core"): Promise<google.maps.CoreLibrary>;
|
||||
public importLibrary(name: "maps"): Promise<google.maps.MapsLibrary>;
|
||||
public importLibrary(name: "places"): Promise<google.maps.PlacesLibrary>;
|
||||
public importLibrary(
|
||||
name: "geocoding"
|
||||
): Promise<google.maps.GeocodingLibrary>;
|
||||
public importLibrary(name: "routes"): Promise<google.maps.RoutesLibrary>;
|
||||
public importLibrary(name: "marker"): Promise<google.maps.MarkerLibrary>;
|
||||
public importLibrary(name: "geometry"): Promise<google.maps.GeometryLibrary>;
|
||||
public importLibrary(
|
||||
name: "elevation"
|
||||
): Promise<google.maps.ElevationLibrary>;
|
||||
public importLibrary(
|
||||
name: "streetView"
|
||||
): Promise<google.maps.StreetViewLibrary>;
|
||||
public importLibrary(
|
||||
name: "journeySharing"
|
||||
): Promise<google.maps.JourneySharingLibrary>;
|
||||
public importLibrary(name: "drawing"): Promise<google.maps.DrawingLibrary>;
|
||||
public importLibrary(
|
||||
name: "visualization"
|
||||
): Promise<google.maps.VisualizationLibrary>;
|
||||
public importLibrary(name: Library): Promise<unknown>;
|
||||
public importLibrary(name: Library): Promise<unknown> {
|
||||
this.execute();
|
||||
return google.maps.importLibrary(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the Google Maps JavaScript API script with a callback.
|
||||
* @deprecated, use importLibrary() instead.
|
||||
*/
|
||||
public loadCallback(fn: (e: ErrorEvent) => void): void {
|
||||
this.callbacks.push(fn);
|
||||
this.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the script on document.
|
||||
*/
|
||||
private setScript(): void {
|
||||
if (document.getElementById(this.id)) {
|
||||
// TODO wrap onerror callback for cases where the script was loaded elsewhere
|
||||
this.callback();
|
||||
return;
|
||||
}
|
||||
|
||||
const params = {
|
||||
key: this.apiKey,
|
||||
channel: this.channel,
|
||||
client: this.client,
|
||||
libraries: this.libraries.length && this.libraries,
|
||||
v: this.version,
|
||||
mapIds: this.mapIds,
|
||||
language: this.language,
|
||||
region: this.region,
|
||||
authReferrerPolicy: this.authReferrerPolicy,
|
||||
};
|
||||
// keep the URL minimal:
|
||||
Object.keys(params).forEach(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(key) => !(params as any)[key] && delete (params as any)[key]
|
||||
);
|
||||
|
||||
if (!window?.google?.maps?.importLibrary) {
|
||||
// tweaked copy of https://developers.google.com/maps/documentation/javascript/load-maps-js-api#dynamic-library-import
|
||||
// which also sets the base url, the id, and the nonce
|
||||
/* eslint-disable */
|
||||
((g) => {
|
||||
// @ts-ignore
|
||||
let h,
|
||||
a,
|
||||
k,
|
||||
p = "The Google Maps JavaScript API",
|
||||
c = "google",
|
||||
l = "importLibrary",
|
||||
q = "__ib__",
|
||||
m = document,
|
||||
b = window;
|
||||
// @ts-ignore
|
||||
b = b[c] || (b[c] = {});
|
||||
// @ts-ignore
|
||||
const d = b.maps || (b.maps = {}),
|
||||
r = new Set(),
|
||||
e = new URLSearchParams(),
|
||||
u = () =>
|
||||
// @ts-ignore
|
||||
h || (h = new Promise(async (f, n) => {
|
||||
await (a = m.createElement("script"));
|
||||
a.id = this.id;
|
||||
e.set("libraries", [...r] + "");
|
||||
// @ts-ignore
|
||||
for (k in g) e.set(k.replace(/[A-Z]/g, (t) => "_" + t[0].toLowerCase()), g[k]);
|
||||
e.set("callback", c + ".maps." + q);
|
||||
a.src = this.url + `?` + e;
|
||||
d[q] = f;
|
||||
a.onerror = () => (h = n(Error(p + " could not load.")));
|
||||
// @ts-ignore
|
||||
a.nonce = this.nonce || m.querySelector("script[nonce]")?.nonce || "";
|
||||
m.head.append(a);
|
||||
}));
|
||||
// @ts-ignore
|
||||
d[l] ? console.warn(p + " only loads once. Ignoring:", g) : (d[l] = (f, ...n) => r.add(f) && u().then(() => d[l](f, ...n)));
|
||||
})(params);
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
// While most libraries populate the global namespace when loaded via bootstrap params,
|
||||
// this is not the case for "marker" when used with the inline bootstrap loader
|
||||
// (and maybe others in the future). So ensure there is an importLibrary for each:
|
||||
const libraryPromises = this.libraries.map((library) =>
|
||||
this.importLibrary(library)
|
||||
);
|
||||
// ensure at least one library, to kick off loading...
|
||||
if (!libraryPromises.length) {
|
||||
libraryPromises.push(this.importLibrary("core"));
|
||||
}
|
||||
Promise.all(libraryPromises).then(
|
||||
() => this.callback(),
|
||||
(error) => {
|
||||
const event = new ErrorEvent("error", { error }); // for backwards compat
|
||||
this.loadErrorCallback(event);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the loader state.
|
||||
*/
|
||||
private reset(): void {
|
||||
this.deleteScript();
|
||||
this.done = false;
|
||||
this.loading = false;
|
||||
this.errors = [];
|
||||
this.onerrorEvent = null;
|
||||
}
|
||||
|
||||
private resetIfRetryingFailed(): void {
|
||||
if (this.failed) {
|
||||
this.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private loadErrorCallback(e: ErrorEvent): void {
|
||||
this.errors.push(e);
|
||||
|
||||
if (this.errors.length <= this.retries) {
|
||||
const delay = this.errors.length * 2 ** this.errors.length;
|
||||
|
||||
console.error(
|
||||
`Failed to load Google Maps script, retrying in ${delay} ms.`
|
||||
);
|
||||
|
||||
setTimeout(() => {
|
||||
this.deleteScript();
|
||||
this.setScript();
|
||||
}, delay);
|
||||
} else {
|
||||
this.onerrorEvent = e;
|
||||
this.callback();
|
||||
}
|
||||
}
|
||||
|
||||
private callback(): void {
|
||||
this.done = true;
|
||||
this.loading = false;
|
||||
|
||||
this.callbacks.forEach((cb) => {
|
||||
cb(this.onerrorEvent);
|
||||
});
|
||||
|
||||
this.callbacks = [];
|
||||
}
|
||||
|
||||
private execute(): void {
|
||||
this.resetIfRetryingFailed();
|
||||
|
||||
if (this.loading) {
|
||||
// do nothing but wait
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.done) {
|
||||
this.callback();
|
||||
} else {
|
||||
// short circuit and warn if google.maps is already loaded
|
||||
if (window.google && window.google.maps && window.google.maps.version) {
|
||||
console.warn(
|
||||
"Google Maps already loaded outside @googlemaps/js-api-loader. " +
|
||||
"This may result in undesirable behavior as options and script parameters may not match."
|
||||
);
|
||||
this.callback();
|
||||
return;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
this.setScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
+459
@@ -0,0 +1,459 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.8.10](https://github.com/xmldom/xmldom/compare/0.8.9...0.8.10)
|
||||
|
||||
### Fixed
|
||||
|
||||
- dom: prevent iteration over deleted items [`#514`](https://github.com/xmldom/xmldom/pull/514)/ [`#499`](https://github.com/xmldom/xmldom/issues/499)
|
||||
|
||||
Thank you, [@qtow](https://github.com/qtow), for your contributions
|
||||
|
||||
|
||||
## [0.8.9](https://github.com/xmldom/xmldom/compare/0.8.8...0.8.9)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Set nodeName property in ProcessingInstruction [`#509`](https://github.com/xmldom/xmldom/pull/509) / [`#505`](https://github.com/xmldom/xmldom/issues/505)
|
||||
|
||||
Thank you, [@cjbarth](https://github.com/cjbarth), for your contributions
|
||||
|
||||
|
||||
## [0.8.8](https://github.com/xmldom/xmldom/compare/0.8.7...0.8.8)
|
||||
|
||||
### Fixed
|
||||
|
||||
- extend list of HTML entities [`#489`](https://github.com/xmldom/xmldom/pull/489)
|
||||
|
||||
Thank you, [@zorkow](https://github.com/zorkow), for your contributions
|
||||
|
||||
## [0.8.7](https://github.com/xmldom/xmldom/compare/0.8.6...0.8.7)
|
||||
|
||||
### Fixed
|
||||
|
||||
- properly parse closing where the last attribute has no value [`#485`](https://github.com/xmldom/xmldom/pull/485) / [`#486`](https://github.com/xmldom/xmldom/issues/486)
|
||||
|
||||
Thank you, [@bulandent](https://github.com/bulandent), for your contributions
|
||||
|
||||
|
||||
## [0.7.10](https://github.com/xmldom/xmldom/compare/0.7.9...0.7.10)
|
||||
|
||||
### Fixed
|
||||
|
||||
- properly parse closing where the last attribute has no value [`#485`](https://github.com/xmldom/xmldom/pull/485) / [`#486`](https://github.com/xmldom/xmldom/issues/486)
|
||||
|
||||
Thank you, [@bulandent](https://github.com/bulandent), for your contributions
|
||||
|
||||
|
||||
## [0.8.6](https://github.com/xmldom/xmldom/compare/0.8.5...0.8.6)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Properly check nodes before replacement [`#457`](https://github.com/xmldom/xmldom/pull/457) / [`#455`](https://github.com/xmldom/xmldom/issues/455) / [`#456`](https://github.com/xmldom/xmldom/issues/456)
|
||||
|
||||
Thank you, [@edemaine](https://github.com/edemaine), [@pedro-l9](https://github.com/pedro-l9), for your contributions
|
||||
|
||||
|
||||
## [0.8.5](https://github.com/xmldom/xmldom/compare/0.8.4...0.8.5)
|
||||
|
||||
### Fixed
|
||||
|
||||
- fix: Restore ES5 compatibility [`#452`](https://github.com/xmldom/xmldom/pull/452) / [`#453`](https://github.com/xmldom/xmldom/issues/453)
|
||||
|
||||
Thank you, [@fengxinming](https://github.com/fengxinming), for your contributions
|
||||
|
||||
|
||||
## [0.8.4](https://github.com/xmldom/xmldom/compare/0.8.3...0.8.4)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Security: Prevent inserting DOM nodes when they are not well-formed [`CVE-2022-39353`](https://github.com/xmldom/xmldom/security/advisories/GHSA-crh6-fp67-6883)
|
||||
In case such a DOM would be created, the part that is not well-formed will be transformed into text nodes, in which xml specific characters like `<` and `>` are encoded accordingly.
|
||||
In the upcoming version 0.9.0 those text nodes will no longer be added and an error will be thrown instead.
|
||||
This change can break your code, if you relied on this behavior, e.g. multiple root elements in the past. We consider it more important to align with the specs that we want to be aligned with, considering the potential security issues that might derive from people not being aware of the difference in behavior.
|
||||
Related Spec: <https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity>
|
||||
|
||||
Thank you, [@frumioj](https://github.com/frumioj), [@cjbarth](https://github.com/cjbarth), [@markgollnick](https://github.com/markgollnick) for your contributions
|
||||
|
||||
|
||||
## [0.8.3](https://github.com/xmldom/xmldom/compare/0.8.3...0.8.2)
|
||||
|
||||
### Fixed
|
||||
- Avoid iterating over prototype properties [`#437`](https://github.com/xmldom/xmldom/pull/437) / [`#436`](https://github.com/xmldom/xmldom/issues/436)
|
||||
|
||||
Thank you, [@Supraja9726](https://github.com/Supraja9726) for your contributions
|
||||
|
||||
|
||||
## [0.8.2](https://github.com/xmldom/xmldom/compare/0.8.1...0.8.2)
|
||||
|
||||
### Fixed
|
||||
- fix(dom): Serialize `>` as specified (#395) [`#58`](https://github.com/xmldom/xmldom/issues/58)
|
||||
|
||||
### Other
|
||||
- docs: Add `nodeType` values to public interface description [`#396`](https://github.com/xmldom/xmldom/pull/396)
|
||||
- test: Add executable examples for node and typescript [`#317`](https://github.com/xmldom/xmldom/pull/317)
|
||||
- fix(dom): Serialize `>` as specified [`#395`](https://github.com/xmldom/xmldom/pull/395)
|
||||
- chore: Add minimal `Object.assign` ponyfill [`#379`](https://github.com/xmldom/xmldom/pull/379)
|
||||
- docs: Refine release documentation [`#378`](https://github.com/xmldom/xmldom/pull/378)
|
||||
- chore: update various dev dependencies
|
||||
|
||||
Thank you [@niklasl](https://github.com/niklasl), [@cburatto](https://github.com/cburatto), [@SheetJSDev](https://github.com/SheetJSDev), [@pyrsmk](https://github.com/pyrsmk) for your contributions
|
||||
|
||||
## [0.8.1](https://github.com/xmldom/xmldom/compare/0.8.0...0.8.1)
|
||||
|
||||
### Fixes
|
||||
- Only use own properties in entityMap [`#374`](https://github.com/xmldom/xmldom/pull/374)
|
||||
|
||||
### Docs
|
||||
- Add security policy [`#365`](https://github.com/xmldom/xmldom/pull/365)
|
||||
- changelog: Correct contributor name and link [`#366`](https://github.com/xmldom/xmldom/pull/366)
|
||||
- Describe release/publish steps [`#358`](https://github.com/xmldom/xmldom/pull/358), [`#376`](https://github.com/xmldom/xmldom/pull/376)
|
||||
- Add snyk package health badge [`#360`](https://github.com/xmldom/xmldom/pull/360)
|
||||
|
||||
|
||||
## [0.8.0](https://github.com/xmldom/xmldom/compare/0.7.5...0.8.0)
|
||||
|
||||
### Fixed
|
||||
- Normalize all line endings according to XML specs [1.0](https://w3.org/TR/xml/#sec-line-ends) and [1.1](https://www.w3.org/TR/xml11/#sec-line-ends) \
|
||||
BREAKING CHANGE: Certain combination of line break characters are normalized to a single `\n` before parsing takes place and will no longer be preserved.
|
||||
- [`#303`](https://github.com/xmldom/xmldom/issues/303) / [`#307`](https://github.com/xmldom/xmldom/pull/307)
|
||||
- [`#49`](https://github.com/xmldom/xmldom/issues/49), [`#97`](https://github.com/xmldom/xmldom/issues/97), [`#324`](https://github.com/xmldom/xmldom/issues/324) / [`#314`](https://github.com/xmldom/xmldom/pull/314)
|
||||
- XMLSerializer: Preserve whitespace character references [`#284`](https://github.com/xmldom/xmldom/issues/284) / [`#310`](https://github.com/xmldom/xmldom/pull/310) \
|
||||
BREAKING CHANGE: If you relied on the not spec compliant preservation of literal `\t`, `\n` or `\r` in **attribute values**.
|
||||
To preserve those you will have to create XML that instead contains the correct numerical (or hexadecimal) equivalent (e.g. `	`, `
`, `
`).
|
||||
- Drop deprecated exports `DOMImplementation` and `XMLSerializer` from `lib/dom-parser.js` [#53](https://github.com/xmldom/xmldom/issues/53) / [`#309`](https://github.com/xmldom/xmldom/pull/309)
|
||||
BREAKING CHANGE: Use the one provided by the main package export.
|
||||
- dom: Remove all links as part of `removeChild` [`#343`](https://github.com/xmldom/xmldom/issues/343) / [`#355`](https://github.com/xmldom/xmldom/pull/355)
|
||||
|
||||
### Chore
|
||||
- ci: Restore latest tested node version to 16.x [`#325`](https://github.com/xmldom/xmldom/pull/325)
|
||||
- ci: Split test and lint steps into jobs [`#111`](https://github.com/xmldom/xmldom/issues/111) / [`#304`](https://github.com/xmldom/xmldom/pull/304)
|
||||
- Pinned and updated devDependencies
|
||||
|
||||
Thank you [@marrus-sh](https://github.com/marrus-sh), [@victorandree](https://github.com/victorandree), [@mdierolf](https://github.com/mdierolf), [@tsabbay](https://github.com/tsabbay), [@fatihpense](https://github.com/fatihpense) for your contributions
|
||||
|
||||
## 0.7.5
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.7.4...0.7.5)
|
||||
|
||||
### Fixes:
|
||||
|
||||
- Preserve default namespace when serializing [`#319`](https://github.com/xmldom/xmldom/issues/319) / [`#321`](https://github.com/xmldom/xmldom/pull/321)
|
||||
Thank you, [@lupestro](https://github.com/lupestro)
|
||||
|
||||
## 0.7.4
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.7.3...0.7.4)
|
||||
|
||||
### Fixes:
|
||||
|
||||
- Restore ability to parse `__prototype__` attributes [`#315`](https://github.com/xmldom/xmldom/pull/315)
|
||||
Thank you, [@dsimpsonOMF](https://github.com/dsimpsonOMF)
|
||||
|
||||
## 0.7.3
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.7.2...0.7.3)
|
||||
|
||||
### Fixes:
|
||||
|
||||
- Add doctype when parsing from string [`#277`](https://github.com/xmldom/xmldom/issues/277) / [`#301`](https://github.com/xmldom/xmldom/pull/301)
|
||||
- Correct typo in error message [`#294`](https://github.com/xmldom/xmldom/pull/294)
|
||||
Thank you, [@rrthomas](https://github.com/rrthomas)
|
||||
|
||||
### Refactor:
|
||||
|
||||
- Improve exports & require statements, new main package entry [`#233`](https://github.com/xmldom/xmldom/pull/233)
|
||||
|
||||
### Docs:
|
||||
|
||||
- Fix Stryker badge [`#298`](https://github.com/xmldom/xmldom/pull/298)
|
||||
- Fix link to help-wanted issues [`#299`](https://github.com/xmldom/xmldom/pull/299)
|
||||
|
||||
### Chore:
|
||||
|
||||
- Execute stryker:dry-run on branches [`#302`](https://github.com/xmldom/xmldom/pull/302)
|
||||
- Fix stryker config [`#300`](https://github.com/xmldom/xmldom/pull/300)
|
||||
- Split test and lint scripts [`#297`](https://github.com/xmldom/xmldom/pull/297)
|
||||
- Switch to stryker dashboard owned by org [`#292`](https://github.com/xmldom/xmldom/pull/292)
|
||||
|
||||
## 0.7.2
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.7.1...0.7.2)
|
||||
|
||||
### Fixes:
|
||||
|
||||
- Types: Add index.d.ts to packaged files [`#288`](https://github.com/xmldom/xmldom/pull/288)
|
||||
Thank you, [@forty](https://github.com/forty)
|
||||
|
||||
## 0.7.1
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.7.0...0.7.1)
|
||||
|
||||
### Fixes:
|
||||
|
||||
- Types: Copy types from DefinitelyTyped [`#283`](https://github.com/xmldom/xmldom/pull/283)
|
||||
Thank you, [@kachkaev](https://github.com/kachkaev)
|
||||
|
||||
### Chore:
|
||||
- package.json: remove author, maintainers, etc. [`#279`](https://github.com/xmldom/xmldom/pull/279)
|
||||
|
||||
## 0.7.0
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.6.0...0.7.0)
|
||||
|
||||
Due to [`#271`](https://github.com/xmldom/xmldom/issue/271) this version was published as
|
||||
- unscoped `xmldom` package to github (git tags [`0.7.0`](https://github.com/xmldom/xmldom/tree/0.7.0) and [`0.7.0+unscoped`](https://github.com/xmldom/xmldom/tree/0.7.0%2Bunscoped))
|
||||
- scoped `@xmldom/xmldom` package to npm (git tag `0.7.0+scoped`)
|
||||
For more details look at [`#278`](https://github.com/xmldom/xmldom/pull/278#issuecomment-902172483)
|
||||
|
||||
### Fixes:
|
||||
|
||||
- Security: Misinterpretation of malicious XML input [`CVE-2021-32796`](https://github.com/xmldom/xmldom/security/advisories/GHSA-5fg8-2547-mr8q)
|
||||
- Implement `Document.getElementsByClassName` as specified [`#213`](https://github.com/xmldom/xmldom/pull/213), thank you, [@ChALkeR](https://github.com/ChALkeR)
|
||||
- Inherit namespace prefix from parent when required [`#268`](https://github.com/xmldom/xmldom/pull/268)
|
||||
- Handle whitespace in closing tags [`#267`](https://github.com/xmldom/xmldom/pull/267)
|
||||
- Update `DOMImplementation` according to recent specs [`#210`](https://github.com/xmldom/xmldom/pull/210)
|
||||
BREAKING CHANGE: Only if you "passed features to be marked as available as a constructor arguments" and expected it to "magically work".
|
||||
- No longer serializes any namespaces with an empty URI [`#244`](https://github.com/xmldom/xmldom/pull/244)
|
||||
(related to [`#168`](https://github.com/xmldom/xmldom/pull/168) released in 0.6.0)
|
||||
BREAKING CHANGE: Only if you rely on ["unsetting" a namespace prefix](https://github.com/xmldom/xmldom/pull/168#issuecomment-886984994) by setting it to an empty string
|
||||
- Set `localName` as part of `Document.createElement` [`#229`](https://github.com/xmldom/xmldom/pull/229), thank you, [@rrthomas](https://github.com/rrthomas)
|
||||
|
||||
### CI
|
||||
|
||||
- We are now additionally running tests against node v16
|
||||
- Stryker tests on the master branch now run against node v14
|
||||
|
||||
### Docs
|
||||
|
||||
- Describe relations with and between specs: [`#211`](https://github.com/xmldom/xmldom/pull/211), [`#247`](https://github.com/xmldom/xmldom/pull/247)
|
||||
|
||||
## 0.6.0
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.5.0...0.6.0)
|
||||
|
||||
### Fixes
|
||||
|
||||
- Stop serializing empty namespace values like `xmlns:ds=""` [`#168`](https://github.com/xmldom/xmldom/pull/168)
|
||||
BREAKING CHANGE: If your code expected empty namespaces attributes to be serialized.
|
||||
Thank you, [@pdecat](https://github.com/pdecat) and [@FranckDepoortere](https://github.com/FranckDepoortere)
|
||||
- Escape `<` to `<` when serializing attribute values [`#198`](https://github.com/xmldom/xmldom/issues/198) / [`#199`](https://github.com/xmldom/xmldom/pull/199)
|
||||
|
||||
## 0.5.0
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.4.0...0.5.0)
|
||||
|
||||
### Fixes
|
||||
- Avoid misinterpretation of malicious XML input - [`GHSA-h6q6-9hqw-rwfv`](https://github.com/xmldom/xmldom/security/advisories/GHSA-h6q6-9hqw-rwfv) (CVE-2021-21366)
|
||||
- Improve error reporting; throw on duplicate attribute\
|
||||
BREAKING CHANGE: It is currently not clear how to consistently deal with duplicate attributes, so it's also safer for our users to fail when detecting them.
|
||||
It's possible to configure the `DOMParser.errorHandler` before parsing, to handle those errors differently.
|
||||
|
||||
To accomplish this and also be able to verify it in tests I needed to
|
||||
- create a new `Error` type `ParseError` and export it
|
||||
- Throw `ParseError` from `errorHandler.fatalError` and prevent those from being caught in `XMLReader`.
|
||||
- export `DOMHandler` constructor as `__DOMHandler`
|
||||
- Preserve quotes in DOCTYPE declaration
|
||||
Since the only purpose of parsing the DOCTYPE is to be able to restore it when serializing, we decided that it would be best to leave the parsed `publicId` and `systemId` as is, including any quotes.
|
||||
BREAKING CHANGE: If somebody relies on the actual unquoted values of those ids, they will need to take care of either single or double quotes and the right escaping.
|
||||
(Without this change this would not have been possible because the SAX parser already dropped the information about the quotes that have been used in the source.)
|
||||
|
||||
https://www.w3.org/TR/2006/REC-xml11-20060816/#dtd
|
||||
https://www.w3.org/TR/2006/REC-xml11-20060816/#IDAX1KS (External Entity Declaration)
|
||||
|
||||
- Fix breaking preprocessors' directives when parsing attributes [`#171`](https://github.com/xmldom/xmldom/pull/171)
|
||||
- fix(dom): Escape `]]>` when serializing CharData [`#181`](https://github.com/xmldom/xmldom/pull/181)
|
||||
- Switch to (only) MIT license (drop problematic LGPL license option) [`#178`](https://github.com/xmldom/xmldom/pull/178)
|
||||
- Export DOMException; remove custom assertions; etc. [`#174`](https://github.com/xmldom/xmldom/pull/174)
|
||||
|
||||
### Docs
|
||||
- Update MDN links in `readme.md` [`#188`](https://github.com/xmldom/xmldom/pull/188)
|
||||
|
||||
## 0.4.0
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.3.0...0.4.0)
|
||||
|
||||
### Fixes
|
||||
- **BREAKING** Restore ` ` behavior from v0.1.27 [`#67`](https://github.com/xmldom/xmldom/pull/67)
|
||||
- **BREAKING** Typecheck source param before parsing [`#113`](https://github.com/xmldom/xmldom/pull/113)
|
||||
- Include documents in package files list [`#156`](https://github.com/xmldom/xmldom/pull/156)
|
||||
- Preserve doctype with sysid [`#144`](https://github.com/xmldom/xmldom/pull/144)
|
||||
- Remove ES6 syntax from getElementsByClassName [`#91`](https://github.com/xmldom/xmldom/pull/91)
|
||||
- Revert "Add lowercase of åäö in entityMap" due to duplicate entries [`#84`](https://github.com/xmldom/xmldom/pull/84)
|
||||
- fix: Convert all line separators to LF [`#66`](https://github.com/xmldom/xmldom/pull/66)
|
||||
|
||||
### Docs
|
||||
- Update CHANGELOG.md through version 0.3.0 [`#63`](https://github.com/xmldom/xmldom/pull/63)
|
||||
- Update badges [`#78`](https://github.com/xmldom/xmldom/pull/78)
|
||||
- Add .editorconfig file [`#104`](https://github.com/xmldom/xmldom/pull/104)
|
||||
- Add note about import [`#79`](https://github.com/xmldom/xmldom/pull/79)
|
||||
- Modernize & improve the example in readme.md [`#81`](https://github.com/xmldom/xmldom/pull/81)
|
||||
|
||||
### CI
|
||||
- Add Stryker Mutator [`#70`](https://github.com/xmldom/xmldom/pull/70)
|
||||
- Add Stryker action to update dashboard [`#77`](https://github.com/xmldom/xmldom/pull/77)
|
||||
- Add Node GitHub action workflow [`#64`](https://github.com/xmldom/xmldom/pull/64)
|
||||
- add & enable eslint [`#106`](https://github.com/xmldom/xmldom/pull/106)
|
||||
- Use eslint-plugin-es5 to enforce ES5 syntax [`#107`](https://github.com/xmldom/xmldom/pull/107)
|
||||
- Recover `vows` tests, drop `proof` tests [`#59`](https://github.com/xmldom/xmldom/pull/59)
|
||||
- Add jest tessuite and first tests [`#114`](https://github.com/xmldom/xmldom/pull/114)
|
||||
- Add jest testsuite with `xmltest` cases [`#112`](https://github.com/xmldom/xmldom/pull/112)
|
||||
- Configure Renovate [`#108`](https://github.com/xmldom/xmldom/pull/108)
|
||||
- Test European HTML entities [`#86`](https://github.com/xmldom/xmldom/pull/86)
|
||||
- Updated devDependencies
|
||||
|
||||
### Other
|
||||
- Remove files that are not of any use [`#131`](https://github.com/xmldom/xmldom/pull/131), [`#65`](https://github.com/xmldom/xmldom/pull/65), [`#33`](https://github.com/xmldom/xmldom/pull/33)
|
||||
|
||||
## 0.3.0
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.2.1...0.3.0)
|
||||
|
||||
- **BREAKING** Node >=10.x is now required.
|
||||
- **BREAKING** Remove `component.json` (deprecated package manager https://github.com/componentjs/guide)
|
||||
- **BREAKING** Move existing sources into `lib` subdirectory.
|
||||
- **POSSIBLY BREAKING** Introduce `files` entry in `package.json` and remove use of `.npmignore`.
|
||||
- [Add `Document.getElementsByClassName`](https://github.com/xmldom/xmldom/issues/24).
|
||||
- [Add `Node` to the list of exports](https://github.com/xmldom/xmldom/pull/27)
|
||||
- [Add lowercase of åäö in `entityMap`](https://github.com/xmldom/xmldom/pull/23).
|
||||
- Move CHANGELOG to markdown file.
|
||||
- Move LICENSE to markdown file.
|
||||
|
||||
## 0.2.1
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/0.2.0...0.2.1)
|
||||
|
||||
- Correct `homepage`, `repository` and `bugs` URLs in `package.json`.
|
||||
|
||||
## 0.2.0
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/v0.1.27...0.2.0)
|
||||
|
||||
- Includes all **BREAKING** changes introduced in [`xmldom-alpha@v0.1.28`](#0128) by the original authors.
|
||||
- **POSSIBLY BREAKING** [remove the `Object.create` check from the `_extends` method of `dom.js` that added a `__proto__` property](https://github.com/xmldom/xmldom/commit/0be2ae910a8a22c9ec2cac042e04de4c04317d2a#diff-7d1c5d97786fdf9af5446a241d0b6d56L19-L22) ().
|
||||
- **POSSIBLY BREAKING** [remove code that added a `__proto__` property](https://github.com/xmldom/xmldom/commit/366159a76a181ce9a0d83f5dc48205686cfaf9cc)
|
||||
- formatting/corrections in `package.json`
|
||||
|
||||
## 0.1.31
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/v0.1.27...v0.1.31)
|
||||
|
||||
The patch versions (`v0.1.29` - `v0.1.31`) that have been released on the [v0.1.x branch](https://github.com/xmldom/xmldom/tree/0.1.x), to reflect the changed maintainers, **are branched off from [`v0.1.27`](#0127) so they don't include the breaking changes introduced in [`xmldom-alpha@v0.1.28`](#0128)**:
|
||||
|
||||
## Maintainer changes
|
||||
|
||||
After the last commit to the original repository <https://github.com/jindw/xmldom> on the 9th of May 2017, the first commit to <https://github.com/xmldom/xmldom> is from the 19th of December 2019. [The fork has been announced in the original repository on the 2nd of March 2020.](https://github.com/jindw/xmldom/issues/259)
|
||||
|
||||
The versions listed below have been published to one or both of the following packages:
|
||||
- <https://www.npmjs.com/package/xmldom-alpha>
|
||||
- <https://www.npmjs.com/package/xmldom>
|
||||
|
||||
It is currently not planned to continue publishing the `xmldom-alpha` package.
|
||||
|
||||
The new maintainers did not invest time to understand changes that led to the last `xmldom` version [`0.1.27`](#0127) published by the original maintainer, but consider it the basis for their work.
|
||||
A timeline of all the changes that happened from that version until `0.3.0` is available in <https://github.com/xmldom/xmldom/issues/62>. Any related questions should be asked there.
|
||||
|
||||
## 0.1.28
|
||||
|
||||
[Commits](https://github.com/xmldom/xmldom/compare/v0.1.27...xmldom-alpha@v0.1.28)
|
||||
|
||||
Published by @jindw on the 9th of May 2017 as
|
||||
- `xmldom-alpha@0.1.28`
|
||||
|
||||
- **BREAKING** includes [regression regarding ` ` (issue #57)](https://github.com/xmldom/xmldom/issues/57)
|
||||
- [Fix `license` field in `package.json`](https://github.com/jindw/xmldom/pull/178)
|
||||
- [Conditional converting of HTML entities](https://github.com/jindw/xmldom/pull/80)
|
||||
- Fix `dom.js` serialization issue for missing document element ([example that failed on `toString()` before this change](https://github.com/xmldom/xmldom/blob/a58dcf7a265522e80ce520fe3be0cddb1b976f6f/test/parse/unclosedcomment.js#L10-L11))
|
||||
- Add new module `entities.js`
|
||||
|
||||
## 0.1.27
|
||||
|
||||
Published by @jindw on the 28th of Nov 2016 as
|
||||
- `xmldom@0.1.27`
|
||||
- `xmldom-alpha@0.1.27`
|
||||
|
||||
- Various bug fixes.
|
||||
|
||||
## 0.1.26
|
||||
|
||||
Published on the 18th of Nov 2016
|
||||
as `xmldom@0.1.26`
|
||||
|
||||
- Details unknown
|
||||
|
||||
## 0.1.25
|
||||
|
||||
Published on the 18th of Nov 2016 as
|
||||
- `xmldom@0.1.25`
|
||||
|
||||
- Details unknown
|
||||
|
||||
## 0.1.24
|
||||
|
||||
Published on the 27th of November 2016 as
|
||||
- `xmldom@0.1.24`
|
||||
- `xmldom-alpha@0.1.24`
|
||||
|
||||
- Added node filter.
|
||||
|
||||
## 0.1.23
|
||||
|
||||
Published on the 5th of May 2016 as
|
||||
- `xmldom-alpha@0.1.23`
|
||||
|
||||
- Add namespace support for nest node serialize.
|
||||
- Various other bug fixes.
|
||||
|
||||
## 0.1.22
|
||||
|
||||
- Merge XMLNS serialization.
|
||||
- Remove \r from source string.
|
||||
- Print namespaces for child elements.
|
||||
- Switch references to nodeType to use named constants.
|
||||
- Add nodelist toString support.
|
||||
|
||||
## 0.1.21
|
||||
|
||||
- Fix serialize bug.
|
||||
|
||||
## 0.1.20
|
||||
|
||||
- Optimize invalid XML support.
|
||||
- Add toString sorter for attributes output.
|
||||
- Add html self closed node button.
|
||||
- Add `*` NS support for getElementsByTagNameNS.
|
||||
- Convert attribute's value to string in setAttributeNS.
|
||||
- Add support for HTML entities for HTML docs only.
|
||||
- Fix TypeError when Document is created with DocumentType.
|
||||
|
||||
## 0.1.19
|
||||
|
||||
- Fix [infinite loop on unclosed comment (jindw/xmldom#68)](https://github.com/jindw/xmldom/issues/68)
|
||||
- Add error report for unclosed tag.
|
||||
- Various other fixes.
|
||||
|
||||
## 0.1.18
|
||||
|
||||
- Add default `ns` support.
|
||||
- parseFromString now renders entirely plain text documents as textNode.
|
||||
- Enable option to ignore white space on parsing.
|
||||
|
||||
## 0.1.17
|
||||
|
||||
**Details missing for this and potential earlier version**
|
||||
|
||||
## 0.1.16
|
||||
|
||||
- Correctly handle multibyte Unicode greater than two byts. #57. #56.
|
||||
- Initial unit testing and test coverage. #53. #46. #19.
|
||||
- Create Bower `component.json` #52.
|
||||
|
||||
## 0.1.8
|
||||
|
||||
- Add: some test case from node-o3-xml(excludes xpath support)
|
||||
- Fix: remove existed attribute before setting (bug introduced in v0.1.5)
|
||||
- Fix: index direct access for childNodes and any NodeList collection(not w3c standard)
|
||||
- Fix: remove last child bug
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
Copyright 2019 - present Christopher J. Brody and other contributors, as listed in: https://github.com/xmldom/xmldom/graphs/contributors
|
||||
Copyright 2012 - 2017 @jindw <jindw@xidea.org> and other contributors, as listed in: https://github.com/jindw/xmldom/graphs/contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
# Security Policy
|
||||
|
||||
The most up-to-date version of this document can be found at <https://github.com/xmldom/xmldom/security/policy>.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
This repository contains the code for the libraries `xmldom` and `@xmldom/xmldom` on npm.
|
||||
|
||||
As long as we didn't publish v1, we aim to maintain the last two minor versions with security fixes. If it is possible we provide security fixes as path versions.
|
||||
If you think there is a good reason to also patch an earlier version let us know in a github issue or the release discussion once the fix has been provided.
|
||||
The maintainers will consider it and if we agree and have/find the required resources, a patch for that version will be provided.
|
||||
|
||||
Please notice that [we are no longer able to publish the (unscoped) `xmldom` package](https://github.com/xmldom/xmldom/issues/271),
|
||||
and that all existing versions of `xmldom` are affected by at least one security vulnerability and should be considered deprecated.
|
||||
You can still report issues regarding `xmldom` as described below.
|
||||
|
||||
If you need help with migrating from `xmldom` to `@xmldom/xmldom`, file a github issue or PR in the affected repository and mention @karfau.
|
||||
|
||||
## Reporting vulnerabilities
|
||||
|
||||
Please email reports about any security related issues you find to `security@xmldom.org`, which will forward it to the list of maintainers.
|
||||
The maintainers will try to respond within 7 calendar days. (If nobody peplies after 7 days, please us send a reminder!)
|
||||
As part of you communication please make sure to always hit "Reply all", so all maintainers are kept in the loop.
|
||||
|
||||
In addition, please include the following information along with your report:
|
||||
|
||||
- Your name and affiliation (if any).
|
||||
- A description of the technical details of the vulnerabilities. It is very important to let us know how we can reproduce your findings.
|
||||
- An explanation who can exploit this vulnerability, and what they gain when doing so -- write an attack scenario. This will help us evaluate your report quickly, especially if the issue is complex.
|
||||
- Whether this vulnerability public or known to third parties. If it is, please provide details.
|
||||
|
||||
If you believe that an existing (public) issue is security-related, please send an email to `security@xmldom.org`.
|
||||
The email should include the issue URL and a short description of why it should be handled according to this security policy.
|
||||
|
||||
Once an issue is reported, the maintainers use the following disclosure process:
|
||||
|
||||
- When a report is received, we confirm the issue, determine its severity and the affected versions.
|
||||
- If we know of specific third-party services or software based on xmldom that require mitigation before publication, those projects will be notified.
|
||||
- A [github security advisory](https://docs.github.com/en/code-security/security-advisories/about-github-security-advisories) is [created](https://docs.github.com/en/code-security/security-advisories/creating-a-security-advisory) (but not published) which details the problem and steps for mitigation.
|
||||
- If the reporter provides a github account and agrees to it, we (add that github account as a collaborator on the advisuory)[https://docs.github.com/en/code-security/security-advisories/adding-a-collaborator-to-a-security-advisory].
|
||||
- The vulnerability is fixed in a [private fork](https://docs.github.com/en/code-security/security-advisories/collaborating-in-a-temporary-private-fork-to-resolve-a-security-vulnerability) and potential workarounds are identified.
|
||||
- The maintainers audit the existing code to find any potential similar problems.
|
||||
- The release for the current minor version and the [security advisory are published](https://docs.github.com/en/code-security/security-advisories/publishing-a-security-advisory).
|
||||
- The release(s) for previous minor version(s) are published.
|
||||
|
||||
We credit reporters for identifying security issues, if they confirm that they want to.
|
||||
|
||||
## Known vulnerabilities
|
||||
|
||||
See https://github.com/xmldom/xmldom/security/advisories?state=published
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/// <reference lib="dom" />
|
||||
|
||||
declare module "@xmldom/xmldom" {
|
||||
var DOMParser: DOMParserStatic;
|
||||
var XMLSerializer: XMLSerializerStatic;
|
||||
var DOMImplementation: DOMImplementationStatic;
|
||||
|
||||
interface DOMImplementationStatic {
|
||||
new(): DOMImplementation;
|
||||
}
|
||||
|
||||
interface DOMParserStatic {
|
||||
new (): DOMParser;
|
||||
new (options: Options): DOMParser;
|
||||
}
|
||||
|
||||
interface XMLSerializerStatic {
|
||||
new (): XMLSerializer;
|
||||
}
|
||||
|
||||
interface DOMParser {
|
||||
parseFromString(xmlsource: string, mimeType?: string): Document;
|
||||
}
|
||||
|
||||
interface XMLSerializer {
|
||||
serializeToString(node: Node): string;
|
||||
}
|
||||
|
||||
interface Options {
|
||||
locator?: any;
|
||||
errorHandler?: ErrorHandlerFunction | ErrorHandlerObject | undefined;
|
||||
}
|
||||
|
||||
interface ErrorHandlerFunction {
|
||||
(level: string, msg: any): any;
|
||||
}
|
||||
|
||||
interface ErrorHandlerObject {
|
||||
warning?: ((msg: any) => any) | undefined;
|
||||
error?: ((msg: any) => any) | undefined;
|
||||
fatalError?: ((msg: any) => any) | undefined;
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
extends:
|
||||
- 'plugin:es5/no-es2015'
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Ponyfill for `Array.prototype.find` which is only available in ES6 runtimes.
|
||||
*
|
||||
* Works with anything that has a `length` property and index access properties, including NodeList.
|
||||
*
|
||||
* @template {unknown} T
|
||||
* @param {Array<T> | ({length:number, [number]: T})} list
|
||||
* @param {function (item: T, index: number, list:Array<T> | ({length:number, [number]: T})):boolean} predicate
|
||||
* @param {Partial<Pick<ArrayConstructor['prototype'], 'find'>>?} ac `Array.prototype` by default,
|
||||
* allows injecting a custom implementation in tests
|
||||
* @returns {T | undefined}
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
|
||||
* @see https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.find
|
||||
*/
|
||||
function find(list, predicate, ac) {
|
||||
if (ac === undefined) {
|
||||
ac = Array.prototype;
|
||||
}
|
||||
if (list && typeof ac.find === 'function') {
|
||||
return ac.find.call(list, predicate);
|
||||
}
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (Object.prototype.hasOwnProperty.call(list, i)) {
|
||||
var item = list[i];
|
||||
if (predicate.call(undefined, item, i, list)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* "Shallow freezes" an object to render it immutable.
|
||||
* Uses `Object.freeze` if available,
|
||||
* otherwise the immutability is only in the type.
|
||||
*
|
||||
* Is used to create "enum like" objects.
|
||||
*
|
||||
* @template T
|
||||
* @param {T} object the object to freeze
|
||||
* @param {Pick<ObjectConstructor, 'freeze'> = Object} oc `Object` by default,
|
||||
* allows to inject custom object constructor for tests
|
||||
* @returns {Readonly<T>}
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
|
||||
*/
|
||||
function freeze(object, oc) {
|
||||
if (oc === undefined) {
|
||||
oc = Object
|
||||
}
|
||||
return oc && typeof oc.freeze === 'function' ? oc.freeze(object) : object
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we can not rely on `Object.assign` we provide a simplified version
|
||||
* that is sufficient for our needs.
|
||||
*
|
||||
* @param {Object} target
|
||||
* @param {Object | null | undefined} source
|
||||
*
|
||||
* @returns {Object} target
|
||||
* @throws TypeError if target is not an object
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
|
||||
* @see https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.assign
|
||||
*/
|
||||
function assign(target, source) {
|
||||
if (target === null || typeof target !== 'object') {
|
||||
throw new TypeError('target is not an object')
|
||||
}
|
||||
for (var key in source) {
|
||||
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
||||
target[key] = source[key]
|
||||
}
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
/**
|
||||
* All mime types that are allowed as input to `DOMParser.parseFromString`
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#Argument02 MDN
|
||||
* @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#domparsersupportedtype WHATWG HTML Spec
|
||||
* @see DOMParser.prototype.parseFromString
|
||||
*/
|
||||
var MIME_TYPE = freeze({
|
||||
/**
|
||||
* `text/html`, the only mime type that triggers treating an XML document as HTML.
|
||||
*
|
||||
* @see DOMParser.SupportedType.isHTML
|
||||
* @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration
|
||||
* @see https://en.wikipedia.org/wiki/HTML Wikipedia
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN
|
||||
* @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring WHATWG HTML Spec
|
||||
*/
|
||||
HTML: 'text/html',
|
||||
|
||||
/**
|
||||
* Helper method to check a mime type if it indicates an HTML document
|
||||
*
|
||||
* @param {string} [value]
|
||||
* @returns {boolean}
|
||||
*
|
||||
* @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration
|
||||
* @see https://en.wikipedia.org/wiki/HTML Wikipedia
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN
|
||||
* @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring */
|
||||
isHTML: function (value) {
|
||||
return value === MIME_TYPE.HTML
|
||||
},
|
||||
|
||||
/**
|
||||
* `application/xml`, the standard mime type for XML documents.
|
||||
*
|
||||
* @see https://www.iana.org/assignments/media-types/application/xml IANA MimeType registration
|
||||
* @see https://tools.ietf.org/html/rfc7303#section-9.1 RFC 7303
|
||||
* @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia
|
||||
*/
|
||||
XML_APPLICATION: 'application/xml',
|
||||
|
||||
/**
|
||||
* `text/html`, an alias for `application/xml`.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc7303#section-9.2 RFC 7303
|
||||
* @see https://www.iana.org/assignments/media-types/text/xml IANA MimeType registration
|
||||
* @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia
|
||||
*/
|
||||
XML_TEXT: 'text/xml',
|
||||
|
||||
/**
|
||||
* `application/xhtml+xml`, indicates an XML document that has the default HTML namespace,
|
||||
* but is parsed as an XML document.
|
||||
*
|
||||
* @see https://www.iana.org/assignments/media-types/application/xhtml+xml IANA MimeType registration
|
||||
* @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument WHATWG DOM Spec
|
||||
* @see https://en.wikipedia.org/wiki/XHTML Wikipedia
|
||||
*/
|
||||
XML_XHTML_APPLICATION: 'application/xhtml+xml',
|
||||
|
||||
/**
|
||||
* `image/svg+xml`,
|
||||
*
|
||||
* @see https://www.iana.org/assignments/media-types/image/svg+xml IANA MimeType registration
|
||||
* @see https://www.w3.org/TR/SVG11/ W3C SVG 1.1
|
||||
* @see https://en.wikipedia.org/wiki/Scalable_Vector_Graphics Wikipedia
|
||||
*/
|
||||
XML_SVG_IMAGE: 'image/svg+xml',
|
||||
})
|
||||
|
||||
/**
|
||||
* Namespaces that are used in this code base.
|
||||
*
|
||||
* @see http://www.w3.org/TR/REC-xml-names
|
||||
*/
|
||||
var NAMESPACE = freeze({
|
||||
/**
|
||||
* The XHTML namespace.
|
||||
*
|
||||
* @see http://www.w3.org/1999/xhtml
|
||||
*/
|
||||
HTML: 'http://www.w3.org/1999/xhtml',
|
||||
|
||||
/**
|
||||
* Checks if `uri` equals `NAMESPACE.HTML`.
|
||||
*
|
||||
* @param {string} [uri]
|
||||
*
|
||||
* @see NAMESPACE.HTML
|
||||
*/
|
||||
isHTML: function (uri) {
|
||||
return uri === NAMESPACE.HTML
|
||||
},
|
||||
|
||||
/**
|
||||
* The SVG namespace.
|
||||
*
|
||||
* @see http://www.w3.org/2000/svg
|
||||
*/
|
||||
SVG: 'http://www.w3.org/2000/svg',
|
||||
|
||||
/**
|
||||
* The `xml:` namespace.
|
||||
*
|
||||
* @see http://www.w3.org/XML/1998/namespace
|
||||
*/
|
||||
XML: 'http://www.w3.org/XML/1998/namespace',
|
||||
|
||||
/**
|
||||
* The `xmlns:` namespace
|
||||
*
|
||||
* @see https://www.w3.org/2000/xmlns/
|
||||
*/
|
||||
XMLNS: 'http://www.w3.org/2000/xmlns/',
|
||||
})
|
||||
|
||||
exports.assign = assign;
|
||||
exports.find = find;
|
||||
exports.freeze = freeze;
|
||||
exports.MIME_TYPE = MIME_TYPE;
|
||||
exports.NAMESPACE = NAMESPACE;
|
||||
+322
@@ -0,0 +1,322 @@
|
||||
var conventions = require("./conventions");
|
||||
var dom = require('./dom')
|
||||
var entities = require('./entities');
|
||||
var sax = require('./sax');
|
||||
|
||||
var DOMImplementation = dom.DOMImplementation;
|
||||
|
||||
var NAMESPACE = conventions.NAMESPACE;
|
||||
|
||||
var ParseError = sax.ParseError;
|
||||
var XMLReader = sax.XMLReader;
|
||||
|
||||
/**
|
||||
* Normalizes line ending according to https://www.w3.org/TR/xml11/#sec-line-ends:
|
||||
*
|
||||
* > XML parsed entities are often stored in computer files which,
|
||||
* > for editing convenience, are organized into lines.
|
||||
* > These lines are typically separated by some combination
|
||||
* > of the characters CARRIAGE RETURN (#xD) and LINE FEED (#xA).
|
||||
* >
|
||||
* > To simplify the tasks of applications, the XML processor must behave
|
||||
* > as if it normalized all line breaks in external parsed entities (including the document entity)
|
||||
* > on input, before parsing, by translating all of the following to a single #xA character:
|
||||
* >
|
||||
* > 1. the two-character sequence #xD #xA
|
||||
* > 2. the two-character sequence #xD #x85
|
||||
* > 3. the single character #x85
|
||||
* > 4. the single character #x2028
|
||||
* > 5. any #xD character that is not immediately followed by #xA or #x85.
|
||||
*
|
||||
* @param {string} input
|
||||
* @returns {string}
|
||||
*/
|
||||
function normalizeLineEndings(input) {
|
||||
return input
|
||||
.replace(/\r[\n\u0085]/g, '\n')
|
||||
.replace(/[\r\u0085\u2028]/g, '\n')
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef Locator
|
||||
* @property {number} [columnNumber]
|
||||
* @property {number} [lineNumber]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef DOMParserOptions
|
||||
* @property {DOMHandler} [domBuilder]
|
||||
* @property {Function} [errorHandler]
|
||||
* @property {(string) => string} [normalizeLineEndings] used to replace line endings before parsing
|
||||
* defaults to `normalizeLineEndings`
|
||||
* @property {Locator} [locator]
|
||||
* @property {Record<string, string>} [xmlns]
|
||||
*
|
||||
* @see normalizeLineEndings
|
||||
*/
|
||||
|
||||
/**
|
||||
* The DOMParser interface provides the ability to parse XML or HTML source code
|
||||
* from a string into a DOM `Document`.
|
||||
*
|
||||
* _xmldom is different from the spec in that it allows an `options` parameter,
|
||||
* to override the default behavior._
|
||||
*
|
||||
* @param {DOMParserOptions} [options]
|
||||
* @constructor
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
|
||||
* @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-parsing-and-serialization
|
||||
*/
|
||||
function DOMParser(options){
|
||||
this.options = options ||{locator:{}};
|
||||
}
|
||||
|
||||
DOMParser.prototype.parseFromString = function(source,mimeType){
|
||||
var options = this.options;
|
||||
var sax = new XMLReader();
|
||||
var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
|
||||
var errorHandler = options.errorHandler;
|
||||
var locator = options.locator;
|
||||
var defaultNSMap = options.xmlns||{};
|
||||
var isHTML = /\/x?html?$/.test(mimeType);//mimeType.toLowerCase().indexOf('html') > -1;
|
||||
var entityMap = isHTML ? entities.HTML_ENTITIES : entities.XML_ENTITIES;
|
||||
if(locator){
|
||||
domBuilder.setDocumentLocator(locator)
|
||||
}
|
||||
|
||||
sax.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator);
|
||||
sax.domBuilder = options.domBuilder || domBuilder;
|
||||
if(isHTML){
|
||||
defaultNSMap[''] = NAMESPACE.HTML;
|
||||
}
|
||||
defaultNSMap.xml = defaultNSMap.xml || NAMESPACE.XML;
|
||||
var normalize = options.normalizeLineEndings || normalizeLineEndings;
|
||||
if (source && typeof source === 'string') {
|
||||
sax.parse(
|
||||
normalize(source),
|
||||
defaultNSMap,
|
||||
entityMap
|
||||
)
|
||||
} else {
|
||||
sax.errorHandler.error('invalid doc source')
|
||||
}
|
||||
return domBuilder.doc;
|
||||
}
|
||||
function buildErrorHandler(errorImpl,domBuilder,locator){
|
||||
if(!errorImpl){
|
||||
if(domBuilder instanceof DOMHandler){
|
||||
return domBuilder;
|
||||
}
|
||||
errorImpl = domBuilder ;
|
||||
}
|
||||
var errorHandler = {}
|
||||
var isCallback = errorImpl instanceof Function;
|
||||
locator = locator||{}
|
||||
function build(key){
|
||||
var fn = errorImpl[key];
|
||||
if(!fn && isCallback){
|
||||
fn = errorImpl.length == 2?function(msg){errorImpl(key,msg)}:errorImpl;
|
||||
}
|
||||
errorHandler[key] = fn && function(msg){
|
||||
fn('[xmldom '+key+']\t'+msg+_locator(locator));
|
||||
}||function(){};
|
||||
}
|
||||
build('warning');
|
||||
build('error');
|
||||
build('fatalError');
|
||||
return errorHandler;
|
||||
}
|
||||
|
||||
//console.log('#\n\n\n\n\n\n\n####')
|
||||
/**
|
||||
* +ContentHandler+ErrorHandler
|
||||
* +LexicalHandler+EntityResolver2
|
||||
* -DeclHandler-DTDHandler
|
||||
*
|
||||
* DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
|
||||
* DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
|
||||
* @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
|
||||
*/
|
||||
function DOMHandler() {
|
||||
this.cdata = false;
|
||||
}
|
||||
function position(locator,node){
|
||||
node.lineNumber = locator.lineNumber;
|
||||
node.columnNumber = locator.columnNumber;
|
||||
}
|
||||
/**
|
||||
* @see org.xml.sax.ContentHandler#startDocument
|
||||
* @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
|
||||
*/
|
||||
DOMHandler.prototype = {
|
||||
startDocument : function() {
|
||||
this.doc = new DOMImplementation().createDocument(null, null, null);
|
||||
if (this.locator) {
|
||||
this.doc.documentURI = this.locator.systemId;
|
||||
}
|
||||
},
|
||||
startElement:function(namespaceURI, localName, qName, attrs) {
|
||||
var doc = this.doc;
|
||||
var el = doc.createElementNS(namespaceURI, qName||localName);
|
||||
var len = attrs.length;
|
||||
appendElement(this, el);
|
||||
this.currentElement = el;
|
||||
|
||||
this.locator && position(this.locator,el)
|
||||
for (var i = 0 ; i < len; i++) {
|
||||
var namespaceURI = attrs.getURI(i);
|
||||
var value = attrs.getValue(i);
|
||||
var qName = attrs.getQName(i);
|
||||
var attr = doc.createAttributeNS(namespaceURI, qName);
|
||||
this.locator &&position(attrs.getLocator(i),attr);
|
||||
attr.value = attr.nodeValue = value;
|
||||
el.setAttributeNode(attr)
|
||||
}
|
||||
},
|
||||
endElement:function(namespaceURI, localName, qName) {
|
||||
var current = this.currentElement
|
||||
var tagName = current.tagName;
|
||||
this.currentElement = current.parentNode;
|
||||
},
|
||||
startPrefixMapping:function(prefix, uri) {
|
||||
},
|
||||
endPrefixMapping:function(prefix) {
|
||||
},
|
||||
processingInstruction:function(target, data) {
|
||||
var ins = this.doc.createProcessingInstruction(target, data);
|
||||
this.locator && position(this.locator,ins)
|
||||
appendElement(this, ins);
|
||||
},
|
||||
ignorableWhitespace:function(ch, start, length) {
|
||||
},
|
||||
characters:function(chars, start, length) {
|
||||
chars = _toString.apply(this,arguments)
|
||||
//console.log(chars)
|
||||
if(chars){
|
||||
if (this.cdata) {
|
||||
var charNode = this.doc.createCDATASection(chars);
|
||||
} else {
|
||||
var charNode = this.doc.createTextNode(chars);
|
||||
}
|
||||
if(this.currentElement){
|
||||
this.currentElement.appendChild(charNode);
|
||||
}else if(/^\s*$/.test(chars)){
|
||||
this.doc.appendChild(charNode);
|
||||
//process xml
|
||||
}
|
||||
this.locator && position(this.locator,charNode)
|
||||
}
|
||||
},
|
||||
skippedEntity:function(name) {
|
||||
},
|
||||
endDocument:function() {
|
||||
this.doc.normalize();
|
||||
},
|
||||
setDocumentLocator:function (locator) {
|
||||
if(this.locator = locator){// && !('lineNumber' in locator)){
|
||||
locator.lineNumber = 0;
|
||||
}
|
||||
},
|
||||
//LexicalHandler
|
||||
comment:function(chars, start, length) {
|
||||
chars = _toString.apply(this,arguments)
|
||||
var comm = this.doc.createComment(chars);
|
||||
this.locator && position(this.locator,comm)
|
||||
appendElement(this, comm);
|
||||
},
|
||||
|
||||
startCDATA:function() {
|
||||
//used in characters() methods
|
||||
this.cdata = true;
|
||||
},
|
||||
endCDATA:function() {
|
||||
this.cdata = false;
|
||||
},
|
||||
|
||||
startDTD:function(name, publicId, systemId) {
|
||||
var impl = this.doc.implementation;
|
||||
if (impl && impl.createDocumentType) {
|
||||
var dt = impl.createDocumentType(name, publicId, systemId);
|
||||
this.locator && position(this.locator,dt)
|
||||
appendElement(this, dt);
|
||||
this.doc.doctype = dt;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @see org.xml.sax.ErrorHandler
|
||||
* @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
|
||||
*/
|
||||
warning:function(error) {
|
||||
console.warn('[xmldom warning]\t'+error,_locator(this.locator));
|
||||
},
|
||||
error:function(error) {
|
||||
console.error('[xmldom error]\t'+error,_locator(this.locator));
|
||||
},
|
||||
fatalError:function(error) {
|
||||
throw new ParseError(error, this.locator);
|
||||
}
|
||||
}
|
||||
function _locator(l){
|
||||
if(l){
|
||||
return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']'
|
||||
}
|
||||
}
|
||||
function _toString(chars,start,length){
|
||||
if(typeof chars == 'string'){
|
||||
return chars.substr(start,length)
|
||||
}else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
|
||||
if(chars.length >= start+length || start){
|
||||
return new java.lang.String(chars,start,length)+'';
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
|
||||
* used method of org.xml.sax.ext.LexicalHandler:
|
||||
* #comment(chars, start, length)
|
||||
* #startCDATA()
|
||||
* #endCDATA()
|
||||
* #startDTD(name, publicId, systemId)
|
||||
*
|
||||
*
|
||||
* IGNORED method of org.xml.sax.ext.LexicalHandler:
|
||||
* #endDTD()
|
||||
* #startEntity(name)
|
||||
* #endEntity(name)
|
||||
*
|
||||
*
|
||||
* @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
|
||||
* IGNORED method of org.xml.sax.ext.DeclHandler
|
||||
* #attributeDecl(eName, aName, type, mode, value)
|
||||
* #elementDecl(name, model)
|
||||
* #externalEntityDecl(name, publicId, systemId)
|
||||
* #internalEntityDecl(name, value)
|
||||
* @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
|
||||
* IGNORED method of org.xml.sax.EntityResolver2
|
||||
* #resolveEntity(String name,String publicId,String baseURI,String systemId)
|
||||
* #resolveEntity(publicId, systemId)
|
||||
* #getExternalSubset(name, baseURI)
|
||||
* @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
|
||||
* IGNORED method of org.xml.sax.DTDHandler
|
||||
* #notationDecl(name, publicId, systemId) {};
|
||||
* #unparsedEntityDecl(name, publicId, systemId, notationName) {};
|
||||
*/
|
||||
"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){
|
||||
DOMHandler.prototype[key] = function(){return null}
|
||||
})
|
||||
|
||||
/* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */
|
||||
function appendElement (hander,node) {
|
||||
if (!hander.currentElement) {
|
||||
hander.doc.appendChild(node);
|
||||
} else {
|
||||
hander.currentElement.appendChild(node);
|
||||
}
|
||||
}//appendChild and setAttributeNS are preformance key
|
||||
|
||||
exports.__DOMHandler = DOMHandler;
|
||||
exports.normalizeLineEndings = normalizeLineEndings;
|
||||
exports.DOMParser = DOMParser;
|
||||
+1840
File diff suppressed because it is too large
Load Diff
+2166
File diff suppressed because it is too large
Load Diff
+4
@@ -0,0 +1,4 @@
|
||||
var dom = require('./dom')
|
||||
exports.DOMImplementation = dom.DOMImplementation
|
||||
exports.XMLSerializer = dom.XMLSerializer
|
||||
exports.DOMParser = require('./dom-parser').DOMParser
|
||||
+662
@@ -0,0 +1,662 @@
|
||||
var NAMESPACE = require("./conventions").NAMESPACE;
|
||||
|
||||
//[4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
|
||||
//[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
|
||||
//[5] Name ::= NameStartChar (NameChar)*
|
||||
var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]///\u10000-\uEFFFF
|
||||
var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
|
||||
var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
|
||||
//var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
|
||||
//var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')
|
||||
|
||||
//S_TAG, S_ATTR, S_EQ, S_ATTR_NOQUOT_VALUE
|
||||
//S_ATTR_SPACE, S_ATTR_END, S_TAG_SPACE, S_TAG_CLOSE
|
||||
var S_TAG = 0;//tag name offerring
|
||||
var S_ATTR = 1;//attr name offerring
|
||||
var S_ATTR_SPACE=2;//attr name end and space offer
|
||||
var S_EQ = 3;//=space?
|
||||
var S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only)
|
||||
var S_ATTR_END = 5;//attr value end and no space(quot end)
|
||||
var S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer)
|
||||
var S_TAG_CLOSE = 7;//closed el<el />
|
||||
|
||||
/**
|
||||
* Creates an error that will not be caught by XMLReader aka the SAX parser.
|
||||
*
|
||||
* @param {string} message
|
||||
* @param {any?} locator Optional, can provide details about the location in the source
|
||||
* @constructor
|
||||
*/
|
||||
function ParseError(message, locator) {
|
||||
this.message = message
|
||||
this.locator = locator
|
||||
if(Error.captureStackTrace) Error.captureStackTrace(this, ParseError);
|
||||
}
|
||||
ParseError.prototype = new Error();
|
||||
ParseError.prototype.name = ParseError.name
|
||||
|
||||
function XMLReader(){
|
||||
|
||||
}
|
||||
|
||||
XMLReader.prototype = {
|
||||
parse:function(source,defaultNSMap,entityMap){
|
||||
var domBuilder = this.domBuilder;
|
||||
domBuilder.startDocument();
|
||||
_copy(defaultNSMap ,defaultNSMap = {})
|
||||
parse(source,defaultNSMap,entityMap,
|
||||
domBuilder,this.errorHandler);
|
||||
domBuilder.endDocument();
|
||||
}
|
||||
}
|
||||
function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
|
||||
function fixedFromCharCode(code) {
|
||||
// String.prototype.fromCharCode does not supports
|
||||
// > 2 bytes unicode chars directly
|
||||
if (code > 0xffff) {
|
||||
code -= 0x10000;
|
||||
var surrogate1 = 0xd800 + (code >> 10)
|
||||
, surrogate2 = 0xdc00 + (code & 0x3ff);
|
||||
|
||||
return String.fromCharCode(surrogate1, surrogate2);
|
||||
} else {
|
||||
return String.fromCharCode(code);
|
||||
}
|
||||
}
|
||||
function entityReplacer(a){
|
||||
var k = a.slice(1,-1);
|
||||
if (Object.hasOwnProperty.call(entityMap, k)) {
|
||||
return entityMap[k];
|
||||
}else if(k.charAt(0) === '#'){
|
||||
return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))
|
||||
}else{
|
||||
errorHandler.error('entity not found:'+a);
|
||||
return a;
|
||||
}
|
||||
}
|
||||
function appendText(end){//has some bugs
|
||||
if(end>start){
|
||||
var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer);
|
||||
locator&&position(start);
|
||||
domBuilder.characters(xt,0,end-start);
|
||||
start = end
|
||||
}
|
||||
}
|
||||
function position(p,m){
|
||||
while(p>=lineEnd && (m = linePattern.exec(source))){
|
||||
lineStart = m.index;
|
||||
lineEnd = lineStart + m[0].length;
|
||||
locator.lineNumber++;
|
||||
//console.log('line++:',locator,startPos,endPos)
|
||||
}
|
||||
locator.columnNumber = p-lineStart+1;
|
||||
}
|
||||
var lineStart = 0;
|
||||
var lineEnd = 0;
|
||||
var linePattern = /.*(?:\r\n?|\n)|.*$/g
|
||||
var locator = domBuilder.locator;
|
||||
|
||||
var parseStack = [{currentNSMap:defaultNSMapCopy}]
|
||||
var closeMap = {};
|
||||
var start = 0;
|
||||
while(true){
|
||||
try{
|
||||
var tagStart = source.indexOf('<',start);
|
||||
if(tagStart<0){
|
||||
if(!source.substr(start).match(/^\s*$/)){
|
||||
var doc = domBuilder.doc;
|
||||
var text = doc.createTextNode(source.substr(start));
|
||||
doc.appendChild(text);
|
||||
domBuilder.currentElement = text;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(tagStart>start){
|
||||
appendText(tagStart);
|
||||
}
|
||||
switch(source.charAt(tagStart+1)){
|
||||
case '/':
|
||||
var end = source.indexOf('>',tagStart+3);
|
||||
var tagName = source.substring(tagStart + 2, end).replace(/[ \t\n\r]+$/g, '');
|
||||
var config = parseStack.pop();
|
||||
if(end<0){
|
||||
|
||||
tagName = source.substring(tagStart+2).replace(/[\s<].*/,'');
|
||||
errorHandler.error("end tag name: "+tagName+' is not complete:'+config.tagName);
|
||||
end = tagStart+1+tagName.length;
|
||||
}else if(tagName.match(/\s</)){
|
||||
tagName = tagName.replace(/[\s<].*/,'');
|
||||
errorHandler.error("end tag name: "+tagName+' maybe not complete');
|
||||
end = tagStart+1+tagName.length;
|
||||
}
|
||||
var localNSMap = config.localNSMap;
|
||||
var endMatch = config.tagName == tagName;
|
||||
var endIgnoreCaseMach = endMatch || config.tagName&&config.tagName.toLowerCase() == tagName.toLowerCase()
|
||||
if(endIgnoreCaseMach){
|
||||
domBuilder.endElement(config.uri,config.localName,tagName);
|
||||
if(localNSMap){
|
||||
for (var prefix in localNSMap) {
|
||||
if (Object.prototype.hasOwnProperty.call(localNSMap, prefix)) {
|
||||
domBuilder.endPrefixMapping(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!endMatch){
|
||||
errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName ); // No known test case
|
||||
}
|
||||
}else{
|
||||
parseStack.push(config)
|
||||
}
|
||||
|
||||
end++;
|
||||
break;
|
||||
// end elment
|
||||
case '?':// <?...?>
|
||||
locator&&position(tagStart);
|
||||
end = parseInstruction(source,tagStart,domBuilder);
|
||||
break;
|
||||
case '!':// <!doctype,<![CDATA,<!--
|
||||
locator&&position(tagStart);
|
||||
end = parseDCC(source,tagStart,domBuilder,errorHandler);
|
||||
break;
|
||||
default:
|
||||
locator&&position(tagStart);
|
||||
var el = new ElementAttributes();
|
||||
var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
|
||||
//elStartEnd
|
||||
var end = parseElementStartPart(source,tagStart,el,currentNSMap,entityReplacer,errorHandler);
|
||||
var len = el.length;
|
||||
|
||||
|
||||
if(!el.closed && fixSelfClosed(source,end,el.tagName,closeMap)){
|
||||
el.closed = true;
|
||||
if(!entityMap.nbsp){
|
||||
errorHandler.warning('unclosed xml attribute');
|
||||
}
|
||||
}
|
||||
if(locator && len){
|
||||
var locator2 = copyLocator(locator,{});
|
||||
//try{//attribute position fixed
|
||||
for(var i = 0;i<len;i++){
|
||||
var a = el[i];
|
||||
position(a.offset);
|
||||
a.locator = copyLocator(locator,{});
|
||||
}
|
||||
domBuilder.locator = locator2
|
||||
if(appendElement(el,domBuilder,currentNSMap)){
|
||||
parseStack.push(el)
|
||||
}
|
||||
domBuilder.locator = locator;
|
||||
}else{
|
||||
if(appendElement(el,domBuilder,currentNSMap)){
|
||||
parseStack.push(el)
|
||||
}
|
||||
}
|
||||
|
||||
if (NAMESPACE.isHTML(el.uri) && !el.closed) {
|
||||
end = parseHtmlSpecialContent(source,end,el.tagName,entityReplacer,domBuilder)
|
||||
} else {
|
||||
end++;
|
||||
}
|
||||
}
|
||||
}catch(e){
|
||||
if (e instanceof ParseError) {
|
||||
throw e;
|
||||
}
|
||||
errorHandler.error('element parse error: '+e)
|
||||
end = -1;
|
||||
}
|
||||
if(end>start){
|
||||
start = end;
|
||||
}else{
|
||||
//TODO: 这里有可能sax回退,有位置错误风险
|
||||
appendText(Math.max(tagStart,start)+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
function copyLocator(f,t){
|
||||
t.lineNumber = f.lineNumber;
|
||||
t.columnNumber = f.columnNumber;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
|
||||
* @return end of the elementStartPart(end of elementEndPart for selfClosed el)
|
||||
*/
|
||||
function parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){
|
||||
|
||||
/**
|
||||
* @param {string} qname
|
||||
* @param {string} value
|
||||
* @param {number} startIndex
|
||||
*/
|
||||
function addAttribute(qname, value, startIndex) {
|
||||
if (el.attributeNames.hasOwnProperty(qname)) {
|
||||
errorHandler.fatalError('Attribute ' + qname + ' redefined')
|
||||
}
|
||||
el.addValue(
|
||||
qname,
|
||||
// @see https://www.w3.org/TR/xml/#AVNormalize
|
||||
// since the xmldom sax parser does not "interpret" DTD the following is not implemented:
|
||||
// - recursive replacement of (DTD) entity references
|
||||
// - trimming and collapsing multiple spaces into a single one for attributes that are not of type CDATA
|
||||
value.replace(/[\t\n\r]/g, ' ').replace(/&#?\w+;/g, entityReplacer),
|
||||
startIndex
|
||||
)
|
||||
}
|
||||
var attrName;
|
||||
var value;
|
||||
var p = ++start;
|
||||
var s = S_TAG;//status
|
||||
while(true){
|
||||
var c = source.charAt(p);
|
||||
switch(c){
|
||||
case '=':
|
||||
if(s === S_ATTR){//attrName
|
||||
attrName = source.slice(start,p);
|
||||
s = S_EQ;
|
||||
}else if(s === S_ATTR_SPACE){
|
||||
s = S_EQ;
|
||||
}else{
|
||||
//fatalError: equal must after attrName or space after attrName
|
||||
throw new Error('attribute equal must after attrName'); // No known test case
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
case '"':
|
||||
if(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
|
||||
){//equal
|
||||
if(s === S_ATTR){
|
||||
errorHandler.warning('attribute value must after "="')
|
||||
attrName = source.slice(start,p)
|
||||
}
|
||||
start = p+1;
|
||||
p = source.indexOf(c,start)
|
||||
if(p>0){
|
||||
value = source.slice(start, p);
|
||||
addAttribute(attrName, value, start-1);
|
||||
s = S_ATTR_END;
|
||||
}else{
|
||||
//fatalError: no end quot match
|
||||
throw new Error('attribute value no end \''+c+'\' match');
|
||||
}
|
||||
}else if(s == S_ATTR_NOQUOT_VALUE){
|
||||
value = source.slice(start, p);
|
||||
addAttribute(attrName, value, start);
|
||||
errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!');
|
||||
start = p+1;
|
||||
s = S_ATTR_END
|
||||
}else{
|
||||
//fatalError: no equal before
|
||||
throw new Error('attribute value must after "="'); // No known test case
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
switch(s){
|
||||
case S_TAG:
|
||||
el.setTagName(source.slice(start,p));
|
||||
case S_ATTR_END:
|
||||
case S_TAG_SPACE:
|
||||
case S_TAG_CLOSE:
|
||||
s =S_TAG_CLOSE;
|
||||
el.closed = true;
|
||||
case S_ATTR_NOQUOT_VALUE:
|
||||
case S_ATTR:
|
||||
break;
|
||||
case S_ATTR_SPACE:
|
||||
el.closed = true;
|
||||
break;
|
||||
//case S_EQ:
|
||||
default:
|
||||
throw new Error("attribute invalid close char('/')") // No known test case
|
||||
}
|
||||
break;
|
||||
case ''://end document
|
||||
errorHandler.error('unexpected end of input');
|
||||
if(s == S_TAG){
|
||||
el.setTagName(source.slice(start,p));
|
||||
}
|
||||
return p;
|
||||
case '>':
|
||||
switch(s){
|
||||
case S_TAG:
|
||||
el.setTagName(source.slice(start,p));
|
||||
case S_ATTR_END:
|
||||
case S_TAG_SPACE:
|
||||
case S_TAG_CLOSE:
|
||||
break;//normal
|
||||
case S_ATTR_NOQUOT_VALUE://Compatible state
|
||||
case S_ATTR:
|
||||
value = source.slice(start,p);
|
||||
if(value.slice(-1) === '/'){
|
||||
el.closed = true;
|
||||
value = value.slice(0,-1)
|
||||
}
|
||||
case S_ATTR_SPACE:
|
||||
if(s === S_ATTR_SPACE){
|
||||
value = attrName;
|
||||
}
|
||||
if(s == S_ATTR_NOQUOT_VALUE){
|
||||
errorHandler.warning('attribute "'+value+'" missed quot(")!');
|
||||
addAttribute(attrName, value, start)
|
||||
}else{
|
||||
if(!NAMESPACE.isHTML(currentNSMap['']) || !value.match(/^(?:disabled|checked|selected)$/i)){
|
||||
errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!')
|
||||
}
|
||||
addAttribute(value, value, start)
|
||||
}
|
||||
break;
|
||||
case S_EQ:
|
||||
throw new Error('attribute value missed!!');
|
||||
}
|
||||
// console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
|
||||
return p;
|
||||
/*xml space '\x20' | #x9 | #xD | #xA; */
|
||||
case '\u0080':
|
||||
c = ' ';
|
||||
default:
|
||||
if(c<= ' '){//space
|
||||
switch(s){
|
||||
case S_TAG:
|
||||
el.setTagName(source.slice(start,p));//tagName
|
||||
s = S_TAG_SPACE;
|
||||
break;
|
||||
case S_ATTR:
|
||||
attrName = source.slice(start,p)
|
||||
s = S_ATTR_SPACE;
|
||||
break;
|
||||
case S_ATTR_NOQUOT_VALUE:
|
||||
var value = source.slice(start, p);
|
||||
errorHandler.warning('attribute "'+value+'" missed quot(")!!');
|
||||
addAttribute(attrName, value, start)
|
||||
case S_ATTR_END:
|
||||
s = S_TAG_SPACE;
|
||||
break;
|
||||
//case S_TAG_SPACE:
|
||||
//case S_EQ:
|
||||
//case S_ATTR_SPACE:
|
||||
// void();break;
|
||||
//case S_TAG_CLOSE:
|
||||
//ignore warning
|
||||
}
|
||||
}else{//not space
|
||||
//S_TAG, S_ATTR, S_EQ, S_ATTR_NOQUOT_VALUE
|
||||
//S_ATTR_SPACE, S_ATTR_END, S_TAG_SPACE, S_TAG_CLOSE
|
||||
switch(s){
|
||||
//case S_TAG:void();break;
|
||||
//case S_ATTR:void();break;
|
||||
//case S_ATTR_NOQUOT_VALUE:void();break;
|
||||
case S_ATTR_SPACE:
|
||||
var tagName = el.tagName;
|
||||
if (!NAMESPACE.isHTML(currentNSMap['']) || !attrName.match(/^(?:disabled|checked|selected)$/i)) {
|
||||
errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead2!!')
|
||||
}
|
||||
addAttribute(attrName, attrName, start);
|
||||
start = p;
|
||||
s = S_ATTR;
|
||||
break;
|
||||
case S_ATTR_END:
|
||||
errorHandler.warning('attribute space is required"'+attrName+'"!!')
|
||||
case S_TAG_SPACE:
|
||||
s = S_ATTR;
|
||||
start = p;
|
||||
break;
|
||||
case S_EQ:
|
||||
s = S_ATTR_NOQUOT_VALUE;
|
||||
start = p;
|
||||
break;
|
||||
case S_TAG_CLOSE:
|
||||
throw new Error("elements closed character '/' and '>' must be connected to");
|
||||
}
|
||||
}
|
||||
}//end outer switch
|
||||
//console.log('p++',p)
|
||||
p++;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return true if has new namespace define
|
||||
*/
|
||||
function appendElement(el,domBuilder,currentNSMap){
|
||||
var tagName = el.tagName;
|
||||
var localNSMap = null;
|
||||
//var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
|
||||
var i = el.length;
|
||||
while(i--){
|
||||
var a = el[i];
|
||||
var qName = a.qName;
|
||||
var value = a.value;
|
||||
var nsp = qName.indexOf(':');
|
||||
if(nsp>0){
|
||||
var prefix = a.prefix = qName.slice(0,nsp);
|
||||
var localName = qName.slice(nsp+1);
|
||||
var nsPrefix = prefix === 'xmlns' && localName
|
||||
}else{
|
||||
localName = qName;
|
||||
prefix = null
|
||||
nsPrefix = qName === 'xmlns' && ''
|
||||
}
|
||||
//can not set prefix,because prefix !== ''
|
||||
a.localName = localName ;
|
||||
//prefix == null for no ns prefix attribute
|
||||
if(nsPrefix !== false){//hack!!
|
||||
if(localNSMap == null){
|
||||
localNSMap = {}
|
||||
//console.log(currentNSMap,0)
|
||||
_copy(currentNSMap,currentNSMap={})
|
||||
//console.log(currentNSMap,1)
|
||||
}
|
||||
currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
|
||||
a.uri = NAMESPACE.XMLNS
|
||||
domBuilder.startPrefixMapping(nsPrefix, value)
|
||||
}
|
||||
}
|
||||
var i = el.length;
|
||||
while(i--){
|
||||
a = el[i];
|
||||
var prefix = a.prefix;
|
||||
if(prefix){//no prefix attribute has no namespace
|
||||
if(prefix === 'xml'){
|
||||
a.uri = NAMESPACE.XML;
|
||||
}if(prefix !== 'xmlns'){
|
||||
a.uri = currentNSMap[prefix || '']
|
||||
|
||||
//{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
|
||||
}
|
||||
}
|
||||
}
|
||||
var nsp = tagName.indexOf(':');
|
||||
if(nsp>0){
|
||||
prefix = el.prefix = tagName.slice(0,nsp);
|
||||
localName = el.localName = tagName.slice(nsp+1);
|
||||
}else{
|
||||
prefix = null;//important!!
|
||||
localName = el.localName = tagName;
|
||||
}
|
||||
//no prefix element has default namespace
|
||||
var ns = el.uri = currentNSMap[prefix || ''];
|
||||
domBuilder.startElement(ns,localName,tagName,el);
|
||||
//endPrefixMapping and startPrefixMapping have not any help for dom builder
|
||||
//localNSMap = null
|
||||
if(el.closed){
|
||||
domBuilder.endElement(ns,localName,tagName);
|
||||
if(localNSMap){
|
||||
for (prefix in localNSMap) {
|
||||
if (Object.prototype.hasOwnProperty.call(localNSMap, prefix)) {
|
||||
domBuilder.endPrefixMapping(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
el.currentNSMap = currentNSMap;
|
||||
el.localNSMap = localNSMap;
|
||||
//parseStack.push(el);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){
|
||||
if(/^(?:script|textarea)$/i.test(tagName)){
|
||||
var elEndStart = source.indexOf('</'+tagName+'>',elStartEnd);
|
||||
var text = source.substring(elStartEnd+1,elEndStart);
|
||||
if(/[&<]/.test(text)){
|
||||
if(/^script$/i.test(tagName)){
|
||||
//if(!/\]\]>/.test(text)){
|
||||
//lexHandler.startCDATA();
|
||||
domBuilder.characters(text,0,text.length);
|
||||
//lexHandler.endCDATA();
|
||||
return elEndStart;
|
||||
//}
|
||||
}//}else{//text area
|
||||
text = text.replace(/&#?\w+;/g,entityReplacer);
|
||||
domBuilder.characters(text,0,text.length);
|
||||
return elEndStart;
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
return elStartEnd+1;
|
||||
}
|
||||
function fixSelfClosed(source,elStartEnd,tagName,closeMap){
|
||||
//if(tagName in closeMap){
|
||||
var pos = closeMap[tagName];
|
||||
if(pos == null){
|
||||
//console.log(tagName)
|
||||
pos = source.lastIndexOf('</'+tagName+'>')
|
||||
if(pos<elStartEnd){//忘记闭合
|
||||
pos = source.lastIndexOf('</'+tagName)
|
||||
}
|
||||
closeMap[tagName] =pos
|
||||
}
|
||||
return pos<elStartEnd;
|
||||
//}
|
||||
}
|
||||
|
||||
function _copy (source, target) {
|
||||
for (var n in source) {
|
||||
if (Object.prototype.hasOwnProperty.call(source, n)) {
|
||||
target[n] = source[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseDCC(source,start,domBuilder,errorHandler){//sure start with '<!'
|
||||
var next= source.charAt(start+2)
|
||||
switch(next){
|
||||
case '-':
|
||||
if(source.charAt(start + 3) === '-'){
|
||||
var end = source.indexOf('-->',start+4);
|
||||
//append comment source.substring(4,end)//<!--
|
||||
if(end>start){
|
||||
domBuilder.comment(source,start+4,end-start-4);
|
||||
return end+3;
|
||||
}else{
|
||||
errorHandler.error("Unclosed comment");
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
//error
|
||||
return -1;
|
||||
}
|
||||
default:
|
||||
if(source.substr(start+3,6) == 'CDATA['){
|
||||
var end = source.indexOf(']]>',start+9);
|
||||
domBuilder.startCDATA();
|
||||
domBuilder.characters(source,start+9,end-start-9);
|
||||
domBuilder.endCDATA()
|
||||
return end+3;
|
||||
}
|
||||
//<!DOCTYPE
|
||||
//startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId)
|
||||
var matchs = split(source,start);
|
||||
var len = matchs.length;
|
||||
if(len>1 && /!doctype/i.test(matchs[0][0])){
|
||||
var name = matchs[1][0];
|
||||
var pubid = false;
|
||||
var sysid = false;
|
||||
if(len>3){
|
||||
if(/^public$/i.test(matchs[2][0])){
|
||||
pubid = matchs[3][0];
|
||||
sysid = len>4 && matchs[4][0];
|
||||
}else if(/^system$/i.test(matchs[2][0])){
|
||||
sysid = matchs[3][0];
|
||||
}
|
||||
}
|
||||
var lastMatch = matchs[len-1]
|
||||
domBuilder.startDTD(name, pubid, sysid);
|
||||
domBuilder.endDTD();
|
||||
|
||||
return lastMatch.index+lastMatch[0].length
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function parseInstruction(source,start,domBuilder){
|
||||
var end = source.indexOf('?>',start);
|
||||
if(end){
|
||||
var match = source.substring(start,end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
|
||||
if(match){
|
||||
var len = match[0].length;
|
||||
domBuilder.processingInstruction(match[1], match[2]) ;
|
||||
return end+2;
|
||||
}else{//error
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function ElementAttributes(){
|
||||
this.attributeNames = {}
|
||||
}
|
||||
ElementAttributes.prototype = {
|
||||
setTagName:function(tagName){
|
||||
if(!tagNamePattern.test(tagName)){
|
||||
throw new Error('invalid tagName:'+tagName)
|
||||
}
|
||||
this.tagName = tagName
|
||||
},
|
||||
addValue:function(qName, value, offset) {
|
||||
if(!tagNamePattern.test(qName)){
|
||||
throw new Error('invalid attribute:'+qName)
|
||||
}
|
||||
this.attributeNames[qName] = this.length;
|
||||
this[this.length++] = {qName:qName,value:value,offset:offset}
|
||||
},
|
||||
length:0,
|
||||
getLocalName:function(i){return this[i].localName},
|
||||
getLocator:function(i){return this[i].locator},
|
||||
getQName:function(i){return this[i].qName},
|
||||
getURI:function(i){return this[i].uri},
|
||||
getValue:function(i){return this[i].value}
|
||||
// ,getIndex:function(uri, localName)){
|
||||
// if(localName){
|
||||
//
|
||||
// }else{
|
||||
// var qName = uri
|
||||
// }
|
||||
// },
|
||||
// getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
|
||||
// getType:function(uri,localName){}
|
||||
// getType:function(i){},
|
||||
}
|
||||
|
||||
|
||||
|
||||
function split(source,start){
|
||||
var match;
|
||||
var buf = [];
|
||||
var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
|
||||
reg.lastIndex = start;
|
||||
reg.exec(source);//skip <
|
||||
while(match = reg.exec(source)){
|
||||
buf.push(match);
|
||||
if(match[1])return buf;
|
||||
}
|
||||
}
|
||||
|
||||
exports.XMLReader = XMLReader;
|
||||
exports.ParseError = ParseError;
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"name": "@xmldom/xmldom",
|
||||
"version": "0.8.10",
|
||||
"description": "A pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module.",
|
||||
"keywords": [
|
||||
"w3c",
|
||||
"dom",
|
||||
"xml",
|
||||
"parser",
|
||||
"javascript",
|
||||
"DOMParser",
|
||||
"XMLSerializer",
|
||||
"ponyfill"
|
||||
],
|
||||
"homepage": "https://github.com/xmldom/xmldom",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/xmldom/xmldom.git"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"types": "index.d.ts",
|
||||
"files": [
|
||||
"CHANGELOG.md",
|
||||
"LICENSE",
|
||||
"readme.md",
|
||||
"SECURITY.md",
|
||||
"index.d.ts",
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "eslint lib test",
|
||||
"format": "prettier --write test",
|
||||
"changelog": "auto-changelog --unreleased-only",
|
||||
"start": "nodemon --watch package.json --watch lib --watch test --exec 'npm --silent run test && npm --silent run lint'",
|
||||
"stryker": "stryker run",
|
||||
"stryker:dry-run": "stryker run -m '' --reporters progress",
|
||||
"test": "jest",
|
||||
"testrelease": "npm test && eslint lib",
|
||||
"version": "./changelog-has-version.sh",
|
||||
"release": "np --no-yarn --test-script testrelease --branch release-0.8.x patch"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@stryker-mutator/core": "5.6.1",
|
||||
"auto-changelog": "2.4.0",
|
||||
"eslint": "8.25.0",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-plugin-es5": "1.5.0",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"get-stream": "6.0.1",
|
||||
"jest": "27.5.1",
|
||||
"nodemon": "2.0.20",
|
||||
"np": "7.6.2",
|
||||
"prettier": "2.7.1",
|
||||
"xmltest": "1.5.0",
|
||||
"yauzl": "2.10.0"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/xmldom/xmldom/issues"
|
||||
},
|
||||
"license": "MIT",
|
||||
"auto-changelog": {
|
||||
"prepend": true,
|
||||
"remote": "upstream",
|
||||
"tagPrefix": "",
|
||||
"template": "./auto-changelog.hbs"
|
||||
}
|
||||
}
|
||||
+356
@@ -0,0 +1,356 @@
|
||||
# @xmldom/xmldom
|
||||
|
||||
***Since version 0.7.0 this package is published to npm as [`@xmldom/xmldom`](https://www.npmjs.com/package/@xmldom/xmldom) and no longer as [`xmldom`](https://www.npmjs.com/package/xmldom), because [we are no longer able to publish `xmldom`](https://github.com/xmldom/xmldom/issues/271).***
|
||||
*For better readability in the docs we will continue to talk about this library as "xmldom".*
|
||||
|
||||
[](https://github.com/xmldom/xmldom/blob/master/LICENSE)
|
||||
[](https://www.npmjs.com/package/@xmldom/xmldom)
|
||||
[](https://snyk.io/advisor/npm-package/@xmldom/xmldom)
|
||||
[](https://github.com/xmldom/xmldom/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
|
||||
[](https://github.com/xmldom/xmldom/issues?q=is%3Aissue+is%3Aopen+label%3Ahelp-wanted)
|
||||
[](https://dashboard.stryker-mutator.io/reports/github.com/xmldom/xmldom/master)
|
||||
|
||||
|
||||
xmldom is a javascript [ponyfill](https://ponyfill.com/) to provide the following APIs [that are present in modern browsers](https://caniuse.com/xml-serializer) to other runtimes:
|
||||
- convert an XML string into a DOM tree
|
||||
```
|
||||
new DOMParser().parseFromString(xml, mimeType) => Document
|
||||
```
|
||||
- create, access and modify a DOM tree
|
||||
```
|
||||
new DOMImplementation().createDocument(...) => Document
|
||||
```
|
||||
- serialize a DOM tree back into an XML string
|
||||
```
|
||||
new XMLSerializer().serializeToString(node) => string
|
||||
```
|
||||
|
||||
The target runtimes `xmldom` supports are currently Node >= v10 (ES5) and Rhino ([not tested as part of CI](https://github.com/xmldom/xmldom/discussions/214)).
|
||||
|
||||
When deciding how to fix bugs or implement features, `xmldom` tries to stay as close as possible to the various [related specifications/standards](#specs).
|
||||
As indicated by the version starting with `0.`, this implementation is not feature complete and some implemented features differ from what the specifications describe.
|
||||
**Issues and PRs for such differences are always welcome, even when they only provide a failing test case.**
|
||||
|
||||
This project was forked from it's [original source](https://github.com/jindw/xmldom) in 2019, more details about that transition can be found in the [CHANGELOG](CHANGELOG.md#maintainer-changes).
|
||||
|
||||
## Usage
|
||||
|
||||
### Install:
|
||||
|
||||
> npm install @xmldom/xmldom
|
||||
|
||||
### Example:
|
||||
|
||||
[In NodeJS](examples/nodejs/src/index.js)
|
||||
```javascript
|
||||
const { DOMParser, XMLSerializer } = require('@xmldom/xmldom')
|
||||
|
||||
const source = `<xml xmlns="a">
|
||||
<child>test</child>
|
||||
<child/>
|
||||
</xml>`
|
||||
|
||||
const doc = new DOMParser().parseFromString(source, 'text/xml')
|
||||
|
||||
const serialized = new XMLSerializer().serializeToString(doc)
|
||||
```
|
||||
|
||||
Note: in Typescript ~and ES6~(see #316) you can use the `import` approach, as follows:
|
||||
|
||||
```typescript
|
||||
import { DOMParser } from '@xmldom/xmldom'
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
* [DOMParser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser):
|
||||
|
||||
```javascript
|
||||
parseFromString(xmlsource,mimeType)
|
||||
```
|
||||
* **options extension** _by xmldom_ (not DOM standard!!)
|
||||
|
||||
```javascript
|
||||
//added the options argument
|
||||
new DOMParser(options)
|
||||
|
||||
//errorHandler is supported
|
||||
new DOMParser({
|
||||
/**
|
||||
* locator is always need for error position info
|
||||
*/
|
||||
locator:{},
|
||||
/**
|
||||
* you can override the errorHandler for xml parser
|
||||
* @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
|
||||
*/
|
||||
errorHandler:{warning:function(w){console.warn(w)},error:callback,fatalError:callback}
|
||||
//only callback model
|
||||
//errorHandler:function(level,msg){console.log(level,msg)}
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
* [XMLSerializer](https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer)
|
||||
|
||||
```javascript
|
||||
serializeToString(node)
|
||||
```
|
||||
### DOM level2 method and attribute:
|
||||
|
||||
* [Node](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247)
|
||||
|
||||
readonly class properties (aka `NodeType`),
|
||||
these can be accessed from any `Node` instance `node`:
|
||||
`if (node.nodeType === node.ELEMENT_NODE) {...`
|
||||
|
||||
1. `ELEMENT_NODE` (`1`)
|
||||
2. `ATTRIBUTE_NODE` (`2`)
|
||||
3. `TEXT_NODE` (`3`)
|
||||
4. `CDATA_SECTION_NODE` (`4`)
|
||||
5. `ENTITY_REFERENCE_NODE` (`5`)
|
||||
6. `ENTITY_NODE` (`6`)
|
||||
7. `PROCESSING_INSTRUCTION_NODE` (`7`)
|
||||
8. `COMMENT_NODE` (`8`)
|
||||
9. `DOCUMENT_NODE` (`9`)
|
||||
10. `DOCUMENT_TYPE_NODE` (`10`)
|
||||
11. `DOCUMENT_FRAGMENT_NODE` (`11`)
|
||||
12. `NOTATION_NODE` (`12`)
|
||||
|
||||
attribute:
|
||||
- `nodeValue` | `prefix`
|
||||
|
||||
readonly attribute:
|
||||
- `nodeName` | `nodeType` | `parentNode` | `childNodes` | `firstChild` | `lastChild` | `previousSibling` | `nextSibling` | `attributes` | `ownerDocument` | `namespaceURI` | `localName`
|
||||
|
||||
method:
|
||||
* `insertBefore(newChild, refChild)`
|
||||
* `replaceChild(newChild, oldChild)`
|
||||
* `removeChild(oldChild)`
|
||||
* `appendChild(newChild)`
|
||||
* `hasChildNodes()`
|
||||
* `cloneNode(deep)`
|
||||
* `normalize()`
|
||||
* `isSupported(feature, version)`
|
||||
* `hasAttributes()`
|
||||
* [DOMException](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html)
|
||||
|
||||
extends the Error type thrown as part of DOM API.
|
||||
|
||||
readonly class properties:
|
||||
- `INDEX_SIZE_ERR` (`1`)
|
||||
- `DOMSTRING_SIZE_ERR` (`2`)
|
||||
- `HIERARCHY_REQUEST_ERR` (`3`)
|
||||
- `WRONG_DOCUMENT_ERR` (`4`)
|
||||
- `INVALID_CHARACTER_ERR` (`5`)
|
||||
- `NO_DATA_ALLOWED_ERR` (`6`)
|
||||
- `NO_MODIFICATION_ALLOWED_ERR` (`7`)
|
||||
- `NOT_FOUND_ERR` (`8`)
|
||||
- `NOT_SUPPORTED_ERR` (`9`)
|
||||
- `INUSE_ATTRIBUTE_ERR` (`10`)
|
||||
- `INVALID_STATE_ERR` (`11`)
|
||||
- `SYNTAX_ERR` (`12`)
|
||||
- `INVALID_MODIFICATION_ERR` (`13`)
|
||||
- `NAMESPACE_ERR` (`14`)
|
||||
- `INVALID_ACCESS_ERR` (`15`)
|
||||
|
||||
attributes:
|
||||
- `code` with a value matching one of the above constants.
|
||||
|
||||
* [DOMImplementation](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-102161490)
|
||||
|
||||
method:
|
||||
- `hasFeature(feature, version)`
|
||||
- `createDocumentType(qualifiedName, publicId, systemId)`
|
||||
- `createDocument(namespaceURI, qualifiedName, doctype)`
|
||||
|
||||
* [Document](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#i-Document) : Node
|
||||
|
||||
readonly attribute:
|
||||
- `doctype` | `implementation` | `documentElement`
|
||||
|
||||
method:
|
||||
- `createElement(tagName)`
|
||||
- `createDocumentFragment()`
|
||||
- `createTextNode(data)`
|
||||
- `createComment(data)`
|
||||
- `createCDATASection(data)`
|
||||
- `createProcessingInstruction(target, data)`
|
||||
- `createAttribute(name)`
|
||||
- `createEntityReference(name)`
|
||||
- `getElementsByTagName(tagname)`
|
||||
- `importNode(importedNode, deep)`
|
||||
- `createElementNS(namespaceURI, qualifiedName)`
|
||||
- `createAttributeNS(namespaceURI, qualifiedName)`
|
||||
- `getElementsByTagNameNS(namespaceURI, localName)`
|
||||
- `getElementById(elementId)`
|
||||
|
||||
* [DocumentFragment](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-B63ED1A3) : Node
|
||||
* [Element](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-745549614) : Node
|
||||
|
||||
readonly attribute:
|
||||
- `tagName`
|
||||
|
||||
method:
|
||||
- `getAttribute(name)`
|
||||
- `setAttribute(name, value)`
|
||||
- `removeAttribute(name)`
|
||||
- `getAttributeNode(name)`
|
||||
- `setAttributeNode(newAttr)`
|
||||
- `removeAttributeNode(oldAttr)`
|
||||
- `getElementsByTagName(name)`
|
||||
- `getAttributeNS(namespaceURI, localName)`
|
||||
- `setAttributeNS(namespaceURI, qualifiedName, value)`
|
||||
- `removeAttributeNS(namespaceURI, localName)`
|
||||
- `getAttributeNodeNS(namespaceURI, localName)`
|
||||
- `setAttributeNodeNS(newAttr)`
|
||||
- `getElementsByTagNameNS(namespaceURI, localName)`
|
||||
- `hasAttribute(name)`
|
||||
- `hasAttributeNS(namespaceURI, localName)`
|
||||
|
||||
* [Attr](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-637646024) : Node
|
||||
|
||||
attribute:
|
||||
- `value`
|
||||
|
||||
readonly attribute:
|
||||
- `name` | `specified` | `ownerElement`
|
||||
|
||||
* [NodeList](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177)
|
||||
|
||||
readonly attribute:
|
||||
- `length`
|
||||
|
||||
method:
|
||||
- `item(index)`
|
||||
|
||||
* [NamedNodeMap](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1780488922)
|
||||
|
||||
readonly attribute:
|
||||
- `length`
|
||||
|
||||
method:
|
||||
- `getNamedItem(name)`
|
||||
- `setNamedItem(arg)`
|
||||
- `removeNamedItem(name)`
|
||||
- `item(index)`
|
||||
- `getNamedItemNS(namespaceURI, localName)`
|
||||
- `setNamedItemNS(arg)`
|
||||
- `removeNamedItemNS(namespaceURI, localName)`
|
||||
|
||||
* [CharacterData](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-FF21A306) : Node
|
||||
|
||||
method:
|
||||
- `substringData(offset, count)`
|
||||
- `appendData(arg)`
|
||||
- `insertData(offset, arg)`
|
||||
- `deleteData(offset, count)`
|
||||
- `replaceData(offset, count, arg)`
|
||||
|
||||
* [Text](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1312295772) : CharacterData
|
||||
|
||||
method:
|
||||
- `splitText(offset)`
|
||||
|
||||
* [CDATASection](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-667469212)
|
||||
* [Comment](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1728279322) : CharacterData
|
||||
|
||||
* [DocumentType](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-412266927)
|
||||
|
||||
readonly attribute:
|
||||
- `name` | `entities` | `notations` | `publicId` | `systemId` | `internalSubset`
|
||||
|
||||
* Notation : Node
|
||||
|
||||
readonly attribute:
|
||||
- `publicId` | `systemId`
|
||||
|
||||
* Entity : Node
|
||||
|
||||
readonly attribute:
|
||||
- `publicId` | `systemId` | `notationName`
|
||||
|
||||
* EntityReference : Node
|
||||
* ProcessingInstruction : Node
|
||||
|
||||
attribute:
|
||||
- `data`
|
||||
readonly attribute:
|
||||
- `target`
|
||||
|
||||
### DOM level 3 support:
|
||||
|
||||
* [Node](http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-textContent)
|
||||
|
||||
attribute:
|
||||
- `textContent`
|
||||
|
||||
method:
|
||||
- `isDefaultNamespace(namespaceURI)`
|
||||
- `lookupNamespaceURI(prefix)`
|
||||
|
||||
### DOM extension by xmldom
|
||||
|
||||
* [Node] Source position extension;
|
||||
|
||||
attribute:
|
||||
- `lineNumber` //number starting from `1`
|
||||
- `columnNumber` //number starting from `1`
|
||||
|
||||
## Specs
|
||||
|
||||
The implementation is based on several specifications:
|
||||
|
||||
<!-- Should open in new tab and the links in the SVG should be clickable there! -->
|
||||
<a href="https://raw.githubusercontent.com/xmldom/xmldom/master/docs/specs.svg" target="_blank" rel="noopener noreferrer nofollow" ></a>
|
||||
|
||||
### DOM Parsing and Serialization
|
||||
|
||||
From the [W3C DOM Parsing and Serialization (WD 2016)](https://www.w3.org/TR/2016/WD-DOM-Parsing-20160517/) `xmldom` provides an implementation for the interfaces:
|
||||
- `DOMParser`
|
||||
- `XMLSerializer`
|
||||
|
||||
Note that there are some known deviations between this implementation and the W3 specifications.
|
||||
|
||||
Note: [The latest version of this spec](https://w3c.github.io/DOM-Parsing/) has the status "Editors Draft", since it is under active development. One major change is that [the definition of the `DOMParser` interface has been moved to the HTML spec](https://w3c.github.io/DOM-Parsing/#the-domparser-interface)
|
||||
|
||||
|
||||
### DOM
|
||||
|
||||
The original author claims that xmldom implements [DOM Level 2] in a "fully compatible" way and some parts of [DOM Level 3], but there are not enough tests to prove this. Both Specifications are now superseded by the [DOM Level 4 aka Living standard] wich has a much broader scope than xmldom.
|
||||
|
||||
xmldom implements the following interfaces (most constructors are currently not exposed):
|
||||
- `Attr`
|
||||
- `CDATASection`
|
||||
- `CharacterData`
|
||||
- `Comment`
|
||||
- `Document`
|
||||
- `DocumentFragment`
|
||||
- `DocumentType`
|
||||
- `DOMException` (constructor exposed)
|
||||
- `DOMImplementation` (constructor exposed)
|
||||
- `Element`
|
||||
- `Entity`
|
||||
- `EntityReference`
|
||||
- `LiveNodeList`
|
||||
- `NamedNodeMap`
|
||||
- `Node` (constructor exposed)
|
||||
- `NodeList`
|
||||
- `Notation`
|
||||
- `ProcessingInstruction`
|
||||
- `Text`
|
||||
|
||||
more details are available in the (incomplete) [API Reference](#api-reference) section.
|
||||
|
||||
### HTML
|
||||
|
||||
xmldom does not have any goal of supporting the full spec, but it has some capability to parse, report and serialize things differently when "detecting HTML" (by checking the default namespace).
|
||||
There is an upcoming change to better align the implementation with the latest specs, related to <https://github.com/xmldom/xmldom/issues/203>.
|
||||
|
||||
### SAX, XML, XMLNS
|
||||
|
||||
xmldom has an own SAX parser implementation to do the actual parsing, which implements some interfaces in alignment with the Java interfaces SAX defines:
|
||||
- `XMLReader`
|
||||
- `DOMHandler`
|
||||
|
||||
There is an idea/proposal to make it possible to replace it with something else in <https://github.com/xmldom/xmldom/issues/55>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"laxcomma": true,
|
||||
"asi": true
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
|
||||
0.3.1 / 2016-01-14
|
||||
==================
|
||||
|
||||
* add MIT LICENSE file (#23, @kasicka)
|
||||
* preserve chaining after redundant style-method calls (#19, @drewblaisdell)
|
||||
* package: add "license" field (#16, @BenjaminTsai)
|
||||
|
||||
0.3.0 / 2014-05-09
|
||||
==================
|
||||
|
||||
* package: remove "test" script and "devDependencies"
|
||||
* package: remove "engines" section
|
||||
* pacakge: remove "bin" section
|
||||
* package: beautify
|
||||
* examples: remove `starwars` example (#15)
|
||||
* Documented goto, horizontalAbsolute, and eraseLine methods in README.md (#12, @Jammerwoch)
|
||||
* add `.jshintrc` file
|
||||
|
||||
< 0.3.0
|
||||
=======
|
||||
|
||||
* Prehistoric
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
ansi.js
|
||||
=========
|
||||
### Advanced ANSI formatting tool for Node.js
|
||||
|
||||
`ansi.js` is a module for Node.js that provides an easy-to-use API for
|
||||
writing ANSI escape codes to `Stream` instances. ANSI escape codes are used to do
|
||||
fancy things in a terminal window, like render text in colors, delete characters,
|
||||
lines, the entire window, or hide and show the cursor, and lots more!
|
||||
|
||||
#### Features:
|
||||
|
||||
* 256 color support for the terminal!
|
||||
* Make a beep sound from your terminal!
|
||||
* Works with *any* writable `Stream` instance.
|
||||
* Allows you to move the cursor anywhere on the terminal window.
|
||||
* Allows you to delete existing contents from the terminal window.
|
||||
* Allows you to hide and show the cursor.
|
||||
* Converts CSS color codes and RGB values into ANSI escape codes.
|
||||
* Low-level; you are in control of when escape codes are used, it's not abstracted.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Install with `npm`:
|
||||
|
||||
``` bash
|
||||
$ npm install ansi
|
||||
```
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
``` js
|
||||
var ansi = require('ansi')
|
||||
, cursor = ansi(process.stdout)
|
||||
|
||||
// You can chain your calls forever:
|
||||
cursor
|
||||
.red() // Set font color to red
|
||||
.bg.grey() // Set background color to grey
|
||||
.write('Hello World!') // Write 'Hello World!' to stdout
|
||||
.bg.reset() // Reset the bgcolor before writing the trailing \n,
|
||||
// to avoid Terminal glitches
|
||||
.write('\n') // And a final \n to wrap things up
|
||||
|
||||
// Rendering modes are persistent:
|
||||
cursor.hex('#660000').bold().underline()
|
||||
|
||||
// You can use the regular logging functions, text will be green:
|
||||
console.log('This is blood red, bold text')
|
||||
|
||||
// To reset just the foreground color:
|
||||
cursor.fg.reset()
|
||||
|
||||
console.log('This will still be bold')
|
||||
|
||||
// to go to a location (x,y) on the console
|
||||
// note: 1-indexed, not 0-indexed:
|
||||
cursor.goto(10, 5).write('Five down, ten over')
|
||||
|
||||
// to clear the current line:
|
||||
cursor.horizontalAbsolute(0).eraseLine().write('Starting again')
|
||||
|
||||
// to go to a different column on the current line:
|
||||
cursor.horizontalAbsolute(5).write('column five')
|
||||
|
||||
// Clean up after yourself!
|
||||
cursor.reset()
|
||||
```
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Invokes the terminal "beep" sound once per second on every exact second.
|
||||
*/
|
||||
|
||||
process.title = 'beep'
|
||||
|
||||
var cursor = require('../../')(process.stdout)
|
||||
|
||||
function beep () {
|
||||
cursor.beep()
|
||||
setTimeout(beep, 1000 - (new Date()).getMilliseconds())
|
||||
}
|
||||
|
||||
setTimeout(beep, 1000 - (new Date()).getMilliseconds())
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Like GNU ncurses "clear" command.
|
||||
* https://github.com/mscdex/node-ncurses/blob/master/deps/ncurses/progs/clear.c
|
||||
*/
|
||||
|
||||
process.title = 'clear'
|
||||
|
||||
function lf () { return '\n' }
|
||||
|
||||
require('../../')(process.stdout)
|
||||
.write(Array.apply(null, Array(process.stdout.getWindowSize()[1])).map(lf).join(''))
|
||||
.eraseData(2)
|
||||
.goto(1, 1)
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var tty = require('tty')
|
||||
var cursor = require('../')(process.stdout)
|
||||
|
||||
// listen for the queryPosition report on stdin
|
||||
process.stdin.resume()
|
||||
raw(true)
|
||||
|
||||
process.stdin.once('data', function (b) {
|
||||
var match = /\[(\d+)\;(\d+)R$/.exec(b.toString())
|
||||
if (match) {
|
||||
var xy = match.slice(1, 3).reverse().map(Number)
|
||||
console.error(xy)
|
||||
}
|
||||
|
||||
// cleanup and close stdin
|
||||
raw(false)
|
||||
process.stdin.pause()
|
||||
})
|
||||
|
||||
|
||||
// send the query position request code to stdout
|
||||
cursor.queryPosition()
|
||||
|
||||
function raw (mode) {
|
||||
if (process.stdin.setRawMode) {
|
||||
process.stdin.setRawMode(mode)
|
||||
} else {
|
||||
tty.setRawMode(mode)
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var assert = require('assert')
|
||||
, ansi = require('../../')
|
||||
|
||||
function Progress (stream, width) {
|
||||
this.cursor = ansi(stream)
|
||||
this.delta = this.cursor.newlines
|
||||
this.width = width | 0 || 10
|
||||
this.open = '['
|
||||
this.close = ']'
|
||||
this.complete = '█'
|
||||
this.incomplete = '_'
|
||||
|
||||
// initial render
|
||||
this.progress = 0
|
||||
}
|
||||
|
||||
Object.defineProperty(Progress.prototype, 'progress', {
|
||||
get: get
|
||||
, set: set
|
||||
, configurable: true
|
||||
, enumerable: true
|
||||
})
|
||||
|
||||
function get () {
|
||||
return this._progress
|
||||
}
|
||||
|
||||
function set (v) {
|
||||
this._progress = Math.max(0, Math.min(v, 100))
|
||||
|
||||
var w = this.width - this.complete.length - this.incomplete.length
|
||||
, n = w * (this._progress / 100) | 0
|
||||
, i = w - n
|
||||
, com = c(this.complete, n)
|
||||
, inc = c(this.incomplete, i)
|
||||
, delta = this.cursor.newlines - this.delta
|
||||
|
||||
assert.equal(com.length + inc.length, w)
|
||||
|
||||
if (delta > 0) {
|
||||
this.cursor.up(delta)
|
||||
this.delta = this.cursor.newlines
|
||||
}
|
||||
|
||||
this.cursor
|
||||
.horizontalAbsolute(0)
|
||||
.eraseLine(2)
|
||||
.fg.white()
|
||||
.write(this.open)
|
||||
.fg.grey()
|
||||
.bold()
|
||||
.write(com)
|
||||
.resetBold()
|
||||
.write(inc)
|
||||
.fg.white()
|
||||
.write(this.close)
|
||||
.fg.reset()
|
||||
.write('\n')
|
||||
}
|
||||
|
||||
function c (char, length) {
|
||||
return Array.apply(null, Array(length)).map(function () {
|
||||
return char
|
||||
}).join('')
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Usage
|
||||
var width = parseInt(process.argv[2], 10) || process.stdout.getWindowSize()[0] / 2
|
||||
, p = new Progress(process.stdout, width)
|
||||
|
||||
;(function tick () {
|
||||
p.progress += Math.random() * 5
|
||||
p.cursor
|
||||
.eraseLine(2)
|
||||
.write('Progress: ')
|
||||
.bold().write(p.progress.toFixed(2))
|
||||
.write('%')
|
||||
.resetBold()
|
||||
.write('\n')
|
||||
if (p.progress < 100)
|
||||
setTimeout(tick, 100)
|
||||
})()
|
||||
+405
@@ -0,0 +1,405 @@
|
||||
|
||||
/**
|
||||
* References:
|
||||
*
|
||||
* - http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
* - http://www.termsys.demon.co.uk/vtansi.htm
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var emitNewlineEvents = require('./newlines')
|
||||
, prefix = '\x1b[' // For all escape codes
|
||||
, suffix = 'm' // Only for color codes
|
||||
|
||||
/**
|
||||
* The ANSI escape sequences.
|
||||
*/
|
||||
|
||||
var codes = {
|
||||
up: 'A'
|
||||
, down: 'B'
|
||||
, forward: 'C'
|
||||
, back: 'D'
|
||||
, nextLine: 'E'
|
||||
, previousLine: 'F'
|
||||
, horizontalAbsolute: 'G'
|
||||
, eraseData: 'J'
|
||||
, eraseLine: 'K'
|
||||
, scrollUp: 'S'
|
||||
, scrollDown: 'T'
|
||||
, savePosition: 's'
|
||||
, restorePosition: 'u'
|
||||
, queryPosition: '6n'
|
||||
, hide: '?25l'
|
||||
, show: '?25h'
|
||||
}
|
||||
|
||||
/**
|
||||
* Rendering ANSI codes.
|
||||
*/
|
||||
|
||||
var styles = {
|
||||
bold: 1
|
||||
, italic: 3
|
||||
, underline: 4
|
||||
, inverse: 7
|
||||
}
|
||||
|
||||
/**
|
||||
* The negating ANSI code for the rendering modes.
|
||||
*/
|
||||
|
||||
var reset = {
|
||||
bold: 22
|
||||
, italic: 23
|
||||
, underline: 24
|
||||
, inverse: 27
|
||||
}
|
||||
|
||||
/**
|
||||
* The standard, styleable ANSI colors.
|
||||
*/
|
||||
|
||||
var colors = {
|
||||
white: 37
|
||||
, black: 30
|
||||
, blue: 34
|
||||
, cyan: 36
|
||||
, green: 32
|
||||
, magenta: 35
|
||||
, red: 31
|
||||
, yellow: 33
|
||||
, grey: 90
|
||||
, brightBlack: 90
|
||||
, brightRed: 91
|
||||
, brightGreen: 92
|
||||
, brightYellow: 93
|
||||
, brightBlue: 94
|
||||
, brightMagenta: 95
|
||||
, brightCyan: 96
|
||||
, brightWhite: 97
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Cursor instance based off the given `writable stream` instance.
|
||||
*/
|
||||
|
||||
function ansi (stream, options) {
|
||||
if (stream._ansicursor) {
|
||||
return stream._ansicursor
|
||||
} else {
|
||||
return stream._ansicursor = new Cursor(stream, options)
|
||||
}
|
||||
}
|
||||
module.exports = exports = ansi
|
||||
|
||||
/**
|
||||
* The `Cursor` class.
|
||||
*/
|
||||
|
||||
function Cursor (stream, options) {
|
||||
if (!(this instanceof Cursor)) {
|
||||
return new Cursor(stream, options)
|
||||
}
|
||||
if (typeof stream != 'object' || typeof stream.write != 'function') {
|
||||
throw new Error('a valid Stream instance must be passed in')
|
||||
}
|
||||
|
||||
// the stream to use
|
||||
this.stream = stream
|
||||
|
||||
// when 'enabled' is false then all the functions are no-ops except for write()
|
||||
this.enabled = options && options.enabled
|
||||
if (typeof this.enabled === 'undefined') {
|
||||
this.enabled = stream.isTTY
|
||||
}
|
||||
this.enabled = !!this.enabled
|
||||
|
||||
// then `buffering` is true, then `write()` calls are buffered in
|
||||
// memory until `flush()` is invoked
|
||||
this.buffering = !!(options && options.buffering)
|
||||
this._buffer = []
|
||||
|
||||
// controls the foreground and background colors
|
||||
this.fg = this.foreground = new Colorer(this, 0)
|
||||
this.bg = this.background = new Colorer(this, 10)
|
||||
|
||||
// defaults
|
||||
this.Bold = false
|
||||
this.Italic = false
|
||||
this.Underline = false
|
||||
this.Inverse = false
|
||||
|
||||
// keep track of the number of "newlines" that get encountered
|
||||
this.newlines = 0
|
||||
emitNewlineEvents(stream)
|
||||
stream.on('newline', function () {
|
||||
this.newlines++
|
||||
}.bind(this))
|
||||
}
|
||||
exports.Cursor = Cursor
|
||||
|
||||
/**
|
||||
* Helper function that calls `write()` on the underlying Stream.
|
||||
* Returns `this` instead of the write() return value to keep
|
||||
* the chaining going.
|
||||
*/
|
||||
|
||||
Cursor.prototype.write = function (data) {
|
||||
if (this.buffering) {
|
||||
this._buffer.push(arguments)
|
||||
} else {
|
||||
this.stream.write.apply(this.stream, arguments)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffer `write()` calls into memory.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Cursor.prototype.buffer = function () {
|
||||
this.buffering = true
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the in-memory buffer.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Cursor.prototype.flush = function () {
|
||||
this.buffering = false
|
||||
var str = this._buffer.map(function (args) {
|
||||
if (args.length != 1) throw new Error('unexpected args length! ' + args.length);
|
||||
return args[0];
|
||||
}).join('');
|
||||
this._buffer.splice(0); // empty
|
||||
this.write(str);
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The `Colorer` class manages both the background and foreground colors.
|
||||
*/
|
||||
|
||||
function Colorer (cursor, base) {
|
||||
this.current = null
|
||||
this.cursor = cursor
|
||||
this.base = base
|
||||
}
|
||||
exports.Colorer = Colorer
|
||||
|
||||
/**
|
||||
* Write an ANSI color code, ensuring that the same code doesn't get rewritten.
|
||||
*/
|
||||
|
||||
Colorer.prototype._setColorCode = function setColorCode (code) {
|
||||
var c = String(code)
|
||||
if (this.current === c) return
|
||||
this.cursor.enabled && this.cursor.write(prefix + c + suffix)
|
||||
this.current = c
|
||||
return this
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set up the positional ANSI codes.
|
||||
*/
|
||||
|
||||
Object.keys(codes).forEach(function (name) {
|
||||
var code = String(codes[name])
|
||||
Cursor.prototype[name] = function () {
|
||||
var c = code
|
||||
if (arguments.length > 0) {
|
||||
c = toArray(arguments).map(Math.round).join(';') + code
|
||||
}
|
||||
this.enabled && this.write(prefix + c)
|
||||
return this
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Set up the functions for the rendering ANSI codes.
|
||||
*/
|
||||
|
||||
Object.keys(styles).forEach(function (style) {
|
||||
var name = style[0].toUpperCase() + style.substring(1)
|
||||
, c = styles[style]
|
||||
, r = reset[style]
|
||||
|
||||
Cursor.prototype[style] = function () {
|
||||
if (this[name]) return this
|
||||
this.enabled && this.write(prefix + c + suffix)
|
||||
this[name] = true
|
||||
return this
|
||||
}
|
||||
|
||||
Cursor.prototype['reset' + name] = function () {
|
||||
if (!this[name]) return this
|
||||
this.enabled && this.write(prefix + r + suffix)
|
||||
this[name] = false
|
||||
return this
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Setup the functions for the standard colors.
|
||||
*/
|
||||
|
||||
Object.keys(colors).forEach(function (color) {
|
||||
var code = colors[color]
|
||||
|
||||
Colorer.prototype[color] = function () {
|
||||
this._setColorCode(this.base + code)
|
||||
return this.cursor
|
||||
}
|
||||
|
||||
Cursor.prototype[color] = function () {
|
||||
return this.foreground[color]()
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Makes a beep sound!
|
||||
*/
|
||||
|
||||
Cursor.prototype.beep = function () {
|
||||
this.enabled && this.write('\x07')
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves cursor to specific position
|
||||
*/
|
||||
|
||||
Cursor.prototype.goto = function (x, y) {
|
||||
x = x | 0
|
||||
y = y | 0
|
||||
this.enabled && this.write(prefix + y + ';' + x + 'H')
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the color.
|
||||
*/
|
||||
|
||||
Colorer.prototype.reset = function () {
|
||||
this._setColorCode(this.base + 39)
|
||||
return this.cursor
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all ANSI formatting on the stream.
|
||||
*/
|
||||
|
||||
Cursor.prototype.reset = function () {
|
||||
this.enabled && this.write(prefix + '0' + suffix)
|
||||
this.Bold = false
|
||||
this.Italic = false
|
||||
this.Underline = false
|
||||
this.Inverse = false
|
||||
this.foreground.current = null
|
||||
this.background.current = null
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the foreground color with the given RGB values.
|
||||
* The closest match out of the 216 colors is picked.
|
||||
*/
|
||||
|
||||
Colorer.prototype.rgb = function (r, g, b) {
|
||||
var base = this.base + 38
|
||||
, code = rgb(r, g, b)
|
||||
this._setColorCode(base + ';5;' + code)
|
||||
return this.cursor
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `cursor.fg.rgb(r, g, b)`.
|
||||
*/
|
||||
|
||||
Cursor.prototype.rgb = function (r, g, b) {
|
||||
return this.foreground.rgb(r, g, b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts CSS color codes for use with ANSI escape codes.
|
||||
* For example: `#FF000` would be bright red.
|
||||
*/
|
||||
|
||||
Colorer.prototype.hex = function (color) {
|
||||
return this.rgb.apply(this, hex(color))
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `cursor.fg.hex(color)`.
|
||||
*/
|
||||
|
||||
Cursor.prototype.hex = function (color) {
|
||||
return this.foreground.hex(color)
|
||||
}
|
||||
|
||||
|
||||
// UTIL FUNCTIONS //
|
||||
|
||||
/**
|
||||
* Translates a 255 RGB value to a 0-5 ANSI RGV value,
|
||||
* then returns the single ANSI color code to use.
|
||||
*/
|
||||
|
||||
function rgb (r, g, b) {
|
||||
var red = r / 255 * 5
|
||||
, green = g / 255 * 5
|
||||
, blue = b / 255 * 5
|
||||
return rgb5(red, green, blue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns rgb 0-5 values into a single ANSI color code to use.
|
||||
*/
|
||||
|
||||
function rgb5 (r, g, b) {
|
||||
var red = Math.round(r)
|
||||
, green = Math.round(g)
|
||||
, blue = Math.round(b)
|
||||
return 16 + (red*36) + (green*6) + blue
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a hex CSS color code string (# is optional) and
|
||||
* translates it into an Array of 3 RGB 0-255 values, which
|
||||
* can then be used with rgb().
|
||||
*/
|
||||
|
||||
function hex (color) {
|
||||
var c = color[0] === '#' ? color.substring(1) : color
|
||||
, r = c.substring(0, 2)
|
||||
, g = c.substring(2, 4)
|
||||
, b = c.substring(4, 6)
|
||||
return [parseInt(r, 16), parseInt(g, 16), parseInt(b, 16)]
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns an array-like object into a real array.
|
||||
*/
|
||||
|
||||
function toArray (a) {
|
||||
var i = 0
|
||||
, l = a.length
|
||||
, rtn = []
|
||||
for (; i<l; i++) {
|
||||
rtn.push(a[i])
|
||||
}
|
||||
return rtn
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
|
||||
/**
|
||||
* Accepts any node Stream instance and hijacks its "write()" function,
|
||||
* so that it can count any newlines that get written to the output.
|
||||
*
|
||||
* When a '\n' byte is encountered, then a "newline" event will be emitted
|
||||
* on the stream, with no arguments. It is up to the listeners to determine
|
||||
* any necessary deltas required for their use-case.
|
||||
*
|
||||
* Ex:
|
||||
*
|
||||
* var cursor = ansi(process.stdout)
|
||||
* , ln = 0
|
||||
* process.stdout.on('newline', function () {
|
||||
* ln++
|
||||
* })
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var assert = require('assert')
|
||||
var NEWLINE = '\n'.charCodeAt(0)
|
||||
|
||||
function emitNewlineEvents (stream) {
|
||||
if (stream._emittingNewlines) {
|
||||
// already emitting newline events
|
||||
return
|
||||
}
|
||||
|
||||
var write = stream.write
|
||||
|
||||
stream.write = function (data) {
|
||||
// first write the data
|
||||
var rtn = write.apply(stream, arguments)
|
||||
|
||||
if (stream.listeners('newline').length > 0) {
|
||||
var len = data.length
|
||||
, i = 0
|
||||
// now try to calculate any deltas
|
||||
if (typeof data == 'string') {
|
||||
for (; i<len; i++) {
|
||||
processByte(stream, data.charCodeAt(i))
|
||||
}
|
||||
} else {
|
||||
// buffer
|
||||
for (; i<len; i++) {
|
||||
processByte(stream, data[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rtn
|
||||
}
|
||||
|
||||
stream._emittingNewlines = true
|
||||
}
|
||||
module.exports = emitNewlineEvents
|
||||
|
||||
|
||||
/**
|
||||
* Processes an individual byte being written to a stream
|
||||
*/
|
||||
|
||||
function processByte (stream, b) {
|
||||
assert.equal(typeof b, 'number')
|
||||
if (b === NEWLINE) {
|
||||
stream.emit('newline')
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "ansi",
|
||||
"description": "Advanced ANSI formatting tool for Node.js",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"ansi",
|
||||
"formatting",
|
||||
"cursor",
|
||||
"color",
|
||||
"terminal",
|
||||
"rgb",
|
||||
"256",
|
||||
"stream"
|
||||
],
|
||||
"version": "0.3.1",
|
||||
"author": "Nathan Rajlich <nathan@tootallnate.net> (http://tootallnate.net)",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/TooTallNate/ansi.js.git"
|
||||
},
|
||||
"main": "./lib/ansi.js"
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
tidelift: "npm/balanced-match"
|
||||
patreon: juliangruber
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
(MIT)
|
||||
|
||||
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
# balanced-match
|
||||
|
||||
Match balanced string pairs, like `{` and `}` or `<b>` and `</b>`. Supports regular expressions as well!
|
||||
|
||||
[](http://travis-ci.org/juliangruber/balanced-match)
|
||||
[](https://www.npmjs.org/package/balanced-match)
|
||||
|
||||
[](https://ci.testling.com/juliangruber/balanced-match)
|
||||
|
||||
## Example
|
||||
|
||||
Get the first matching pair of braces:
|
||||
|
||||
```js
|
||||
var balanced = require('balanced-match');
|
||||
|
||||
console.log(balanced('{', '}', 'pre{in{nested}}post'));
|
||||
console.log(balanced('{', '}', 'pre{first}between{second}post'));
|
||||
console.log(balanced(/\s+\{\s+/, /\s+\}\s+/, 'pre { in{nest} } post'));
|
||||
```
|
||||
|
||||
The matches are:
|
||||
|
||||
```bash
|
||||
$ node example.js
|
||||
{ start: 3, end: 14, pre: 'pre', body: 'in{nested}', post: 'post' }
|
||||
{ start: 3,
|
||||
end: 9,
|
||||
pre: 'pre',
|
||||
body: 'first',
|
||||
post: 'between{second}post' }
|
||||
{ start: 3, end: 17, pre: 'pre', body: 'in{nest}', post: 'post' }
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### var m = balanced(a, b, str)
|
||||
|
||||
For the first non-nested matching pair of `a` and `b` in `str`, return an
|
||||
object with those keys:
|
||||
|
||||
* **start** the index of the first match of `a`
|
||||
* **end** the index of the matching `b`
|
||||
* **pre** the preamble, `a` and `b` not included
|
||||
* **body** the match, `a` and `b` not included
|
||||
* **post** the postscript, `a` and `b` not included
|
||||
|
||||
If there's no match, `undefined` will be returned.
|
||||
|
||||
If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `['{', 'a', '']` and `{a}}` will match `['', 'a', '}']`.
|
||||
|
||||
### var r = balanced.range(a, b, str)
|
||||
|
||||
For the first non-nested matching pair of `a` and `b` in `str`, return an
|
||||
array with indexes: `[ <a index>, <b index> ]`.
|
||||
|
||||
If there's no match, `undefined` will be returned.
|
||||
|
||||
If the `str` contains more `a` than `b` / there are unmatched pairs, the first match that was closed will be used. For example, `{{a}` will match `[ 1, 3 ]` and `{a}}` will match `[0, 2]`.
|
||||
|
||||
## Installation
|
||||
|
||||
With [npm](https://npmjs.org) do:
|
||||
|
||||
```bash
|
||||
npm install balanced-match
|
||||
```
|
||||
|
||||
## Security contact information
|
||||
|
||||
To report a security vulnerability, please use the
|
||||
[Tidelift security contact](https://tidelift.com/security).
|
||||
Tidelift will coordinate the fix and disclosure.
|
||||
|
||||
## License
|
||||
|
||||
(MIT)
|
||||
|
||||
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
module.exports = balanced;
|
||||
function balanced(a, b, str) {
|
||||
if (a instanceof RegExp) a = maybeMatch(a, str);
|
||||
if (b instanceof RegExp) b = maybeMatch(b, str);
|
||||
|
||||
var r = range(a, b, str);
|
||||
|
||||
return r && {
|
||||
start: r[0],
|
||||
end: r[1],
|
||||
pre: str.slice(0, r[0]),
|
||||
body: str.slice(r[0] + a.length, r[1]),
|
||||
post: str.slice(r[1] + b.length)
|
||||
};
|
||||
}
|
||||
|
||||
function maybeMatch(reg, str) {
|
||||
var m = str.match(reg);
|
||||
return m ? m[0] : null;
|
||||
}
|
||||
|
||||
balanced.range = range;
|
||||
function range(a, b, str) {
|
||||
var begs, beg, left, right, result;
|
||||
var ai = str.indexOf(a);
|
||||
var bi = str.indexOf(b, ai + 1);
|
||||
var i = ai;
|
||||
|
||||
if (ai >= 0 && bi > 0) {
|
||||
if(a===b) {
|
||||
return [ai, bi];
|
||||
}
|
||||
begs = [];
|
||||
left = str.length;
|
||||
|
||||
while (i >= 0 && !result) {
|
||||
if (i == ai) {
|
||||
begs.push(i);
|
||||
ai = str.indexOf(a, i + 1);
|
||||
} else if (begs.length == 1) {
|
||||
result = [ begs.pop(), bi ];
|
||||
} else {
|
||||
beg = begs.pop();
|
||||
if (beg < left) {
|
||||
left = beg;
|
||||
right = bi;
|
||||
}
|
||||
|
||||
bi = str.indexOf(b, i + 1);
|
||||
}
|
||||
|
||||
i = ai < bi && ai >= 0 ? ai : bi;
|
||||
}
|
||||
|
||||
if (begs.length) {
|
||||
result = [ left, right ];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "balanced-match",
|
||||
"description": "Match balanced character pairs, like \"{\" and \"}\"",
|
||||
"version": "1.0.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/juliangruber/balanced-match.git"
|
||||
},
|
||||
"homepage": "https://github.com/juliangruber/balanced-match",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "tape test/test.js",
|
||||
"bench": "matcha test/bench.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"matcha": "^0.7.0",
|
||||
"tape": "^4.6.0"
|
||||
},
|
||||
"keywords": [
|
||||
"match",
|
||||
"regexp",
|
||||
"test",
|
||||
"balanced",
|
||||
"parse"
|
||||
],
|
||||
"author": {
|
||||
"name": "Julian Gruber",
|
||||
"email": "mail@juliangruber.com",
|
||||
"url": "http://juliangruber.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"testling": {
|
||||
"files": "test/*.js",
|
||||
"browsers": [
|
||||
"ie/8..latest",
|
||||
"firefox/20..latest",
|
||||
"firefox/nightly",
|
||||
"chrome/25..latest",
|
||||
"chrome/canary",
|
||||
"opera/12..latest",
|
||||
"opera/next",
|
||||
"safari/5.1..latest",
|
||||
"ipad/6.0..latest",
|
||||
"iphone/6.0..latest",
|
||||
"android-browser/4.2..latest"
|
||||
]
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Jameson Little
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
base64-js
|
||||
=========
|
||||
|
||||
`base64-js` does basic base64 encoding/decoding in pure JS.
|
||||
|
||||
[](http://travis-ci.org/beatgammit/base64-js)
|
||||
|
||||
Many browsers already have base64 encoding/decoding functionality, but it is for text data, not all-purpose binary data.
|
||||
|
||||
Sometimes encoding/decoding binary data in the browser is useful, and that is what this module does.
|
||||
|
||||
## install
|
||||
|
||||
With [npm](https://npmjs.org) do:
|
||||
|
||||
`npm install base64-js` and `var base64js = require('base64-js')`
|
||||
|
||||
For use in web browsers do:
|
||||
|
||||
`<script src="base64js.min.js"></script>`
|
||||
|
||||
[Get supported base64-js with the Tidelift Subscription](https://tidelift.com/subscription/pkg/npm-base64-js?utm_source=npm-base64-js&utm_medium=referral&utm_campaign=readme)
|
||||
|
||||
## methods
|
||||
|
||||
`base64js` has three exposed functions, `byteLength`, `toByteArray` and `fromByteArray`, which both take a single argument.
|
||||
|
||||
* `byteLength` - Takes a base64 string and returns length of byte array
|
||||
* `toByteArray` - Takes a base64 string and returns a byte array
|
||||
* `fromByteArray` - Takes a byte array and returns a base64 string
|
||||
|
||||
## license
|
||||
|
||||
MIT
|
||||
+1
@@ -0,0 +1 @@
|
||||
(function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"==typeof window?"undefined"==typeof global?"undefined"==typeof self?this:self:global:window,b.base64js=a()}})(function(){return function(){function b(d,e,g){function a(j,i){if(!e[j]){if(!d[j]){var f="function"==typeof require&&require;if(!i&&f)return f(j,!0);if(h)return h(j,!0);var c=new Error("Cannot find module '"+j+"'");throw c.code="MODULE_NOT_FOUND",c}var k=e[j]={exports:{}};d[j][0].call(k.exports,function(b){var c=d[j][1][b];return a(c||b)},k,k.exports,b,d,e,g)}return e[j].exports}for(var h="function"==typeof require&&require,c=0;c<g.length;c++)a(g[c]);return a}return b}()({"/":[function(a,b,c){'use strict';function d(a){var b=a.length;if(0<b%4)throw new Error("Invalid string. Length must be a multiple of 4");var c=a.indexOf("=");-1===c&&(c=b);var d=c===b?0:4-c%4;return[c,d]}function e(a,b,c){return 3*(b+c)/4-c}function f(a){var b,c,f=d(a),g=f[0],h=f[1],j=new m(e(a,g,h)),k=0,n=0<h?g-4:g;for(c=0;c<n;c+=4)b=l[a.charCodeAt(c)]<<18|l[a.charCodeAt(c+1)]<<12|l[a.charCodeAt(c+2)]<<6|l[a.charCodeAt(c+3)],j[k++]=255&b>>16,j[k++]=255&b>>8,j[k++]=255&b;return 2===h&&(b=l[a.charCodeAt(c)]<<2|l[a.charCodeAt(c+1)]>>4,j[k++]=255&b),1===h&&(b=l[a.charCodeAt(c)]<<10|l[a.charCodeAt(c+1)]<<4|l[a.charCodeAt(c+2)]>>2,j[k++]=255&b>>8,j[k++]=255&b),j}function g(a){return k[63&a>>18]+k[63&a>>12]+k[63&a>>6]+k[63&a]}function h(a,b,c){for(var d,e=[],f=b;f<c;f+=3)d=(16711680&a[f]<<16)+(65280&a[f+1]<<8)+(255&a[f+2]),e.push(g(d));return e.join("")}function j(a){for(var b,c=a.length,d=c%3,e=[],f=16383,g=0,j=c-d;g<j;g+=f)e.push(h(a,g,g+f>j?j:g+f));return 1===d?(b=a[c-1],e.push(k[b>>2]+k[63&b<<4]+"==")):2===d&&(b=(a[c-2]<<8)+a[c-1],e.push(k[b>>10]+k[63&b>>4]+k[63&b<<2]+"=")),e.join("")}c.byteLength=function(a){var b=d(a),c=b[0],e=b[1];return 3*(c+e)/4-e},c.toByteArray=f,c.fromByteArray=j;for(var k=[],l=[],m="undefined"==typeof Uint8Array?Array:Uint8Array,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=0,p=n.length;o<p;++o)k[o]=n[o],l[n.charCodeAt(o)]=o;l[45]=62,l[95]=63},{}]},{},[])("/")});
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
export function byteLength(b64: string): number;
|
||||
export function toByteArray(b64: string): Uint8Array;
|
||||
export function fromByteArray(uint8: Uint8Array): string;
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
'use strict'
|
||||
|
||||
exports.byteLength = byteLength
|
||||
exports.toByteArray = toByteArray
|
||||
exports.fromByteArray = fromByteArray
|
||||
|
||||
var lookup = []
|
||||
var revLookup = []
|
||||
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
|
||||
|
||||
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
for (var i = 0, len = code.length; i < len; ++i) {
|
||||
lookup[i] = code[i]
|
||||
revLookup[code.charCodeAt(i)] = i
|
||||
}
|
||||
|
||||
// Support decoding URL-safe base64 strings, as Node.js does.
|
||||
// See: https://en.wikipedia.org/wiki/Base64#URL_applications
|
||||
revLookup['-'.charCodeAt(0)] = 62
|
||||
revLookup['_'.charCodeAt(0)] = 63
|
||||
|
||||
function getLens (b64) {
|
||||
var len = b64.length
|
||||
|
||||
if (len % 4 > 0) {
|
||||
throw new Error('Invalid string. Length must be a multiple of 4')
|
||||
}
|
||||
|
||||
// Trim off extra bytes after placeholder bytes are found
|
||||
// See: https://github.com/beatgammit/base64-js/issues/42
|
||||
var validLen = b64.indexOf('=')
|
||||
if (validLen === -1) validLen = len
|
||||
|
||||
var placeHoldersLen = validLen === len
|
||||
? 0
|
||||
: 4 - (validLen % 4)
|
||||
|
||||
return [validLen, placeHoldersLen]
|
||||
}
|
||||
|
||||
// base64 is 4/3 + up to two characters of the original data
|
||||
function byteLength (b64) {
|
||||
var lens = getLens(b64)
|
||||
var validLen = lens[0]
|
||||
var placeHoldersLen = lens[1]
|
||||
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
|
||||
}
|
||||
|
||||
function _byteLength (b64, validLen, placeHoldersLen) {
|
||||
return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
|
||||
}
|
||||
|
||||
function toByteArray (b64) {
|
||||
var tmp
|
||||
var lens = getLens(b64)
|
||||
var validLen = lens[0]
|
||||
var placeHoldersLen = lens[1]
|
||||
|
||||
var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
|
||||
|
||||
var curByte = 0
|
||||
|
||||
// if there are placeholders, only get up to the last complete 4 chars
|
||||
var len = placeHoldersLen > 0
|
||||
? validLen - 4
|
||||
: validLen
|
||||
|
||||
var i
|
||||
for (i = 0; i < len; i += 4) {
|
||||
tmp =
|
||||
(revLookup[b64.charCodeAt(i)] << 18) |
|
||||
(revLookup[b64.charCodeAt(i + 1)] << 12) |
|
||||
(revLookup[b64.charCodeAt(i + 2)] << 6) |
|
||||
revLookup[b64.charCodeAt(i + 3)]
|
||||
arr[curByte++] = (tmp >> 16) & 0xFF
|
||||
arr[curByte++] = (tmp >> 8) & 0xFF
|
||||
arr[curByte++] = tmp & 0xFF
|
||||
}
|
||||
|
||||
if (placeHoldersLen === 2) {
|
||||
tmp =
|
||||
(revLookup[b64.charCodeAt(i)] << 2) |
|
||||
(revLookup[b64.charCodeAt(i + 1)] >> 4)
|
||||
arr[curByte++] = tmp & 0xFF
|
||||
}
|
||||
|
||||
if (placeHoldersLen === 1) {
|
||||
tmp =
|
||||
(revLookup[b64.charCodeAt(i)] << 10) |
|
||||
(revLookup[b64.charCodeAt(i + 1)] << 4) |
|
||||
(revLookup[b64.charCodeAt(i + 2)] >> 2)
|
||||
arr[curByte++] = (tmp >> 8) & 0xFF
|
||||
arr[curByte++] = tmp & 0xFF
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
|
||||
function tripletToBase64 (num) {
|
||||
return lookup[num >> 18 & 0x3F] +
|
||||
lookup[num >> 12 & 0x3F] +
|
||||
lookup[num >> 6 & 0x3F] +
|
||||
lookup[num & 0x3F]
|
||||
}
|
||||
|
||||
function encodeChunk (uint8, start, end) {
|
||||
var tmp
|
||||
var output = []
|
||||
for (var i = start; i < end; i += 3) {
|
||||
tmp =
|
||||
((uint8[i] << 16) & 0xFF0000) +
|
||||
((uint8[i + 1] << 8) & 0xFF00) +
|
||||
(uint8[i + 2] & 0xFF)
|
||||
output.push(tripletToBase64(tmp))
|
||||
}
|
||||
return output.join('')
|
||||
}
|
||||
|
||||
function fromByteArray (uint8) {
|
||||
var tmp
|
||||
var len = uint8.length
|
||||
var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
|
||||
var parts = []
|
||||
var maxChunkLength = 16383 // must be multiple of 3
|
||||
|
||||
// go through the array every three bytes, we'll deal with trailing stuff later
|
||||
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
|
||||
parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
|
||||
}
|
||||
|
||||
// pad the end with zeros, but make sure to not forget the extra bytes
|
||||
if (extraBytes === 1) {
|
||||
tmp = uint8[len - 1]
|
||||
parts.push(
|
||||
lookup[tmp >> 2] +
|
||||
lookup[(tmp << 4) & 0x3F] +
|
||||
'=='
|
||||
)
|
||||
} else if (extraBytes === 2) {
|
||||
tmp = (uint8[len - 2] << 8) + uint8[len - 1]
|
||||
parts.push(
|
||||
lookup[tmp >> 10] +
|
||||
lookup[(tmp >> 4) & 0x3F] +
|
||||
lookup[(tmp << 2) & 0x3F] +
|
||||
'='
|
||||
)
|
||||
}
|
||||
|
||||
return parts.join('')
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "base64-js",
|
||||
"description": "Base64 encoding/decoding in pure JS",
|
||||
"version": "1.5.1",
|
||||
"author": "T. Jameson Little <t.jameson.little@gmail.com>",
|
||||
"typings": "index.d.ts",
|
||||
"bugs": {
|
||||
"url": "https://github.com/beatgammit/base64-js/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-minify": "^0.5.1",
|
||||
"benchmark": "^2.1.4",
|
||||
"browserify": "^16.3.0",
|
||||
"standard": "*",
|
||||
"tape": "4.x"
|
||||
},
|
||||
"homepage": "https://github.com/beatgammit/base64-js",
|
||||
"keywords": [
|
||||
"base64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/beatgammit/base64-js.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "browserify -s base64js -r ./ | minify > base64js.min.js",
|
||||
"lint": "standard",
|
||||
"test": "npm run lint && npm run unit",
|
||||
"unit": "tape test/*.js"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
}
|
||||
+2393
File diff suppressed because it is too large
Load Diff
+1453
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
+24
@@ -0,0 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
+589
@@ -0,0 +1,589 @@
|
||||
# BigInteger.js [![Build Status][travis-img]][travis-url] [![Coverage Status][coveralls-img]][coveralls-url] [![Monthly Downloads][downloads-img]][downloads-url]
|
||||
|
||||
[travis-url]: https://travis-ci.org/peterolson/BigInteger.js
|
||||
[travis-img]: https://travis-ci.org/peterolson/BigInteger.js.svg?branch=master
|
||||
[coveralls-url]: https://coveralls.io/github/peterolson/BigInteger.js?branch=master
|
||||
[coveralls-img]: https://coveralls.io/repos/peterolson/BigInteger.js/badge.svg?branch=master&service=github
|
||||
[downloads-url]: https://www.npmjs.com/package/big-integer
|
||||
[downloads-img]: https://img.shields.io/npm/dm/big-integer.svg
|
||||
|
||||
**BigInteger.js** is an arbitrary-length integer library for Javascript, allowing arithmetic operations on integers of unlimited size, notwithstanding memory and time limitations.
|
||||
|
||||
**Update (December 2, 2018):** [`BigInt` is being added as a native feature of JavaScript](https://tc39.github.io/proposal-bigint/). This library now works as a polyfill: if the environment supports the native `BigInt`, this library acts as a thin wrapper over the native implementation.
|
||||
|
||||
## Installation
|
||||
|
||||
If you are using a browser, you can download [BigInteger.js from GitHub](http://peterolson.github.com/BigInteger.js/BigInteger.min.js) or just hotlink to it:
|
||||
|
||||
<script src="https://peterolson.github.io/BigInteger.js/BigInteger.min.js"></script>
|
||||
|
||||
If you are using node, you can install BigInteger with [npm](https://npmjs.org/).
|
||||
|
||||
npm install big-integer
|
||||
|
||||
Then you can include it in your code:
|
||||
|
||||
var bigInt = require("big-integer");
|
||||
|
||||
|
||||
## Usage
|
||||
### `bigInt(number, [base], [alphabet], [caseSensitive])`
|
||||
|
||||
You can create a bigInt by calling the `bigInt` function. You can pass in
|
||||
|
||||
- a string, which it will parse as an bigInt and throw an `"Invalid integer"` error if the parsing fails.
|
||||
- a Javascript number, which it will parse as an bigInt and throw an `"Invalid integer"` error if the parsing fails.
|
||||
- another bigInt.
|
||||
- nothing, and it will return `bigInt.zero`.
|
||||
|
||||
If you provide a second parameter, then it will parse `number` as a number in base `base`. Note that `base` can be any bigInt (even negative or zero). The letters "a-z" and "A-Z" will be interpreted as the numbers 10 to 35. Higher digits can be specified in angle brackets (`<` and `>`). The default `base` is `10`.
|
||||
|
||||
You can specify a custom alphabet for base conversion with the third parameter. The default `alphabet` is `"0123456789abcdefghijklmnopqrstuvwxyz"`.
|
||||
|
||||
The fourth parameter specifies whether or not the number string should be case-sensitive, i.e. whether `a` and `A` should be treated as different digits. By default `caseSensitive` is `false`.
|
||||
|
||||
Examples:
|
||||
|
||||
var zero = bigInt();
|
||||
var ninetyThree = bigInt(93);
|
||||
var largeNumber = bigInt("75643564363473453456342378564387956906736546456235345");
|
||||
var googol = bigInt("1e100");
|
||||
var bigNumber = bigInt(largeNumber);
|
||||
|
||||
var maximumByte = bigInt("FF", 16);
|
||||
var fiftyFiveGoogol = bigInt("<55>0", googol);
|
||||
|
||||
Note that Javascript numbers larger than `9007199254740992` and smaller than `-9007199254740992` are not precisely represented numbers and will not produce exact results. If you are dealing with numbers outside that range, it is better to pass in strings.
|
||||
|
||||
### Method Chaining
|
||||
|
||||
Note that bigInt operations return bigInts, which allows you to chain methods, for example:
|
||||
|
||||
var salary = bigInt(dollarsPerHour).times(hoursWorked).plus(randomBonuses)
|
||||
|
||||
### Constants
|
||||
|
||||
There are three named constants already stored that you do not have to construct with the `bigInt` function yourself:
|
||||
|
||||
- `bigInt.one`, equivalent to `bigInt(1)`
|
||||
- `bigInt.zero`, equivalent to `bigInt(0)`
|
||||
- `bigInt.minusOne`, equivalent to `bigInt(-1)`
|
||||
|
||||
The numbers from -999 to 999 are also already prestored and can be accessed using `bigInt[index]`, for example:
|
||||
|
||||
- `bigInt[-999]`, equivalent to `bigInt(-999)`
|
||||
- `bigInt[256]`, equivalent to `bigInt(256)`
|
||||
|
||||
### Methods
|
||||
|
||||
#### `abs()`
|
||||
|
||||
Returns the absolute value of a bigInt.
|
||||
|
||||
- `bigInt(-45).abs()` => `45`
|
||||
- `bigInt(45).abs()` => `45`
|
||||
|
||||
#### `add(number)`
|
||||
|
||||
Performs addition.
|
||||
|
||||
- `bigInt(5).add(7)` => `12`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Addition)
|
||||
|
||||
#### `and(number)`
|
||||
|
||||
Performs the bitwise AND operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement).
|
||||
|
||||
- `bigInt(6).and(3)` => `2`
|
||||
- `bigInt(6).and(-3)` => `4`
|
||||
|
||||
#### `bitLength()`
|
||||
|
||||
Returns the number of digits required to represent a bigInt in binary.
|
||||
|
||||
- `bigInt(5)` => `3` (since 5 is `101` in binary, which is three digits long)
|
||||
|
||||
#### `compare(number)`
|
||||
|
||||
Performs a comparison between two numbers. If the numbers are equal, it returns `0`. If the first number is greater, it returns `1`. If the first number is lesser, it returns `-1`.
|
||||
|
||||
- `bigInt(5).compare(5)` => `0`
|
||||
- `bigInt(5).compare(4)` => `1`
|
||||
- `bigInt(4).compare(5)` => `-1`
|
||||
|
||||
#### `compareAbs(number)`
|
||||
|
||||
Performs a comparison between the absolute value of two numbers.
|
||||
|
||||
- `bigInt(5).compareAbs(-5)` => `0`
|
||||
- `bigInt(5).compareAbs(4)` => `1`
|
||||
- `bigInt(4).compareAbs(-5)` => `-1`
|
||||
|
||||
#### `compareTo(number)`
|
||||
|
||||
Alias for the `compare` method.
|
||||
|
||||
#### `divide(number)`
|
||||
|
||||
Performs integer division, disregarding the remainder.
|
||||
|
||||
- `bigInt(59).divide(5)` => `11`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division)
|
||||
|
||||
#### `divmod(number)`
|
||||
|
||||
Performs division and returns an object with two properties: `quotient` and `remainder`. The sign of the remainder will match the sign of the dividend.
|
||||
|
||||
- `bigInt(59).divmod(5)` => `{quotient: bigInt(11), remainder: bigInt(4) }`
|
||||
- `bigInt(-5).divmod(2)` => `{quotient: bigInt(-2), remainder: bigInt(-1) }`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division)
|
||||
|
||||
#### `eq(number)`
|
||||
|
||||
Alias for the `equals` method.
|
||||
|
||||
#### `equals(number)`
|
||||
|
||||
Checks if two numbers are equal.
|
||||
|
||||
- `bigInt(5).equals(5)` => `true`
|
||||
- `bigInt(4).equals(7)` => `false`
|
||||
|
||||
#### `geq(number)`
|
||||
|
||||
Alias for the `greaterOrEquals` method.
|
||||
|
||||
|
||||
#### `greater(number)`
|
||||
|
||||
Checks if the first number is greater than the second.
|
||||
|
||||
- `bigInt(5).greater(6)` => `false`
|
||||
- `bigInt(5).greater(5)` => `false`
|
||||
- `bigInt(5).greater(4)` => `true`
|
||||
|
||||
#### `greaterOrEquals(number)`
|
||||
|
||||
Checks if the first number is greater than or equal to the second.
|
||||
|
||||
- `bigInt(5).greaterOrEquals(6)` => `false`
|
||||
- `bigInt(5).greaterOrEquals(5)` => `true`
|
||||
- `bigInt(5).greaterOrEquals(4)` => `true`
|
||||
|
||||
#### `gt(number)`
|
||||
|
||||
Alias for the `greater` method.
|
||||
|
||||
#### `isDivisibleBy(number)`
|
||||
|
||||
Returns `true` if the first number is divisible by the second number, `false` otherwise.
|
||||
|
||||
- `bigInt(999).isDivisibleBy(333)` => `true`
|
||||
- `bigInt(99).isDivisibleBy(5)` => `false`
|
||||
|
||||
#### `isEven()`
|
||||
|
||||
Returns `true` if the number is even, `false` otherwise.
|
||||
|
||||
- `bigInt(6).isEven()` => `true`
|
||||
- `bigInt(3).isEven()` => `false`
|
||||
|
||||
#### `isNegative()`
|
||||
|
||||
Returns `true` if the number is negative, `false` otherwise.
|
||||
Returns `false` for `0` and `-0`.
|
||||
|
||||
- `bigInt(-23).isNegative()` => `true`
|
||||
- `bigInt(50).isNegative()` => `false`
|
||||
|
||||
#### `isOdd()`
|
||||
|
||||
Returns `true` if the number is odd, `false` otherwise.
|
||||
|
||||
- `bigInt(13).isOdd()` => `true`
|
||||
- `bigInt(40).isOdd()` => `false`
|
||||
|
||||
#### `isPositive()`
|
||||
|
||||
Return `true` if the number is positive, `false` otherwise.
|
||||
Returns `false` for `0` and `-0`.
|
||||
|
||||
- `bigInt(54).isPositive()` => `true`
|
||||
- `bigInt(-1).isPositive()` => `false`
|
||||
|
||||
#### `isPrime(strict?)`
|
||||
|
||||
Returns `true` if the number is prime, `false` otherwise.
|
||||
Set "strict" boolean to true to force GRH-supported lower bound of 2*log(N)^2.
|
||||
|
||||
- `bigInt(5).isPrime()` => `true`
|
||||
- `bigInt(6).isPrime()` => `false`
|
||||
|
||||
#### `isProbablePrime([iterations], [rng])`
|
||||
|
||||
Returns `true` if the number is very likely to be prime, `false` otherwise.
|
||||
Supplying `iterations` is optional - it determines the number of iterations of the test (default: `5`). The more iterations, the lower chance of getting a false positive.
|
||||
This uses the [Miller Rabin test](https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test).
|
||||
|
||||
- `bigInt(5).isProbablePrime()` => `true`
|
||||
- `bigInt(49).isProbablePrime()` => `false`
|
||||
- `bigInt(1729).isProbablePrime()` => `false`
|
||||
|
||||
Note that this function is not deterministic, since it relies on random sampling of factors, so the result for some numbers is not always the same - unless you pass a predictable random number generator as `rng`. The behavior and requirements are the same as with `randBetween`.
|
||||
|
||||
- `bigInt(1729).isProbablePrime(1, () => 0.1)` => `false`
|
||||
- `bigInt(1729).isProbablePrime(1, () => 0.2)` => `true`
|
||||
|
||||
If the number is composite then the Miller–Rabin primality test declares the number probably prime with a probability at most `4` to the power `−iterations`.
|
||||
If the number is prime, this function always returns `true`.
|
||||
|
||||
#### `isUnit()`
|
||||
|
||||
Returns `true` if the number is `1` or `-1`, `false` otherwise.
|
||||
|
||||
- `bigInt.one.isUnit()` => `true`
|
||||
- `bigInt.minusOne.isUnit()` => `true`
|
||||
- `bigInt(5).isUnit()` => `false`
|
||||
|
||||
#### `isZero()`
|
||||
|
||||
Return `true` if the number is `0` or `-0`, `false` otherwise.
|
||||
|
||||
- `bigInt.zero.isZero()` => `true`
|
||||
- `bigInt("-0").isZero()` => `true`
|
||||
- `bigInt(50).isZero()` => `false`
|
||||
|
||||
#### `leq(number)`
|
||||
|
||||
Alias for the `lesserOrEquals` method.
|
||||
|
||||
#### `lesser(number)`
|
||||
|
||||
Checks if the first number is lesser than the second.
|
||||
|
||||
- `bigInt(5).lesser(6)` => `true`
|
||||
- `bigInt(5).lesser(5)` => `false`
|
||||
- `bigInt(5).lesser(4)` => `false`
|
||||
|
||||
#### `lesserOrEquals(number)`
|
||||
|
||||
Checks if the first number is less than or equal to the second.
|
||||
|
||||
- `bigInt(5).lesserOrEquals(6)` => `true`
|
||||
- `bigInt(5).lesserOrEquals(5)` => `true`
|
||||
- `bigInt(5).lesserOrEquals(4)` => `false`
|
||||
|
||||
#### `lt(number)`
|
||||
|
||||
Alias for the `lesser` method.
|
||||
|
||||
#### `minus(number)`
|
||||
|
||||
Alias for the `subtract` method.
|
||||
|
||||
- `bigInt(3).minus(5)` => `-2`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Subtraction)
|
||||
|
||||
#### `mod(number)`
|
||||
|
||||
Performs division and returns the remainder, disregarding the quotient. The sign of the remainder will match the sign of the dividend.
|
||||
|
||||
- `bigInt(59).mod(5)` => `4`
|
||||
- `bigInt(-5).mod(2)` => `-1`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division)
|
||||
|
||||
#### `modInv(mod)`
|
||||
|
||||
Finds the [multiplicative inverse](https://en.wikipedia.org/wiki/Modular_multiplicative_inverse) of the number modulo `mod`.
|
||||
|
||||
- `bigInt(3).modInv(11)` => `4`
|
||||
- `bigInt(42).modInv(2017)` => `1969`
|
||||
|
||||
#### `modPow(exp, mod)`
|
||||
|
||||
Takes the number to the power `exp` modulo `mod`.
|
||||
|
||||
- `bigInt(10).modPow(3, 30)` => `10`
|
||||
|
||||
#### `multiply(number)`
|
||||
|
||||
Performs multiplication.
|
||||
|
||||
- `bigInt(111).multiply(111)` => `12321`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Multiplication)
|
||||
|
||||
#### `neq(number)`
|
||||
|
||||
Alias for the `notEquals` method.
|
||||
|
||||
#### `next()`
|
||||
|
||||
Adds one to the number.
|
||||
|
||||
- `bigInt(6).next()` => `7`
|
||||
|
||||
#### `not()`
|
||||
|
||||
Performs the bitwise NOT operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement).
|
||||
|
||||
- `bigInt(10).not()` => `-11`
|
||||
- `bigInt(0).not()` => `-1`
|
||||
|
||||
#### `notEquals(number)`
|
||||
|
||||
Checks if two numbers are not equal.
|
||||
|
||||
- `bigInt(5).notEquals(5)` => `false`
|
||||
- `bigInt(4).notEquals(7)` => `true`
|
||||
|
||||
#### `or(number)`
|
||||
|
||||
Performs the bitwise OR operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement).
|
||||
|
||||
- `bigInt(13).or(10)` => `15`
|
||||
- `bigInt(13).or(-8)` => `-3`
|
||||
|
||||
#### `over(number)`
|
||||
|
||||
Alias for the `divide` method.
|
||||
|
||||
- `bigInt(59).over(5)` => `11`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division)
|
||||
|
||||
#### `plus(number)`
|
||||
|
||||
Alias for the `add` method.
|
||||
|
||||
- `bigInt(5).plus(7)` => `12`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Addition)
|
||||
|
||||
#### `pow(number)`
|
||||
|
||||
Performs exponentiation. If the exponent is less than `0`, `pow` returns `0`. `bigInt.zero.pow(0)` returns `1`.
|
||||
|
||||
- `bigInt(16).pow(16)` => `18446744073709551616`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Exponentiation)
|
||||
|
||||
#### `prev(number)`
|
||||
|
||||
Subtracts one from the number.
|
||||
|
||||
- `bigInt(6).prev()` => `5`
|
||||
|
||||
#### `remainder(number)`
|
||||
|
||||
Alias for the `mod` method.
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Division)
|
||||
|
||||
#### `shiftLeft(n)`
|
||||
|
||||
Shifts the number left by `n` places in its binary representation. If a negative number is provided, it will shift right. Throws an error if `n` is outside of the range `[-9007199254740992, 9007199254740992]`.
|
||||
|
||||
- `bigInt(8).shiftLeft(2)` => `32`
|
||||
- `bigInt(8).shiftLeft(-2)` => `2`
|
||||
|
||||
#### `shiftRight(n)`
|
||||
|
||||
Shifts the number right by `n` places in its binary representation. If a negative number is provided, it will shift left. Throws an error if `n` is outside of the range `[-9007199254740992, 9007199254740992]`.
|
||||
|
||||
- `bigInt(8).shiftRight(2)` => `2`
|
||||
- `bigInt(8).shiftRight(-2)` => `32`
|
||||
|
||||
#### `square()`
|
||||
|
||||
Squares the number
|
||||
|
||||
- `bigInt(3).square()` => `9`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Squaring)
|
||||
|
||||
#### `subtract(number)`
|
||||
|
||||
Performs subtraction.
|
||||
|
||||
- `bigInt(3).subtract(5)` => `-2`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Subtraction)
|
||||
|
||||
#### `times(number)`
|
||||
|
||||
Alias for the `multiply` method.
|
||||
|
||||
- `bigInt(111).times(111)` => `12321`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#Multiplication)
|
||||
|
||||
#### `toArray(radix)`
|
||||
|
||||
Converts a bigInt into an object with the properties "value" and "isNegative." "Value" is an array of integers modulo the given radix. "isNegative" is a boolean that represents the sign of the result.
|
||||
|
||||
- `bigInt("1e9").toArray(10)` => {
|
||||
value: [1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
isNegative: false
|
||||
}
|
||||
- `bigInt("1e9").toArray(16)` => {
|
||||
value: [3, 11, 9, 10, 12, 10, 0, 0],
|
||||
isNegative: false
|
||||
}
|
||||
- `bigInt(567890).toArray(100)` => {
|
||||
value: [56, 78, 90],
|
||||
isNegative: false
|
||||
}
|
||||
|
||||
Negative bases are supported.
|
||||
|
||||
- `bigInt(12345).toArray(-10)` => {
|
||||
value: [2, 8, 4, 6, 5],
|
||||
isNegative: false
|
||||
}
|
||||
|
||||
Base 1 and base -1 are also supported.
|
||||
|
||||
- `bigInt(-15).toArray(1)` => {
|
||||
value: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
|
||||
isNegative: true
|
||||
}
|
||||
- `bigInt(-15).toArray(-1)` => {
|
||||
value: [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
|
||||
isNegative: false
|
||||
}
|
||||
|
||||
Base 0 is only allowed for the number zero.
|
||||
|
||||
- `bigInt(0).toArray(0)` => {
|
||||
value: [0],
|
||||
isNegative: false
|
||||
}
|
||||
- `bigInt(1).toArray(0)` => `Error: Cannot convert nonzero numbers to base 0.`
|
||||
|
||||
#### `toJSNumber()`
|
||||
|
||||
Converts a bigInt into a native Javascript number. Loses precision for numbers outside the range `[-9007199254740992, 9007199254740992]`.
|
||||
|
||||
- `bigInt("18446744073709551616").toJSNumber()` => `18446744073709552000`
|
||||
|
||||
#### `xor(number)`
|
||||
|
||||
Performs the bitwise XOR operation. The operands are treated as if they were represented using [two's complement representation](http://en.wikipedia.org/wiki/Two%27s_complement).
|
||||
|
||||
- `bigInt(12).xor(5)` => `9`
|
||||
- `bigInt(12).xor(-5)` => `-9`
|
||||
|
||||
### Static Methods
|
||||
|
||||
#### `fromArray(digits, base = 10, isNegative?)`
|
||||
|
||||
Constructs a bigInt from an array of digits in base `base`. The optional `isNegative` flag will make the number negative.
|
||||
|
||||
- `bigInt.fromArray([1, 2, 3, 4, 5], 10)` => `12345`
|
||||
- `bigInt.fromArray([1, 0, 0], 2, true)` => `-4`
|
||||
|
||||
#### `gcd(a, b)`
|
||||
|
||||
Finds the greatest common denominator of `a` and `b`.
|
||||
|
||||
- `bigInt.gcd(42,56)` => `14`
|
||||
|
||||
#### `isInstance(x)`
|
||||
|
||||
Returns `true` if `x` is a BigInteger, `false` otherwise.
|
||||
|
||||
- `bigInt.isInstance(bigInt(14))` => `true`
|
||||
- `bigInt.isInstance(14)` => `false`
|
||||
|
||||
#### `lcm(a,b)`
|
||||
|
||||
Finds the least common multiple of `a` and `b`.
|
||||
|
||||
- `bigInt.lcm(21, 6)` => `42`
|
||||
|
||||
#### `max(a,b)`
|
||||
|
||||
Returns the largest of `a` and `b`.
|
||||
|
||||
- `bigInt.max(77, 432)` => `432`
|
||||
|
||||
#### `min(a,b)`
|
||||
|
||||
Returns the smallest of `a` and `b`.
|
||||
|
||||
- `bigInt.min(77, 432)` => `77`
|
||||
|
||||
#### `randBetween(min, max, [rng])`
|
||||
|
||||
Returns a random number between `min` and `max`, optionally using `rng` to generate randomness.
|
||||
|
||||
- `bigInt.randBetween("-1e100", "1e100")` => (for example) `8494907165436643479673097939554427056789510374838494147955756275846226209006506706784609314471378745`
|
||||
|
||||
`rng` should take no arguments and return a `number` between 0 and 1. It defaults to `Math.random`.
|
||||
|
||||
- `bigInt.randBetween("-1e100", "1e100", () => 0.5)` => (always) `50000005000000500000050000005000000500000050000005000000500000050000005000000500000050000005000000`
|
||||
|
||||
|
||||
### Override Methods
|
||||
|
||||
#### `toString(radix = 10, [alphabet])`
|
||||
|
||||
Converts a bigInt to a string. There is an optional radix parameter (which defaults to 10) that converts the number to the given radix. Digits in the range `10-35` will use the letters `a-z`.
|
||||
|
||||
- `bigInt("1e9").toString()` => `"1000000000"`
|
||||
- `bigInt("1e9").toString(16)` => `"3b9aca00"`
|
||||
|
||||
You can use a custom base alphabet with the second parameter. The default `alphabet` is `"0123456789abcdefghijklmnopqrstuvwxyz"`.
|
||||
|
||||
- `bigInt("5").toString(2, "aA")` => `"AaA"`
|
||||
|
||||
**Note that arithmetical operators will trigger the `valueOf` function rather than the `toString` function.** When converting a bigInteger to a string, you should use the `toString` method or the `String` function instead of adding the empty string.
|
||||
|
||||
- `bigInt("999999999999999999").toString()` => `"999999999999999999"`
|
||||
- `String(bigInt("999999999999999999"))` => `"999999999999999999"`
|
||||
- `bigInt("999999999999999999") + ""` => `1000000000000000000`
|
||||
|
||||
Bases larger than 36 are supported. If a digit is greater than or equal to 36, it will be enclosed in angle brackets.
|
||||
|
||||
- `bigInt(567890).toString(100)` => `"<56><78><90>"`
|
||||
|
||||
Negative bases are also supported.
|
||||
|
||||
- `bigInt(12345).toString(-10)` => `"28465"`
|
||||
|
||||
Base 1 and base -1 are also supported.
|
||||
|
||||
- `bigInt(-15).toString(1)` => `"-111111111111111"`
|
||||
- `bigInt(-15).toString(-1)` => `"101010101010101010101010101010"`
|
||||
|
||||
Base 0 is only allowed for the number zero.
|
||||
|
||||
- `bigInt(0).toString(0)` => `0`
|
||||
- `bigInt(1).toString(0)` => `Error: Cannot convert nonzero numbers to base 0.`
|
||||
|
||||
[View benchmarks for this method](http://peterolson.github.io/BigInteger.js/benchmark/#toString)
|
||||
|
||||
#### `valueOf()`
|
||||
|
||||
Converts a bigInt to a native Javascript number. This override allows you to use native arithmetic operators without explicit conversion:
|
||||
|
||||
- `bigInt("100") + bigInt("200") === 300; //true`
|
||||
|
||||
## Contributors
|
||||
|
||||
To contribute, just fork the project, make some changes, and submit a pull request. Please verify that the unit tests pass before submitting.
|
||||
|
||||
The unit tests are contained in the `spec/spec.js` file. You can run them locally by opening the `spec/SpecRunner.html` or file or running `npm test`. You can also [run the tests online from GitHub](http://peterolson.github.io/BigInteger.js/spec/SpecRunner.html).
|
||||
|
||||
There are performance benchmarks that can be viewed from the `benchmarks/index.html` page. You can [run them online from GitHub](http://peterolson.github.io/BigInteger.js/benchmark/).
|
||||
|
||||
## License
|
||||
|
||||
This project is public domain. For more details, read about the [Unlicense](http://unlicense.org/).
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "big-integer",
|
||||
"description": "An arbitrary length integer library for Javascript",
|
||||
"main": "./BigInteger.js",
|
||||
"authors": [
|
||||
"Peter Olson"
|
||||
],
|
||||
"license": "Unlicense",
|
||||
"keywords": [
|
||||
"math",
|
||||
"big",
|
||||
"bignum",
|
||||
"bigint",
|
||||
"biginteger",
|
||||
"integer",
|
||||
"arbitrary",
|
||||
"precision",
|
||||
"arithmetic"
|
||||
],
|
||||
"homepage": "https://github.com/peterolson/BigInteger.js",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"coverage",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "big-integer",
|
||||
"version": "1.6.52",
|
||||
"author": "Peter Olson <peter.e.c.olson+npm@gmail.com>",
|
||||
"description": "An arbitrary length integer library for Javascript",
|
||||
"contributors": [],
|
||||
"bin": {},
|
||||
"scripts": {
|
||||
"test": "tsc && karma start my.conf.js && node spec/tsDefinitions.js",
|
||||
"minify": "uglifyjs BigInteger.js -o BigInteger.min.js"
|
||||
},
|
||||
"main": "./BigInteger",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:peterolson/BigInteger.js.git"
|
||||
},
|
||||
"keywords": [
|
||||
"math",
|
||||
"big",
|
||||
"bignum",
|
||||
"bigint",
|
||||
"biginteger",
|
||||
"integer",
|
||||
"arbitrary",
|
||||
"precision",
|
||||
"arithmetic"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.175",
|
||||
"@types/node": "^7.10.2",
|
||||
"coveralls": "^3.0.6",
|
||||
"jasmine": "3.5.0",
|
||||
"jasmine-core": "^3.5.0",
|
||||
"karma": "^6.3.4",
|
||||
"karma-cli": "^2.0.0",
|
||||
"karma-coverage": "^2.0.3",
|
||||
"karma-jasmine": "^4.0.1",
|
||||
"karma-phantomjs-launcher": "^1.0.4",
|
||||
"lodash": "^4.17.21",
|
||||
"typescript": "^5.3.2",
|
||||
"uglify-js": "^3.17.4"
|
||||
},
|
||||
"license": "Unlicense",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"typings": "./BigInteger.d.ts"
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "commonjs",
|
||||
"lib": [
|
||||
"es6"
|
||||
],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": false,
|
||||
"baseUrl": "./",
|
||||
"moduleResolution": "node",
|
||||
"allowJs": true,
|
||||
"typeRoots": [
|
||||
"./"
|
||||
],
|
||||
"types": [],
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": [
|
||||
"BigInteger.d.ts",
|
||||
"spec/tsDefinitions.ts"
|
||||
]
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
/build/*
|
||||
node_modules
|
||||
*.node
|
||||
*.sh
|
||||
*.swp
|
||||
.lock*
|
||||
npm-debug.log
|
||||
.idea
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
bplist-parser
|
||||
=============
|
||||
|
||||
Binary Mac OS X Plist (property list) parser.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install bplist-parser
|
||||
```
|
||||
|
||||
## Quick Examples
|
||||
|
||||
```javascript
|
||||
var bplist = require('bplist-parser');
|
||||
|
||||
bplist.parseFile('myPlist.bplist', function(err, obj) {
|
||||
if (err) throw err;
|
||||
|
||||
console.log(JSON.stringify(obj));
|
||||
});
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2012 Near Infinity Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
'use strict';
|
||||
|
||||
// adapted from http://code.google.com/p/plist/source/browse/trunk/src/com/dd/plist/BinaryPropertyListParser.java
|
||||
|
||||
var fs = require('fs');
|
||||
var bigInt = require("big-integer");
|
||||
var debug = false;
|
||||
|
||||
exports.maxObjectSize = 100 * 1000 * 1000; // 100Meg
|
||||
exports.maxObjectCount = 32768;
|
||||
|
||||
// EPOCH = new SimpleDateFormat("yyyy MM dd zzz").parse("2001 01 01 GMT").getTime();
|
||||
// ...but that's annoying in a static initializer because it can throw exceptions, ick.
|
||||
// So we just hardcode the correct value.
|
||||
var EPOCH = 978307200000;
|
||||
|
||||
// UID object definition
|
||||
var UID = exports.UID = function(id) {
|
||||
this.UID = id;
|
||||
}
|
||||
|
||||
var parseFile = exports.parseFile = function (fileNameOrBuffer, callback) {
|
||||
function tryParseBuffer(buffer) {
|
||||
var err = null;
|
||||
var result;
|
||||
try {
|
||||
result = parseBuffer(buffer);
|
||||
} catch (ex) {
|
||||
err = ex;
|
||||
}
|
||||
callback(err, result);
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(fileNameOrBuffer)) {
|
||||
return tryParseBuffer(fileNameOrBuffer);
|
||||
} else {
|
||||
fs.readFile(fileNameOrBuffer, function (err, data) {
|
||||
if (err) { return callback(err); }
|
||||
tryParseBuffer(data);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var parseBuffer = exports.parseBuffer = function (buffer) {
|
||||
var result = {};
|
||||
|
||||
// check header
|
||||
var header = buffer.slice(0, 'bplist'.length).toString('utf8');
|
||||
if (header !== 'bplist') {
|
||||
throw new Error("Invalid binary plist. Expected 'bplist' at offset 0.");
|
||||
}
|
||||
|
||||
// Handle trailer, last 32 bytes of the file
|
||||
var trailer = buffer.slice(buffer.length - 32, buffer.length);
|
||||
// 6 null bytes (index 0 to 5)
|
||||
var offsetSize = trailer.readUInt8(6);
|
||||
if (debug) {
|
||||
console.log("offsetSize: " + offsetSize);
|
||||
}
|
||||
var objectRefSize = trailer.readUInt8(7);
|
||||
if (debug) {
|
||||
console.log("objectRefSize: " + objectRefSize);
|
||||
}
|
||||
var numObjects = readUInt64BE(trailer, 8);
|
||||
if (debug) {
|
||||
console.log("numObjects: " + numObjects);
|
||||
}
|
||||
var topObject = readUInt64BE(trailer, 16);
|
||||
if (debug) {
|
||||
console.log("topObject: " + topObject);
|
||||
}
|
||||
var offsetTableOffset = readUInt64BE(trailer, 24);
|
||||
if (debug) {
|
||||
console.log("offsetTableOffset: " + offsetTableOffset);
|
||||
}
|
||||
|
||||
if (numObjects > exports.maxObjectCount) {
|
||||
throw new Error("maxObjectCount exceeded");
|
||||
}
|
||||
|
||||
// Handle offset table
|
||||
var offsetTable = [];
|
||||
|
||||
for (var i = 0; i < numObjects; i++) {
|
||||
var offsetBytes = buffer.slice(offsetTableOffset + i * offsetSize, offsetTableOffset + (i + 1) * offsetSize);
|
||||
offsetTable[i] = readUInt(offsetBytes, 0);
|
||||
if (debug) {
|
||||
console.log("Offset for Object #" + i + " is " + offsetTable[i] + " [" + offsetTable[i].toString(16) + "]");
|
||||
}
|
||||
}
|
||||
|
||||
// Parses an object inside the currently parsed binary property list.
|
||||
// For the format specification check
|
||||
// <a href="http://www.opensource.apple.com/source/CF/CF-635/CFBinaryPList.c">
|
||||
// Apple's binary property list parser implementation</a>.
|
||||
function parseObject(tableOffset) {
|
||||
var offset = offsetTable[tableOffset];
|
||||
var type = buffer[offset];
|
||||
var objType = (type & 0xF0) >> 4; //First 4 bits
|
||||
var objInfo = (type & 0x0F); //Second 4 bits
|
||||
switch (objType) {
|
||||
case 0x0:
|
||||
return parseSimple();
|
||||
case 0x1:
|
||||
return parseInteger();
|
||||
case 0x8:
|
||||
return parseUID();
|
||||
case 0x2:
|
||||
return parseReal();
|
||||
case 0x3:
|
||||
return parseDate();
|
||||
case 0x4:
|
||||
return parseData();
|
||||
case 0x5: // ASCII
|
||||
return parsePlistString();
|
||||
case 0x6: // UTF-16
|
||||
return parsePlistString(true);
|
||||
case 0xA:
|
||||
return parseArray();
|
||||
case 0xD:
|
||||
return parseDictionary();
|
||||
default:
|
||||
throw new Error("Unhandled type 0x" + objType.toString(16));
|
||||
}
|
||||
|
||||
function parseSimple() {
|
||||
//Simple
|
||||
switch (objInfo) {
|
||||
case 0x0: // null
|
||||
return null;
|
||||
case 0x8: // false
|
||||
return false;
|
||||
case 0x9: // true
|
||||
return true;
|
||||
case 0xF: // filler byte
|
||||
return null;
|
||||
default:
|
||||
throw new Error("Unhandled simple type 0x" + objType.toString(16));
|
||||
}
|
||||
}
|
||||
|
||||
function bufferToHexString(buffer) {
|
||||
var str = '';
|
||||
var i;
|
||||
for (i = 0; i < buffer.length; i++) {
|
||||
if (buffer[i] != 0x00) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (; i < buffer.length; i++) {
|
||||
var part = '00' + buffer[i].toString(16);
|
||||
str += part.substr(part.length - 2);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function parseInteger() {
|
||||
var length = Math.pow(2, objInfo);
|
||||
if (length > 4) {
|
||||
var data = buffer.slice(offset + 1, offset + 1 + length);
|
||||
var str = bufferToHexString(data);
|
||||
return bigInt(str, 16);
|
||||
} if (length < exports.maxObjectSize) {
|
||||
return readUInt(buffer.slice(offset + 1, offset + 1 + length));
|
||||
} else {
|
||||
throw new Error("To little heap space available! Wanted to read " + length + " bytes, but only " + exports.maxObjectSize + " are available.");
|
||||
}
|
||||
}
|
||||
|
||||
function parseUID() {
|
||||
var length = objInfo + 1;
|
||||
if (length < exports.maxObjectSize) {
|
||||
return new UID(readUInt(buffer.slice(offset + 1, offset + 1 + length)));
|
||||
} else {
|
||||
throw new Error("To little heap space available! Wanted to read " + length + " bytes, but only " + exports.maxObjectSize + " are available.");
|
||||
}
|
||||
}
|
||||
|
||||
function parseReal() {
|
||||
var length = Math.pow(2, objInfo);
|
||||
if (length < exports.maxObjectSize) {
|
||||
var realBuffer = buffer.slice(offset + 1, offset + 1 + length);
|
||||
if (length === 4) {
|
||||
return realBuffer.readFloatBE(0);
|
||||
}
|
||||
else if (length === 8) {
|
||||
return realBuffer.readDoubleBE(0);
|
||||
}
|
||||
} else {
|
||||
throw new Error("To little heap space available! Wanted to read " + length + " bytes, but only " + exports.maxObjectSize + " are available.");
|
||||
}
|
||||
}
|
||||
|
||||
function parseDate() {
|
||||
if (objInfo != 0x3) {
|
||||
console.error("Unknown date type :" + objInfo + ". Parsing anyway...");
|
||||
}
|
||||
var dateBuffer = buffer.slice(offset + 1, offset + 9);
|
||||
return new Date(EPOCH + (1000 * dateBuffer.readDoubleBE(0)));
|
||||
}
|
||||
|
||||
function parseData() {
|
||||
var dataoffset = 1;
|
||||
var length = objInfo;
|
||||
if (objInfo == 0xF) {
|
||||
var int_type = buffer[offset + 1];
|
||||
var intType = (int_type & 0xF0) / 0x10;
|
||||
if (intType != 0x1) {
|
||||
console.error("0x4: UNEXPECTED LENGTH-INT TYPE! " + intType);
|
||||
}
|
||||
var intInfo = int_type & 0x0F;
|
||||
var intLength = Math.pow(2, intInfo);
|
||||
dataoffset = 2 + intLength;
|
||||
if (intLength < 3) {
|
||||
length = readUInt(buffer.slice(offset + 2, offset + 2 + intLength));
|
||||
} else {
|
||||
length = readUInt(buffer.slice(offset + 2, offset + 2 + intLength));
|
||||
}
|
||||
}
|
||||
if (length < exports.maxObjectSize) {
|
||||
return buffer.slice(offset + dataoffset, offset + dataoffset + length);
|
||||
} else {
|
||||
throw new Error("To little heap space available! Wanted to read " + length + " bytes, but only " + exports.maxObjectSize + " are available.");
|
||||
}
|
||||
}
|
||||
|
||||
function parsePlistString (isUtf16) {
|
||||
isUtf16 = isUtf16 || 0;
|
||||
var enc = "utf8";
|
||||
var length = objInfo;
|
||||
var stroffset = 1;
|
||||
if (objInfo == 0xF) {
|
||||
var int_type = buffer[offset + 1];
|
||||
var intType = (int_type & 0xF0) / 0x10;
|
||||
if (intType != 0x1) {
|
||||
console.err("UNEXPECTED LENGTH-INT TYPE! " + intType);
|
||||
}
|
||||
var intInfo = int_type & 0x0F;
|
||||
var intLength = Math.pow(2, intInfo);
|
||||
var stroffset = 2 + intLength;
|
||||
if (intLength < 3) {
|
||||
length = readUInt(buffer.slice(offset + 2, offset + 2 + intLength));
|
||||
} else {
|
||||
length = readUInt(buffer.slice(offset + 2, offset + 2 + intLength));
|
||||
}
|
||||
}
|
||||
// length is String length -> to get byte length multiply by 2, as 1 character takes 2 bytes in UTF-16
|
||||
length *= (isUtf16 + 1);
|
||||
if (length < exports.maxObjectSize) {
|
||||
var plistString = new Buffer(buffer.slice(offset + stroffset, offset + stroffset + length));
|
||||
if (isUtf16) {
|
||||
plistString = swapBytes(plistString);
|
||||
enc = "ucs2";
|
||||
}
|
||||
return plistString.toString(enc);
|
||||
} else {
|
||||
throw new Error("To little heap space available! Wanted to read " + length + " bytes, but only " + exports.maxObjectSize + " are available.");
|
||||
}
|
||||
}
|
||||
|
||||
function parseArray() {
|
||||
var length = objInfo;
|
||||
var arrayoffset = 1;
|
||||
if (objInfo == 0xF) {
|
||||
var int_type = buffer[offset + 1];
|
||||
var intType = (int_type & 0xF0) / 0x10;
|
||||
if (intType != 0x1) {
|
||||
console.error("0xa: UNEXPECTED LENGTH-INT TYPE! " + intType);
|
||||
}
|
||||
var intInfo = int_type & 0x0F;
|
||||
var intLength = Math.pow(2, intInfo);
|
||||
arrayoffset = 2 + intLength;
|
||||
if (intLength < 3) {
|
||||
length = readUInt(buffer.slice(offset + 2, offset + 2 + intLength));
|
||||
} else {
|
||||
length = readUInt(buffer.slice(offset + 2, offset + 2 + intLength));
|
||||
}
|
||||
}
|
||||
if (length * objectRefSize > exports.maxObjectSize) {
|
||||
throw new Error("To little heap space available!");
|
||||
}
|
||||
var array = [];
|
||||
for (var i = 0; i < length; i++) {
|
||||
var objRef = readUInt(buffer.slice(offset + arrayoffset + i * objectRefSize, offset + arrayoffset + (i + 1) * objectRefSize));
|
||||
array[i] = parseObject(objRef);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
function parseDictionary() {
|
||||
var length = objInfo;
|
||||
var dictoffset = 1;
|
||||
if (objInfo == 0xF) {
|
||||
var int_type = buffer[offset + 1];
|
||||
var intType = (int_type & 0xF0) / 0x10;
|
||||
if (intType != 0x1) {
|
||||
console.error("0xD: UNEXPECTED LENGTH-INT TYPE! " + intType);
|
||||
}
|
||||
var intInfo = int_type & 0x0F;
|
||||
var intLength = Math.pow(2, intInfo);
|
||||
dictoffset = 2 + intLength;
|
||||
if (intLength < 3) {
|
||||
length = readUInt(buffer.slice(offset + 2, offset + 2 + intLength));
|
||||
} else {
|
||||
length = readUInt(buffer.slice(offset + 2, offset + 2 + intLength));
|
||||
}
|
||||
}
|
||||
if (length * 2 * objectRefSize > exports.maxObjectSize) {
|
||||
throw new Error("To little heap space available!");
|
||||
}
|
||||
if (debug) {
|
||||
console.log("Parsing dictionary #" + tableOffset);
|
||||
}
|
||||
var dict = {};
|
||||
for (var i = 0; i < length; i++) {
|
||||
var keyRef = readUInt(buffer.slice(offset + dictoffset + i * objectRefSize, offset + dictoffset + (i + 1) * objectRefSize));
|
||||
var valRef = readUInt(buffer.slice(offset + dictoffset + (length * objectRefSize) + i * objectRefSize, offset + dictoffset + (length * objectRefSize) + (i + 1) * objectRefSize));
|
||||
var key = parseObject(keyRef);
|
||||
var val = parseObject(valRef);
|
||||
if (debug) {
|
||||
console.log(" DICT #" + tableOffset + ": Mapped " + key + " to " + val);
|
||||
}
|
||||
dict[key] = val;
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
|
||||
return [ parseObject(topObject) ];
|
||||
};
|
||||
|
||||
function readUInt(buffer, start) {
|
||||
start = start || 0;
|
||||
|
||||
var l = 0;
|
||||
for (var i = start; i < buffer.length; i++) {
|
||||
l <<= 8;
|
||||
l |= buffer[i] & 0xFF;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
// we're just going to toss the high order bits because javascript doesn't have 64-bit ints
|
||||
function readUInt64BE(buffer, start) {
|
||||
var data = buffer.slice(start, start + 8);
|
||||
return data.readUInt32BE(4, 8);
|
||||
}
|
||||
|
||||
function swapBytes(buffer) {
|
||||
var len = buffer.length;
|
||||
for (var i = 0; i < len; i += 2) {
|
||||
var a = buffer[i];
|
||||
buffer[i] = buffer[i+1];
|
||||
buffer[i+1] = a;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "bplist-parser",
|
||||
"version": "0.1.1",
|
||||
"description": "Binary plist parser.",
|
||||
"main": "bplistParser.js",
|
||||
"scripts": {
|
||||
"test": "./node_modules/nodeunit/bin/nodeunit test"
|
||||
},
|
||||
"keywords": [
|
||||
"bplist",
|
||||
"plist",
|
||||
"parser"
|
||||
],
|
||||
"author": "Joe Ferner <joe.ferner@nearinfinity.com>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"nodeunit": "~0.9.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nearinfinity/node-bplist-parser.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"big-integer": "^1.6.7"
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>zero</key>
|
||||
<integer>0</integer>
|
||||
<key>int64item</key>
|
||||
<integer>12345678901234567890</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
'use strict';
|
||||
|
||||
// tests are adapted from https://github.com/TooTallNate/node-plist
|
||||
|
||||
var path = require('path');
|
||||
var nodeunit = require('nodeunit');
|
||||
var bplist = require('../');
|
||||
|
||||
module.exports = {
|
||||
'iTunes Small': function (test) {
|
||||
var file = path.join(__dirname, "iTunes-small.bplist");
|
||||
var startTime1 = new Date();
|
||||
|
||||
bplist.parseFile(file, function (err, dicts) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var endTime = new Date();
|
||||
console.log('Parsed "' + file + '" in ' + (endTime - startTime1) + 'ms');
|
||||
var dict = dicts[0];
|
||||
test.equal(dict['Application Version'], "9.0.3");
|
||||
test.equal(dict['Library Persistent ID'], "6F81D37F95101437");
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
|
||||
'sample1': function (test) {
|
||||
var file = path.join(__dirname, "sample1.bplist");
|
||||
var startTime = new Date();
|
||||
|
||||
bplist.parseFile(file, function (err, dicts) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var endTime = new Date();
|
||||
console.log('Parsed "' + file + '" in ' + (endTime - startTime) + 'ms');
|
||||
var dict = dicts[0];
|
||||
test.equal(dict['CFBundleIdentifier'], 'com.apple.dictionary.MySample');
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
|
||||
'sample2': function (test) {
|
||||
var file = path.join(__dirname, "sample2.bplist");
|
||||
var startTime = new Date();
|
||||
|
||||
bplist.parseFile(file, function (err, dicts) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var endTime = new Date();
|
||||
console.log('Parsed "' + file + '" in ' + (endTime - startTime) + 'ms');
|
||||
var dict = dicts[0];
|
||||
test.equal(dict['PopupMenu'][2]['Key'], "\n #import <Cocoa/Cocoa.h>\n\n#import <MacRuby/MacRuby.h>\n\nint main(int argc, char *argv[])\n{\n return macruby_main(\"rb_main.rb\", argc, argv);\n}\n");
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
|
||||
'airplay': function (test) {
|
||||
var file = path.join(__dirname, "airplay.bplist");
|
||||
var startTime = new Date();
|
||||
|
||||
bplist.parseFile(file, function (err, dicts) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var endTime = new Date();
|
||||
console.log('Parsed "' + file + '" in ' + (endTime - startTime) + 'ms');
|
||||
|
||||
var dict = dicts[0];
|
||||
test.equal(dict['duration'], 5555.0495000000001);
|
||||
test.equal(dict['position'], 4.6269989039999997);
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
|
||||
'utf16': function (test) {
|
||||
var file = path.join(__dirname, "utf16.bplist");
|
||||
var startTime = new Date();
|
||||
|
||||
bplist.parseFile(file, function (err, dicts) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var endTime = new Date();
|
||||
console.log('Parsed "' + file + '" in ' + (endTime - startTime) + 'ms');
|
||||
|
||||
var dict = dicts[0];
|
||||
test.equal(dict['CFBundleName'], 'sellStuff');
|
||||
test.equal(dict['CFBundleShortVersionString'], '2.6.1');
|
||||
test.equal(dict['NSHumanReadableCopyright'], '©2008-2012, sellStuff, Inc.');
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
|
||||
'utf16chinese': function (test) {
|
||||
var file = path.join(__dirname, "utf16_chinese.plist");
|
||||
var startTime = new Date();
|
||||
|
||||
bplist.parseFile(file, function (err, dicts) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var endTime = new Date();
|
||||
console.log('Parsed "' + file + '" in ' + (endTime - startTime) + 'ms');
|
||||
|
||||
var dict = dicts[0];
|
||||
test.equal(dict['CFBundleName'], '天翼阅读');
|
||||
test.equal(dict['CFBundleDisplayName'], '天翼阅读');
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
'uid': function (test) {
|
||||
var file = path.join(__dirname, "uid.bplist");
|
||||
var startTime = new Date();
|
||||
|
||||
bplist.parseFile(file, function (err, dicts) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var endTime = new Date();
|
||||
console.log('Parsed "' + file + '" in ' + (endTime - startTime) + 'ms');
|
||||
|
||||
var dict = dicts[0];
|
||||
test.deepEqual(dict['$objects'][1]['NS.keys'], [{UID:2}, {UID:3}, {UID:4}]);
|
||||
test.deepEqual(dict['$objects'][1]['NS.objects'], [{UID: 5}, {UID:6}, {UID:7}]);
|
||||
test.deepEqual(dict['$top']['root'], {UID:1});
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
|
||||
'int64': function (test) {
|
||||
var file = path.join(__dirname, "int64.bplist");
|
||||
var startTime = new Date();
|
||||
|
||||
bplist.parseFile(file, function (err, dicts) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var endTime = new Date();
|
||||
console.log('Parsed "' + file + '" in ' + (endTime - startTime) + 'ms');
|
||||
var dict = dicts[0];
|
||||
test.equal(dict['zero'], '0');
|
||||
test.equal(dict['int64item'], '12345678901234567890');
|
||||
test.done();
|
||||
});
|
||||
}
|
||||
};
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
# brace-expansion
|
||||
|
||||
[Brace expansion](https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html),
|
||||
as known from sh/bash, in JavaScript.
|
||||
|
||||
[](http://travis-ci.org/juliangruber/brace-expansion)
|
||||
[](https://www.npmjs.org/package/brace-expansion)
|
||||
[](https://greenkeeper.io/)
|
||||
|
||||
[](https://ci.testling.com/juliangruber/brace-expansion)
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
var expand = require('brace-expansion');
|
||||
|
||||
expand('file-{a,b,c}.jpg')
|
||||
// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
|
||||
|
||||
expand('-v{,,}')
|
||||
// => ['-v', '-v', '-v']
|
||||
|
||||
expand('file{0..2}.jpg')
|
||||
// => ['file0.jpg', 'file1.jpg', 'file2.jpg']
|
||||
|
||||
expand('file-{a..c}.jpg')
|
||||
// => ['file-a.jpg', 'file-b.jpg', 'file-c.jpg']
|
||||
|
||||
expand('file{2..0}.jpg')
|
||||
// => ['file2.jpg', 'file1.jpg', 'file0.jpg']
|
||||
|
||||
expand('file{0..4..2}.jpg')
|
||||
// => ['file0.jpg', 'file2.jpg', 'file4.jpg']
|
||||
|
||||
expand('file-{a..e..2}.jpg')
|
||||
// => ['file-a.jpg', 'file-c.jpg', 'file-e.jpg']
|
||||
|
||||
expand('file{00..10..5}.jpg')
|
||||
// => ['file00.jpg', 'file05.jpg', 'file10.jpg']
|
||||
|
||||
expand('{{A..C},{a..c}}')
|
||||
// => ['A', 'B', 'C', 'a', 'b', 'c']
|
||||
|
||||
expand('ppp{,config,oe{,conf}}')
|
||||
// => ['ppp', 'pppconfig', 'pppoe', 'pppoeconf']
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var expand = require('brace-expansion');
|
||||
```
|
||||
|
||||
### var expanded = expand(str)
|
||||
|
||||
Return an array of all possible and valid expansions of `str`. If none are
|
||||
found, `[str]` is returned.
|
||||
|
||||
Valid expansions are:
|
||||
|
||||
```js
|
||||
/^(.*,)+(.+)?$/
|
||||
// {a,b,...}
|
||||
```
|
||||
|
||||
A comma separated list of options, like `{a,b}` or `{a,{b,c}}` or `{,a,}`.
|
||||
|
||||
```js
|
||||
/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
|
||||
// {x..y[..incr]}
|
||||
```
|
||||
|
||||
A numeric sequence from `x` to `y` inclusive, with optional increment.
|
||||
If `x` or `y` start with a leading `0`, all the numbers will be padded
|
||||
to have equal length. Negative numbers and backwards iteration work too.
|
||||
|
||||
```js
|
||||
/^-?\d+\.\.-?\d+(\.\.-?\d+)?$/
|
||||
// {x..y[..incr]}
|
||||
```
|
||||
|
||||
An alphabetic sequence from `x` to `y` inclusive, with optional increment.
|
||||
`x` and `y` must be exactly one character, and if given, `incr` must be a
|
||||
number.
|
||||
|
||||
For compatibility reasons, the string `${` is not eligible for brace expansion.
|
||||
|
||||
## Installation
|
||||
|
||||
With [npm](https://npmjs.org) do:
|
||||
|
||||
```bash
|
||||
npm install brace-expansion
|
||||
```
|
||||
|
||||
## Contributors
|
||||
|
||||
- [Julian Gruber](https://github.com/juliangruber)
|
||||
- [Isaac Z. Schlueter](https://github.com/isaacs)
|
||||
|
||||
## Sponsors
|
||||
|
||||
This module is proudly supported by my [Sponsors](https://github.com/juliangruber/sponsors)!
|
||||
|
||||
Do you want to support modules like this to improve their quality, stability and weigh in on new features? Then please consider donating to my [Patreon](https://www.patreon.com/juliangruber). Not sure how much of my modules you're using? Try [feross/thanks](https://github.com/feross/thanks)!
|
||||
|
||||
## License
|
||||
|
||||
(MIT)
|
||||
|
||||
Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
var concatMap = require('concat-map');
|
||||
var balanced = require('balanced-match');
|
||||
|
||||
module.exports = expandTop;
|
||||
|
||||
var escSlash = '\0SLASH'+Math.random()+'\0';
|
||||
var escOpen = '\0OPEN'+Math.random()+'\0';
|
||||
var escClose = '\0CLOSE'+Math.random()+'\0';
|
||||
var escComma = '\0COMMA'+Math.random()+'\0';
|
||||
var escPeriod = '\0PERIOD'+Math.random()+'\0';
|
||||
|
||||
function numeric(str) {
|
||||
return parseInt(str, 10) == str
|
||||
? parseInt(str, 10)
|
||||
: str.charCodeAt(0);
|
||||
}
|
||||
|
||||
function escapeBraces(str) {
|
||||
return str.split('\\\\').join(escSlash)
|
||||
.split('\\{').join(escOpen)
|
||||
.split('\\}').join(escClose)
|
||||
.split('\\,').join(escComma)
|
||||
.split('\\.').join(escPeriod);
|
||||
}
|
||||
|
||||
function unescapeBraces(str) {
|
||||
return str.split(escSlash).join('\\')
|
||||
.split(escOpen).join('{')
|
||||
.split(escClose).join('}')
|
||||
.split(escComma).join(',')
|
||||
.split(escPeriod).join('.');
|
||||
}
|
||||
|
||||
|
||||
// Basically just str.split(","), but handling cases
|
||||
// where we have nested braced sections, which should be
|
||||
// treated as individual members, like {a,{b,c},d}
|
||||
function parseCommaParts(str) {
|
||||
if (!str)
|
||||
return [''];
|
||||
|
||||
var parts = [];
|
||||
var m = balanced('{', '}', str);
|
||||
|
||||
if (!m)
|
||||
return str.split(',');
|
||||
|
||||
var pre = m.pre;
|
||||
var body = m.body;
|
||||
var post = m.post;
|
||||
var p = pre.split(',');
|
||||
|
||||
p[p.length-1] += '{' + body + '}';
|
||||
var postParts = parseCommaParts(post);
|
||||
if (post.length) {
|
||||
p[p.length-1] += postParts.shift();
|
||||
p.push.apply(p, postParts);
|
||||
}
|
||||
|
||||
parts.push.apply(parts, p);
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
function expandTop(str) {
|
||||
if (!str)
|
||||
return [];
|
||||
|
||||
// I don't know why Bash 4.3 does this, but it does.
|
||||
// Anything starting with {} will have the first two bytes preserved
|
||||
// but *only* at the top level, so {},a}b will not expand to anything,
|
||||
// but a{},b}c will be expanded to [a}c,abc].
|
||||
// One could argue that this is a bug in Bash, but since the goal of
|
||||
// this module is to match Bash's rules, we escape a leading {}
|
||||
if (str.substr(0, 2) === '{}') {
|
||||
str = '\\{\\}' + str.substr(2);
|
||||
}
|
||||
|
||||
return expand(escapeBraces(str), true).map(unescapeBraces);
|
||||
}
|
||||
|
||||
function identity(e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
function embrace(str) {
|
||||
return '{' + str + '}';
|
||||
}
|
||||
function isPadded(el) {
|
||||
return /^-?0\d/.test(el);
|
||||
}
|
||||
|
||||
function lte(i, y) {
|
||||
return i <= y;
|
||||
}
|
||||
function gte(i, y) {
|
||||
return i >= y;
|
||||
}
|
||||
|
||||
function expand(str, isTop) {
|
||||
var expansions = [];
|
||||
|
||||
var m = balanced('{', '}', str);
|
||||
if (!m || /\$$/.test(m.pre)) return [str];
|
||||
|
||||
var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
||||
var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
||||
var isSequence = isNumericSequence || isAlphaSequence;
|
||||
var isOptions = m.body.indexOf(',') >= 0;
|
||||
if (!isSequence && !isOptions) {
|
||||
// {a},b}
|
||||
if (m.post.match(/,.*\}/)) {
|
||||
str = m.pre + '{' + m.body + escClose + m.post;
|
||||
return expand(str);
|
||||
}
|
||||
return [str];
|
||||
}
|
||||
|
||||
var n;
|
||||
if (isSequence) {
|
||||
n = m.body.split(/\.\./);
|
||||
} else {
|
||||
n = parseCommaParts(m.body);
|
||||
if (n.length === 1) {
|
||||
// x{{a,b}}y ==> x{a}y x{b}y
|
||||
n = expand(n[0], false).map(embrace);
|
||||
if (n.length === 1) {
|
||||
var post = m.post.length
|
||||
? expand(m.post, false)
|
||||
: [''];
|
||||
return post.map(function(p) {
|
||||
return m.pre + n[0] + p;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at this point, n is the parts, and we know it's not a comma set
|
||||
// with a single entry.
|
||||
|
||||
// no need to expand pre, since it is guaranteed to be free of brace-sets
|
||||
var pre = m.pre;
|
||||
var post = m.post.length
|
||||
? expand(m.post, false)
|
||||
: [''];
|
||||
|
||||
var N;
|
||||
|
||||
if (isSequence) {
|
||||
var x = numeric(n[0]);
|
||||
var y = numeric(n[1]);
|
||||
var width = Math.max(n[0].length, n[1].length)
|
||||
var incr = n.length == 3
|
||||
? Math.abs(numeric(n[2]))
|
||||
: 1;
|
||||
var test = lte;
|
||||
var reverse = y < x;
|
||||
if (reverse) {
|
||||
incr *= -1;
|
||||
test = gte;
|
||||
}
|
||||
var pad = n.some(isPadded);
|
||||
|
||||
N = [];
|
||||
|
||||
for (var i = x; test(i, y); i += incr) {
|
||||
var c;
|
||||
if (isAlphaSequence) {
|
||||
c = String.fromCharCode(i);
|
||||
if (c === '\\')
|
||||
c = '';
|
||||
} else {
|
||||
c = String(i);
|
||||
if (pad) {
|
||||
var need = width - c.length;
|
||||
if (need > 0) {
|
||||
var z = new Array(need + 1).join('0');
|
||||
if (i < 0)
|
||||
c = '-' + z + c.slice(1);
|
||||
else
|
||||
c = z + c;
|
||||
}
|
||||
}
|
||||
}
|
||||
N.push(c);
|
||||
}
|
||||
} else {
|
||||
N = concatMap(n, function(el) { return expand(el, false) });
|
||||
}
|
||||
|
||||
for (var j = 0; j < N.length; j++) {
|
||||
for (var k = 0; k < post.length; k++) {
|
||||
var expansion = pre + N[j] + post[k];
|
||||
if (!isTop || isSequence || expansion)
|
||||
expansions.push(expansion);
|
||||
}
|
||||
}
|
||||
|
||||
return expansions;
|
||||
}
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "brace-expansion",
|
||||
"description": "Brace expansion as known from sh/bash",
|
||||
"version": "1.1.11",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/juliangruber/brace-expansion.git"
|
||||
},
|
||||
"homepage": "https://github.com/juliangruber/brace-expansion",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "tape test/*.js",
|
||||
"gentest": "bash test/generate.sh",
|
||||
"bench": "matcha test/perf/bench.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"matcha": "^0.7.0",
|
||||
"tape": "^4.6.0"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": {
|
||||
"name": "Julian Gruber",
|
||||
"email": "mail@juliangruber.com",
|
||||
"url": "http://juliangruber.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"testling": {
|
||||
"files": "test/*.js",
|
||||
"browsers": [
|
||||
"ie/8..latest",
|
||||
"firefox/20..latest",
|
||||
"firefox/nightly",
|
||||
"chrome/25..latest",
|
||||
"chrome/canary",
|
||||
"opera/12..latest",
|
||||
"opera/next",
|
||||
"safari/5.1..latest",
|
||||
"ipad/6.0..latest",
|
||||
"iphone/6.0..latest",
|
||||
"android-browser/4.2..latest"
|
||||
]
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.4
|
||||
- 0.6
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
This software is released under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
concat-map
|
||||
==========
|
||||
|
||||
Concatenative mapdashery.
|
||||
|
||||
[](http://ci.testling.com/substack/node-concat-map)
|
||||
|
||||
[](http://travis-ci.org/substack/node-concat-map)
|
||||
|
||||
example
|
||||
=======
|
||||
|
||||
``` js
|
||||
var concatMap = require('concat-map');
|
||||
var xs = [ 1, 2, 3, 4, 5, 6 ];
|
||||
var ys = concatMap(xs, function (x) {
|
||||
return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
|
||||
});
|
||||
console.dir(ys);
|
||||
```
|
||||
|
||||
***
|
||||
|
||||
```
|
||||
[ 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1 ]
|
||||
```
|
||||
|
||||
methods
|
||||
=======
|
||||
|
||||
``` js
|
||||
var concatMap = require('concat-map')
|
||||
```
|
||||
|
||||
concatMap(xs, fn)
|
||||
-----------------
|
||||
|
||||
Return an array of concatenated elements by calling `fn(x, i)` for each element
|
||||
`x` and each index `i` in the array `xs`.
|
||||
|
||||
When `fn(x, i)` returns an array, its result will be concatenated with the
|
||||
result array. If `fn(x, i)` returns anything else, that value will be pushed
|
||||
onto the end of the result array.
|
||||
|
||||
install
|
||||
=======
|
||||
|
||||
With [npm](http://npmjs.org) do:
|
||||
|
||||
```
|
||||
npm install concat-map
|
||||
```
|
||||
|
||||
license
|
||||
=======
|
||||
|
||||
MIT
|
||||
|
||||
notes
|
||||
=====
|
||||
|
||||
This module was written while sitting high above the ground in a tree.
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
var concatMap = require('../');
|
||||
var xs = [ 1, 2, 3, 4, 5, 6 ];
|
||||
var ys = concatMap(xs, function (x) {
|
||||
return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
|
||||
});
|
||||
console.dir(ys);
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
module.exports = function (xs, fn) {
|
||||
var res = [];
|
||||
for (var i = 0; i < xs.length; i++) {
|
||||
var x = fn(xs[i], i);
|
||||
if (isArray(x)) res.push.apply(res, x);
|
||||
else res.push(x);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
var isArray = Array.isArray || function (xs) {
|
||||
return Object.prototype.toString.call(xs) === '[object Array]';
|
||||
};
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name" : "concat-map",
|
||||
"description" : "concatenative mapdashery",
|
||||
"version" : "0.0.1",
|
||||
"repository" : {
|
||||
"type" : "git",
|
||||
"url" : "git://github.com/substack/node-concat-map.git"
|
||||
},
|
||||
"main" : "index.js",
|
||||
"keywords" : [
|
||||
"concat",
|
||||
"concatMap",
|
||||
"map",
|
||||
"functional",
|
||||
"higher-order"
|
||||
],
|
||||
"directories" : {
|
||||
"example" : "example",
|
||||
"test" : "test"
|
||||
},
|
||||
"scripts" : {
|
||||
"test" : "tape test/*.js"
|
||||
},
|
||||
"devDependencies" : {
|
||||
"tape" : "~2.4.0"
|
||||
},
|
||||
"license" : "MIT",
|
||||
"author" : {
|
||||
"name" : "James Halliday",
|
||||
"email" : "mail@substack.net",
|
||||
"url" : "http://substack.net"
|
||||
},
|
||||
"testling" : {
|
||||
"files" : "test/*.js",
|
||||
"browsers" : {
|
||||
"ie" : [ 6, 7, 8, 9 ],
|
||||
"ff" : [ 3.5, 10, 15.0 ],
|
||||
"chrome" : [ 10, 22 ],
|
||||
"safari" : [ 5.1 ],
|
||||
"opera" : [ 12 ]
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
var concatMap = require('../');
|
||||
var test = require('tape');
|
||||
|
||||
test('empty or not', function (t) {
|
||||
var xs = [ 1, 2, 3, 4, 5, 6 ];
|
||||
var ixes = [];
|
||||
var ys = concatMap(xs, function (x, ix) {
|
||||
ixes.push(ix);
|
||||
return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
|
||||
});
|
||||
t.same(ys, [ 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1 ]);
|
||||
t.same(ixes, [ 0, 1, 2, 3, 4, 5 ]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('always something', function (t) {
|
||||
var xs = [ 'a', 'b', 'c', 'd' ];
|
||||
var ys = concatMap(xs, function (x) {
|
||||
return x === 'b' ? [ 'B', 'B', 'B' ] : [ x ];
|
||||
});
|
||||
t.same(ys, [ 'a', 'B', 'B', 'B', 'c', 'd' ]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('scalars', function (t) {
|
||||
var xs = [ 'a', 'b', 'c', 'd' ];
|
||||
var ys = concatMap(xs, function (x) {
|
||||
return x === 'b' ? [ 'B', 'B', 'B' ] : x;
|
||||
});
|
||||
t.same(ys, [ 'a', 'B', 'B', 'B', 'c', 'd' ]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('undefs', function (t) {
|
||||
var xs = [ 'a', 'b', 'c', 'd' ];
|
||||
var ys = concatMap(xs, function () {});
|
||||
t.same(ys, [ undefined, undefined, undefined, undefined ]);
|
||||
t.end();
|
||||
});
|
||||
+1
@@ -0,0 +1 @@
|
||||
spec/fixtures/*
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
root: true
|
||||
extends: semistandard
|
||||
rules:
|
||||
indent:
|
||||
- error
|
||||
- 4
|
||||
camelcase: off
|
||||
no-unused-vars:
|
||||
- error
|
||||
- args: after-used
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
<!--
|
||||
Please have a look at the issue templates you get when you click "New issue" in the GitHub UI.
|
||||
We very much prefer issues created by using one of these templates.
|
||||
-->
|
||||
|
||||
### Issue Type
|
||||
<!-- Please check the boxes by putting an x in the [ ] like so: [x] -->
|
||||
|
||||
- [ ] Bug Report
|
||||
- [ ] Feature Request
|
||||
- [ ] Support Question
|
||||
|
||||
## Description
|
||||
|
||||
## Information
|
||||
<!-- Include all relevant information that might help understand and reproduce the problem -->
|
||||
|
||||
### Command or Code
|
||||
<!-- What command or code is needed to reproduce the problem? -->
|
||||
|
||||
### Environment, Platform, Device
|
||||
<!-- In what environment, on what platform or on which device are you experiencing the issue? -->
|
||||
|
||||
|
||||
|
||||
### Version information
|
||||
<!--
|
||||
What are relevant versions you are using?
|
||||
For example:
|
||||
Cordova: Cordova CLI, Cordova Platforms, Cordova Plugins
|
||||
Other Frameworks: Ionic Framework and CLI version
|
||||
Operating System, Android Studio, Xcode etc.
|
||||
-->
|
||||
|
||||
|
||||
|
||||
## Checklist
|
||||
<!-- Please check the boxes by putting an `x` in the `[ ]` like so: `[x]` -->
|
||||
|
||||
- [ ] I searched for already existing GitHub issues about this
|
||||
- [ ] I updated all Cordova tooling to their most recent version
|
||||
- [ ] I included all the necessary information above
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
---
|
||||
name: 🐛 Bug Report
|
||||
about: If something isn't working as expected.
|
||||
|
||||
---
|
||||
|
||||
# Bug Report
|
||||
|
||||
## Problem
|
||||
|
||||
### What is expected to happen?
|
||||
|
||||
|
||||
|
||||
### What does actually happen?
|
||||
|
||||
|
||||
|
||||
## Information
|
||||
<!-- Include all relevant information that might help understand and reproduce the problem -->
|
||||
|
||||
|
||||
|
||||
### Command or Code
|
||||
<!-- What command or code is needed to reproduce the problem? -->
|
||||
|
||||
|
||||
|
||||
### Environment, Platform, Device
|
||||
<!-- In what environment, on what platform or on which device are you experiencing the issue? -->
|
||||
|
||||
|
||||
|
||||
### Version information
|
||||
<!--
|
||||
What are relevant versions you are using?
|
||||
For example:
|
||||
Cordova: Cordova CLI, Cordova Platforms, Cordova Plugins
|
||||
Other Frameworks: Ionic Framework and CLI version
|
||||
Operating System, Android Studio, Xcode etc.
|
||||
-->
|
||||
|
||||
|
||||
|
||||
## Checklist
|
||||
<!-- Please check the boxes by putting an x in the [ ] like so: [x] -->
|
||||
|
||||
- [ ] I searched for existing GitHub issues
|
||||
- [ ] I updated all Cordova tooling to most recent version
|
||||
- [ ] I included all the necessary information above
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: 🚀 Feature Request
|
||||
about: A suggestion for a new functionality
|
||||
|
||||
---
|
||||
|
||||
# Feature Request
|
||||
|
||||
## Motivation Behind Feature
|
||||
<!-- Why should this feature be implemented? What problem does it solve? -->
|
||||
|
||||
|
||||
|
||||
## Feature Description
|
||||
<!--
|
||||
Describe your feature request in detail
|
||||
Please provide any code examples or screenshots of what this feature would look like
|
||||
Are there any drawbacks? Will this break anything for existing users?
|
||||
-->
|
||||
|
||||
|
||||
|
||||
## Alternatives or Workarounds
|
||||
<!--
|
||||
Describe alternatives or workarounds you are currently using
|
||||
Are there ways to do this with existing functionality?
|
||||
-->
|
||||
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: 💬 Support Question
|
||||
about: If you have a question, please check out our Slack or StackOverflow!
|
||||
|
||||
---
|
||||
|
||||
<!------------^ Click "Preview" for a nicer view! -->
|
||||
|
||||
Apache Cordova uses GitHub Issues as a feature request and bug tracker _only_.
|
||||
For usage and support questions, please check out the resources below. Thanks!
|
||||
|
||||
---
|
||||
|
||||
You can get answers to your usage and support questions about **Apache Cordova** on:
|
||||
|
||||
* Slack Community Chat: https://cordova.slack.com (you can sign-up at http://slack.cordova.io/)
|
||||
* StackOverflow: https://stackoverflow.com/questions/tagged/cordova using the tag `cordova`
|
||||
|
||||
---
|
||||
|
||||
If you are using a tool that uses Cordova internally, like e.g. Ionic, check their support channels:
|
||||
|
||||
* **Ionic Framework**
|
||||
* [Ionic Community Forum](https://forum.ionicframework.com/)
|
||||
* [Ionic Worldwide Slack](https://ionicworldwide.herokuapp.com/)
|
||||
* **PhoneGap**
|
||||
* [PhoneGap Developer Community](https://forums.adobe.com/community/phonegap)
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<!--
|
||||
Please make sure the checklist boxes are all checked before submitting the PR. The checklist is intended as a quick reference, for complete details please see our Contributor Guidelines:
|
||||
|
||||
http://cordova.apache.org/contribute/contribute_guidelines.html
|
||||
|
||||
Thanks!
|
||||
-->
|
||||
|
||||
### Platforms affected
|
||||
|
||||
|
||||
|
||||
### Motivation and Context
|
||||
<!-- Why is this change required? What problem does it solve? -->
|
||||
<!-- If it fixes an open issue, please link to the issue here. -->
|
||||
|
||||
|
||||
|
||||
### Description
|
||||
<!-- Describe your changes in detail -->
|
||||
|
||||
|
||||
|
||||
### Testing
|
||||
<!-- Please describe in detail how you tested your changes. -->
|
||||
|
||||
|
||||
|
||||
### Checklist
|
||||
|
||||
- [ ] I've run the tests to see all new and existing tests pass
|
||||
- [ ] I added automated test coverage as appropriate for this change
|
||||
- [ ] Commit is prefixed with `(platform)` if this change only applies to one platform (e.g. `(android)`)
|
||||
- [ ] If this Pull Request resolves an issue, I linked to the issue in the text above (and used the correct [keyword to close issues using keywords](https://help.github.com/articles/closing-issues-using-keywords/))
|
||||
- [ ] I've updated the documentation if necessary
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
fixtures
|
||||
coverage
|
||||
jasmine.json
|
||||
appveyor.yml
|
||||
package-lock.json
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
|
||||
node_js:
|
||||
- 6
|
||||
- 8
|
||||
- 10
|
||||
- 12
|
||||
|
||||
install:
|
||||
- npm install
|
||||
- npm install -g codecov
|
||||
|
||||
script:
|
||||
- npm test
|
||||
- npm run cover
|
||||
|
||||
after_script:
|
||||
- codecov
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
<!--
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
-->
|
||||
|
||||
[](https://ci.appveyor.com/project/ApacheSoftwareFoundation/cordova-common/branch/master)
|
||||
[](https://travis-ci.org/apache/cordova-common)
|
||||
[](https://nodei.co/npm/cordova-common/)
|
||||
|
||||
# cordova-common
|
||||
Exposes shared functionality used by [cordova-lib](https://github.com/apache/cordova-lib/) and Cordova platforms.
|
||||
## Exposed APIs
|
||||
|
||||
### `events`
|
||||
|
||||
Represents special instance of NodeJS EventEmitter which is intended to be used to post events to cordova-lib and cordova-cli
|
||||
|
||||
Usage:
|
||||
```js
|
||||
var events = require('cordova-common').events;
|
||||
events.emit('warn', 'Some warning message')
|
||||
```
|
||||
|
||||
There are the following events supported by cordova-cli: `verbose`, `log`, `info`, `warn`, `error`.
|
||||
|
||||
### `CordovaError`
|
||||
|
||||
An error class used by Cordova to throw cordova-specific errors. The CordovaError class is inherited from Error, so CordovaError instances is also valid Error instances (`instanceof` check succeeds).
|
||||
|
||||
Usage:
|
||||
|
||||
```js
|
||||
var CordovaError = require('cordova-common').CordovaError;
|
||||
throw new CordovaError('Some error message', SOME_ERR_CODE);
|
||||
```
|
||||
|
||||
See [CordovaError](src/CordovaError/CordovaError.js) for supported error codes.
|
||||
|
||||
### `ConfigParser`
|
||||
|
||||
Exposes functionality to deal with cordova project `config.xml` files. For ConfigParser API reference check [ConfigParser Readme](src/ConfigParser/README.md).
|
||||
|
||||
Usage:
|
||||
```js
|
||||
var ConfigParser = require('cordova-common').ConfigParser;
|
||||
var appConfig = new ConfigParser('path/to/cordova-app/config.xml');
|
||||
console.log(appconfig.name() + ':' + appConfig.version());
|
||||
```
|
||||
|
||||
### `PluginInfoProvider` and `PluginInfo`
|
||||
|
||||
`PluginInfo` is a wrapper for cordova plugins' `plugin.xml` files. This class may be instantiated directly or via `PluginInfoProvider`. The difference is that `PluginInfoProvider` caches `PluginInfo` instances based on plugin source directory.
|
||||
|
||||
Usage:
|
||||
```js
|
||||
var PluginInfo: require('cordova-common').PluginInfo;
|
||||
var PluginInfoProvider: require('cordova-common').PluginInfoProvider;
|
||||
|
||||
// The following instances are equal
|
||||
var plugin1 = new PluginInfo('path/to/plugin_directory');
|
||||
var plugin2 = new PluginInfoProvider().get('path/to/plugin_directory');
|
||||
|
||||
console.log('The plugin ' + plugin1.id + ' has version ' + plugin1.version)
|
||||
```
|
||||
|
||||
### `ActionStack`
|
||||
|
||||
Utility module for dealing with sequential tasks. Provides a set of tasks that are needed to be done and reverts all tasks that are already completed if one of those tasks fail to complete. Used internally by cordova-lib and platform's plugin installation routines.
|
||||
|
||||
Usage:
|
||||
```js
|
||||
var ActionStack = require('cordova-common').ActionStack;
|
||||
var stack = new ActionStack()
|
||||
|
||||
var action1 = stack.createAction(task1, [<task parameters>], task1_reverter, [<reverter_parameters>]);
|
||||
var action2 = stack.createAction(task2, [<task parameters>], task2_reverter, [<reverter_parameters>]);
|
||||
|
||||
stack.push(action1);
|
||||
stack.push(action2);
|
||||
|
||||
stack.process()
|
||||
.then(function() {
|
||||
// all actions succeded
|
||||
})
|
||||
.catch(function(error){
|
||||
// One of actions failed with error
|
||||
})
|
||||
```
|
||||
|
||||
### `superspawn`
|
||||
|
||||
Module for spawning child processes with some advanced logic.
|
||||
|
||||
Usage:
|
||||
```js
|
||||
var superspawn = require('cordova-common').superspawn;
|
||||
superspawn.spawn('adb', ['devices'])
|
||||
.progress(function(data){
|
||||
if (data.stderr)
|
||||
console.error('"adb devices" raised an error: ' + data.stderr);
|
||||
})
|
||||
.then(function(devices){
|
||||
// Do something...
|
||||
})
|
||||
```
|
||||
|
||||
### `xmlHelpers`
|
||||
|
||||
A set of utility methods for dealing with XML files.
|
||||
|
||||
Usage:
|
||||
```js
|
||||
var xml = require('cordova-common').xmlHelpers;
|
||||
|
||||
var xmlDoc1 = xml.parseElementtreeSync('some/xml/file');
|
||||
var xmlDoc2 = xml.parseElementtreeSync('another/xml/file');
|
||||
|
||||
xml.mergeXml(doc1, doc2); // doc2 now contains all the nodes from doc1
|
||||
```
|
||||
|
||||
### Other APIs
|
||||
|
||||
The APIs listed below are also exposed but are intended to be only used internally by cordova plugin installation routines.
|
||||
|
||||
```
|
||||
PlatformJson
|
||||
ConfigChanges
|
||||
ConfigKeeper
|
||||
ConfigFile
|
||||
mungeUtil
|
||||
```
|
||||
|
||||
## Setup
|
||||
* Clone this repository onto your local machine
|
||||
`git clone https://github.com/apache/cordova-common.git`
|
||||
* Navigate to cordova-common directory, install dependencies and npm-link
|
||||
`cd cordova-common && npm install && npm link`
|
||||
* Navigate to cordova-lib directory and link cordova-common
|
||||
`cd <cordova-lib directory> && npm link cordova-common && npm install`
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user