Created GLSLangProvider class with API for linting and downloading glslangValidator

Moved glslang stuff from Config to GLSLangProvider. ConfigProvider invokes GLSLangValidator to prompt and download glslangValidator instead
This commit is contained in:
Noah Santschi-Cooney 2019-08-11 21:21:41 +01:00
parent 156d76e7de
commit 41995c3f38
16 changed files with 819 additions and 607 deletions

189
client/package-lock.json generated
View file

@ -8,6 +8,7 @@
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
"dev": true,
"requires": { "requires": {
"es6-promisify": "^5.0.0" "es6-promisify": "^5.0.0"
} }
@ -16,6 +17,7 @@
"version": "6.10.2", "version": "6.10.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
"integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
"dev": true,
"requires": { "requires": {
"fast-deep-equal": "^2.0.1", "fast-deep-equal": "^2.0.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@ -27,6 +29,7 @@
"version": "0.2.4", "version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"dev": true,
"requires": { "requires": {
"safer-buffer": "~2.1.0" "safer-buffer": "~2.1.0"
} }
@ -34,32 +37,38 @@
"assert-plus": { "assert-plus": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
}, },
"asynckit": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
}, },
"aws-sign2": { "aws-sign2": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
"dev": true
}, },
"aws4": { "aws4": {
"version": "1.8.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
"dev": true
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
}, },
"bcrypt-pbkdf": { "bcrypt-pbkdf": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"dev": true,
"requires": { "requires": {
"tweetnacl": "^0.14.3" "tweetnacl": "^0.14.3"
} }
@ -68,6 +77,7 @@
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -76,22 +86,26 @@
"browser-stdout": { "browser-stdout": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
"dev": true
}, },
"buffer-from": { "buffer-from": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true
}, },
"caseless": { "caseless": {
"version": "0.12.0", "version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true
}, },
"combined-stream": { "combined-stream": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"requires": { "requires": {
"delayed-stream": "~1.0.0" "delayed-stream": "~1.0.0"
} }
@ -99,22 +113,26 @@
"commander": { "commander": {
"version": "2.15.1", "version": "2.15.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
"dev": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
}, },
"dashdash": { "dashdash": {
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0" "assert-plus": "^1.0.0"
} }
@ -123,6 +141,7 @@
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": { "requires": {
"ms": "2.0.0" "ms": "2.0.0"
} }
@ -130,17 +149,20 @@
"delayed-stream": { "delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
}, },
"diff": { "diff": {
"version": "3.5.0", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
"dev": true
}, },
"ecc-jsbn": { "ecc-jsbn": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"dev": true,
"requires": { "requires": {
"jsbn": "~0.1.0", "jsbn": "~0.1.0",
"safer-buffer": "^2.1.0" "safer-buffer": "^2.1.0"
@ -149,12 +171,14 @@
"es6-promise": { "es6-promise": {
"version": "4.2.8", "version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
"dev": true
}, },
"es6-promisify": { "es6-promisify": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
"dev": true,
"requires": { "requires": {
"es6-promise": "^4.0.3" "es6-promise": "^4.0.3"
} }
@ -162,37 +186,44 @@
"escape-string-regexp": { "escape-string-regexp": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
}, },
"extend": { "extend": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"dev": true
}, },
"extsprintf": { "extsprintf": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"dev": true
}, },
"fast-deep-equal": { "fast-deep-equal": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
"dev": true
}, },
"fast-json-stable-stringify": { "fast-json-stable-stringify": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
"dev": true
}, },
"forever-agent": { "forever-agent": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
"dev": true
}, },
"form-data": { "form-data": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"dev": true,
"requires": { "requires": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"combined-stream": "^1.0.6", "combined-stream": "^1.0.6",
@ -202,12 +233,14 @@
"fs.realpath": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
}, },
"getpass": { "getpass": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0" "assert-plus": "^1.0.0"
} }
@ -216,6 +249,7 @@
"version": "7.1.4", "version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"dev": true,
"requires": { "requires": {
"fs.realpath": "^1.0.0", "fs.realpath": "^1.0.0",
"inflight": "^1.0.4", "inflight": "^1.0.4",
@ -228,17 +262,20 @@
"growl": { "growl": {
"version": "1.10.5", "version": "1.10.5",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==",
"dev": true
}, },
"har-schema": { "har-schema": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
"dev": true
}, },
"har-validator": { "har-validator": {
"version": "5.1.3", "version": "5.1.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
"dev": true,
"requires": { "requires": {
"ajv": "^6.5.5", "ajv": "^6.5.5",
"har-schema": "^2.0.0" "har-schema": "^2.0.0"
@ -247,17 +284,20 @@
"has-flag": { "has-flag": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
}, },
"he": { "he": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
"dev": true
}, },
"http-proxy-agent": { "http-proxy-agent": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
"integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
"dev": true,
"requires": { "requires": {
"agent-base": "4", "agent-base": "4",
"debug": "3.1.0" "debug": "3.1.0"
@ -267,6 +307,7 @@
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0", "assert-plus": "^1.0.0",
"jsprim": "^1.2.2", "jsprim": "^1.2.2",
@ -277,6 +318,7 @@
"version": "2.2.2", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz",
"integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==",
"dev": true,
"requires": { "requires": {
"agent-base": "^4.3.0", "agent-base": "^4.3.0",
"debug": "^3.1.0" "debug": "^3.1.0"
@ -286,6 +328,7 @@
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": { "requires": {
"once": "^1.3.0", "once": "^1.3.0",
"wrappy": "1" "wrappy": "1"
@ -294,42 +337,50 @@
"inherits": { "inherits": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
}, },
"is-typedarray": { "is-typedarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
"dev": true
}, },
"isstream": { "isstream": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true
}, },
"jsbn": { "jsbn": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"dev": true
}, },
"json-schema": { "json-schema": {
"version": "0.2.3", "version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"dev": true
}, },
"json-schema-traverse": { "json-schema-traverse": {
"version": "0.4.1", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true
}, },
"json-stringify-safe": { "json-stringify-safe": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"dev": true
}, },
"jsprim": { "jsprim": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"dev": true,
"requires": { "requires": {
"assert-plus": "1.0.0", "assert-plus": "1.0.0",
"extsprintf": "1.3.0", "extsprintf": "1.3.0",
@ -340,12 +391,14 @@
"mime-db": { "mime-db": {
"version": "1.40.0", "version": "1.40.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==",
"dev": true
}, },
"mime-types": { "mime-types": {
"version": "2.1.24", "version": "2.1.24",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
"integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
"dev": true,
"requires": { "requires": {
"mime-db": "1.40.0" "mime-db": "1.40.0"
} }
@ -354,6 +407,7 @@
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
@ -361,12 +415,14 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
}, },
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -375,6 +431,7 @@
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz",
"integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==",
"dev": true,
"requires": { "requires": {
"browser-stdout": "1.3.1", "browser-stdout": "1.3.1",
"commander": "2.15.1", "commander": "2.15.1",
@ -393,6 +450,7 @@
"version": "7.1.2", "version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"requires": { "requires": {
"fs.realpath": "^1.0.0", "fs.realpath": "^1.0.0",
"inflight": "^1.0.4", "inflight": "^1.0.4",
@ -407,17 +465,20 @@
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
}, },
"oauth-sign": { "oauth-sign": {
"version": "0.9.0", "version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
"dev": true
}, },
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -425,37 +486,44 @@
"path-is-absolute": { "path-is-absolute": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
}, },
"performance-now": { "performance-now": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"dev": true
}, },
"psl": { "psl": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz",
"integrity": "sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==" "integrity": "sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==",
"dev": true
}, },
"punycode": { "punycode": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"dev": true
}, },
"qs": { "qs": {
"version": "6.5.2", "version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
"dev": true
}, },
"querystringify": { "querystringify": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==",
"dev": true
}, },
"request": { "request": {
"version": "2.88.0", "version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
"dev": true,
"requires": { "requires": {
"aws-sign2": "~0.7.0", "aws-sign2": "~0.7.0",
"aws4": "^1.8.0", "aws4": "^1.8.0",
@ -482,32 +550,38 @@
"requires-port": { "requires-port": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
"dev": true
}, },
"safe-buffer": { "safe-buffer": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
"dev": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
}, },
"semver": { "semver": {
"version": "5.7.0", "version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
"dev": true
}, },
"source-map": { "source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}, },
"source-map-support": { "source-map-support": {
"version": "0.5.13", "version": "0.5.13",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
"integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
"dev": true,
"requires": { "requires": {
"buffer-from": "^1.0.0", "buffer-from": "^1.0.0",
"source-map": "^0.6.0" "source-map": "^0.6.0"
@ -517,6 +591,7 @@
"version": "1.16.1", "version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
"dev": true,
"requires": { "requires": {
"asn1": "~0.2.3", "asn1": "~0.2.3",
"assert-plus": "^1.0.0", "assert-plus": "^1.0.0",
@ -533,6 +608,7 @@
"version": "5.4.0", "version": "5.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
"dev": true,
"requires": { "requires": {
"has-flag": "^3.0.0" "has-flag": "^3.0.0"
} }
@ -541,6 +617,7 @@
"version": "2.4.3", "version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
"dev": true,
"requires": { "requires": {
"psl": "^1.1.24", "psl": "^1.1.24",
"punycode": "^1.4.1" "punycode": "^1.4.1"
@ -549,7 +626,8 @@
"punycode": { "punycode": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true
} }
} }
}, },
@ -557,6 +635,7 @@
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"dev": true,
"requires": { "requires": {
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
@ -564,12 +643,14 @@
"tweetnacl": { "tweetnacl": {
"version": "0.14.5", "version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true
}, },
"uri-js": { "uri-js": {
"version": "4.2.2", "version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
"dev": true,
"requires": { "requires": {
"punycode": "^2.1.0" "punycode": "^2.1.0"
} }
@ -578,6 +659,7 @@
"version": "1.4.7", "version": "1.4.7",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
"integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
"dev": true,
"requires": { "requires": {
"querystringify": "^2.1.1", "querystringify": "^2.1.1",
"requires-port": "^1.0.0" "requires-port": "^1.0.0"
@ -586,12 +668,14 @@
"uuid": { "uuid": {
"version": "3.3.2", "version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
"dev": true
}, },
"verror": { "verror": {
"version": "1.10.0", "version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"dev": true,
"requires": { "requires": {
"assert-plus": "^1.0.0", "assert-plus": "^1.0.0",
"core-util-is": "1.0.2", "core-util-is": "1.0.2",
@ -602,6 +686,7 @@
"version": "1.1.36", "version": "1.1.36",
"resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.36.tgz", "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.36.tgz",
"integrity": "sha512-cGFh9jmGLcTapCpPCKvn8aG/j9zVQ+0x5hzYJq5h5YyUXVGa1iamOaB2M2PZXoumQPES4qeAP1FwkI0b6tL4bQ==", "integrity": "sha512-cGFh9jmGLcTapCpPCKvn8aG/j9zVQ+0x5hzYJq5h5YyUXVGa1iamOaB2M2PZXoumQPES4qeAP1FwkI0b6tL4bQ==",
"dev": true,
"requires": { "requires": {
"glob": "^7.1.2", "glob": "^7.1.2",
"mocha": "^5.2.0", "mocha": "^5.2.0",
@ -643,6 +728,7 @@
"version": "0.4.3", "version": "0.4.3",
"resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.4.3.tgz", "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.4.3.tgz",
"integrity": "sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==", "integrity": "sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==",
"dev": true,
"requires": { "requires": {
"http-proxy-agent": "^2.1.0", "http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.1" "https-proxy-agent": "^2.2.1"
@ -651,7 +737,8 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
} }
} }
} }

View file

@ -19,9 +19,9 @@
"compile": "tsc -p ./" "compile": "tsc -p ./"
}, },
"dependencies": { "dependencies": {
"vscode-languageclient": "^4.4.2" "vscode-languageclient": "^4.4.2"
}, },
"devDependencies": { "devDependencies": {
"vscode": "^1.1.36" "vscode": "^1.1.36"
} }
} }

View file

@ -4,6 +4,14 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@types/adm-zip": {
"version": "0.4.32",
"resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.4.32.tgz",
"integrity": "sha512-hv1O7ySn+XvP5OeDQcJFWwVb2v+GFGO1A9aMTQ5B/bzxb7WW21O8iRhVdsKKr8QwuiagzGmPP+gsUAYZ6bRddQ==",
"requires": {
"@types/node": "*"
}
},
"@types/node": { "@types/node": {
"version": "12.7.1", "version": "12.7.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz",
@ -17,27 +25,10 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"binary": { "adm-zip": {
"version": "0.3.0", "version": "0.4.13",
"resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.13.tgz",
"integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", "integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw=="
"requires": {
"buffers": "~0.1.1",
"chainsaw": "~0.1.0"
}
},
"buffers": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
"integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s="
},
"chainsaw": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
"integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=",
"requires": {
"traverse": ">=0.3.0 <0.4"
}
}, },
"error-stack-parser": { "error-stack-parser": {
"version": "1.3.6", "version": "1.3.6",
@ -47,19 +38,6 @@
"stackframe": "^0.3.1" "stackframe": "^0.3.1"
} }
}, },
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
}
},
"node-fetch": { "node-fetch": {
"version": "2.6.0", "version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
@ -109,11 +87,6 @@
"stacktrace-gps": "^2.4.3" "stacktrace-gps": "^2.4.3"
} }
}, },
"traverse": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
"integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk="
},
"typescript-logging": { "typescript-logging": {
"version": "0.6.3", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/typescript-logging/-/typescript-logging-0.6.3.tgz", "resolved": "https://registry.npmjs.org/typescript-logging/-/typescript-logging-0.6.3.tgz",
@ -122,15 +95,6 @@
"stacktrace-js": "1.3.1" "stacktrace-js": "1.3.1"
} }
}, },
"unzip-stream": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/unzip-stream/-/unzip-stream-0.3.0.tgz",
"integrity": "sha512-NG1h/MdGIX3HzyqMjyj1laBCmlPYhcO4xEy7gEqqzGiSLw7XqDQCnY4nYSn5XSaH8mQ6TFkaujrO8d/PIZN85A==",
"requires": {
"binary": "^0.3.0",
"mkdirp": "^0.5.1"
}
},
"vscode-jsonrpc": { "vscode-jsonrpc": {
"version": "3.6.2", "version": "3.6.2",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.6.2.tgz", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.6.2.tgz",

View file

@ -12,10 +12,11 @@
"node": "*" "node": "*"
}, },
"dependencies": { "dependencies": {
"@types/adm-zip": "^0.4.32",
"@types/node-fetch": "^2.5.0", "@types/node-fetch": "^2.5.0",
"adm-zip": "^0.4.13",
"node-fetch": "^2.6.0", "node-fetch": "^2.6.0",
"typescript-logging": "^0.6.3", "typescript-logging": "^0.6.3",
"unzip-stream": "^0.3.0",
"vscode-languageserver": "^4.4.2" "vscode-languageserver": "^4.4.2"
}, },
"scripts": { "scripts": {

View file

@ -1,14 +1,8 @@
import { connection, documents, onEvent } from './server' import { connection } from './server'
import fetch from 'node-fetch' import { serverLog as log } from './logging'
import { platform } from 'os'
import { createWriteStream, chmodSync, createReadStream, unlinkSync, read } from 'fs'
import * as unzip from 'unzip-stream'
import { postError } from './utils'
import { execSync } from 'child_process'
import { serverLog } from './logging'
import { dirname } from 'path' import { dirname } from 'path'
import { DidChangeConfigurationParams } from 'vscode-languageserver' import { DidChangeConfigurationParams } from 'vscode-languageserver'
import { win } from './linter' import { GLSLangProvider } from './glslangValidator'
const url = { const url = {
'win32': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-windows-x64-Release.zip', 'win32': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-windows-x64-Release.zip',
@ -18,26 +12,75 @@ const url = {
export let glslangReady = false export let glslangReady = false
export interface Config { export class ConfigProvider {
readonly shaderpacksPath: string private _config: Config
readonly glslangPath: string private _onChange: (settings: Config) => void
private _glslang: GLSLangProvider
public constructor(func?: (confProv: ConfigProvider, settings: Config) => void) {
this._config = {
shaderpacksPath: '',
glslangValidatorPath: ''
}
if (!func) {
this._onChange = (settings: Config) => {
onConfigChange(this, settings)
}
} else {
this._onChange = (settings: Config) => {
func(this, settings)
}
}
}
public set config(c: Config) {
Object.assign(this._config, c)
}
public get config(): Config {
return this._config
}
public set onChange(func: (confProv: ConfigProvider, settings: Config) => void) {
this._onChange = (settings: Config) => {
func(this, settings)
}
}
public onConfigChange = (change: DidChangeConfigurationParams) => {
this._onChange(change.settings.mcglsl as Config)
}
public set glslang(glslang: GLSLangProvider) {
this._glslang = glslang
}
public get glslang(): GLSLangProvider {
return this._glslang
}
} }
export let conf: Config = {shaderpacksPath: '', glslangPath: ''} interface Config {
shaderpacksPath: string
glslangValidatorPath: string
}
let supress = false let supress = false
export async function onConfigChange(change: DidChangeConfigurationParams) { async function onConfigChange(confProv: ConfigProvider, old: Config) {
const temp = change.settings.mcglsl as Config if (!confProv.config == undefined &&
if (temp.shaderpacksPath === conf.shaderpacksPath && temp.glslangPath === conf.glslangPath) return old.shaderpacksPath === confProv.config.shaderpacksPath &&
conf = {shaderpacksPath: temp['shaderpacksPath'].replace(/\\/g, '/'), glslangPath: temp['glslangValidatorPath'].replace(/\\/g, '/')} old.glslangValidatorPath === confProv.config.glslangValidatorPath) return
serverLog.debug(() => 'new config: ' + JSON.stringify(temp))
serverLog.debug(() => 'old config: ' + JSON.stringify(conf))
if (conf.shaderpacksPath === '' || conf.shaderpacksPath.replace(dirname(conf.shaderpacksPath), '') !== '/shaderpacks') { confProv.config = {shaderpacksPath: old['shaderpacksPath'], glslangValidatorPath: old['glslangValidatorPath']}
log.debug(() => 'new config: ' + JSON.stringify(old))
log.debug(() => 'old config: ' + JSON.stringify(confProv.config))
if (confProv.config.shaderpacksPath === '' || confProv.config.shaderpacksPath.replace(dirname(confProv.config.shaderpacksPath), '') !== '/shaderpacks') {
if (supress) return if (supress) return
serverLog.error(() => 'shaderpack path not set or doesn\'t end in \'shaderpacks\'', null) log.error(() => `shaderpack path '${confProv.config.shaderpacksPath.replace(dirname(confProv.config.shaderpacksPath), '')}' not set or doesn't end in 'shaderpacks'`, null)
supress = true supress = true
const clicked = await connection.window.showErrorMessage( const clicked = await connection.window.showErrorMessage(
@ -48,81 +91,9 @@ export async function onConfigChange(change: DidChangeConfigurationParams) {
return return
} }
try { if (!confProv.glslang.testExecutable()) {
if (!execSync(conf.glslangPath).toString().startsWith('Usage')) { await confProv.glslang.promptDownload()
documents.all().forEach(onEvent) } else {
glslangReady = true glslangReady = true
} else {
promptDownloadGlslang()
}
} catch (e) {
if ((e.stdout.toString() as string).startsWith('Usage')) {
documents.all().forEach(onEvent)
glslangReady = true
} else {
promptDownloadGlslang()
}
} }
} }
async function promptDownloadGlslang() {
const chosen = await connection.window.showErrorMessage(
`[mc-glsl] glslangValidator not found at: '${conf.glslangPath}'.`,
{title: 'Download'},
{title: 'Cancel'}
)
if (!chosen || chosen.title !== 'Download') return
downloadGlslang()
}
async function downloadGlslang() {
connection.window.showInformationMessage('Downloading. Your settings will be updated automatically and you\'ll be notified when its done.')
serverLog.info(() => 'downloading glslangValidator...')
const res = await fetch(url[platform()])
serverLog.info(() => 'glslangValidator downloaded. Extracting...')
try {
const zip = createWriteStream(conf.shaderpacksPath + '/glslangValidator.zip')
res.body.pipe(zip)
const glslang = '/glslangValidator' + (win ? '.exe' : '')
zip.on('finish', () => {
try {
createReadStream(conf.shaderpacksPath + '/glslangValidator.zip')
.pipe(unzip.Parse())
.on('entry', entry => {
try {
if (entry.path === 'bin' + glslang) {
entry.pipe(createWriteStream(conf.shaderpacksPath + glslang))
return
}
entry.autodrain()
} catch (e) {
postError(e)
}
})
.on('close', () => {
try {
chmodSync(conf.shaderpacksPath + glslang, 0o775)
unlinkSync(conf.shaderpacksPath + '/glslangValidator.zip')
connection.sendNotification('update-config', conf.shaderpacksPath + glslang)
connection.window.showInformationMessage('glslangValidator has been downloaded to ' + conf.shaderpacksPath + '/glslangValidator. Your config should be updated automatically.')
glslangReady = true
} catch (e) {
postError(e)
}
})
} catch (e) {
postError(e)
}
})
} catch (e) {
postError(e)
}
}

9
server/src/fileTypes.ts Normal file
View file

@ -0,0 +1,9 @@
export type ShaderFileExtension = '.fsh' | '.gsh' | '.vsh'
export type ShaderFileType = 'frag' | 'geom' | 'vert'
export const extensionMap = new Map<ShaderFileExtension, ShaderFileType>([
['.fsh', 'frag'],
['.gsh', 'geom'],
['.vsh', 'vert'],
])

View file

@ -0,0 +1,100 @@
import { ConfigProvider } from './config'
import { execSync } from 'child_process'
import { extensionMap, ShaderFileExtension } from './fileTypes'
import * as path from 'path'
import fetch from 'node-fetch';
import { platform } from 'os';
import * as unzip from 'adm-zip'
import { createWriteStream } from 'fs'
import { writeFileSync, fstat } from 'fs';
import { connection } from './server';
import { glslProviderLog as log } from './logging';
const url = {
'win32': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-windows-x64-Release.zip',
'linux': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-linux-Release.zip',
'darwin': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-osx-Release.zip'
}
export class GLSLangProvider {
private _config: ConfigProvider
public constructor(c: ConfigProvider) {
this._config = c
}
public lint(document: string, fileExtension: ShaderFileExtension): string {
try {
execSync(`${this._config.config.glslangValidatorPath} --stdin -S ${extensionMap.get(fileExtension)}`, {input: document})
} catch (e) {
return e.stdout.toString()
}
}
public promptDownload = async () => {
const chosen = await connection.window.showErrorMessage(
`[mc-glsl] glslangValidator not found at: '${this._config.config.glslangValidatorPath}'.`,
{title: 'Download'},
{title: 'Cancel'}
)
if (!chosen || chosen.title !== 'Download') return
await this.installExecutable()
}
public installExecutable = async () => {
try {
const glslangBin = '/glslangValidator' + (platform() === 'win32' ? '.exe' : '')
const glslangPath = this._config.config.shaderpacksPath + glslangBin
const response = await fetch(url[platform()])
const zip = new unzip(await response.buffer())
const bin = zip.readFile('bin' + glslangBin)
writeFileSync(glslangPath, bin)
if (!this.testExecutable()) {
connection.window.showErrorMessage(
'Unexpected error occurred. Please try again'
)
return
}
// why doesnt this work????????
log.info(() => `successfully downloaded glslangValidator to ${glslangPath}`)
connection.window.showInformationMessage(
`glslangValidator has been downloaded to ${glslangPath}. Your config should be updated automatically.`
)
connection.sendNotification('update-config', glslangPath)
} catch (e) {
log.error(() => `failed downloading glslangValidator`, e)
connection.window.showErrorMessage(
`Failed to install glslangValidator: ${e}`
)
}
}
public testExecutable(glslangPath?: string): boolean {
let success = false
try {
const stdout = execSync(glslangPath || this._config.config.glslangValidatorPath, {
stdio: 'pipe',
}).toString()
success = stdout.startsWith('Usage')
} catch (e) {
success = (e.stdout.toString() as string).startsWith('Usage')
}
if (success) {
log.info(() => `glslangValidator found at ${this._config.config.glslangValidatorPath}`)
} else {
log.error(() => `glslangValidator not found at ${this._config.config.glslangValidatorPath}`, null)
}
return success
}
}

View file

@ -38,4 +38,24 @@ export class Graph {
} }
this.nodes.set(parent, par) this.nodes.set(parent, par)
} }
public toString(): string {
let result = ''
let start = true
this.nodes.forEach((node, key) => {
if (!start) {
key += '\n'
start = false
}
result += `${key}:\n\tchildren: `
node.children.forEach((_, key) => {
result += key + ' '
})
result + '\n\tparents: '
node.parents.forEach((_, key) => {
result += key + ' '
})
})
return result
}
} }

View file

@ -1,8 +1,8 @@
import * as vsclang from 'vscode-languageserver' import * as vsclang from 'vscode-languageserver'
import { linkLog } from './logging' import { linkLog as log} from './logging'
import { formatURI } from './utils' import { formatURI } from './utils'
export function getDocumentLinks(file: string): vsclang.DocumentLink[] { export function getDocumentLinks(file: string): vsclang.DocumentLink[] {
linkLog.debug(() => formatURI(file) + ' ' + file) log.debug(() => formatURI(file) + ' ' + file)
return [vsclang.DocumentLink.create(vsclang.Range.create(8, 0, 8, 32), 'file:///home/noah/.minecraft/shaderpacks/robobo1221Shaders-7.9.01/shaders/lib/utilities.glsl')] return [vsclang.DocumentLink.create(vsclang.Range.create(8, 0, 8, 32), 'file:///e:\\shaderpacks\\Sushi-Shader\\shaders\\composite1.vsh')]
} }

View file

@ -1,383 +1,4 @@
import { execSync } from 'child_process'
import { readFileSync, statSync } from 'fs' export class Linter {
import { platform } from 'os'
import * as path from 'path'
import { Diagnostic, DiagnosticSeverity, Range } from 'vscode-languageserver'
import { Comment } from './comment'
import { conf } from './config'
import { Graph } from './graph'
import { linterLog } from './logging'
import { connection } from './server'
import { formatURI, getDocumentContents, trimPath } from './utils'
const reDiag = /^(ERROR|WARNING): ([^?<>*|"]+?):(\d+): (?:'.*?' : )?(.+)\r?/
const reVersion = /#version [\d]{3}/
const reInclude = /^(?:\s)*?(?:#include) "(.+)"\r?/
const reIncludeExt = /#extension GL_GOOGLE_include_directive ?: ?require/
const include = '#extension GL_GOOGLE_include_directive : require'
export const win = platform() === 'win32'
const errorFilters = [
/stdin/,
/(No code generated)/,
/(compilation terminated)/,
/Could not process include directive for header name:/,
]
export const includeGraph = new Graph()
type IncludeObj = {
lineNum: number,
lineNumTopLevel: number,
path: string,
parent: string,
match: RegExpMatchArray
}
type ErrorMatch = {
type: DiagnosticSeverity,
file: string,
line: number,
msg: string,
}
type LinesProcessingInfo = {
total: number,
comment: Comment.State,
parStack: string[],
count: number[],
}
export const ext = new Map([
['.fsh', 'frag'],
['.gsh', 'geom'],
['.vsh', 'vert'],
])
const tokens = new Map([
['SEMICOLON', ';'],
['COMMA', ','],
['COLON', ':'],
['EQUAL', '='],
['LEFT_PAREN', '('],
['RIGHT_PAREN', ')'],
['DOT', '.'],
['BANG', '!'],
['DASH', '-'],
['TILDE', '~'],
['PLUS', '+'],
['STAR', '*'],
['SLASH', '/'],
['PERCENT', '%'],
['LEFT_ANGEL', '<'],
['RIGHT_ANGEL', '>'],
['VERICAL_BAR', '|'],
['CARET', '^'],
['AMPERSAND', '&'],
['QUESTION', '?'],
['[LEFT_BRACKET', '['],
['RIGHT_BRACKET', ']'],
['LEFT_BRACE', '{'],
['RIGHT_BRACE', '}'],
])
export function preprocess(lines: string[], docURI: string) {
const hasDirective = includeDirective(lines)
const diagnostics = new Map<string, Diagnostic[]>()
processIncludes(lines, [docURI], new Set<IncludeObj>(), diagnostics, hasDirective)
//const includeMap = new Map<string, IncludeObj>(Array.from(allIncludes).map(obj => [obj.path, obj]) as [string, IncludeObj][])
lint(docURI, lines, diagnostics, hasDirective)
}
function includeDirective(lines: string[]): boolean {
if (lines.findIndex(x => reIncludeExt.test(x)) > -1) {
linterLog.info(() => 'include directive found')
return true
}
let hasDirective = true
linterLog.info(() => 'include directive not found')
hasDirective = false
for (let i = 0; i < lines.length; i++) {
const line = lines[i]
if (reVersion.test(line)) {
linterLog.info(() => 'found version on line ' + (i + 1))
lines.splice(i + 1, 0, include)
break
}
/* if (i === lines.length - 1) {
linterLog.warn(() => `no version found for ${docURI}. inserting at top`)
lines.splice(0, 0, include)
break
} */
}
return hasDirective
}
const buildIncludeGraph = (inc: IncludeObj) => includeGraph.setParent(inc.path, inc.parent, inc.lineNum)
function processIncludes(lines: string[], incStack: string[], allIncludes: Set<IncludeObj>, diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
const parent = incStack[incStack.length - 1]
const includes = getIncludes(parent, lines)
includes.forEach(i => allIncludes.add(i))
includeGraph.nodes.get(parent).children.forEach((node, uri) => {
if (!includes.has(uri)) {
includeGraph.nodes.get(parent).children.delete(uri)
node.parents.delete(parent)
}
})
const includeList = Array.from(includes.values())
if (includeList.length > 0) {
linterLog.info(() => `${trimPath(parent)} has ${includeList.length} include(s). [${includeList.map(i => '\n\t\t' + trimPath(i.path))}\n\t]`)
includeList.reverse().forEach(inc => {
buildIncludeGraph(inc)
mergeInclude(inc, lines, incStack, diagnostics, hasDirective)
})
// recursively check for more includes to be merged
processIncludes(lines, incStack, allIncludes, diagnostics, hasDirective)
}
}
function getIncludes(uri: string, lines: string[]) {
const lineInfo: LinesProcessingInfo = {
total: 0,
comment: Comment.State.No,
parStack: [uri],
count: [0],
}
return lines.reduce<Map<string, IncludeObj>>((out, line, i) => processLine(out, line, lines, i, lineInfo), new Map())
}
// TODO can surely be reworked
function processLine(includes: Map<string, IncludeObj>, line: string, lines: string[], i: number, linesInfo: LinesProcessingInfo): Map<string, IncludeObj> {
const updated = Comment.update(line, linesInfo.comment)
linesInfo.comment = updated[0]
if (updated[1] !== line) linterLog.debug(() => `change:\n\t'${line}'\n\t'${updated[1]}'`)
line = updated[1]
lines[i] = line
linesInfo.count[linesInfo.count.length - 1]++
linesInfo.total++
if (linesInfo.comment) return includes
if (line.startsWith('#line')) {
const inc = line.slice(line.indexOf('"') + 1, line.lastIndexOf('"'))
if (inc.length + 1 === line.length) lines[i] = ''
if (inc === linesInfo.parStack[linesInfo.parStack.length - 2]) {
linesInfo.count.pop()
linesInfo.parStack.pop()
} else {
linesInfo.count.push(0)
linesInfo.parStack.push(inc)
}
return includes
}
const match = line.match(reInclude)
if (match) {
includes.set(
formatURI(absPath(linesInfo.parStack[linesInfo.parStack.length - 1], match[1])),
{
path: formatURI(absPath(linesInfo.parStack[linesInfo.parStack.length - 1], match[1])),
lineNum: linesInfo.count[linesInfo.count.length - 1] - 1,
lineNumTopLevel: linesInfo.total - 1,
parent: formatURI(linesInfo.parStack[linesInfo.parStack.length - 1]),
match
}
)
}
return includes
}
function ifInvalidFile(inc: IncludeObj, lines: string[], incStack: string[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
const msg = `${trimPath(inc.path)} is missing or an invalid file.`
linterLog.error(msg, null)
const file = incStack[incStack.length - 1]
const diag: Diagnostic = {
severity: DiagnosticSeverity.Error,
range: calcRange(inc.lineNum - ((!hasDirective && includeGraph.get(file).parents.size === 0) ? 1 : 0), file),
message: msg,
source: 'mc-glsl'
}
diagnostics.set(inc.parent, [...(diagnostics.get(inc.parent) || []), diag])
lines[inc.lineNumTopLevel] = lines[inc.lineNumTopLevel].replace(reInclude, '')
const error: ErrorMatch = {
type: DiagnosticSeverity.Error,
line: inc.lineNum,
msg, file,
}
propogateDiagnostic(error, diagnostics, hasDirective)
}
function mergeInclude(inc: IncludeObj, lines: string[], incStack: string[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
try {
const stats = statSync(inc.path)
if (!stats.isFile()) {
const err = new Error()
err['code'] = 'ENOENT'
throw err
}
} catch (e) {
if (e.code === 'ENOENT') {
ifInvalidFile(inc, lines, incStack, diagnostics, hasDirective)
return
}
throw e
}
const dataLines = readFileSync(inc.path).toString().split('\n')
// if the includes parent is the top level (aka where the include directive is placed)
// and we had to manually add the directive, - 1 the line number to account for the extra line
if (inc.parent === incStack[0] && !hasDirective) inc.lineNum = inc.lineNum - 1
incStack.push(inc.path)
// add #line indicating we are entering a new include block
lines[inc.lineNumTopLevel] = `#line 0 "${formatURI(inc.path)}"`
// merge the lines of the file into the current document
lines.splice(inc.lineNumTopLevel + 1, 0, ...dataLines)
// add the closing #line indicating we're re-entering a block a level up
lines.splice(inc.lineNumTopLevel + 1 + dataLines.length, 0, `#line ${inc.lineNum + 1} "${inc.parent}"`)
}
function lint(docURI: string, lines: string[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
console.log(lines.join('\n'))
let out: string = ''
try {
execSync(`${conf.glslangPath} --stdin -S ${ext.get(path.extname(docURI))}`, {input: lines.join('\n')})
} catch (e) {
out = e.stdout.toString()
}
if (!diagnostics.has(docURI)) diagnostics.set(docURI, [])
includeGraph.nodes.forEach((node, key) => {
if (!diagnostics.has(key)) diagnostics.set(key, [])
})
processErrors(out, docURI, diagnostics, hasDirective)
diagnostics.forEach((diags, uri) => {
if (diags.length === 0) return
const errors = diags.filter(d => d.severity === DiagnosticSeverity.Error)
const warnings = diags.filter(d => d.severity === DiagnosticSeverity.Warning)
linterLog.info(() => `found ${errors.length} error(s) and ${warnings.length} warning(s) for ${trimPath(uri)}`)
})
const diagsList = daigsArray(diagnostics)
if (diagsList.filter(d => d.diag.length > 0).length === 0) linterLog.info(() => 'no errors found')
//console.log(JSON.stringify(diagsList.filter(d => d.diag.length > 0), null, 2))
diagsList.forEach(d => {
if (win) {
const drive = d.uri[7]
d.uri = d.uri.replace(`file://${drive}:`, `file:///${drive.toLowerCase()}%3A`)
}
connection.sendDiagnostics({uri: d.uri, diagnostics: d.diag})
})
}
function processErrors(out: string, docURI: string, diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
linterLog.debug(() => out.split('\n').filter(s => s.length > 2).join('\n'))
filterMatches(out).forEach(match => {
const error: ErrorMatch = {
type: errorType(match[1]),
file: match[2],
line: parseInt(match[3]),
msg: match[4]
}
const fileName = error.file.length - 1 ? error.file : docURI
const diag: Diagnostic = {
severity: error.type,
//range: calcRange(error.line - 1, fileName),
range: calcRange(error.line - ((!hasDirective && includeGraph.get(fileName).parents.size === 0) ? 2 : 1), fileName),
message: `Line ${error.line + ((!hasDirective && includeGraph.get(fileName).parents.size === 0) ? 2 : 1)} ${replaceWords(error.msg)}`,
source: 'mc-glsl'
}
diagnostics.get(fileName).push(diag)
// if is an include, highlight an error in the parents line of inclusion
propogateDiagnostic(error, diagnostics, hasDirective)
})
}
function propogateDiagnostic(error: ErrorMatch, diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean, parentURI?: string) {
includeGraph.get(parentURI || error.file).parents.forEach((pair, parURI) => {
const diag: Diagnostic = {
severity: error.type,
range: calcRange(pair.first - ((!hasDirective && pair.second.parents.size === 0) ? 1 : 0), parURI),
message: `Line ${error.line + 1} ${trimPath(error.file)} ${replaceWords(error.msg)}`,
source: 'mc-glsl'
}
if (!diagnostics.has(parURI)) diagnostics.set(parURI, [])
diagnostics.get(parURI).push(diag)
if (pair.second.parents.size > 0) {
propogateDiagnostic(error, diagnostics, hasDirective, parURI)
}
})
}
const replaceWords = (msg: string) => Array.from(tokens.entries()).reduce((acc, [key, value]) => acc.replace(key, value), msg)
const errorType = (error: string) => error === 'ERROR' ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning
const daigsArray = (diags: Map<string, Diagnostic[]>) => Array.from(diags).map(kv => ({uri: 'file://' + kv[0], diag: kv[1]}))
const filterMatches = (output: string) => output
.split('\n')
.filter(s => s.length > 1 && !errorFilters.some(reg => reg.test(s)))
.map(s => s.match(reDiag))
.filter(match => match && match.length === 5)
function calcRange(lineNum: number, uri: string) {
linterLog.debug(() => `calculating range for ${trimPath(uri)} at L${lineNum + 1}, index ${lineNum}`)
const lines = getDocumentContents(uri).split('\n')
const line = lines[Math.min(Math.max(lineNum, 0), lines.length - 1)]
const startOfLine = line.length - line.trimLeft().length
const endOfLine = line.trimRight().length + 1
//const endOfLine = line.slice(0, line.indexOf('//')).trimRight().length + 2
return Range.create(lineNum, startOfLine, lineNum, endOfLine)
}
function absPath(currFile: string, includeFile: string) {
if (!currFile.startsWith(conf.shaderpacksPath) || conf.shaderpacksPath === '') {
connection.window.showErrorMessage(`Shaderpacks path may not be correct. Current file is in '${currFile}' but the path is set to '${conf.shaderpacksPath}'`)
return ''
}
// TODO add explanation comment
if (includeFile.charAt(0) === '/' || (includeFile.charAt(0) === '.' && includeFile.charAt(1) === '.')) {
const shaderPath = trimPath(currFile).split('/').slice(0, 3).join('/')
return path.join(conf.shaderpacksPath, shaderPath, includeFile)
} /* else if (includeFile.charAt(0) === '.' && includeFile.charAt(1) === '.') {
} */
return path.join(path.dirname(currFile), includeFile)
} }

376
server/src/linter.ts.old Normal file
View file

@ -0,0 +1,376 @@
import { execSync } from 'child_process'
import { readFileSync, statSync } from 'fs'
import { platform } from 'os'
import * as path from 'path'
import { Diagnostic, DiagnosticSeverity, Range } from 'vscode-languageserver'
import { Comment } from './comment'
import { Graph } from './graph'
import { linterLog } from './logging'
import { connection } from './server'
import { formatURI, getDocumentContents, trimPath } from './utils'
const reDiag = /^(ERROR|WARNING): ([^?<>*|"]+?):(\d+): (?:'.*?' : )?(.+)\r?/
const reVersion = /#version [\d]{3}/
const reInclude = /^(?:\s)*?(?:#include) "(.+)"\r?/
const reIncludeExt = /#extension GL_GOOGLE_include_directive ?: ?require/
const include = '#extension GL_GOOGLE_include_directive : require'
export const win = platform() === 'win32'
const errorFilters = [
/stdin/,
/(No code generated)/,
/(compilation terminated)/,
/Could not process include directive for header name:/,
]
export const includeGraph = new Graph()
type IncludeObj = {
lineNum: number,
lineNumTopLevel: number,
path: string,
parent: string,
match: RegExpMatchArray
}
type ErrorMatch = {
type: DiagnosticSeverity,
file: string,
line: number,
msg: string,
}
type LinesProcessingInfo = {
total: number,
comment: Comment.State,
parStack: string[],
count: number[],
}
const tokens = new Map([
['SEMICOLON', ';'],
['COMMA', ','],
['COLON', ':'],
['EQUAL', '='],
['LEFT_PAREN', '('],
['RIGHT_PAREN', ')'],
['DOT', '.'],
['BANG', '!'],
['DASH', '-'],
['TILDE', '~'],
['PLUS', '+'],
['STAR', '*'],
['SLASH', '/'],
['PERCENT', '%'],
['LEFT_ANGEL', '<'],
['RIGHT_ANGEL', '>'],
['VERICAL_BAR', '|'],
['CARET', '^'],
['AMPERSAND', '&'],
['QUESTION', '?'],
['[LEFT_BRACKET', '['],
['RIGHT_BRACKET', ']'],
['LEFT_BRACE', '{'],
['RIGHT_BRACE', '}'],
])
export function preprocess(lines: string[], docURI: string) {
const hasDirective = includeDirective(lines)
const diagnostics = new Map<string, Diagnostic[]>()
processIncludes(lines, [docURI], new Set<IncludeObj>(), diagnostics, hasDirective)
//const includeMap = new Map<string, IncludeObj>(Array.from(allIncludes).map(obj => [obj.path, obj]) as [string, IncludeObj][])
lint(docURI, lines, diagnostics, hasDirective)
}
function includeDirective(lines: string[]): boolean {
if (lines.findIndex(x => reIncludeExt.test(x)) > -1) {
linterLog.info(() => 'include directive found')
return true
}
let hasDirective = true
linterLog.info(() => 'include directive not found')
hasDirective = false
for (let i = 0; i < lines.length; i++) {
const line = lines[i]
if (reVersion.test(line)) {
linterLog.info(() => 'found version on line ' + (i + 1))
lines.splice(i + 1, 0, include)
break
}
/* if (i === lines.length - 1) {
linterLog.warn(() => `no version found for ${docURI}. inserting at top`)
lines.splice(0, 0, include)
break
} */
}
return hasDirective
}
const buildIncludeGraph = (inc: IncludeObj) => includeGraph.setParent(inc.path, inc.parent, inc.lineNum)
function processIncludes(lines: string[], incStack: string[], allIncludes: Set<IncludeObj>, diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
const parent = incStack[incStack.length - 1]
const includes = getIncludes(parent, lines)
includes.forEach(i => allIncludes.add(i))
includeGraph.nodes.get(parent).children.forEach((node, uri) => {
if (!includes.has(uri)) {
includeGraph.nodes.get(parent).children.delete(uri)
node.parents.delete(parent)
}
})
const includeList = Array.from(includes.values())
if (includeList.length > 0) {
linterLog.info(() => `${trimPath(parent)} has ${includeList.length} include(s). [${includeList.map(i => '\n\t\t' + trimPath(i.path))}\n\t]`)
includeList.reverse().forEach(inc => {
buildIncludeGraph(inc)
mergeInclude(inc, lines, incStack, diagnostics, hasDirective)
})
// recursively check for more includes to be merged
processIncludes(lines, incStack, allIncludes, diagnostics, hasDirective)
}
}
function getIncludes(uri: string, lines: string[]) {
const lineInfo: LinesProcessingInfo = {
total: 0,
comment: Comment.State.No,
parStack: [uri],
count: [0],
}
return lines.reduce<Map<string, IncludeObj>>((out, line, i) => processLine(out, line, lines, i, lineInfo), new Map())
}
// TODO can surely be reworked
function processLine(includes: Map<string, IncludeObj>, line: string, lines: string[], i: number, linesInfo: LinesProcessingInfo): Map<string, IncludeObj> {
const updated = Comment.update(line, linesInfo.comment)
linesInfo.comment = updated[0]
if (updated[1] !== line) linterLog.debug(() => `change:\n\t'${line}'\n\t'${updated[1]}'`)
line = updated[1]
lines[i] = line
linesInfo.count[linesInfo.count.length - 1]++
linesInfo.total++
if (linesInfo.comment) return includes
if (line.startsWith('#line')) {
const inc = line.slice(line.indexOf('"') + 1, line.lastIndexOf('"'))
if (inc.length + 1 === line.length) lines[i] = ''
if (inc === linesInfo.parStack[linesInfo.parStack.length - 2]) {
linesInfo.count.pop()
linesInfo.parStack.pop()
} else {
linesInfo.count.push(0)
linesInfo.parStack.push(inc)
}
return includes
}
const match = line.match(reInclude)
if (match) {
includes.set(
formatURI(absPath(linesInfo.parStack[linesInfo.parStack.length - 1], match[1])),
{
path: formatURI(absPath(linesInfo.parStack[linesInfo.parStack.length - 1], match[1])),
lineNum: linesInfo.count[linesInfo.count.length - 1] - 1,
lineNumTopLevel: linesInfo.total - 1,
parent: formatURI(linesInfo.parStack[linesInfo.parStack.length - 1]),
match
}
)
}
return includes
}
function ifInvalidFile(inc: IncludeObj, lines: string[], incStack: string[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
const msg = `${trimPath(inc.path)} is missing or an invalid file.`
linterLog.error(msg, null)
const file = incStack[incStack.length - 1]
const diag: Diagnostic = {
severity: DiagnosticSeverity.Error,
range: calcRange(inc.lineNum - ((!hasDirective && includeGraph.get(file).parents.size === 0) ? 1 : 0), file),
message: msg,
source: 'mc-glsl'
}
diagnostics.set(inc.parent, [...(diagnostics.get(inc.parent) || []), diag])
lines[inc.lineNumTopLevel] = lines[inc.lineNumTopLevel].replace(reInclude, '')
const error: ErrorMatch = {
type: DiagnosticSeverity.Error,
line: inc.lineNum,
msg, file,
}
propogateDiagnostic(error, diagnostics, hasDirective)
}
function mergeInclude(inc: IncludeObj, lines: string[], incStack: string[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
try {
const stats = statSync(inc.path)
if (!stats.isFile()) {
const err = new Error()
err['code'] = 'ENOENT'
throw err
}
} catch (e) {
if (e.code === 'ENOENT') {
ifInvalidFile(inc, lines, incStack, diagnostics, hasDirective)
return
}
throw e
}
const dataLines = readFileSync(inc.path).toString().split('\n')
// if the includes parent is the top level (aka where the include directive is placed)
// and we had to manually add the directive, - 1 the line number to account for the extra line
if (inc.parent === incStack[0] && !hasDirective) inc.lineNum = inc.lineNum - 1
incStack.push(inc.path)
// add #line indicating we are entering a new include block
lines[inc.lineNumTopLevel] = `#line 0 "${formatURI(inc.path)}"`
// merge the lines of the file into the current document
lines.splice(inc.lineNumTopLevel + 1, 0, ...dataLines)
// add the closing #line indicating we're re-entering a block a level up
lines.splice(inc.lineNumTopLevel + 1 + dataLines.length, 0, `#line ${inc.lineNum + 1} "${inc.parent}"`)
}
function lint(docURI: string, lines: string[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
console.log(lines.join('\n'))
let out: string = ''
try {
//execSync(`${conf.glslangPath} --stdin -S ${ext.get(path.extname(docURI))}`, {input: lines.join('\n')})
} catch (e) {
out = e.stdout.toString()
}
if (!diagnostics.has(docURI)) diagnostics.set(docURI, [])
includeGraph.nodes.forEach((node, key) => {
if (!diagnostics.has(key)) diagnostics.set(key, [])
})
processErrors(out, docURI, diagnostics, hasDirective)
diagnostics.forEach((diags, uri) => {
if (diags.length === 0) return
const errors = diags.filter(d => d.severity === DiagnosticSeverity.Error)
const warnings = diags.filter(d => d.severity === DiagnosticSeverity.Warning)
linterLog.info(() => `found ${errors.length} error(s) and ${warnings.length} warning(s) for ${trimPath(uri)}`)
})
const diagsList = daigsArray(diagnostics)
if (diagsList.filter(d => d.diag.length > 0).length === 0) linterLog.info(() => 'no errors found')
//console.log(JSON.stringify(diagsList.filter(d => d.diag.length > 0), null, 2))
diagsList.forEach(d => {
if (win) {
const drive = d.uri[7]
d.uri = d.uri.replace(`file://${drive}:`, `file:///${drive.toLowerCase()}%3A`)
}
connection.sendDiagnostics({uri: d.uri, diagnostics: d.diag})
})
}
function processErrors(out: string, docURI: string, diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
linterLog.debug(() => out.split('\n').filter(s => s.length > 2).join('\n'))
filterMatches(out).forEach(match => {
const error: ErrorMatch = {
type: errorType(match[1]),
file: match[2],
line: parseInt(match[3]),
msg: match[4]
}
const fileName = error.file.length - 1 ? error.file : docURI
const diag: Diagnostic = {
severity: error.type,
//range: calcRange(error.line - 1, fileName),
range: calcRange(error.line - ((!hasDirective && includeGraph.get(fileName).parents.size === 0) ? 2 : 1), fileName),
message: `Line ${error.line + ((!hasDirective && includeGraph.get(fileName).parents.size === 0) ? 2 : 1)} ${replaceWords(error.msg)}`,
source: 'mc-glsl'
}
diagnostics.get(fileName).push(diag)
// if is an include, highlight an error in the parents line of inclusion
propogateDiagnostic(error, diagnostics, hasDirective)
})
}
function propogateDiagnostic(error: ErrorMatch, diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean, parentURI?: string) {
includeGraph.get(parentURI || error.file).parents.forEach((pair, parURI) => {
const diag: Diagnostic = {
severity: error.type,
range: calcRange(pair.first - ((!hasDirective && pair.second.parents.size === 0) ? 1 : 0), parURI),
message: `Line ${error.line + 1} ${trimPath(error.file)} ${replaceWords(error.msg)}`,
source: 'mc-glsl'
}
if (!diagnostics.has(parURI)) diagnostics.set(parURI, [])
diagnostics.get(parURI).push(diag)
if (pair.second.parents.size > 0) {
propogateDiagnostic(error, diagnostics, hasDirective, parURI)
}
})
}
const replaceWords = (msg: string) => Array.from(tokens.entries()).reduce((acc, [key, value]) => acc.replace(key, value), msg)
const errorType = (error: string) => error === 'ERROR' ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning
const daigsArray = (diags: Map<string, Diagnostic[]>) => Array.from(diags).map(kv => ({uri: 'file://' + kv[0], diag: kv[1]}))
const filterMatches = (output: string) => output
.split('\n')
.filter(s => s.length > 1 && !errorFilters.some(reg => reg.test(s)))
.map(s => s.match(reDiag))
.filter(match => match && match.length === 5)
function calcRange(lineNum: number, uri: string) {
linterLog.debug(() => `calculating range for ${trimPath(uri)} at L${lineNum + 1}, index ${lineNum}`)
const lines = getDocumentContents(uri).split('\n')
const line = lines[Math.min(Math.max(lineNum, 0), lines.length - 1)]
const startOfLine = line.length - line.trimLeft().length
const endOfLine = line.trimRight().length + 1
//const endOfLine = line.slice(0, line.indexOf('//')).trimRight().length + 2
return Range.create(lineNum, startOfLine, lineNum, endOfLine)
}
function absPath(currFile: string, includeFile: string) {
if (!currFile.startsWith(conf.shaderpacksPath) || conf.shaderpacksPath === '') {
connection.window.showErrorMessage(`Shaderpacks path may not be correct. Current file is in '${currFile}' but the path is set to '${conf.shaderpacksPath}'`)
return ''
}
// TODO add explanation comment
if (includeFile.charAt(0) === '/' || (includeFile.charAt(0) === '.' && includeFile.charAt(1) === '.')) {
const shaderPath = trimPath(currFile).split('/').slice(0, 3).join('/')
return path.join(conf.shaderpacksPath, shaderPath, includeFile)
} /* else if (includeFile.charAt(0) === '.' && includeFile.charAt(1) === '.') {
} */
return path.join(path.dirname(currFile), includeFile)
}

View file

@ -2,7 +2,10 @@ import { Category, CategoryConfiguration, CategoryServiceFactory, LogLevel } fro
CategoryServiceFactory.setDefaultConfiguration(new CategoryConfiguration(LogLevel.Debug)) CategoryServiceFactory.setDefaultConfiguration(new CategoryConfiguration(LogLevel.Debug))
export const linterLog = new Category('linter') export const linterLog = new Category('linter')
export const completionLog = new Category('completion') export const completionLog = new Category('completion')
export const serverLog = new Category('server') export const serverLog = new Category('server')
export const linkLog = new Category('links') export const linkLog = new Category('links')
export const glslProviderLog = new Category('glslangProvider')
export const uriLog = new Category('uri')

View file

@ -1,11 +1,9 @@
import { dirname } from 'path'
import * as vsclang from 'vscode-languageserver' import * as vsclang from 'vscode-languageserver'
import * as vsclangproto from 'vscode-languageserver-protocol' import * as vsclangproto from 'vscode-languageserver-protocol'
import { completions } from './completionProvider' import { completions } from './completionProvider'
import { conf, glslangReady, onConfigChange } from './config' import { ConfigProvider } from './config'
import { getDocumentLinks } from './linksProvider' import { getDocumentLinks } from './linksProvider'
import { includeGraph, preprocess } from './linter' import { GLSLangProvider } from './glslangValidator';
import { formatURI, getDocumentContents, postError } from './utils'
const reVersion = /#version [\d]{3}/ const reVersion = /#version [\d]{3}/
@ -14,10 +12,14 @@ export let connection = vsclang.createConnection(vsclang.ProposedFeatures.all)
console.log = connection.console.log.bind(connection.console) console.log = connection.console.log.bind(connection.console)
console.error = connection.console.error.bind(connection.console) console.error = connection.console.error.bind(connection.console)
const configProvider = new ConfigProvider()
const glslangValidator = new GLSLangProvider(configProvider)
configProvider.glslang = glslangValidator
export const documents = new vsclang.TextDocuments() export const documents = new vsclang.TextDocuments()
documents.listen(connection) documents.listen(connection)
connection.onInitialize((params) => ( connection.onInitialize((_) => (
{ {
capabilities: { capabilities: {
textDocumentSync: documents.syncKind, textDocumentSync: documents.syncKind,
@ -33,9 +35,9 @@ connection.onInitialize((params) => (
connection.onExit(() => {}) connection.onExit(() => {})
documents.onDidOpen((event) => onEvent(event.document)) documents.onDidOpen((event) => lint(event.document))
documents.onDidSave((event) => onEvent(event.document)) documents.onDidSave((event) => lint(event.document))
// what am i saying here // what am i saying here
// dont do this for include files, for non-include files, clear diags for all its includes. Cache this maybe // dont do this for include files, for non-include files, clear diags for all its includes. Cache this maybe
@ -45,8 +47,13 @@ documents.onDidClose((event) => {
//documents.onDidChangeContent(onEvent) //documents.onDidChangeContent(onEvent)
export function onEvent(document: vsclangproto.TextDocument) { export function lint(document: vsclangproto.TextDocument) {
if (conf.shaderpacksPath.replace(dirname(conf.shaderpacksPath), '') !== '/shaderpacks' || !glslangReady) return if (!glslangValidator.testExecutable()) {
}
/*
let sanitizedPath = conf.shaderpacksPath.replace(dirname(conf.shaderpacksPath), '')
if (sanitizedPath.startsWith('/shaderpacks') || glslangReady) return
const uri = formatURI(document.uri) const uri = formatURI(document.uri)
if (includeGraph.get(uri).parents.size > 0) { if (includeGraph.get(uri).parents.size > 0) {
@ -63,10 +70,10 @@ export function onEvent(document: vsclangproto.TextDocument) {
preprocess(document.getText().split('\n'), uri) preprocess(document.getText().split('\n'), uri)
} catch (e) { } catch (e) {
postError(e) postError(e)
} } */
} }
function lintBubbleDown(uri: string) { /* function lintBubbleDown(uri: string) {
includeGraph.get(uri).parents.forEach((parent, parentURI) => { includeGraph.get(uri).parents.forEach((parent, parentURI) => {
if (parent.second.parents.size > 0) { if (parent.second.parents.size > 0) {
lintBubbleDown(parentURI) lintBubbleDown(parentURI)
@ -82,11 +89,11 @@ function lintBubbleDown(uri: string) {
} }
} }
}) })
} } */
connection.onDocumentLinks((params: vsclang.DocumentLinkParams) => getDocumentLinks(params.textDocument.uri)) connection.onDocumentLinks((params: vsclang.DocumentLinkParams) => getDocumentLinks(params.textDocument.uri))
connection.onDidChangeConfiguration(onConfigChange) connection.onDidChangeConfiguration(configProvider.onConfigChange)
connection.onCompletion((textDocumentPosition: vsclang.TextDocumentPositionParams) => completions) connection.onCompletion((textDocumentPosition: vsclang.TextDocumentPositionParams) => completions)

52
server/src/uri.ts Normal file
View file

@ -0,0 +1,52 @@
import { Category } from 'typescript-logging'
import { platform } from 'os'
import { uriLog as log } from './logging';
export function formatURI(uri: string): string {
const drive = uri[7]
uri = uri.replace(`file:///${drive.toUpperCase()}%3A`, `file://${drive}:`)
return uri.replace(/^file:\/\//, '').replace(/\\/, '/')
}
export class URI {
public static fromFileURI(uri: string): string {
log.debug(() => `normalizing ${uri}`)
if (URI.isNormalized(uri)) {
log.debug(() => `already normalized ${uri}`)
return uri
}
return ''
}
public static toFileURI(uri: string): string {
let fileURI = uri
if (!fileURI.startsWith('file:///')) {
if (/^\\[a-zA-Z]/.test(fileURI)) {
fileURI = 'file:///' + fileURI.substr(1)
} else if (fileURI.startsWith('/')) {
fileURI = 'file://' + fileURI
}
} else if (fileURI.startsWith('file://\\')) {
fileURI = fileURI.replace('file://\\', 'file:///')
} else if (/^file:\/\/[a-zA-Z]/.test(fileURI)) {
fileURI = fileURI.replace('file://', 'file:///')
}
log.debug(() => `formatted '${uri}' to '${fileURI}'`)
return fileURI
}
private static isNormalized(uri: string): boolean {
if (uri.startsWith('file://') || uri.includes('%3A')) {
return false
}
return true
}
}

View file

@ -1,18 +1,19 @@
import { readFileSync } from 'fs' import { readFileSync, FSWatcher, ReadStream } from 'fs'
import { conf } from './config' import * as urL from 'url'
import { serverLog } from './logging' import { serverLog as log } from './logging'
import { connection, documents } from './server' import { connection, documents } from './server'
import { url } from 'inspector';
import { Readable } from 'stream';
export function postError(e: Error) { export function postError(e: Error) {
connection.window.showErrorMessage(e.message) connection.window.showErrorMessage(e.message)
serverLog.error(e.message, null) log.error(() => e.message, null)
console.log(e)
} }
export function formatURI(uri: string): string { export function formatURI(uri: string): string {
const drive = uri[7] const drive = uri[7]
uri = uri.replace(`file:///${drive.toUpperCase()}%3A`, `file://${drive}:`) uri = uri.replace(`file:///${drive.toUpperCase()}%3A`, `file://${drive}:`)
return uri.replace(/^file:\/\//, '').replace(/\\/g, '/') return uri.replace(/^file:\/\//, '').replace(/\\/, '/')
} }
export function getDocumentContents(uri: string): string { export function getDocumentContents(uri: string): string {
@ -20,6 +21,6 @@ export function getDocumentContents(uri: string): string {
else return readFileSync(uri).toString() else return readFileSync(uri).toString()
} }
export function trimPath(path: string): string { /* export function trimPath(path: string): string {
return path.replace(conf.shaderpacksPath, '') return path.replace(conf.shaderpacksPath, '')
} } */

View file

@ -6,7 +6,7 @@
"sourceMap": true, "sourceMap": true,
"outDir": "out", "outDir": "out",
"rootDir": "src", "rootDir": "src",
"lib": [ "es6", "es2017" ] "lib": [ "es6", "es2017", "dom" ]
}, },
"include": [ "include": [
"src" "src"