├── .gitattributes ├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── LICENSE ├── README.md ├── gulpfile.js ├── images └── icon.png ├── language-configuration.json ├── package-lock.json ├── package.json ├── server ├── .gitignore ├── .vscode │ ├── launch.json │ └── settings.json ├── bin │ └── installDevServerIntoExtension ├── package-lock.json ├── package.json ├── src │ ├── analysis │ │ ├── analysis.ts │ │ ├── astVisitor.ts │ │ ├── index.ts │ │ ├── scope.ts │ │ └── symbol.ts │ ├── main.ts │ ├── server.ts │ ├── services │ │ ├── completionService.ts │ │ ├── documentSymbolService.ts │ │ ├── formatService.ts │ │ ├── lintingService.ts │ │ └── workspaceSymbolService.ts │ └── utils.ts ├── tsconfig.json └── typings │ ├── index.d.ts │ └── modules │ └── luaparse │ ├── extensions.d.ts │ └── index.d.ts ├── src ├── extension.ts └── versionSelector.ts ├── test.lua ├── tsconfig.json └── tslint.json /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Optional npm cache directory 40 | .npm 41 | 42 | # Optional eslint cache 43 | .eslintcache 44 | 45 | # Optional REPL history 46 | .node_repl_history 47 | 48 | # Output of 'npm pack' 49 | *.tgz 50 | 51 | # Yarn Integrity file 52 | .yarn-integrity 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # Compiled server 58 | server/out/ 59 | 60 | # Build output 61 | out/ 62 | 63 | test_data/ 64 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | os: 3 | - linux 4 | language: node_js 5 | 6 | node_js: 7 | - "node" 8 | 9 | script: 10 | - npm install -g gulp 11 | - gulp 12 | 13 | after_success: 14 | - npm run package 15 | 16 | env: 17 | global: 18 | secure: QAM0xjbrfX2M2hEFpUR95vJM5o9Q9CkrkYPa2zNbKqRIqXFQ+++LHBTEj3uVCnewqN92Od4lyaYlmUOuSQhAPenp6FbU7sIwU556mDYHfkJeFYw6QqheiKPpe89Zdt6/TgB/v/Muzchl+ts2NI/JE1Lh7jgTn7jlQaGWkj/e5MVUQmYACu57Vd7BXA9m8PqZPhUQuHL0DnjeT/QeI4hS0o1H5Q1/14VRCJ120679v+EAACrwxVQ1ZUtMhja7r0q1CzotLtrzSRbgJ5laMiOkXtmYMqawiVwr1d098vUxgS3d27geH/oa1W/tDNKRDNzae0/4aQxokdM0ZXIJC/Ts2nGaD6Z6iqWDq2l279d/kkAOKZ4u829G4oO22V1bOxbFpqN08a3yFqpGSZvsP/Jukn1mUj325q+haC7CWqc29ycsgqB54FHVmS6mGB3rbUSXdH5eCzPylG/XXYuNCIQOGcDmH3K4CsXK9mhrBJV/wZhKPKn8HYtWC8a+2eN9B7wxxz3CRDPi7vmRtYF75x0mD7GBQhw1fwBXZVfIhhH1DJGZfl5pz10Iza+Mfgc3ga0CQjO+705DHZjIRD3RZb+9/dOcrXaOVMHUb4SFj3/ElbEpLzqRy0LuaEX5kCAOSQouNb2N5drW47U36C4gLgZnA8hwL0AcctoEg3d5oKA3mFQ= 19 | 20 | deploy: 21 | - provider: releases 22 | api_key: 23 | secure: rgl8x1sjWLXO/hueU8pL0aBSg0PT+PJiNDRxn+EMuzSESEDgihMBCyz8CR+gjSqfYDXnnPLqUk/BZL+3H1cAWiRVPlh7A5icYd1x7g6xuswQxvVamdBQ8e3BSsdj3BFWu4YYKzSW3ZoCpg5ANL1e5EUysPkmorrsNma8jt3O0TLDU7eSkxtRm4/UOunWVytckH15nmOjo5AWeiuJ3qc+iuSFFjg4/Mm9OfRfHI47Fc9m7hx5g/9nGvV+o5vJNq1i+Gii3+0rd1ewGyD0kkVl7JetYOAiUN8Q6qA58TVXOlFZ45lxGAwzOSryDmpOw8tjn/aVGugibmqbd1yVKimQnXW8bAQrGcJ3obYsbImAPTrhJRLrn3LRQichj9sbvBhH4b4F9K40be+sTOh2oNUyqfgN+qoKWz9tDk2S3g5moEnCUp4jED61hEWEoUNX7mV+hPQpnJHvSkbXPlXrIfslEWYytNYQL1TBJXOg99fKLjIHqOYokt0nOw46uaGN2IxStFMDTpSCF3+h47uYRBItrk9tHxT/ZmfL1tUD2n4W5dLvqLkp7YLIbuSdhgFD9+GVaB8vrQnkxw5pbXzmP7FHs4INE6qvOlwrDh5WwZDSCB8zSRtuTfiKoJXBhAjIv0p8HbZKhOxgdbGoCj0IO1XgTJys0lcPhyf55mEEblb0N/I= 24 | file_glob: true 25 | file: "*.vsix" 26 | skip_cleanup: true 27 | on: 28 | repo: trixnz/vscode-lua 29 | tags: true 30 | - provider: script 31 | script: npm run travis-deploy 32 | skip_cleanup: true 33 | on: 34 | repo: trixnz/vscode-lua 35 | tags: true 36 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.1.0", 4 | "configurations": [ 5 | { 6 | "name": "Launch Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "runtimeExecutable": "${execPath}", 10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], 11 | "stopOnEntry": false, 12 | "sourceMaps": true, 13 | "outFiles": [ "${workspaceRoot}/out/src/**/*.js" ], 14 | "preLaunchTask": "npm" 15 | }, 16 | { 17 | "name": "Launch Tests", 18 | "type": "extensionHost", 19 | "request": "launch", 20 | "runtimeExecutable": "${execPath}", 21 | "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], 22 | "stopOnEntry": false, 23 | "sourceMaps": true, 24 | "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ], 25 | "preLaunchTask": "npm" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/out": true, 5 | "**/node_modules": true 6 | }, 7 | "search.exclude": { 8 | "**/node_modules": true, 9 | "**/bower_components": true 10 | }, 11 | "vsicons.presets.angular": false, 12 | "editor.rulers": [ 13 | 120 14 | ], 15 | "files.eol": "\n", 16 | "files.insertFinalNewline": true, 17 | "files.trimTrailingWhitespace": true, 18 | "typescript.tsdk": "./node_modules/typescript/lib", 19 | "typescript.format.enable": true, 20 | "typescript.format.insertSpaceAfterCommaDelimiter": true, 21 | "typescript.format.insertSpaceAfterSemicolonInForStatements": true, 22 | "typescript.format.insertSpaceBeforeAndAfterBinaryOperators": true, 23 | "typescript.format.insertSpaceAfterKeywordsInControlFlowStatements": true, 24 | "typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true, 25 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, 26 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, 27 | "typescript.format.placeOpenBraceOnNewLineForFunctions": false, 28 | "typescript.format.placeOpenBraceOnNewLineForControlBlocks": false, 29 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, 30 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false 31 | } 32 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | // A task runner that calls a custom npm script that compiles the extension. 10 | { 11 | "version": "0.1.0", 12 | 13 | // we want to run npm 14 | "command": "npm", 15 | 16 | // the command is a shell script 17 | "isShellCommand": true, 18 | 19 | // show the output window only if unrecognized errors occur. 20 | "showOutput": "silent", 21 | 22 | // we run the custom script "compile" as defined in package.json 23 | "args": ["run", "compile", "--loglevel", "silent"], 24 | 25 | // The tsc compiler is started in watching mode 26 | "isWatching": true, 27 | 28 | // use the standard tsc in watch mode problem matcher to find compile problems in the output. 29 | "problemMatcher": "$tsc-watch" 30 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | vsc-extension-quickstart.md 10 | 11 | server/** 12 | test_data/** 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Cam 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/trixnz/vscode-lua.svg?branch=master)](https://travis-ci.org/trixnz/vscode-lua) [![Visual Studio Marketplace](https://vsmarketplacebadge.apphb.com/version/trixnz.vscode-lua.svg)](https://marketplace.visualstudio.com/items?itemName=trixnz.vscode-lua) 2 | 3 | # Lua for Visual Studio Code 4 | Provides Intellisense and Linting for Lua in VSCode 5 | 6 | ## Features 7 | - [x] Autocompletion 8 | - [x] Go to Symbol 9 | - [x] Error checking 10 | - [x] Linting 11 | - [x] Formatting 12 | - [ ] Code Snippets 13 | 14 | ## Installing 15 | * Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter: 16 | * `ext install vscode-lua` 17 | 18 | Alternatively, you can download the extension from the [marketplace](https://marketplace.visualstudio.com/items?itemName=trixnz.vscode-lua). 19 | 20 | ## Settings 21 | #### lua.luacheckPath (Default: `null`) 22 | Specifies the path to luacheck binary (if not found on `PATH`). 23 | #### lua.preferLuaCheckErrors (Default: `false`) 24 | Specifies whether to prefer luacheck errors over the standard luaparse errors if luacheck is available. 25 | #### lua.targetVersion (Default: `5.1`) 26 | Specifies the target version of Lua. Valid options: 27 | * 5.1 28 | * 5.2 29 | * 5.3 30 | 31 | Can also be changed using the version selector in the bottom right of the IDE. 32 | 33 | #### lua.format.enabled (Default: `true`) 34 | Specifies whether to use the Lua formatter 35 | #### lua.format.lineWidth (Default: `120`) 36 | Maximum length of a line before it will be wrapped. 37 | #### lua.format.indentCount (Default: `4`) 38 | Number of characters to indent. 39 | #### lua.format.singleQuote (Default: `false`) 40 | Whether to use single or double quotes on strings. Defaults to double quotes. 41 | 42 | #### lua.linting.enabled (Default: `true`) 43 | Specifies whether to enable linting of source files 44 | #### lua.linting.luaCheckConfig (Default: `null`) 45 | Path to a .luacheckrc to be used for linting, instead of the default luacheck search path 46 | #### lua.linting.luaCheckArgs (Default: `[]`) 47 | Additional arguments to pass to luacheck 48 | 49 | ## Luacheck 50 | Support for linting is provided via [luacheck](https://github.com/mpeterv/luacheck). Installation instructions can be found on the `luacheck` [repository](https://github.com/mpeterv/luacheck#installation). 51 | 52 | Once installed, `luacheck` support can be activated by assigning the `lua.luacheckPath` setting to the path of the `luacheck` executable. Additionally, since `luacheck` provides vastly more detailed and contextually aware errors that may sometimes duplicate those created by `luaparse`, the setting `lua.preferLuaCheckErrors` can be set to `true` to suppress `luaparse` errors. 53 | 54 | ## License 55 | 56 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 57 | 58 | ## Acknowledgments 59 | * [Oskar Schöldström](https://github.com/oxyc) - [luaparse](https://github.com/oxyc/luaparse): A Lua parser written in JavaScript 60 | * [Mikael Hermansson](https://github.com/mihe) - [node-hot](https://github.com/mihe/node-hot): Hot-reloading for Node.js 61 | * [Peter Melnichenko](https://github.com/mpeterv) - [luacheck](https://github.com/mpeterv/luacheck): A tool for linting and static analysis of Lua code. 62 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var tslint = require('gulp-tslint'); 3 | var shell = require('gulp-shell') 4 | var bump = require('gulp-bump') 5 | var git = require('gulp-git'); 6 | var tag_version = require('gulp-tag-version'); 7 | 8 | var serverFiles = { 9 | src: 'server/src/**/*.ts' 10 | }; 11 | 12 | var clientFiles = { 13 | src: './src/**/*.ts' 14 | } 15 | 16 | function bumpVersion(ver) { 17 | return gulp.src(['./package.json']) 18 | .pipe(bump({ type: ver })) 19 | .pipe(gulp.dest('./')) 20 | .pipe(git.commit('Bump package version')) 21 | .pipe(tag_version()); 22 | } 23 | 24 | gulp.task('compileClient', shell.task([ 25 | 'npm run vscode:prepublish' 26 | ])); 27 | 28 | gulp.task('compileServer', shell.task([ 29 | 'cd server && npm install && npm run compile' 30 | ])); 31 | 32 | gulp.task('tslint', function () { 33 | return gulp.src([serverFiles.src, clientFiles.src]) 34 | .pipe(tslint({ 35 | formatter: "verbose" 36 | })) 37 | .pipe(tslint.report()) 38 | }); 39 | 40 | gulp.task('build', gulp.series('compileClient', 'compileServer')) 41 | gulp.task('buildAndLint', gulp.series('tslint', 'build')) 42 | const buildAndLint = gulp.task('buildAndLint') 43 | 44 | gulp.task('patch', gulp.series(buildAndLint, function () { return bumpVersion('patch'); })); 45 | gulp.task('minor', gulp.series(buildAndLint, function () { return bumpVersion('minor'); })); 46 | gulp.task('major', gulp.series(buildAndLint, function () { return bumpVersion('major'); })); 47 | 48 | gulp.task('default', buildAndLint) 49 | -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trixnz/vscode-lua/e3c21515a86148a149cbbd272a01bcf53feaf578/images/icon.png -------------------------------------------------------------------------------- /language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | // Inherited from https://github.com/Microsoft/vscode/blob/a70d7cc9aebb782d6d3dbf7faa3c092081f44b58/extensions/lua/language-configuration.json 3 | "comments": { 4 | "lineComment": "--", 5 | "blockComment": [ 6 | "--[[", 7 | "]]" 8 | ] 9 | }, 10 | "brackets": [ 11 | [ 12 | "{", 13 | "}" 14 | ], 15 | [ 16 | "[", 17 | "]" 18 | ], 19 | [ 20 | "(", 21 | ")" 22 | ] 23 | ], 24 | "autoClosingPairs": [ 25 | [ 26 | "{", 27 | "}" 28 | ], 29 | [ 30 | "[", 31 | "]" 32 | ], 33 | [ 34 | "(", 35 | ")" 36 | ], 37 | [ 38 | "\"", 39 | "\"" 40 | ], 41 | [ 42 | "'", 43 | "'" 44 | ] 45 | ], 46 | "surroundingPairs": [ 47 | [ 48 | "{", 49 | "}" 50 | ], 51 | [ 52 | "[", 53 | "]" 54 | ], 55 | [ 56 | "(", 57 | ")" 58 | ], 59 | [ 60 | "\"", 61 | "\"" 62 | ], 63 | [ 64 | "'", 65 | "'" 66 | ] 67 | ], 68 | "indentationRules": { 69 | "increaseIndentPattern": "((\\b(else|function|then|do|repeat)\\b((?!\\b(end|until)\\b).)*)|(\\{\\s*))$", 70 | "decreaseIndentPattern": "^\\s*((\\b(elseif|else|end|until)\\b)|(\\})|(\\)))" 71 | }, 72 | // Added by vscode-lua 73 | "folding": { 74 | "markers": { 75 | "start": "^\\s*--\\s*#?region\\b", 76 | "end": "^\\s*--\\s*#?endregion\\b" 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-lua", 3 | "displayName": "vscode-lua", 4 | "description": "Intellisense and Linting for Lua", 5 | "version": "0.12.4", 6 | "publisher": "trixnz", 7 | "homepage": "https://github.com/trixnz/vscode-lua#readme", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/trixnz/vscode-lua" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/trixnz/vscode-lua/issues" 14 | }, 15 | "license": "MIT", 16 | "icon": "images/icon.png", 17 | "galleryBanner": { 18 | "color": "#313191", 19 | "theme": "dark" 20 | }, 21 | "engines": { 22 | "vscode": "^1.6.0" 23 | }, 24 | "categories": [ 25 | "Programming Languages", 26 | "Linters", 27 | "Formatters" 28 | ], 29 | "activationEvents": [ 30 | "onLanguage:lua" 31 | ], 32 | "main": "./out/src/extension", 33 | "contributes": { 34 | "languages": [ 35 | { 36 | "id": "lua", 37 | "aliases": [ 38 | "Lua" 39 | ], 40 | "extensions": [ 41 | ".lua", 42 | ".luacheckrc" 43 | ], 44 | "configuration": "./language-configuration.json" 45 | } 46 | ], 47 | "configuration": { 48 | "title": "Lua", 49 | "properties": { 50 | "lua.luacheckPath": { 51 | "type": [ 52 | "string" 53 | ], 54 | "default": "luacheck", 55 | "description": "Specifies the path to the luacheck binary (if not found on PATH).\nNote: luacheck can be invoked via a .bat or a .exe file, depending on the version you have. Make sure you specify the correct one." 56 | }, 57 | "lua.preferLuaCheckErrors": { 58 | "type": "boolean", 59 | "default": false, 60 | "description": "Specifies whether to prefer luacheck errors over the standard luaparse errors if luacheck is available" 61 | }, 62 | "lua.targetVersion": { 63 | "type": "string", 64 | "default": "5.1", 65 | "description": "Specifies the target version of Lua", 66 | "enum": [ 67 | "5.1", 68 | "5.2", 69 | "5.3" 70 | ] 71 | }, 72 | "lua.format.enabled": { 73 | "type": "boolean", 74 | "default": true, 75 | "description": "Specifies whether to use the Lua formatter" 76 | }, 77 | "lua.format.lineWidth": { 78 | "type": "integer", 79 | "default": 120, 80 | "description": "Maximum length of a line before it will be wrapped" 81 | }, 82 | "lua.format.useTabs": { 83 | "type": [ 84 | "null", 85 | "boolean" 86 | ], 87 | "default": null, 88 | "description": "Force the formatter to use tabs over spaces. A value of null (default) indicates that editor settings should be used." 89 | }, 90 | "lua.format.indentCount": { 91 | "type": [ 92 | "null", 93 | "integer" 94 | ], 95 | "default": null, 96 | "description": "Number of spaces to indent. A value of null (default) indicates that editor settings should be used." 97 | }, 98 | "lua.format.singleQuote": { 99 | "type": "boolean", 100 | "default": false, 101 | "description": "Whether to use single or double quotes on strings. Defaults to double quotes" 102 | }, 103 | "lua.server.command": { 104 | "type": [ 105 | "string", 106 | "null" 107 | ], 108 | "default": null, 109 | "description": "When defined, uses an external language server using the given shell command." 110 | }, 111 | "lua.server.arguments": { 112 | "type": "array", 113 | "items": { 114 | "type": "string", 115 | "title": "arguments" 116 | }, 117 | "default": [], 118 | "description": "When lua.server.command is defined, pass as command line arguments." 119 | }, 120 | "lua.format.linebreakMultipleAssignments": { 121 | "type": "boolean", 122 | "default": false, 123 | "description": "Whether to split multiple assignments onto separate lines. Defaults to false" 124 | }, 125 | "lua.linting.enabled": { 126 | "type": "boolean", 127 | "default": true, 128 | "description": "Specifies whether to enable linting of source files" 129 | }, 130 | "lua.linting.luaCheckConfig": { 131 | "type": [ 132 | "string", 133 | "null" 134 | ], 135 | "default": null, 136 | "description": "Path to a .luacheckrc to be used for linting, instead of the default luacheck search path" 137 | }, 138 | "lua.linting.luaCheckArgs": { 139 | "type": "array", 140 | "items": { 141 | "type": "string", 142 | "title": "arguments" 143 | }, 144 | "default": [], 145 | "description": "Additional arguments to pass to luacheck" 146 | } 147 | } 148 | } 149 | }, 150 | "scripts": { 151 | "vscode:prepublish": "tsc -p ./", 152 | "compile": "tsc -watch -p ./", 153 | "postinstall": "node ./node_modules/vscode/bin/install", 154 | "package": "vsce package", 155 | "travis-deploy": "vsce publish -p $VS_TOKEN" 156 | }, 157 | "devDependencies": { 158 | "@types/node": "^10.12.18", 159 | "gulp": "^4.0.0", 160 | "gulp-bump": "^3.1.1", 161 | "gulp-git": "^2.8.0", 162 | "gulp-shell": "^0.6.5", 163 | "gulp-tag-version": "^1.3.1", 164 | "gulp-tslint": "^8.1.3", 165 | "require-dir": "^1.2.0", 166 | "tslint": "^5.12.0", 167 | "typescript": "^3.2.2", 168 | "vsce": "^1.54.0", 169 | "vscode": "^1.1.26" 170 | }, 171 | "dependencies": { 172 | "vscode-languageclient": "^5.2.1" 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Optional npm cache directory 40 | .npm 41 | 42 | # Optional eslint cache 43 | .eslintcache 44 | 45 | # Optional REPL history 46 | .node_repl_history 47 | 48 | # Output of 'npm pack' 49 | *.tgz 50 | 51 | # Yarn Integrity file 52 | .yarn-integrity 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # Build output 58 | out/ -------------------------------------------------------------------------------- /server/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible Node.js debug attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Attach to Process", 9 | "type": "node", 10 | "request": "attach", 11 | "port": 6009, 12 | "sourceMaps": true, 13 | "outFiles": [ 14 | "../out/server/**/*.js" 15 | ] 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /server/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/out": true, 5 | "**/node_modules": true 6 | }, 7 | "search.exclude": { 8 | "**/node_modules": true, 9 | "**/bower_components": true 10 | }, 11 | "vsicons.presets.angular": false, 12 | "editor.rulers": [ 13 | 120 14 | ], 15 | "files.eol": "\n", 16 | "files.insertFinalNewline": true, 17 | "files.trimTrailingWhitespace": true, 18 | "typescript.tsdk": "./node_modules/typescript/lib", 19 | "typescript.format.enable": true, 20 | "typescript.format.insertSpaceAfterCommaDelimiter": true, 21 | "typescript.format.insertSpaceAfterSemicolonInForStatements": true, 22 | "typescript.format.insertSpaceBeforeAndAfterBinaryOperators": true, 23 | "typescript.format.insertSpaceAfterKeywordsInControlFlowStatements": true, 24 | "typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true, 25 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, 26 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, 27 | "typescript.format.placeOpenBraceOnNewLineForFunctions": false, 28 | "typescript.format.placeOpenBraceOnNewLineForControlBlocks": false, 29 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, 30 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false 31 | } 32 | -------------------------------------------------------------------------------- /server/bin/installDevServerIntoExtension: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | var cp = require('child_process'); 6 | 7 | var extensionDirectory = process.argv[2]; 8 | if (!extensionDirectory) { 9 | console.error('No extension directory provided.'); 10 | process.exit(1) 11 | } 12 | extensionDirectory = path.resolve(extensionDirectory) 13 | if (!fs.existsSync(extensionDirectory)) { 14 | console.error('Extension directory ' + extensionDirectory + ' doesn\'t exist on disk.'); 15 | process.exit(1); 16 | } 17 | 18 | var packageFile = process.argv[3]; 19 | if (!packageFile) { 20 | console.error('No package.json file provided.'); 21 | process.exit(1); 22 | } 23 | packageFile = path.resolve(packageFile); 24 | if (!fs.existsSync(packageFile)) { 25 | console.error('Package file ' + packageFile + ' doesn\'t exist on disk.'); 26 | process.exit(1); 27 | } 28 | var tsconfigFile = process.argv[4]; 29 | if (!tsconfigFile) { 30 | console.error('No tsconfig.json file provided'); 31 | process.exit(1); 32 | } 33 | tsconfigFile = path.resolve(tsconfigFile); 34 | if (!fs.existsSync(tsconfigFile)) { 35 | console.error('tsconfig file ' + tsconfigFile + ' doesn\'t exist on disk.') 36 | process.exit(1); 37 | } 38 | 39 | var extensionServerDirectory = path.join(extensionDirectory, 'server') 40 | 41 | var json = require(tsconfigFile); 42 | var compilerOptions = json.compilerOptions; 43 | if (compilerOptions) { 44 | var outDir = compilerOptions.outDir; 45 | if (!outDir || path.join(path.dirname(tsconfigFile), outDir) !== extensionServerDirectory) { 46 | console.error('outDir in ' + process.argv[4] + ' must point to ' + extensionServerDirectory + ' but it points to ' + path.join(path.dirname(tsconfigFile), outDir)); 47 | console.error('Please change outDir in ' + process.argv[4] + ' to ' + path.relative(path.dirname(tsconfigFile), extensionServerDirectory).replace(/\\/g, '/')); 48 | process.exit(1); 49 | } 50 | } 51 | 52 | if (!fs.existsSync(extensionServerDirectory)) { 53 | fs.mkdirSync(extensionServerDirectory); 54 | } 55 | 56 | var dest = path.join(extensionServerDirectory, 'package.json'); 57 | console.log('Copying package.json to extension\'s server location...'); 58 | fs.writeFileSync(dest, fs.readFileSync(packageFile)); 59 | 60 | console.log('Updating server npm modules into extension\'s server location...'); 61 | cp.execSync('npm update --prefix ' + extensionServerDirectory); 62 | 63 | console.log('Updating server dev-npm modules into extension\'s server location...'); 64 | cp.execSync('npm update -D --prefix ' + extensionServerDirectory); 65 | -------------------------------------------------------------------------------- /server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "language-server-lua", 3 | "version": "0.0.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/commander": { 8 | "version": "2.12.2", 9 | "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.2.tgz", 10 | "integrity": "sha1-GDBBojhC1CgUePpdI8XKeOb9CK4=", 11 | "requires": { 12 | "commander": "*" 13 | } 14 | }, 15 | "@types/diff": { 16 | "version": "3.5.2", 17 | "resolved": "https://registry.npmjs.org/@types/diff/-/diff-3.5.2.tgz", 18 | "integrity": "sha512-T1y8ed2DipuUGqgzWzBDUMlJM1bD1CG73ETOi08VURsGArjRfC4nqfeC5owrV7SFvgbeKDbonI/Es4vQgJ2IKA==" 19 | }, 20 | "@types/get-stdin": { 21 | "version": "5.0.1", 22 | "resolved": "https://registry.npmjs.org/@types/get-stdin/-/get-stdin-5.0.1.tgz", 23 | "integrity": "sha1-Rq+8rwnpT+Alr6B66ZSsMWitvfM=", 24 | "requires": { 25 | "@types/node": "*" 26 | } 27 | }, 28 | "@types/node": { 29 | "version": "10.12.18", 30 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", 31 | "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" 32 | }, 33 | "@types/node-dir": { 34 | "version": "0.0.32", 35 | "resolved": "https://registry.npmjs.org/@types/node-dir/-/node-dir-0.0.32.tgz", 36 | "integrity": "sha512-M0++KmfiQ3DkSwx4O7glGut17ORbb+wuSfxLafMakAv8wmhAazTKb7ghfwYoqhRRErZ2quYQBYIppj5TPGaKVw==", 37 | "requires": { 38 | "@types/node": "*" 39 | } 40 | }, 41 | "ansi-regex": { 42 | "version": "2.1.1", 43 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 44 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 45 | "dev": true 46 | }, 47 | "ansi-styles": { 48 | "version": "2.2.1", 49 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 50 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 51 | "dev": true 52 | }, 53 | "anymatch": { 54 | "version": "2.0.0", 55 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", 56 | "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", 57 | "dev": true, 58 | "requires": { 59 | "micromatch": "^3.1.4", 60 | "normalize-path": "^2.1.1" 61 | } 62 | }, 63 | "argparse": { 64 | "version": "1.0.10", 65 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 66 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 67 | "dev": true, 68 | "requires": { 69 | "sprintf-js": "~1.0.2" 70 | } 71 | }, 72 | "arr-diff": { 73 | "version": "4.0.0", 74 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", 75 | "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", 76 | "dev": true 77 | }, 78 | "arr-flatten": { 79 | "version": "1.1.0", 80 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", 81 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", 82 | "dev": true 83 | }, 84 | "arr-union": { 85 | "version": "3.1.0", 86 | "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", 87 | "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", 88 | "dev": true 89 | }, 90 | "array-unique": { 91 | "version": "0.3.2", 92 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", 93 | "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", 94 | "dev": true 95 | }, 96 | "assign-symbols": { 97 | "version": "1.0.0", 98 | "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", 99 | "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", 100 | "dev": true 101 | }, 102 | "async-each": { 103 | "version": "1.0.1", 104 | "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", 105 | "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", 106 | "dev": true 107 | }, 108 | "atob": { 109 | "version": "2.1.2", 110 | "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", 111 | "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", 112 | "dev": true 113 | }, 114 | "babel-code-frame": { 115 | "version": "6.26.0", 116 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 117 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 118 | "dev": true, 119 | "requires": { 120 | "chalk": "^1.1.3", 121 | "esutils": "^2.0.2", 122 | "js-tokens": "^3.0.2" 123 | }, 124 | "dependencies": { 125 | "chalk": { 126 | "version": "1.1.3", 127 | "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 128 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 129 | "dev": true, 130 | "requires": { 131 | "ansi-styles": "^2.2.1", 132 | "escape-string-regexp": "^1.0.2", 133 | "has-ansi": "^2.0.0", 134 | "strip-ansi": "^3.0.0", 135 | "supports-color": "^2.0.0" 136 | } 137 | } 138 | } 139 | }, 140 | "balanced-match": { 141 | "version": "1.0.0", 142 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 143 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 144 | }, 145 | "base": { 146 | "version": "0.11.2", 147 | "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", 148 | "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", 149 | "dev": true, 150 | "requires": { 151 | "cache-base": "^1.0.1", 152 | "class-utils": "^0.3.5", 153 | "component-emitter": "^1.2.1", 154 | "define-property": "^1.0.0", 155 | "isobject": "^3.0.1", 156 | "mixin-deep": "^1.2.0", 157 | "pascalcase": "^0.1.1" 158 | }, 159 | "dependencies": { 160 | "define-property": { 161 | "version": "1.0.0", 162 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 163 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 164 | "dev": true, 165 | "requires": { 166 | "is-descriptor": "^1.0.0" 167 | } 168 | }, 169 | "is-accessor-descriptor": { 170 | "version": "1.0.0", 171 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 172 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 173 | "dev": true, 174 | "requires": { 175 | "kind-of": "^6.0.0" 176 | } 177 | }, 178 | "is-data-descriptor": { 179 | "version": "1.0.0", 180 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 181 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 182 | "dev": true, 183 | "requires": { 184 | "kind-of": "^6.0.0" 185 | } 186 | }, 187 | "is-descriptor": { 188 | "version": "1.0.2", 189 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 190 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 191 | "dev": true, 192 | "requires": { 193 | "is-accessor-descriptor": "^1.0.0", 194 | "is-data-descriptor": "^1.0.0", 195 | "kind-of": "^6.0.2" 196 | } 197 | } 198 | } 199 | }, 200 | "binary-extensions": { 201 | "version": "1.12.0", 202 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", 203 | "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", 204 | "dev": true 205 | }, 206 | "brace-expansion": { 207 | "version": "1.1.11", 208 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 209 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 210 | "requires": { 211 | "balanced-match": "^1.0.0", 212 | "concat-map": "0.0.1" 213 | } 214 | }, 215 | "braces": { 216 | "version": "2.3.2", 217 | "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", 218 | "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", 219 | "dev": true, 220 | "requires": { 221 | "arr-flatten": "^1.1.0", 222 | "array-unique": "^0.3.2", 223 | "extend-shallow": "^2.0.1", 224 | "fill-range": "^4.0.0", 225 | "isobject": "^3.0.1", 226 | "repeat-element": "^1.1.2", 227 | "snapdragon": "^0.8.1", 228 | "snapdragon-node": "^2.0.1", 229 | "split-string": "^3.0.2", 230 | "to-regex": "^3.0.1" 231 | }, 232 | "dependencies": { 233 | "extend-shallow": { 234 | "version": "2.0.1", 235 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 236 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 237 | "dev": true, 238 | "requires": { 239 | "is-extendable": "^0.1.0" 240 | } 241 | } 242 | } 243 | }, 244 | "buffer-from": { 245 | "version": "1.1.1", 246 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 247 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 248 | }, 249 | "builtin-modules": { 250 | "version": "1.1.1", 251 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 252 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 253 | "dev": true 254 | }, 255 | "cache-base": { 256 | "version": "1.0.1", 257 | "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", 258 | "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", 259 | "dev": true, 260 | "requires": { 261 | "collection-visit": "^1.0.0", 262 | "component-emitter": "^1.2.1", 263 | "get-value": "^2.0.6", 264 | "has-value": "^1.0.0", 265 | "isobject": "^3.0.1", 266 | "set-value": "^2.0.0", 267 | "to-object-path": "^0.3.0", 268 | "union-value": "^1.0.0", 269 | "unset-value": "^1.0.0" 270 | } 271 | }, 272 | "chalk": { 273 | "version": "2.4.1", 274 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 275 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 276 | "dev": true, 277 | "requires": { 278 | "ansi-styles": "^3.2.1", 279 | "escape-string-regexp": "^1.0.5", 280 | "supports-color": "^5.3.0" 281 | }, 282 | "dependencies": { 283 | "ansi-styles": { 284 | "version": "3.2.1", 285 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 286 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 287 | "dev": true, 288 | "requires": { 289 | "color-convert": "^1.9.0" 290 | } 291 | }, 292 | "supports-color": { 293 | "version": "5.5.0", 294 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 295 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 296 | "dev": true, 297 | "requires": { 298 | "has-flag": "^3.0.0" 299 | } 300 | } 301 | } 302 | }, 303 | "chokidar": { 304 | "version": "2.0.4", 305 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", 306 | "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", 307 | "dev": true, 308 | "requires": { 309 | "anymatch": "^2.0.0", 310 | "async-each": "^1.0.0", 311 | "braces": "^2.3.0", 312 | "fsevents": "^1.2.2", 313 | "glob-parent": "^3.1.0", 314 | "inherits": "^2.0.1", 315 | "is-binary-path": "^1.0.0", 316 | "is-glob": "^4.0.0", 317 | "lodash.debounce": "^4.0.8", 318 | "normalize-path": "^2.1.1", 319 | "path-is-absolute": "^1.0.0", 320 | "readdirp": "^2.0.0", 321 | "upath": "^1.0.5" 322 | } 323 | }, 324 | "class-utils": { 325 | "version": "0.3.6", 326 | "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", 327 | "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", 328 | "dev": true, 329 | "requires": { 330 | "arr-union": "^3.1.0", 331 | "define-property": "^0.2.5", 332 | "isobject": "^3.0.0", 333 | "static-extend": "^0.1.1" 334 | }, 335 | "dependencies": { 336 | "define-property": { 337 | "version": "0.2.5", 338 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 339 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 340 | "dev": true, 341 | "requires": { 342 | "is-descriptor": "^0.1.0" 343 | } 344 | } 345 | } 346 | }, 347 | "collection-visit": { 348 | "version": "1.0.0", 349 | "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", 350 | "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", 351 | "dev": true, 352 | "requires": { 353 | "map-visit": "^1.0.0", 354 | "object-visit": "^1.0.0" 355 | } 356 | }, 357 | "color-convert": { 358 | "version": "1.9.3", 359 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 360 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 361 | "dev": true, 362 | "requires": { 363 | "color-name": "1.1.3" 364 | } 365 | }, 366 | "color-name": { 367 | "version": "1.1.3", 368 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 369 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 370 | "dev": true 371 | }, 372 | "commander": { 373 | "version": "2.15.0", 374 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.0.tgz", 375 | "integrity": "sha512-7B1ilBwtYSbetCgTY1NJFg+gVpestg0fdA1MhC1Vs4ssyfSXnCAjFr+QcQM9/RedXC0EaUx1sG8Smgw2VfgKEg==" 376 | }, 377 | "component-emitter": { 378 | "version": "1.2.1", 379 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 380 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", 381 | "dev": true 382 | }, 383 | "concat-map": { 384 | "version": "0.0.1", 385 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 386 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 387 | }, 388 | "copy-descriptor": { 389 | "version": "0.1.1", 390 | "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", 391 | "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", 392 | "dev": true 393 | }, 394 | "core-util-is": { 395 | "version": "1.0.2", 396 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 397 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 398 | "dev": true 399 | }, 400 | "debug": { 401 | "version": "2.6.9", 402 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 403 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 404 | "dev": true, 405 | "requires": { 406 | "ms": "2.0.0" 407 | } 408 | }, 409 | "decode-uri-component": { 410 | "version": "0.2.0", 411 | "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", 412 | "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", 413 | "dev": true 414 | }, 415 | "define-property": { 416 | "version": "2.0.2", 417 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", 418 | "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", 419 | "dev": true, 420 | "requires": { 421 | "is-descriptor": "^1.0.2", 422 | "isobject": "^3.0.1" 423 | }, 424 | "dependencies": { 425 | "is-accessor-descriptor": { 426 | "version": "1.0.0", 427 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 428 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 429 | "dev": true, 430 | "requires": { 431 | "kind-of": "^6.0.0" 432 | } 433 | }, 434 | "is-data-descriptor": { 435 | "version": "1.0.0", 436 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 437 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 438 | "dev": true, 439 | "requires": { 440 | "kind-of": "^6.0.0" 441 | } 442 | }, 443 | "is-descriptor": { 444 | "version": "1.0.2", 445 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 446 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 447 | "dev": true, 448 | "requires": { 449 | "is-accessor-descriptor": "^1.0.0", 450 | "is-data-descriptor": "^1.0.0", 451 | "kind-of": "^6.0.2" 452 | } 453 | } 454 | } 455 | }, 456 | "diff": { 457 | "version": "3.5.0", 458 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 459 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" 460 | }, 461 | "escape-string-regexp": { 462 | "version": "1.0.5", 463 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 464 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 465 | "dev": true 466 | }, 467 | "esprima": { 468 | "version": "4.0.1", 469 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 470 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 471 | "dev": true 472 | }, 473 | "esutils": { 474 | "version": "2.0.2", 475 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 476 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 477 | "dev": true 478 | }, 479 | "expand-brackets": { 480 | "version": "2.1.4", 481 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", 482 | "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", 483 | "dev": true, 484 | "requires": { 485 | "debug": "^2.3.3", 486 | "define-property": "^0.2.5", 487 | "extend-shallow": "^2.0.1", 488 | "posix-character-classes": "^0.1.0", 489 | "regex-not": "^1.0.0", 490 | "snapdragon": "^0.8.1", 491 | "to-regex": "^3.0.1" 492 | }, 493 | "dependencies": { 494 | "define-property": { 495 | "version": "0.2.5", 496 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 497 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 498 | "dev": true, 499 | "requires": { 500 | "is-descriptor": "^0.1.0" 501 | } 502 | }, 503 | "extend-shallow": { 504 | "version": "2.0.1", 505 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 506 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 507 | "dev": true, 508 | "requires": { 509 | "is-extendable": "^0.1.0" 510 | } 511 | } 512 | } 513 | }, 514 | "extend-shallow": { 515 | "version": "3.0.2", 516 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", 517 | "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", 518 | "dev": true, 519 | "requires": { 520 | "assign-symbols": "^1.0.0", 521 | "is-extendable": "^1.0.1" 522 | }, 523 | "dependencies": { 524 | "is-extendable": { 525 | "version": "1.0.1", 526 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 527 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 528 | "dev": true, 529 | "requires": { 530 | "is-plain-object": "^2.0.4" 531 | } 532 | } 533 | } 534 | }, 535 | "extglob": { 536 | "version": "2.0.4", 537 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", 538 | "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", 539 | "dev": true, 540 | "requires": { 541 | "array-unique": "^0.3.2", 542 | "define-property": "^1.0.0", 543 | "expand-brackets": "^2.1.4", 544 | "extend-shallow": "^2.0.1", 545 | "fragment-cache": "^0.2.1", 546 | "regex-not": "^1.0.0", 547 | "snapdragon": "^0.8.1", 548 | "to-regex": "^3.0.1" 549 | }, 550 | "dependencies": { 551 | "define-property": { 552 | "version": "1.0.0", 553 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 554 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 555 | "dev": true, 556 | "requires": { 557 | "is-descriptor": "^1.0.0" 558 | } 559 | }, 560 | "extend-shallow": { 561 | "version": "2.0.1", 562 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 563 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 564 | "dev": true, 565 | "requires": { 566 | "is-extendable": "^0.1.0" 567 | } 568 | }, 569 | "is-accessor-descriptor": { 570 | "version": "1.0.0", 571 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 572 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 573 | "dev": true, 574 | "requires": { 575 | "kind-of": "^6.0.0" 576 | } 577 | }, 578 | "is-data-descriptor": { 579 | "version": "1.0.0", 580 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 581 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 582 | "dev": true, 583 | "requires": { 584 | "kind-of": "^6.0.0" 585 | } 586 | }, 587 | "is-descriptor": { 588 | "version": "1.0.2", 589 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 590 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 591 | "dev": true, 592 | "requires": { 593 | "is-accessor-descriptor": "^1.0.0", 594 | "is-data-descriptor": "^1.0.0", 595 | "kind-of": "^6.0.2" 596 | } 597 | } 598 | } 599 | }, 600 | "fill-range": { 601 | "version": "4.0.0", 602 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", 603 | "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", 604 | "dev": true, 605 | "requires": { 606 | "extend-shallow": "^2.0.1", 607 | "is-number": "^3.0.0", 608 | "repeat-string": "^1.6.1", 609 | "to-regex-range": "^2.1.0" 610 | }, 611 | "dependencies": { 612 | "extend-shallow": { 613 | "version": "2.0.1", 614 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 615 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 616 | "dev": true, 617 | "requires": { 618 | "is-extendable": "^0.1.0" 619 | } 620 | } 621 | } 622 | }, 623 | "for-in": { 624 | "version": "1.0.2", 625 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", 626 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", 627 | "dev": true 628 | }, 629 | "fragment-cache": { 630 | "version": "0.2.1", 631 | "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", 632 | "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", 633 | "dev": true, 634 | "requires": { 635 | "map-cache": "^0.2.2" 636 | } 637 | }, 638 | "fs.realpath": { 639 | "version": "1.0.0", 640 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 641 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 642 | "dev": true 643 | }, 644 | "fsevents": { 645 | "version": "1.2.4", 646 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", 647 | "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", 648 | "dev": true, 649 | "optional": true, 650 | "requires": { 651 | "nan": "^2.9.2", 652 | "node-pre-gyp": "^0.10.0" 653 | }, 654 | "dependencies": { 655 | "abbrev": { 656 | "version": "1.1.1", 657 | "bundled": true, 658 | "dev": true, 659 | "optional": true 660 | }, 661 | "ansi-regex": { 662 | "version": "2.1.1", 663 | "bundled": true, 664 | "dev": true 665 | }, 666 | "aproba": { 667 | "version": "1.2.0", 668 | "bundled": true, 669 | "dev": true, 670 | "optional": true 671 | }, 672 | "are-we-there-yet": { 673 | "version": "1.1.4", 674 | "bundled": true, 675 | "dev": true, 676 | "optional": true, 677 | "requires": { 678 | "delegates": "^1.0.0", 679 | "readable-stream": "^2.0.6" 680 | } 681 | }, 682 | "balanced-match": { 683 | "version": "1.0.0", 684 | "bundled": true, 685 | "dev": true 686 | }, 687 | "brace-expansion": { 688 | "version": "1.1.11", 689 | "bundled": true, 690 | "dev": true, 691 | "requires": { 692 | "balanced-match": "^1.0.0", 693 | "concat-map": "0.0.1" 694 | } 695 | }, 696 | "chownr": { 697 | "version": "1.0.1", 698 | "bundled": true, 699 | "dev": true, 700 | "optional": true 701 | }, 702 | "code-point-at": { 703 | "version": "1.1.0", 704 | "bundled": true, 705 | "dev": true 706 | }, 707 | "concat-map": { 708 | "version": "0.0.1", 709 | "bundled": true, 710 | "dev": true 711 | }, 712 | "console-control-strings": { 713 | "version": "1.1.0", 714 | "bundled": true, 715 | "dev": true 716 | }, 717 | "core-util-is": { 718 | "version": "1.0.2", 719 | "bundled": true, 720 | "dev": true, 721 | "optional": true 722 | }, 723 | "debug": { 724 | "version": "2.6.9", 725 | "bundled": true, 726 | "dev": true, 727 | "optional": true, 728 | "requires": { 729 | "ms": "2.0.0" 730 | } 731 | }, 732 | "deep-extend": { 733 | "version": "0.5.1", 734 | "bundled": true, 735 | "dev": true, 736 | "optional": true 737 | }, 738 | "delegates": { 739 | "version": "1.0.0", 740 | "bundled": true, 741 | "dev": true, 742 | "optional": true 743 | }, 744 | "detect-libc": { 745 | "version": "1.0.3", 746 | "bundled": true, 747 | "dev": true, 748 | "optional": true 749 | }, 750 | "fs-minipass": { 751 | "version": "1.2.5", 752 | "bundled": true, 753 | "dev": true, 754 | "optional": true, 755 | "requires": { 756 | "minipass": "^2.2.1" 757 | } 758 | }, 759 | "fs.realpath": { 760 | "version": "1.0.0", 761 | "bundled": true, 762 | "dev": true, 763 | "optional": true 764 | }, 765 | "gauge": { 766 | "version": "2.7.4", 767 | "bundled": true, 768 | "dev": true, 769 | "optional": true, 770 | "requires": { 771 | "aproba": "^1.0.3", 772 | "console-control-strings": "^1.0.0", 773 | "has-unicode": "^2.0.0", 774 | "object-assign": "^4.1.0", 775 | "signal-exit": "^3.0.0", 776 | "string-width": "^1.0.1", 777 | "strip-ansi": "^3.0.1", 778 | "wide-align": "^1.1.0" 779 | } 780 | }, 781 | "glob": { 782 | "version": "7.1.2", 783 | "bundled": true, 784 | "dev": true, 785 | "optional": true, 786 | "requires": { 787 | "fs.realpath": "^1.0.0", 788 | "inflight": "^1.0.4", 789 | "inherits": "2", 790 | "minimatch": "^3.0.4", 791 | "once": "^1.3.0", 792 | "path-is-absolute": "^1.0.0" 793 | } 794 | }, 795 | "has-unicode": { 796 | "version": "2.0.1", 797 | "bundled": true, 798 | "dev": true, 799 | "optional": true 800 | }, 801 | "iconv-lite": { 802 | "version": "0.4.21", 803 | "bundled": true, 804 | "dev": true, 805 | "optional": true, 806 | "requires": { 807 | "safer-buffer": "^2.1.0" 808 | } 809 | }, 810 | "ignore-walk": { 811 | "version": "3.0.1", 812 | "bundled": true, 813 | "dev": true, 814 | "optional": true, 815 | "requires": { 816 | "minimatch": "^3.0.4" 817 | } 818 | }, 819 | "inflight": { 820 | "version": "1.0.6", 821 | "bundled": true, 822 | "dev": true, 823 | "optional": true, 824 | "requires": { 825 | "once": "^1.3.0", 826 | "wrappy": "1" 827 | } 828 | }, 829 | "inherits": { 830 | "version": "2.0.3", 831 | "bundled": true, 832 | "dev": true 833 | }, 834 | "ini": { 835 | "version": "1.3.5", 836 | "bundled": true, 837 | "dev": true, 838 | "optional": true 839 | }, 840 | "is-fullwidth-code-point": { 841 | "version": "1.0.0", 842 | "bundled": true, 843 | "dev": true, 844 | "requires": { 845 | "number-is-nan": "^1.0.0" 846 | } 847 | }, 848 | "isarray": { 849 | "version": "1.0.0", 850 | "bundled": true, 851 | "dev": true, 852 | "optional": true 853 | }, 854 | "minimatch": { 855 | "version": "3.0.4", 856 | "bundled": true, 857 | "dev": true, 858 | "requires": { 859 | "brace-expansion": "^1.1.7" 860 | } 861 | }, 862 | "minimist": { 863 | "version": "0.0.8", 864 | "bundled": true, 865 | "dev": true 866 | }, 867 | "minipass": { 868 | "version": "2.2.4", 869 | "bundled": true, 870 | "dev": true, 871 | "requires": { 872 | "safe-buffer": "^5.1.1", 873 | "yallist": "^3.0.0" 874 | } 875 | }, 876 | "minizlib": { 877 | "version": "1.1.0", 878 | "bundled": true, 879 | "dev": true, 880 | "optional": true, 881 | "requires": { 882 | "minipass": "^2.2.1" 883 | } 884 | }, 885 | "mkdirp": { 886 | "version": "0.5.1", 887 | "bundled": true, 888 | "dev": true, 889 | "requires": { 890 | "minimist": "0.0.8" 891 | } 892 | }, 893 | "ms": { 894 | "version": "2.0.0", 895 | "bundled": true, 896 | "dev": true, 897 | "optional": true 898 | }, 899 | "needle": { 900 | "version": "2.2.0", 901 | "bundled": true, 902 | "dev": true, 903 | "optional": true, 904 | "requires": { 905 | "debug": "^2.1.2", 906 | "iconv-lite": "^0.4.4", 907 | "sax": "^1.2.4" 908 | } 909 | }, 910 | "node-pre-gyp": { 911 | "version": "0.10.0", 912 | "bundled": true, 913 | "dev": true, 914 | "optional": true, 915 | "requires": { 916 | "detect-libc": "^1.0.2", 917 | "mkdirp": "^0.5.1", 918 | "needle": "^2.2.0", 919 | "nopt": "^4.0.1", 920 | "npm-packlist": "^1.1.6", 921 | "npmlog": "^4.0.2", 922 | "rc": "^1.1.7", 923 | "rimraf": "^2.6.1", 924 | "semver": "^5.3.0", 925 | "tar": "^4" 926 | } 927 | }, 928 | "nopt": { 929 | "version": "4.0.1", 930 | "bundled": true, 931 | "dev": true, 932 | "optional": true, 933 | "requires": { 934 | "abbrev": "1", 935 | "osenv": "^0.1.4" 936 | } 937 | }, 938 | "npm-bundled": { 939 | "version": "1.0.3", 940 | "bundled": true, 941 | "dev": true, 942 | "optional": true 943 | }, 944 | "npm-packlist": { 945 | "version": "1.1.10", 946 | "bundled": true, 947 | "dev": true, 948 | "optional": true, 949 | "requires": { 950 | "ignore-walk": "^3.0.1", 951 | "npm-bundled": "^1.0.1" 952 | } 953 | }, 954 | "npmlog": { 955 | "version": "4.1.2", 956 | "bundled": true, 957 | "dev": true, 958 | "optional": true, 959 | "requires": { 960 | "are-we-there-yet": "~1.1.2", 961 | "console-control-strings": "~1.1.0", 962 | "gauge": "~2.7.3", 963 | "set-blocking": "~2.0.0" 964 | } 965 | }, 966 | "number-is-nan": { 967 | "version": "1.0.1", 968 | "bundled": true, 969 | "dev": true 970 | }, 971 | "object-assign": { 972 | "version": "4.1.1", 973 | "bundled": true, 974 | "dev": true, 975 | "optional": true 976 | }, 977 | "once": { 978 | "version": "1.4.0", 979 | "bundled": true, 980 | "dev": true, 981 | "requires": { 982 | "wrappy": "1" 983 | } 984 | }, 985 | "os-homedir": { 986 | "version": "1.0.2", 987 | "bundled": true, 988 | "dev": true, 989 | "optional": true 990 | }, 991 | "os-tmpdir": { 992 | "version": "1.0.2", 993 | "bundled": true, 994 | "dev": true, 995 | "optional": true 996 | }, 997 | "osenv": { 998 | "version": "0.1.5", 999 | "bundled": true, 1000 | "dev": true, 1001 | "optional": true, 1002 | "requires": { 1003 | "os-homedir": "^1.0.0", 1004 | "os-tmpdir": "^1.0.0" 1005 | } 1006 | }, 1007 | "path-is-absolute": { 1008 | "version": "1.0.1", 1009 | "bundled": true, 1010 | "dev": true, 1011 | "optional": true 1012 | }, 1013 | "process-nextick-args": { 1014 | "version": "2.0.0", 1015 | "bundled": true, 1016 | "dev": true, 1017 | "optional": true 1018 | }, 1019 | "rc": { 1020 | "version": "1.2.7", 1021 | "bundled": true, 1022 | "dev": true, 1023 | "optional": true, 1024 | "requires": { 1025 | "deep-extend": "^0.5.1", 1026 | "ini": "~1.3.0", 1027 | "minimist": "^1.2.0", 1028 | "strip-json-comments": "~2.0.1" 1029 | }, 1030 | "dependencies": { 1031 | "minimist": { 1032 | "version": "1.2.0", 1033 | "bundled": true, 1034 | "dev": true, 1035 | "optional": true 1036 | } 1037 | } 1038 | }, 1039 | "readable-stream": { 1040 | "version": "2.3.6", 1041 | "bundled": true, 1042 | "dev": true, 1043 | "optional": true, 1044 | "requires": { 1045 | "core-util-is": "~1.0.0", 1046 | "inherits": "~2.0.3", 1047 | "isarray": "~1.0.0", 1048 | "process-nextick-args": "~2.0.0", 1049 | "safe-buffer": "~5.1.1", 1050 | "string_decoder": "~1.1.1", 1051 | "util-deprecate": "~1.0.1" 1052 | } 1053 | }, 1054 | "rimraf": { 1055 | "version": "2.6.2", 1056 | "bundled": true, 1057 | "dev": true, 1058 | "optional": true, 1059 | "requires": { 1060 | "glob": "^7.0.5" 1061 | } 1062 | }, 1063 | "safe-buffer": { 1064 | "version": "5.1.1", 1065 | "bundled": true, 1066 | "dev": true 1067 | }, 1068 | "safer-buffer": { 1069 | "version": "2.1.2", 1070 | "bundled": true, 1071 | "dev": true, 1072 | "optional": true 1073 | }, 1074 | "sax": { 1075 | "version": "1.2.4", 1076 | "bundled": true, 1077 | "dev": true, 1078 | "optional": true 1079 | }, 1080 | "semver": { 1081 | "version": "5.5.0", 1082 | "bundled": true, 1083 | "dev": true, 1084 | "optional": true 1085 | }, 1086 | "set-blocking": { 1087 | "version": "2.0.0", 1088 | "bundled": true, 1089 | "dev": true, 1090 | "optional": true 1091 | }, 1092 | "signal-exit": { 1093 | "version": "3.0.2", 1094 | "bundled": true, 1095 | "dev": true, 1096 | "optional": true 1097 | }, 1098 | "string-width": { 1099 | "version": "1.0.2", 1100 | "bundled": true, 1101 | "dev": true, 1102 | "requires": { 1103 | "code-point-at": "^1.0.0", 1104 | "is-fullwidth-code-point": "^1.0.0", 1105 | "strip-ansi": "^3.0.0" 1106 | } 1107 | }, 1108 | "string_decoder": { 1109 | "version": "1.1.1", 1110 | "bundled": true, 1111 | "dev": true, 1112 | "optional": true, 1113 | "requires": { 1114 | "safe-buffer": "~5.1.0" 1115 | } 1116 | }, 1117 | "strip-ansi": { 1118 | "version": "3.0.1", 1119 | "bundled": true, 1120 | "dev": true, 1121 | "requires": { 1122 | "ansi-regex": "^2.0.0" 1123 | } 1124 | }, 1125 | "strip-json-comments": { 1126 | "version": "2.0.1", 1127 | "bundled": true, 1128 | "dev": true, 1129 | "optional": true 1130 | }, 1131 | "tar": { 1132 | "version": "4.4.1", 1133 | "bundled": true, 1134 | "dev": true, 1135 | "optional": true, 1136 | "requires": { 1137 | "chownr": "^1.0.1", 1138 | "fs-minipass": "^1.2.5", 1139 | "minipass": "^2.2.4", 1140 | "minizlib": "^1.1.0", 1141 | "mkdirp": "^0.5.0", 1142 | "safe-buffer": "^5.1.1", 1143 | "yallist": "^3.0.2" 1144 | } 1145 | }, 1146 | "util-deprecate": { 1147 | "version": "1.0.2", 1148 | "bundled": true, 1149 | "dev": true, 1150 | "optional": true 1151 | }, 1152 | "wide-align": { 1153 | "version": "1.1.2", 1154 | "bundled": true, 1155 | "dev": true, 1156 | "optional": true, 1157 | "requires": { 1158 | "string-width": "^1.0.2" 1159 | } 1160 | }, 1161 | "wrappy": { 1162 | "version": "1.0.2", 1163 | "bundled": true, 1164 | "dev": true 1165 | }, 1166 | "yallist": { 1167 | "version": "3.0.2", 1168 | "bundled": true, 1169 | "dev": true 1170 | } 1171 | } 1172 | }, 1173 | "get-stdin": { 1174 | "version": "5.0.1", 1175 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", 1176 | "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=" 1177 | }, 1178 | "get-value": { 1179 | "version": "2.0.6", 1180 | "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", 1181 | "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", 1182 | "dev": true 1183 | }, 1184 | "glob": { 1185 | "version": "7.1.3", 1186 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 1187 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 1188 | "dev": true, 1189 | "requires": { 1190 | "fs.realpath": "^1.0.0", 1191 | "inflight": "^1.0.4", 1192 | "inherits": "2", 1193 | "minimatch": "^3.0.4", 1194 | "once": "^1.3.0", 1195 | "path-is-absolute": "^1.0.0" 1196 | }, 1197 | "dependencies": { 1198 | "balanced-match": { 1199 | "version": "1.0.0", 1200 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 1201 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 1202 | "dev": true 1203 | }, 1204 | "brace-expansion": { 1205 | "version": "1.1.11", 1206 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1207 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1208 | "dev": true, 1209 | "requires": { 1210 | "balanced-match": "^1.0.0", 1211 | "concat-map": "0.0.1" 1212 | } 1213 | }, 1214 | "minimatch": { 1215 | "version": "3.0.4", 1216 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1217 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1218 | "dev": true, 1219 | "requires": { 1220 | "brace-expansion": "^1.1.7" 1221 | } 1222 | } 1223 | } 1224 | }, 1225 | "glob-parent": { 1226 | "version": "3.1.0", 1227 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", 1228 | "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", 1229 | "dev": true, 1230 | "requires": { 1231 | "is-glob": "^3.1.0", 1232 | "path-dirname": "^1.0.0" 1233 | }, 1234 | "dependencies": { 1235 | "is-glob": { 1236 | "version": "3.1.0", 1237 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", 1238 | "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", 1239 | "dev": true, 1240 | "requires": { 1241 | "is-extglob": "^2.1.0" 1242 | } 1243 | } 1244 | } 1245 | }, 1246 | "graceful-fs": { 1247 | "version": "4.1.15", 1248 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", 1249 | "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", 1250 | "dev": true 1251 | }, 1252 | "has-ansi": { 1253 | "version": "2.0.0", 1254 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 1255 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 1256 | "dev": true, 1257 | "requires": { 1258 | "ansi-regex": "^2.0.0" 1259 | } 1260 | }, 1261 | "has-flag": { 1262 | "version": "3.0.0", 1263 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1264 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 1265 | "dev": true 1266 | }, 1267 | "has-value": { 1268 | "version": "1.0.0", 1269 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", 1270 | "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", 1271 | "dev": true, 1272 | "requires": { 1273 | "get-value": "^2.0.6", 1274 | "has-values": "^1.0.0", 1275 | "isobject": "^3.0.0" 1276 | } 1277 | }, 1278 | "has-values": { 1279 | "version": "1.0.0", 1280 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", 1281 | "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", 1282 | "dev": true, 1283 | "requires": { 1284 | "is-number": "^3.0.0", 1285 | "kind-of": "^4.0.0" 1286 | }, 1287 | "dependencies": { 1288 | "kind-of": { 1289 | "version": "4.0.0", 1290 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", 1291 | "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", 1292 | "dev": true, 1293 | "requires": { 1294 | "is-buffer": "^1.1.5" 1295 | } 1296 | } 1297 | } 1298 | }, 1299 | "inflight": { 1300 | "version": "1.0.6", 1301 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1302 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1303 | "dev": true, 1304 | "requires": { 1305 | "once": "^1.3.0", 1306 | "wrappy": "1" 1307 | } 1308 | }, 1309 | "inherits": { 1310 | "version": "2.0.3", 1311 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1312 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 1313 | "dev": true 1314 | }, 1315 | "is-accessor-descriptor": { 1316 | "version": "0.1.6", 1317 | "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", 1318 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", 1319 | "dev": true, 1320 | "requires": { 1321 | "kind-of": "^3.0.2" 1322 | }, 1323 | "dependencies": { 1324 | "kind-of": { 1325 | "version": "3.2.2", 1326 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1327 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1328 | "dev": true, 1329 | "requires": { 1330 | "is-buffer": "^1.1.5" 1331 | } 1332 | } 1333 | } 1334 | }, 1335 | "is-binary-path": { 1336 | "version": "1.0.1", 1337 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", 1338 | "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", 1339 | "dev": true, 1340 | "requires": { 1341 | "binary-extensions": "^1.0.0" 1342 | } 1343 | }, 1344 | "is-buffer": { 1345 | "version": "1.1.6", 1346 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 1347 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", 1348 | "dev": true 1349 | }, 1350 | "is-data-descriptor": { 1351 | "version": "0.1.4", 1352 | "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", 1353 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", 1354 | "dev": true, 1355 | "requires": { 1356 | "kind-of": "^3.0.2" 1357 | }, 1358 | "dependencies": { 1359 | "kind-of": { 1360 | "version": "3.2.2", 1361 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1362 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1363 | "dev": true, 1364 | "requires": { 1365 | "is-buffer": "^1.1.5" 1366 | } 1367 | } 1368 | } 1369 | }, 1370 | "is-descriptor": { 1371 | "version": "0.1.6", 1372 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", 1373 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", 1374 | "dev": true, 1375 | "requires": { 1376 | "is-accessor-descriptor": "^0.1.6", 1377 | "is-data-descriptor": "^0.1.4", 1378 | "kind-of": "^5.0.0" 1379 | }, 1380 | "dependencies": { 1381 | "kind-of": { 1382 | "version": "5.1.0", 1383 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", 1384 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", 1385 | "dev": true 1386 | } 1387 | } 1388 | }, 1389 | "is-extendable": { 1390 | "version": "0.1.1", 1391 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 1392 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", 1393 | "dev": true 1394 | }, 1395 | "is-extglob": { 1396 | "version": "2.1.1", 1397 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1398 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 1399 | "dev": true 1400 | }, 1401 | "is-glob": { 1402 | "version": "4.0.0", 1403 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", 1404 | "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", 1405 | "dev": true, 1406 | "requires": { 1407 | "is-extglob": "^2.1.1" 1408 | } 1409 | }, 1410 | "is-number": { 1411 | "version": "3.0.0", 1412 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", 1413 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", 1414 | "dev": true, 1415 | "requires": { 1416 | "kind-of": "^3.0.2" 1417 | }, 1418 | "dependencies": { 1419 | "kind-of": { 1420 | "version": "3.2.2", 1421 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1422 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1423 | "dev": true, 1424 | "requires": { 1425 | "is-buffer": "^1.1.5" 1426 | } 1427 | } 1428 | } 1429 | }, 1430 | "is-plain-object": { 1431 | "version": "2.0.4", 1432 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", 1433 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", 1434 | "dev": true, 1435 | "requires": { 1436 | "isobject": "^3.0.1" 1437 | } 1438 | }, 1439 | "is-windows": { 1440 | "version": "1.0.2", 1441 | "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", 1442 | "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", 1443 | "dev": true 1444 | }, 1445 | "isarray": { 1446 | "version": "1.0.0", 1447 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1448 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 1449 | "dev": true 1450 | }, 1451 | "isobject": { 1452 | "version": "3.0.1", 1453 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 1454 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", 1455 | "dev": true 1456 | }, 1457 | "js-tokens": { 1458 | "version": "3.0.2", 1459 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 1460 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 1461 | "dev": true 1462 | }, 1463 | "js-yaml": { 1464 | "version": "3.12.0", 1465 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", 1466 | "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", 1467 | "dev": true, 1468 | "requires": { 1469 | "argparse": "^1.0.7", 1470 | "esprima": "^4.0.0" 1471 | } 1472 | }, 1473 | "kind-of": { 1474 | "version": "6.0.2", 1475 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", 1476 | "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", 1477 | "dev": true 1478 | }, 1479 | "lodash.debounce": { 1480 | "version": "4.0.8", 1481 | "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", 1482 | "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", 1483 | "dev": true 1484 | }, 1485 | "lua-fmt": { 1486 | "version": "2.6.0", 1487 | "resolved": "https://registry.npmjs.org/lua-fmt/-/lua-fmt-2.6.0.tgz", 1488 | "integrity": "sha1-75rAVz0dpzMNygnAIsOaM67TR6M=", 1489 | "requires": { 1490 | "@types/commander": "^2.3.31", 1491 | "@types/diff": "^3.2.0", 1492 | "@types/get-stdin": "^5.0.0", 1493 | "commander": "^2.9.0", 1494 | "diff": "^3.3.0", 1495 | "get-stdin": "^5.0.1", 1496 | "luaparse": "github:oxyc/luaparse#ac42a00ebf4020b8c9d3219e4b0f84bf7ce6e802" 1497 | }, 1498 | "dependencies": { 1499 | "luaparse": { 1500 | "version": "github:oxyc/luaparse#ac42a00ebf4020b8c9d3219e4b0f84bf7ce6e802", 1501 | "from": "github:oxyc/luaparse#ac42a00ebf4020b8c9d3219e4b0f84bf7ce6e802" 1502 | } 1503 | } 1504 | }, 1505 | "luaparse": { 1506 | "version": "0.2.1", 1507 | "resolved": "https://registry.npmjs.org/luaparse/-/luaparse-0.2.1.tgz", 1508 | "integrity": "sha1-qo9WEysN6X0388mRqd9C4OF/ZWw=" 1509 | }, 1510 | "map-cache": { 1511 | "version": "0.2.2", 1512 | "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", 1513 | "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", 1514 | "dev": true 1515 | }, 1516 | "map-visit": { 1517 | "version": "1.0.0", 1518 | "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", 1519 | "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", 1520 | "dev": true, 1521 | "requires": { 1522 | "object-visit": "^1.0.0" 1523 | } 1524 | }, 1525 | "micromatch": { 1526 | "version": "3.1.10", 1527 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", 1528 | "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", 1529 | "dev": true, 1530 | "requires": { 1531 | "arr-diff": "^4.0.0", 1532 | "array-unique": "^0.3.2", 1533 | "braces": "^2.3.1", 1534 | "define-property": "^2.0.2", 1535 | "extend-shallow": "^3.0.2", 1536 | "extglob": "^2.0.4", 1537 | "fragment-cache": "^0.2.1", 1538 | "kind-of": "^6.0.2", 1539 | "nanomatch": "^1.2.9", 1540 | "object.pick": "^1.3.0", 1541 | "regex-not": "^1.0.0", 1542 | "snapdragon": "^0.8.1", 1543 | "to-regex": "^3.0.2" 1544 | } 1545 | }, 1546 | "minimatch": { 1547 | "version": "3.0.3", 1548 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz", 1549 | "integrity": "sha1-Kk5AkLlrLbBqnX3wEFWmKnfJt3Q=", 1550 | "requires": { 1551 | "brace-expansion": "^1.0.0" 1552 | } 1553 | }, 1554 | "mixin-deep": { 1555 | "version": "1.3.1", 1556 | "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", 1557 | "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", 1558 | "dev": true, 1559 | "requires": { 1560 | "for-in": "^1.0.2", 1561 | "is-extendable": "^1.0.1" 1562 | }, 1563 | "dependencies": { 1564 | "is-extendable": { 1565 | "version": "1.0.1", 1566 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 1567 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 1568 | "dev": true, 1569 | "requires": { 1570 | "is-plain-object": "^2.0.4" 1571 | } 1572 | } 1573 | } 1574 | }, 1575 | "ms": { 1576 | "version": "2.0.0", 1577 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1578 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 1579 | "dev": true 1580 | }, 1581 | "nan": { 1582 | "version": "2.12.1", 1583 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", 1584 | "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==", 1585 | "dev": true, 1586 | "optional": true 1587 | }, 1588 | "nanomatch": { 1589 | "version": "1.2.13", 1590 | "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", 1591 | "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", 1592 | "dev": true, 1593 | "requires": { 1594 | "arr-diff": "^4.0.0", 1595 | "array-unique": "^0.3.2", 1596 | "define-property": "^2.0.2", 1597 | "extend-shallow": "^3.0.2", 1598 | "fragment-cache": "^0.2.1", 1599 | "is-windows": "^1.0.2", 1600 | "kind-of": "^6.0.2", 1601 | "object.pick": "^1.3.0", 1602 | "regex-not": "^1.0.0", 1603 | "snapdragon": "^0.8.1", 1604 | "to-regex": "^3.0.1" 1605 | } 1606 | }, 1607 | "node-dir": { 1608 | "version": "0.1.17", 1609 | "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", 1610 | "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", 1611 | "requires": { 1612 | "minimatch": "^3.0.2" 1613 | } 1614 | }, 1615 | "node-hot": { 1616 | "version": "4.0.1", 1617 | "resolved": "https://registry.npmjs.org/node-hot/-/node-hot-4.0.1.tgz", 1618 | "integrity": "sha512-jMULVUfui3wIGE9HFBXdt6CHuTjXpg+stE+utJk9UtTgtwQKNPDHl5BiDIVFifC5SCowSWFcAC3kS+2yVN7OiQ==", 1619 | "dev": true, 1620 | "requires": { 1621 | "chokidar": "2.0.4" 1622 | } 1623 | }, 1624 | "normalize-path": { 1625 | "version": "2.1.1", 1626 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", 1627 | "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", 1628 | "dev": true, 1629 | "requires": { 1630 | "remove-trailing-separator": "^1.0.1" 1631 | } 1632 | }, 1633 | "object-copy": { 1634 | "version": "0.1.0", 1635 | "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", 1636 | "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", 1637 | "dev": true, 1638 | "requires": { 1639 | "copy-descriptor": "^0.1.0", 1640 | "define-property": "^0.2.5", 1641 | "kind-of": "^3.0.3" 1642 | }, 1643 | "dependencies": { 1644 | "define-property": { 1645 | "version": "0.2.5", 1646 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 1647 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 1648 | "dev": true, 1649 | "requires": { 1650 | "is-descriptor": "^0.1.0" 1651 | } 1652 | }, 1653 | "kind-of": { 1654 | "version": "3.2.2", 1655 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1656 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1657 | "dev": true, 1658 | "requires": { 1659 | "is-buffer": "^1.1.5" 1660 | } 1661 | } 1662 | } 1663 | }, 1664 | "object-visit": { 1665 | "version": "1.0.1", 1666 | "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", 1667 | "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", 1668 | "dev": true, 1669 | "requires": { 1670 | "isobject": "^3.0.0" 1671 | } 1672 | }, 1673 | "object.pick": { 1674 | "version": "1.3.0", 1675 | "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", 1676 | "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", 1677 | "dev": true, 1678 | "requires": { 1679 | "isobject": "^3.0.1" 1680 | } 1681 | }, 1682 | "once": { 1683 | "version": "1.4.0", 1684 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1685 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1686 | "dev": true, 1687 | "requires": { 1688 | "wrappy": "1" 1689 | } 1690 | }, 1691 | "pascalcase": { 1692 | "version": "0.1.1", 1693 | "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", 1694 | "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", 1695 | "dev": true 1696 | }, 1697 | "path-dirname": { 1698 | "version": "1.0.2", 1699 | "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", 1700 | "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", 1701 | "dev": true 1702 | }, 1703 | "path-is-absolute": { 1704 | "version": "1.0.1", 1705 | "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1706 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1707 | "dev": true 1708 | }, 1709 | "path-parse": { 1710 | "version": "1.0.6", 1711 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1712 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 1713 | "dev": true 1714 | }, 1715 | "posix-character-classes": { 1716 | "version": "0.1.1", 1717 | "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", 1718 | "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", 1719 | "dev": true 1720 | }, 1721 | "process-nextick-args": { 1722 | "version": "2.0.0", 1723 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 1724 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", 1725 | "dev": true 1726 | }, 1727 | "readable-stream": { 1728 | "version": "2.3.6", 1729 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 1730 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 1731 | "dev": true, 1732 | "requires": { 1733 | "core-util-is": "~1.0.0", 1734 | "inherits": "~2.0.3", 1735 | "isarray": "~1.0.0", 1736 | "process-nextick-args": "~2.0.0", 1737 | "safe-buffer": "~5.1.1", 1738 | "string_decoder": "~1.1.1", 1739 | "util-deprecate": "~1.0.1" 1740 | } 1741 | }, 1742 | "readdirp": { 1743 | "version": "2.2.1", 1744 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", 1745 | "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", 1746 | "dev": true, 1747 | "requires": { 1748 | "graceful-fs": "^4.1.11", 1749 | "micromatch": "^3.1.10", 1750 | "readable-stream": "^2.0.2" 1751 | } 1752 | }, 1753 | "regex-not": { 1754 | "version": "1.0.2", 1755 | "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", 1756 | "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", 1757 | "dev": true, 1758 | "requires": { 1759 | "extend-shallow": "^3.0.2", 1760 | "safe-regex": "^1.1.0" 1761 | } 1762 | }, 1763 | "remove-trailing-separator": { 1764 | "version": "1.1.0", 1765 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", 1766 | "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", 1767 | "dev": true 1768 | }, 1769 | "repeat-element": { 1770 | "version": "1.1.3", 1771 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", 1772 | "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", 1773 | "dev": true 1774 | }, 1775 | "repeat-string": { 1776 | "version": "1.6.1", 1777 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 1778 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", 1779 | "dev": true 1780 | }, 1781 | "resolve": { 1782 | "version": "1.9.0", 1783 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz", 1784 | "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==", 1785 | "dev": true, 1786 | "requires": { 1787 | "path-parse": "^1.0.6" 1788 | } 1789 | }, 1790 | "resolve-url": { 1791 | "version": "0.2.1", 1792 | "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", 1793 | "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", 1794 | "dev": true 1795 | }, 1796 | "ret": { 1797 | "version": "0.1.15", 1798 | "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", 1799 | "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", 1800 | "dev": true 1801 | }, 1802 | "safe-buffer": { 1803 | "version": "5.1.2", 1804 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1805 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1806 | "dev": true 1807 | }, 1808 | "safe-regex": { 1809 | "version": "1.1.0", 1810 | "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", 1811 | "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", 1812 | "dev": true, 1813 | "requires": { 1814 | "ret": "~0.1.10" 1815 | } 1816 | }, 1817 | "semver": { 1818 | "version": "5.6.0", 1819 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", 1820 | "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", 1821 | "dev": true 1822 | }, 1823 | "set-value": { 1824 | "version": "2.0.0", 1825 | "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", 1826 | "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", 1827 | "dev": true, 1828 | "requires": { 1829 | "extend-shallow": "^2.0.1", 1830 | "is-extendable": "^0.1.1", 1831 | "is-plain-object": "^2.0.3", 1832 | "split-string": "^3.0.1" 1833 | }, 1834 | "dependencies": { 1835 | "extend-shallow": { 1836 | "version": "2.0.1", 1837 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 1838 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 1839 | "dev": true, 1840 | "requires": { 1841 | "is-extendable": "^0.1.0" 1842 | } 1843 | } 1844 | } 1845 | }, 1846 | "snapdragon": { 1847 | "version": "0.8.2", 1848 | "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", 1849 | "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", 1850 | "dev": true, 1851 | "requires": { 1852 | "base": "^0.11.1", 1853 | "debug": "^2.2.0", 1854 | "define-property": "^0.2.5", 1855 | "extend-shallow": "^2.0.1", 1856 | "map-cache": "^0.2.2", 1857 | "source-map": "^0.5.6", 1858 | "source-map-resolve": "^0.5.0", 1859 | "use": "^3.1.0" 1860 | }, 1861 | "dependencies": { 1862 | "define-property": { 1863 | "version": "0.2.5", 1864 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 1865 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 1866 | "dev": true, 1867 | "requires": { 1868 | "is-descriptor": "^0.1.0" 1869 | } 1870 | }, 1871 | "extend-shallow": { 1872 | "version": "2.0.1", 1873 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 1874 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 1875 | "dev": true, 1876 | "requires": { 1877 | "is-extendable": "^0.1.0" 1878 | } 1879 | }, 1880 | "source-map": { 1881 | "version": "0.5.7", 1882 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 1883 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 1884 | "dev": true 1885 | } 1886 | } 1887 | }, 1888 | "snapdragon-node": { 1889 | "version": "2.1.1", 1890 | "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", 1891 | "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", 1892 | "dev": true, 1893 | "requires": { 1894 | "define-property": "^1.0.0", 1895 | "isobject": "^3.0.0", 1896 | "snapdragon-util": "^3.0.1" 1897 | }, 1898 | "dependencies": { 1899 | "define-property": { 1900 | "version": "1.0.0", 1901 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 1902 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 1903 | "dev": true, 1904 | "requires": { 1905 | "is-descriptor": "^1.0.0" 1906 | } 1907 | }, 1908 | "is-accessor-descriptor": { 1909 | "version": "1.0.0", 1910 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 1911 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 1912 | "dev": true, 1913 | "requires": { 1914 | "kind-of": "^6.0.0" 1915 | } 1916 | }, 1917 | "is-data-descriptor": { 1918 | "version": "1.0.0", 1919 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 1920 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 1921 | "dev": true, 1922 | "requires": { 1923 | "kind-of": "^6.0.0" 1924 | } 1925 | }, 1926 | "is-descriptor": { 1927 | "version": "1.0.2", 1928 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 1929 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 1930 | "dev": true, 1931 | "requires": { 1932 | "is-accessor-descriptor": "^1.0.0", 1933 | "is-data-descriptor": "^1.0.0", 1934 | "kind-of": "^6.0.2" 1935 | } 1936 | } 1937 | } 1938 | }, 1939 | "snapdragon-util": { 1940 | "version": "3.0.1", 1941 | "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", 1942 | "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", 1943 | "dev": true, 1944 | "requires": { 1945 | "kind-of": "^3.2.0" 1946 | }, 1947 | "dependencies": { 1948 | "kind-of": { 1949 | "version": "3.2.2", 1950 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1951 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1952 | "dev": true, 1953 | "requires": { 1954 | "is-buffer": "^1.1.5" 1955 | } 1956 | } 1957 | } 1958 | }, 1959 | "source-map": { 1960 | "version": "0.6.1", 1961 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1962 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 1963 | }, 1964 | "source-map-resolve": { 1965 | "version": "0.5.2", 1966 | "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", 1967 | "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", 1968 | "dev": true, 1969 | "requires": { 1970 | "atob": "^2.1.1", 1971 | "decode-uri-component": "^0.2.0", 1972 | "resolve-url": "^0.2.1", 1973 | "source-map-url": "^0.4.0", 1974 | "urix": "^0.1.0" 1975 | } 1976 | }, 1977 | "source-map-support": { 1978 | "version": "0.5.9", 1979 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", 1980 | "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", 1981 | "requires": { 1982 | "buffer-from": "^1.0.0", 1983 | "source-map": "^0.6.0" 1984 | } 1985 | }, 1986 | "source-map-url": { 1987 | "version": "0.4.0", 1988 | "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", 1989 | "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", 1990 | "dev": true 1991 | }, 1992 | "split-string": { 1993 | "version": "3.1.0", 1994 | "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", 1995 | "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", 1996 | "dev": true, 1997 | "requires": { 1998 | "extend-shallow": "^3.0.0" 1999 | } 2000 | }, 2001 | "sprintf-js": { 2002 | "version": "1.0.3", 2003 | "resolved": "http://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 2004 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 2005 | "dev": true 2006 | }, 2007 | "static-extend": { 2008 | "version": "0.1.2", 2009 | "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", 2010 | "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", 2011 | "dev": true, 2012 | "requires": { 2013 | "define-property": "^0.2.5", 2014 | "object-copy": "^0.1.0" 2015 | }, 2016 | "dependencies": { 2017 | "define-property": { 2018 | "version": "0.2.5", 2019 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 2020 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 2021 | "dev": true, 2022 | "requires": { 2023 | "is-descriptor": "^0.1.0" 2024 | } 2025 | } 2026 | } 2027 | }, 2028 | "string_decoder": { 2029 | "version": "1.1.1", 2030 | "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 2031 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 2032 | "dev": true, 2033 | "requires": { 2034 | "safe-buffer": "~5.1.0" 2035 | } 2036 | }, 2037 | "strip-ansi": { 2038 | "version": "3.0.1", 2039 | "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 2040 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 2041 | "dev": true, 2042 | "requires": { 2043 | "ansi-regex": "^2.0.0" 2044 | } 2045 | }, 2046 | "supports-color": { 2047 | "version": "2.0.0", 2048 | "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 2049 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 2050 | "dev": true 2051 | }, 2052 | "to-object-path": { 2053 | "version": "0.3.0", 2054 | "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", 2055 | "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", 2056 | "dev": true, 2057 | "requires": { 2058 | "kind-of": "^3.0.2" 2059 | }, 2060 | "dependencies": { 2061 | "kind-of": { 2062 | "version": "3.2.2", 2063 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 2064 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 2065 | "dev": true, 2066 | "requires": { 2067 | "is-buffer": "^1.1.5" 2068 | } 2069 | } 2070 | } 2071 | }, 2072 | "to-regex": { 2073 | "version": "3.0.2", 2074 | "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", 2075 | "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", 2076 | "dev": true, 2077 | "requires": { 2078 | "define-property": "^2.0.2", 2079 | "extend-shallow": "^3.0.2", 2080 | "regex-not": "^1.0.2", 2081 | "safe-regex": "^1.1.0" 2082 | } 2083 | }, 2084 | "to-regex-range": { 2085 | "version": "2.1.1", 2086 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", 2087 | "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", 2088 | "dev": true, 2089 | "requires": { 2090 | "is-number": "^3.0.0", 2091 | "repeat-string": "^1.6.1" 2092 | } 2093 | }, 2094 | "tslib": { 2095 | "version": "1.9.3", 2096 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", 2097 | "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", 2098 | "dev": true 2099 | }, 2100 | "tslint": { 2101 | "version": "5.12.0", 2102 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.12.0.tgz", 2103 | "integrity": "sha512-CKEcH1MHUBhoV43SA/Jmy1l24HJJgI0eyLbBNSRyFlsQvb9v6Zdq+Nz2vEOH00nC5SUx4SneJ59PZUS/ARcokQ==", 2104 | "dev": true, 2105 | "requires": { 2106 | "babel-code-frame": "^6.22.0", 2107 | "builtin-modules": "^1.1.1", 2108 | "chalk": "^2.3.0", 2109 | "commander": "^2.12.1", 2110 | "diff": "^3.2.0", 2111 | "glob": "^7.1.1", 2112 | "js-yaml": "^3.7.0", 2113 | "minimatch": "^3.0.4", 2114 | "resolve": "^1.3.2", 2115 | "semver": "^5.3.0", 2116 | "tslib": "^1.8.0", 2117 | "tsutils": "^2.27.2" 2118 | }, 2119 | "dependencies": { 2120 | "balanced-match": { 2121 | "version": "1.0.0", 2122 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 2123 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 2124 | "dev": true 2125 | }, 2126 | "brace-expansion": { 2127 | "version": "1.1.11", 2128 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 2129 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 2130 | "dev": true, 2131 | "requires": { 2132 | "balanced-match": "^1.0.0", 2133 | "concat-map": "0.0.1" 2134 | } 2135 | }, 2136 | "minimatch": { 2137 | "version": "3.0.4", 2138 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 2139 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 2140 | "dev": true, 2141 | "requires": { 2142 | "brace-expansion": "^1.1.7" 2143 | } 2144 | } 2145 | } 2146 | }, 2147 | "tsutils": { 2148 | "version": "2.29.0", 2149 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 2150 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 2151 | "dev": true, 2152 | "requires": { 2153 | "tslib": "^1.8.1" 2154 | } 2155 | }, 2156 | "typescript": { 2157 | "version": "3.2.2", 2158 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz", 2159 | "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", 2160 | "dev": true 2161 | }, 2162 | "union-value": { 2163 | "version": "1.0.0", 2164 | "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", 2165 | "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", 2166 | "dev": true, 2167 | "requires": { 2168 | "arr-union": "^3.1.0", 2169 | "get-value": "^2.0.6", 2170 | "is-extendable": "^0.1.1", 2171 | "set-value": "^0.4.3" 2172 | }, 2173 | "dependencies": { 2174 | "extend-shallow": { 2175 | "version": "2.0.1", 2176 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 2177 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 2178 | "dev": true, 2179 | "requires": { 2180 | "is-extendable": "^0.1.0" 2181 | } 2182 | }, 2183 | "set-value": { 2184 | "version": "0.4.3", 2185 | "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", 2186 | "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", 2187 | "dev": true, 2188 | "requires": { 2189 | "extend-shallow": "^2.0.1", 2190 | "is-extendable": "^0.1.1", 2191 | "is-plain-object": "^2.0.1", 2192 | "to-object-path": "^0.3.0" 2193 | } 2194 | } 2195 | } 2196 | }, 2197 | "unset-value": { 2198 | "version": "1.0.0", 2199 | "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", 2200 | "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", 2201 | "dev": true, 2202 | "requires": { 2203 | "has-value": "^0.3.1", 2204 | "isobject": "^3.0.0" 2205 | }, 2206 | "dependencies": { 2207 | "has-value": { 2208 | "version": "0.3.1", 2209 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", 2210 | "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", 2211 | "dev": true, 2212 | "requires": { 2213 | "get-value": "^2.0.3", 2214 | "has-values": "^0.1.4", 2215 | "isobject": "^2.0.0" 2216 | }, 2217 | "dependencies": { 2218 | "isobject": { 2219 | "version": "2.1.0", 2220 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", 2221 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", 2222 | "dev": true, 2223 | "requires": { 2224 | "isarray": "1.0.0" 2225 | } 2226 | } 2227 | } 2228 | }, 2229 | "has-values": { 2230 | "version": "0.1.4", 2231 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", 2232 | "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", 2233 | "dev": true 2234 | } 2235 | } 2236 | }, 2237 | "upath": { 2238 | "version": "1.1.0", 2239 | "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", 2240 | "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", 2241 | "dev": true 2242 | }, 2243 | "urix": { 2244 | "version": "0.1.0", 2245 | "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", 2246 | "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", 2247 | "dev": true 2248 | }, 2249 | "use": { 2250 | "version": "3.1.1", 2251 | "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", 2252 | "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", 2253 | "dev": true 2254 | }, 2255 | "util-deprecate": { 2256 | "version": "1.0.2", 2257 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2258 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 2259 | "dev": true 2260 | }, 2261 | "vscode-jsonrpc": { 2262 | "version": "4.0.0", 2263 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz", 2264 | "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==" 2265 | }, 2266 | "vscode-languageserver": { 2267 | "version": "5.2.1", 2268 | "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.2.1.tgz", 2269 | "integrity": "sha512-GuayqdKZqAwwaCUjDvMTAVRPJOp/SLON3mJ07eGsx/Iq9HjRymhKWztX41rISqDKhHVVyFM+IywICyZDla6U3A==", 2270 | "requires": { 2271 | "vscode-languageserver-protocol": "3.14.1", 2272 | "vscode-uri": "^1.0.6" 2273 | } 2274 | }, 2275 | "vscode-languageserver-protocol": { 2276 | "version": "3.14.1", 2277 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz", 2278 | "integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==", 2279 | "requires": { 2280 | "vscode-jsonrpc": "^4.0.0", 2281 | "vscode-languageserver-types": "3.14.0" 2282 | } 2283 | }, 2284 | "vscode-languageserver-types": { 2285 | "version": "3.14.0", 2286 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz", 2287 | "integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==" 2288 | }, 2289 | "vscode-uri": { 2290 | "version": "1.0.6", 2291 | "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.6.tgz", 2292 | "integrity": "sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==" 2293 | }, 2294 | "wrappy": { 2295 | "version": "1.0.2", 2296 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2297 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2298 | "dev": true 2299 | } 2300 | } 2301 | } 2302 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "language-server-lua", 3 | "version": "0.0.1", 4 | "description": "Language server for Lua", 5 | "main": "server.ts", 6 | "author": "trixnz", 7 | "license": "MIT", 8 | "bin": { 9 | "installDevServerIntoExtension": "./bin/installDevServerIntoExtension" 10 | }, 11 | "dependencies": { 12 | "@types/diff": "^3.5.2", 13 | "@types/node-dir": "0.0.32", 14 | "diff": "^3.5.0", 15 | "lua-fmt": "^2.6.0", 16 | "luaparse": "^0.2.1", 17 | "node-dir": "^0.1.16", 18 | "source-map-support": "^0.5.9", 19 | "vscode-languageserver": "^5.2.1", 20 | "vscode-uri": "^1.0.6" 21 | }, 22 | "devDependencies": { 23 | "@types/node": "^10.12.18", 24 | "node-hot": "^4.0.1", 25 | "tslint": "^5.12.0", 26 | "typescript": "^3.2.2" 27 | }, 28 | "scripts": { 29 | "compile": "installServerIntoExtension ../out ./package.json ./tsconfig.json && tsc -p .", 30 | "dev-compile": "installDevServerIntoExtension ../out ./package.json ./tsconfig.json && tsc -p .", 31 | "watch": "installServerIntoExtension ../out ./package.json ./tsconfig.json && tsc --watch -p .", 32 | "dev-watch": "installDevServerIntoExtension ../out ./package.json ./tsconfig.json && tsc --watch -p ." 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /server/src/analysis/analysis.ts: -------------------------------------------------------------------------------- 1 | import * as luaparse from 'luaparse'; 2 | 3 | import { Symbol, SymbolKind } from './symbol'; 4 | import { Scope } from './scope'; 5 | import { getNodeRange } from '../utils'; 6 | 7 | export class Analysis { 8 | public symbols: Symbol[] = []; 9 | 10 | private scopeStack: Scope[] = []; 11 | private globalScope: Scope | null = null; 12 | private cursorScope: Scope | null = null; 13 | private completionTableName: string | null = null; 14 | 15 | public constructor() { 16 | luaparse.parse({ 17 | locations: true, 18 | scope: true, 19 | wait: true, 20 | comments: false, 21 | onCreateScope: () => { 22 | const newScope = new Scope(); 23 | 24 | // Flag the first encountered scope as the global scope. 25 | if (this.globalScope == null) { 26 | this.globalScope = newScope; 27 | } 28 | 29 | newScope.parentScope = this.scopeStack.length ? this.scopeStack[this.scopeStack.length - 1] : null; 30 | 31 | this.scopeStack.push(newScope); 32 | }, 33 | onCreateNode: (node) => { 34 | // The chunk is meaningless to us, so ignore it. 35 | if (node.type === 'Chunk') { 36 | return; 37 | } 38 | 39 | if (this.scopeStack.length === 0) { 40 | throw new Error('Empty scope stack when encountering node of type ' + node.type); 41 | } 42 | 43 | const scope = this.scopeStack[this.scopeStack.length - 1]; 44 | 45 | // Assign the scope to the node so we can access it later 46 | node.scope = scope; 47 | 48 | // And add the node to the scope for ease of iteration 49 | scope.nodes.push(node); 50 | 51 | // If the current node is our scope marker, notedown the scope it corresponds to so we know where to 52 | // start our search from. 53 | if (node.type === 'Identifier' && node.name === '__scope_marker__') { 54 | this.cursorScope = scope; 55 | } 56 | else if (node.type === 'CallExpression' && node.base.type === 'MemberExpression') { 57 | const { name, container } = this.getIdentifierName(node.base); 58 | if (name === '__completion_helper__') { 59 | this.completionTableName = container; 60 | } 61 | } 62 | }, 63 | onDestroyScope: () => { 64 | this.scopeStack.pop(); 65 | } 66 | }); 67 | } 68 | 69 | public write(text: string) { 70 | luaparse.write(text); 71 | } 72 | 73 | public end(text: string) { 74 | luaparse.end(text); 75 | } 76 | 77 | public buildScopedSymbols(isTableScope: boolean = false) { 78 | // If we didn't find the scope containing the cursor, we can't provide scope-aware suggestions. 79 | // TODO: Fall back to just providing global symbols? 80 | if (this.cursorScope === null) { 81 | return; 82 | } 83 | 84 | if (isTableScope) { 85 | this.addTableScopeSymbols(); 86 | return; 87 | } 88 | 89 | this.addScopedSymbols(); 90 | } 91 | 92 | public buildGlobalSymbols() { 93 | if (this.globalScope) { 94 | this.globalScope.nodes.forEach((n) => this.addSymbolsForNode(n, false)); 95 | } 96 | } 97 | 98 | private addTableScopeSymbols() { 99 | if (!this.completionTableName) { 100 | return; 101 | } 102 | 103 | let currentScope = this.cursorScope; 104 | let abortScopeTraversal = false; 105 | while (currentScope !== null) { 106 | for (const n of currentScope.nodes) { 107 | if (n.type === 'LocalStatement') { 108 | // If the cursor scope has introduced a shadowing variable, don't continue traversing the scope 109 | // parent tree. 110 | if (currentScope === this.cursorScope && 111 | n.variables.some(ident => ident.name === this.completionTableName)) { 112 | abortScopeTraversal = true; 113 | } 114 | } 115 | else if (n.type === 'AssignmentStatement') { 116 | // Add any member fields being assigned to the symbol 117 | 118 | // filter<> specialization due to a bug in the current Typescript. 119 | // Should be fixed in 2.7 by https://github.com/Microsoft/TypeScript/pull/17600 120 | n.variables 121 | .filter((v): v is luaparse.MemberExpression => 122 | v.type === 'MemberExpression') 123 | .forEach(v => { 124 | if (v.base.type === 'Identifier' && v.base.name === this.completionTableName) { 125 | this.addSymbolHelper(v.identifier, v.identifier.name, 'Variable', 126 | undefined, this.completionTableName); 127 | } 128 | }); 129 | } 130 | 131 | if (n.type === 'LocalStatement' || n.type === 'AssignmentStatement') { 132 | // Find the variable that matches the current symbol to provide completions for, if any. 133 | let variableIndex = -1; 134 | for (const [i, variable] of n.variables.entries()) { 135 | if (variable.type === 'Identifier' && variable.name === this.completionTableName) { 136 | variableIndex = i; 137 | } 138 | } 139 | 140 | if (variableIndex >= 0) { 141 | const variableInit = n.init[variableIndex]; 142 | 143 | // If the field was initialised with a table, add the fields from it. 144 | if (variableInit && variableInit.type === 'TableConstructorExpression') { 145 | for (const field of variableInit.fields) { 146 | switch (field.type) { 147 | case 'TableKey': 148 | if (field.key.type === 'StringLiteral') { 149 | this.addSymbolHelper(field, field.key.value, 'Variable', undefined, 150 | this.completionTableName); 151 | } 152 | break; 153 | 154 | case 'TableKeyString': 155 | if (field.key.type === 'Identifier') { 156 | this.addSymbolHelper(field, field.key.name, 'Variable', undefined, 157 | this.completionTableName); 158 | } 159 | break; 160 | } 161 | } 162 | } 163 | } 164 | } 165 | } 166 | 167 | if (abortScopeTraversal) { 168 | break; 169 | } 170 | 171 | currentScope = currentScope.parentScope; 172 | } 173 | } 174 | 175 | private addScopedSymbols() { 176 | // Add all of the symbols for the current cursor scope 177 | let currentScope: Scope | null = this.cursorScope; 178 | while (currentScope !== null) { 179 | currentScope.nodes.forEach((n) => this.addSymbolsForNode(n, true)); 180 | currentScope = currentScope.parentScope; 181 | } 182 | } 183 | 184 | // Nodes don't necessarily need to have an identifier name, nor are their identifiers all of type 'Identifier'. 185 | // Return an appropriate name, given the context of the node. 186 | private getIdentifierName(identifier: luaparse.Identifier | luaparse.MemberExpression | null) { 187 | if (identifier) { 188 | switch (identifier.type) { 189 | case 'Identifier': 190 | return { name: identifier.name, container: null }; 191 | 192 | case 'MemberExpression': 193 | switch (identifier.base.type) { 194 | case 'Identifier': 195 | return { name: identifier.identifier.name, container: identifier.base.name }; 196 | default: 197 | return { name: identifier.identifier.name, container: null }; 198 | } 199 | } 200 | } 201 | 202 | return { name: null, container: null }; 203 | } 204 | 205 | private addSymbolsForNode(node: luaparse.Node, scopedQuery: boolean) { 206 | switch (node.type) { 207 | case 'LocalStatement': 208 | case 'AssignmentStatement': 209 | this.addLocalAndAssignmentSymbols(node); 210 | break; 211 | 212 | case 'FunctionDeclaration': 213 | this.addFunctionSymbols(node, scopedQuery); 214 | break; 215 | } 216 | } 217 | 218 | private addSymbolHelper(node: luaparse.Node, name: string | null, kind: SymbolKind, 219 | container?: string, display?: string) { 220 | this.symbols.push({ 221 | kind, 222 | name, 223 | container, 224 | display, 225 | range: getNodeRange(node), 226 | isGlobalScope: node.scope === this.globalScope, 227 | isOuterScope: node.scope !== this.cursorScope 228 | }); 229 | } 230 | 231 | private addLocalAndAssignmentSymbols(node: luaparse.LocalStatement | luaparse.AssignmentStatement) { 232 | for (const variable of node.variables) { 233 | switch (variable.type) { 234 | case 'Identifier': 235 | this.addSymbolHelper(variable, variable.name, 'Variable'); 236 | break; 237 | } 238 | } 239 | } 240 | 241 | private addFunctionSymbols(node: luaparse.FunctionDeclaration, scopedQuery: boolean) { 242 | const { name, container } = this.getIdentifierName(node.identifier); 243 | // filter<> specialization due to a bug in the current Typescript. 244 | // Should be fixed in 2.7 by https://github.com/Microsoft/TypeScript/pull/17600 245 | const parameters = node.parameters 246 | .filter((v): v is luaparse.Identifier => v.type === 'Identifier'); 247 | 248 | // Build a represesntation of the function declaration 249 | let display = 'function '; 250 | if (container) { display += container + ':'; } 251 | if (name) { display += name; } 252 | display += '('; 253 | display += parameters 254 | .map((param: luaparse.Identifier) => param.name) 255 | .join(', '); 256 | 257 | display += ')'; 258 | 259 | this.addSymbolHelper(node, name, 'Function', container || undefined, display); 260 | 261 | if (scopedQuery) { 262 | parameters 263 | .filter(param => param.scope.containsScope(this.cursorScope)) 264 | .forEach((param: luaparse.Identifier) => { 265 | this.addSymbolHelper(param, param.name, 'FunctionParameter'); 266 | }); 267 | } 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /server/src/analysis/astVisitor.ts: -------------------------------------------------------------------------------- 1 | import * as luaparse from 'luaparse'; 2 | 3 | type Callback = (node: luaparse.Node) => void; 4 | 5 | interface Visitor { 6 | onEnterNode?: Callback; 7 | onExitNode?: Callback; 8 | onVisitNode: Callback; 9 | } 10 | 11 | export function visitAST(node: luaparse.Node | null, visitor: Visitor) { 12 | function visitNode(obj: luaparse.Node | null) { 13 | visitAST(obj, visitor); 14 | } 15 | function visitNodes>(obj: T) { 16 | obj.forEach(n => visitAST(n, visitor)); 17 | } 18 | 19 | if (node === null) { 20 | return; 21 | } 22 | 23 | if (visitor.onEnterNode != null) { visitor.onEnterNode(node); } 24 | 25 | visitor.onVisitNode(node); 26 | 27 | switch (node.type) { 28 | case 'Chunk': 29 | visitNodes(node.body); 30 | break; 31 | case 'FunctionDeclaration': 32 | visitNode(node.identifier); 33 | visitNodes(node.parameters); 34 | visitNodes(node.body); 35 | break; 36 | case 'LocalStatement': 37 | case 'AssignmentStatement': 38 | visitNodes(node.variables); 39 | visitNodes(node.init); 40 | break; 41 | case 'MemberExpression': 42 | visitNode(node.base); 43 | visitNode(node.identifier); 44 | break; 45 | case 'Identifier': 46 | case 'NumericLiteral': 47 | case 'BooleanLiteral': 48 | case 'StringLiteral': 49 | case 'VarargLiteral': 50 | case 'NilLiteral': 51 | case 'BreakStatement': 52 | break; 53 | case 'CallStatement': 54 | visitNode(node.expression); 55 | break; 56 | case 'CallExpression': 57 | visitNode(node.base); 58 | visitNodes(node.arguments); 59 | break; 60 | case 'StringCallExpression': 61 | visitNode(node.base); 62 | visitNode(node.argument); 63 | break; 64 | case 'RepeatStatement': 65 | case 'WhileStatement': 66 | visitNode(node.condition); 67 | visitNodes(node.body); 68 | break; 69 | case 'ForGenericStatement': 70 | visitNodes(node.variables); 71 | visitNodes(node.iterators); 72 | visitNodes(node.body); 73 | break; 74 | case 'ForNumericStatement': 75 | visitNode(node.variable); 76 | visitNode(node.start); 77 | visitNode(node.end); 78 | visitNode(node.step); 79 | visitNodes(node.body); 80 | break; 81 | case 'IfStatement': 82 | visitNodes(node.clauses); 83 | break; 84 | case 'IfClause': 85 | case 'ElseifClause': 86 | visitNode(node.condition); 87 | visitNodes(node.body); 88 | break; 89 | case 'ElseClause': 90 | visitNodes(node.body); 91 | break; 92 | case 'DoStatement': 93 | visitNodes(node.body); 94 | break; 95 | case 'TableConstructorExpression': 96 | visitNodes(node.fields); 97 | break; 98 | case 'TableKeyString': 99 | case 'TableKey': 100 | visitNode(node.key); 101 | visitNode(node.value); 102 | break; 103 | case 'TableCallExpression': 104 | visitNode(node.base); 105 | visitNode(node.arguments); 106 | break; 107 | case 'TableValue': 108 | visitNode(node.value); 109 | break; 110 | case 'LabelStatement': 111 | case 'GotoStatement': 112 | visitNode(node.label); 113 | break; 114 | case 'BinaryExpression': 115 | visitNode(node.left); 116 | visitNode(node.right); 117 | break; 118 | case 'LogicalExpression': 119 | visitNode(node.left); 120 | visitNode(node.right); 121 | break; 122 | case 'IndexExpression': 123 | visitNode(node.base); 124 | visitNode(node.index); 125 | break; 126 | case 'UnaryExpression': 127 | // visitNode(node.argument); 128 | break; 129 | case 'ReturnStatement': 130 | visitNodes(node.arguments); 131 | break; 132 | } 133 | 134 | if (visitor.onExitNode != null) { visitor.onExitNode(node); } 135 | } 136 | -------------------------------------------------------------------------------- /server/src/analysis/index.ts: -------------------------------------------------------------------------------- 1 | export { Analysis } from './analysis'; 2 | export { Symbol } from './symbol'; 3 | -------------------------------------------------------------------------------- /server/src/analysis/scope.ts: -------------------------------------------------------------------------------- 1 | import { Node } from 'luaparse'; 2 | 3 | export class Scope { 4 | public nodes: Node[] = []; 5 | public parentScope: Scope | null = null; 6 | 7 | public containsScope(otherScope: Scope | null) { 8 | let currentScope = otherScope; 9 | while (currentScope !== null) { 10 | if (currentScope === this) { 11 | return true; 12 | } 13 | currentScope = currentScope.parentScope; 14 | } 15 | 16 | return false; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /server/src/analysis/symbol.ts: -------------------------------------------------------------------------------- 1 | import { Range } from 'vscode-languageserver'; 2 | 3 | export type SymbolKind = 'Function' | 'FunctionParameter' | 'Variable'; 4 | 5 | export interface Symbol { 6 | kind: SymbolKind; 7 | 8 | name: string | null; 9 | display?: string | null; 10 | container?: string | null; 11 | range: Range; 12 | isGlobalScope: boolean; 13 | isOuterScope: boolean; 14 | } 15 | -------------------------------------------------------------------------------- /server/src/main.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import 'source-map-support/register'; 4 | if (process.env.NODE_ENV === 'development') { 5 | require('node-hot'); 6 | } 7 | import './server'; 8 | -------------------------------------------------------------------------------- /server/src/server.ts: -------------------------------------------------------------------------------- 1 | import { 2 | IPCMessageReader, IPCMessageWriter, 3 | createConnection, 4 | InitializeResult, 5 | Diagnostic, DiagnosticSeverity, Range, 6 | CompletionItem, 7 | TextDocument, TextDocuments, TextDocumentChangeEvent, TextDocumentPositionParams, 8 | DocumentSymbolParams, DocumentFormattingParams, DocumentRangeFormattingParams, 9 | TextEdit, 10 | SymbolInformation, WorkspaceSymbolParams, InitializeParams 11 | } from 'vscode-languageserver'; 12 | 13 | import { getCursorWordBoundry } from './utils'; 14 | import * as Analysis from './analysis'; 15 | import { CompletionService } from './services/completionService'; 16 | import { buildDocumentSymbols } from './services/documentSymbolService'; 17 | import { buildWorkspaceSymbols } from './services/workspaceSymbolService'; 18 | import { buildLintingErrors } from './services/lintingService'; 19 | import { buildDocumentFormatEdits, buildDocumentRangeFormatEdits } from './services/formatService'; 20 | 21 | import { readFiles, FileNamedCallback } from 'node-dir'; 22 | import Uri from 'vscode-uri'; 23 | 24 | import * as luaparse from 'luaparse'; 25 | import { basename } from 'path'; 26 | 27 | export interface FormatOptions { 28 | enabled: boolean; 29 | indentCount: number; 30 | useTabs: boolean; 31 | lineWidth: number; 32 | singleQuote: boolean; 33 | linebreakMultipleAssignments: boolean; 34 | } 35 | 36 | export interface LintingOptions { 37 | enabled: boolean; 38 | luaCheckConfig: string; 39 | luaCheckArgs: string[]; 40 | } 41 | 42 | export interface Settings { 43 | luacheckPath: string; 44 | preferLuaCheckErrors: boolean; 45 | targetVersion: string; 46 | format: FormatOptions; 47 | linting: LintingOptions; 48 | } 49 | 50 | class ServiceDispatcher { 51 | 52 | private connection = createConnection( 53 | new IPCMessageReader(process), 54 | new IPCMessageWriter(process) 55 | ); 56 | 57 | private rootUri: string | null = null; 58 | private settings: Settings = {} as any; 59 | private documents: TextDocuments = new TextDocuments(); 60 | private perDocumentAnalysis = new Map(); 61 | private readonly triggerCharacters = ['.', ':']; 62 | 63 | public constructor() { 64 | this.documents.onDidChangeContent(change => this.onDidChangeContent(change)); 65 | this.documents.onDidClose(change => this.onDidClose(change)); 66 | 67 | this.connection.onInitialize(handler => this.onInitialize(handler)); 68 | this.connection.onCompletion(pos => this.onCompletion(pos)); 69 | this.connection.onDocumentSymbol(handler => this.onDocumentSymbol(handler)); 70 | this.connection.onWorkspaceSymbol(handler => this.onWorkspaceSymbol(handler)); 71 | this.connection.onDidChangeConfiguration(change => this.onDidChangeConfiguration(change)); 72 | this.connection.onDocumentFormatting((params) => this.onDocumentFormatting(params)); 73 | this.connection.onDocumentRangeFormatting((params) => this.onDocumentRangeFormatting(params)); 74 | 75 | this.documents.listen(this.connection); 76 | this.connection.listen(); 77 | } 78 | 79 | private onInitialize(initializeParams: InitializeParams): InitializeResult { 80 | this.rootUri = initializeParams.rootUri; 81 | 82 | return { 83 | capabilities: { 84 | // Use full sync mode for now. 85 | // TODO: Add support for Incremental changes. Full syncs will not scale very well. 86 | textDocumentSync: this.documents.syncKind, 87 | documentSymbolProvider: true, 88 | workspaceSymbolProvider: true, 89 | completionProvider: { 90 | resolveProvider: false, 91 | triggerCharacters: this.triggerCharacters 92 | }, 93 | documentFormattingProvider: true, 94 | documentRangeFormattingProvider: true 95 | } 96 | }; 97 | } 98 | 99 | private onDocumentSymbol(handler: DocumentSymbolParams): SymbolInformation[] { 100 | const uri = handler.textDocument.uri; 101 | const analysis: Analysis.Analysis = this.perDocumentAnalysis[uri]; 102 | 103 | return buildDocumentSymbols(uri, analysis); 104 | } 105 | 106 | private onWorkspaceSymbol(handler: WorkspaceSymbolParams) { 107 | if (!this.rootUri) { 108 | return []; 109 | } 110 | 111 | const query = handler.query.toLowerCase(); 112 | 113 | return new Promise((resolve, reject) => { 114 | const symbols: SymbolInformation[] = []; 115 | const callback: FileNamedCallback = (err, content, filename, next) => { 116 | if (err) { 117 | return; 118 | } 119 | 120 | try { 121 | const analysis = new Analysis.Analysis(); 122 | analysis.end(content.toString()); 123 | analysis.buildGlobalSymbols(); 124 | 125 | symbols.push(...buildWorkspaceSymbols(filename, query, analysis)); 126 | } catch (e) { 127 | } 128 | 129 | next(); 130 | }; 131 | 132 | const uri = Uri.parse(this.rootUri!); 133 | readFiles(uri.fsPath, { match: /.lua$/ }, callback, (err) => { 134 | if (err) { 135 | reject(err); 136 | return; 137 | } 138 | 139 | resolve(symbols); 140 | }); 141 | }); 142 | } 143 | 144 | private onCompletion(textDocumentPosition: TextDocumentPositionParams): CompletionItem[] { 145 | const uri = textDocumentPosition.textDocument.uri; 146 | const document = this.documents.get(uri); 147 | 148 | if (!document) { 149 | return []; 150 | } 151 | 152 | const documentText = document.getText(); 153 | 154 | const { prefixStartPosition, suffixEndPosition } = getCursorWordBoundry(documentText, 155 | textDocumentPosition.position); 156 | 157 | const startOffset = document.offsetAt(prefixStartPosition); 158 | const endOffset = document.offsetAt(suffixEndPosition); 159 | 160 | const analysis = new Analysis.Analysis(); 161 | // Write everything up to the beginning of the potentially invalid text 162 | analysis.write(documentText.substring(0, startOffset)); 163 | 164 | // Is the completion for a table? 165 | let isTableScoped = false; 166 | 167 | const charAt = documentText.charAt(startOffset - 1); 168 | // If the completion is prefixed by a trigger character, insert a dummy function call to keep the Lua 169 | // syntactically valid and parsable. 170 | if (this.triggerCharacters.indexOf(charAt) >= 0) { 171 | analysis.write('__completion_helper__()'); 172 | isTableScoped = true; 173 | } 174 | 175 | // Insert a scope marker to help us find which scope we're in 176 | analysis.write('__scope_marker__()'); 177 | 178 | // And everything after 179 | try { 180 | analysis.end(documentText.substring(endOffset)); 181 | analysis.buildScopedSymbols(isTableScoped); 182 | } catch (err) { 183 | if (!(err instanceof SyntaxError)) { throw err; } 184 | 185 | // Suppress the failure due to syntax errors 186 | return []; 187 | } 188 | 189 | const suggestionService = new CompletionService(analysis); 190 | 191 | const word = documentText.substring(startOffset, endOffset); 192 | return suggestionService.buildCompletions(word.toLowerCase()); 193 | } 194 | 195 | private onDidChangeContent(change: TextDocumentChangeEvent) { 196 | this.parseAndLintDocument(change.document).then(diagnostics => { 197 | this.connection.sendDiagnostics({ 198 | uri: change.document.uri, 199 | diagnostics 200 | }); 201 | }); 202 | } 203 | 204 | private onDidClose(change: TextDocumentChangeEvent) { 205 | this.connection.sendDiagnostics({ 206 | uri: change.document.uri, 207 | diagnostics: [] 208 | }); 209 | } 210 | 211 | private onDidChangeConfiguration(change: any) { 212 | const oldVersion = this.settings ? this.settings.targetVersion : null; 213 | const oldLinterSettings = this.settings ? this.settings.linting : null; 214 | this.settings = change.settings.lua as Settings; 215 | 216 | // Because the JSON we get in `change` can be anything, we need to make sure that we've actually been passed 217 | // a valid type, and not something else, like a string. 218 | const validateSetting = (v: any, defaultVal: T) => { 219 | if (typeof (v) === typeof (defaultVal)) { return v; } 220 | return defaultVal; 221 | }; 222 | 223 | this.settings.preferLuaCheckErrors = validateSetting(this.settings.preferLuaCheckErrors, false); 224 | // indentCount defaults to `null`, which means we should use the editor settings. Anything else shall override 225 | // what the editor tells us. 226 | if (this.settings.format.indentCount !== null) { 227 | this.settings.format.indentCount = validateSetting(this.settings.format.indentCount, 4); 228 | } 229 | this.settings.format.lineWidth = validateSetting(this.settings.format.lineWidth, 120); 230 | this.settings.format.singleQuote = validateSetting(this.settings.format.singleQuote, false); 231 | this.settings.format.linebreakMultipleAssignments = validateSetting( 232 | this.settings.format.linebreakMultipleAssignments, false); 233 | 234 | // Validate the version. onDidChangeConfiguration seems to be called for every keystroke the user enters, 235 | // so its possible that the version string will be malformed. 236 | if (!['5.1', '5.2', '5.3'].includes(this.settings.targetVersion)) { 237 | this.settings.targetVersion = '5.1'; 238 | } 239 | 240 | // Update luaparse to reflect the user's choice in Lua version. This is much easier than 241 | // remembering to pass it in every time we may use it. 242 | luaparse.defaultOptions.luaVersion = this.settings.targetVersion; 243 | 244 | let relintAllDocuments = false; 245 | // If the version has changed, we should most definitely re-lint all documents 246 | if (oldVersion !== null && oldVersion !== this.settings.targetVersion) { 247 | relintAllDocuments = true; 248 | } 249 | 250 | // If any linter settings have changed, we should be nice and re-lint. 251 | if (oldLinterSettings !== null && oldLinterSettings !== this.settings.linting) { 252 | relintAllDocuments = true; 253 | } 254 | 255 | if (relintAllDocuments) { 256 | this.documents.all().forEach((doc) => { 257 | this.parseAndLintDocument(doc).then(diagnostics => { 258 | this.connection.sendDiagnostics({ 259 | uri: doc.uri, 260 | diagnostics 261 | }); 262 | }); 263 | }); 264 | } 265 | } 266 | 267 | private onDocumentFormatting(params: DocumentFormattingParams): TextEdit[] { 268 | if (!this.settings.format.enabled) { 269 | return []; 270 | } 271 | 272 | const uri = params.textDocument.uri; 273 | const document = this.documents.get(uri); 274 | 275 | if (!document) { 276 | return []; 277 | } 278 | 279 | return buildDocumentFormatEdits(uri, document, this.settings.format, params.options); 280 | } 281 | 282 | private onDocumentRangeFormatting(params: DocumentRangeFormattingParams): TextEdit[] { 283 | if (!this.settings.format.enabled) { 284 | return []; 285 | } 286 | 287 | const uri = params.textDocument.uri; 288 | const document = this.documents.get(uri); 289 | 290 | if (!document) { 291 | return []; 292 | } 293 | 294 | return buildDocumentRangeFormatEdits(uri, document, params.range, this.settings.format, params.options); 295 | } 296 | 297 | private async parseAndLintDocument(document: TextDocument) { 298 | const documentUri = document.uri; 299 | const documentText = document.getText(); 300 | 301 | const parsedUri = Uri.parse(documentUri); 302 | // Don't lint the diff view. Fixes #22. 303 | if (parsedUri.scheme === 'showModifications') { 304 | return []; 305 | } 306 | 307 | // Run the docment through luaparse and output any errors it finds 308 | const parseDocument = (): Promise => { 309 | return new Promise((resolve) => { 310 | try { 311 | this.perDocumentAnalysis[documentUri] = new Analysis.Analysis(); 312 | this.perDocumentAnalysis[documentUri].end(documentText); 313 | this.perDocumentAnalysis[documentUri].buildGlobalSymbols(); 314 | 315 | return resolve([]); 316 | } catch (err) { 317 | if (!(err instanceof SyntaxError)) { throw err; } 318 | const e = err as any; 319 | 320 | const lines = documentText.split(/\r?\n/g); 321 | const line = lines[e.line - 1]; 322 | 323 | const range = Range.create(e.line - 1, e.column, 324 | e.line - 1, line.length); 325 | 326 | // Strip out the row and column from the message 327 | const message = e.message.match(/\[\d+:\d+\] (.*)/)[1]; 328 | 329 | const diagnostic: Diagnostic = { 330 | range, 331 | message, 332 | severity: DiagnosticSeverity.Error, 333 | source: 'luaparse' 334 | }; 335 | 336 | return resolve([diagnostic]); 337 | } 338 | }); 339 | }; 340 | 341 | let errors = await parseDocument(); 342 | 343 | if (!this.settings.linting.enabled) { 344 | return []; 345 | } 346 | 347 | // Don't lint .luacheckrc files. Just return any parsing errors encountered. 348 | if (basename(parsedUri.fsPath) === '.luacheckrc') { 349 | return errors; 350 | } 351 | 352 | try { 353 | // TODO: Clean up the dependency on this.settings.. should probably have a SettingsManager type class. 354 | const lintingErrors = buildLintingErrors(this.settings, documentUri, documentText); 355 | 356 | // If luacheck errors are preferred and luacheck has provided us with some, usurp any luaparse errors. 357 | if (this.settings.preferLuaCheckErrors && lintingErrors.length > 0) { 358 | errors = lintingErrors; 359 | } else { 360 | // Otherwise, join the two lists together. 361 | errors = errors.concat(lintingErrors); 362 | } 363 | } catch (e) { } 364 | 365 | return errors; 366 | } 367 | } 368 | 369 | let serviceDispatcher: ServiceDispatcher | null = null; 370 | 371 | if (module.hot) { 372 | module.hot.accept(); 373 | 374 | module.hot.store(stash => { 375 | stash.serviceDispatcher = serviceDispatcher; 376 | }); 377 | 378 | module.hot.restore(stash => { 379 | if (stash.serviceDispatcher) { 380 | serviceDispatcher = stash.serviceDispatcher; 381 | const oldProto = Object.getPrototypeOf(serviceDispatcher); 382 | const newProto = ServiceDispatcher.prototype; 383 | for (const p of Object.getOwnPropertyNames(newProto)) { 384 | oldProto[p] = newProto[p]; 385 | } 386 | } 387 | }); 388 | } 389 | 390 | if (serviceDispatcher === null) { 391 | serviceDispatcher = new ServiceDispatcher(); 392 | } 393 | -------------------------------------------------------------------------------- /server/src/services/completionService.ts: -------------------------------------------------------------------------------- 1 | import { CompletionItem, CompletionItemKind } from 'vscode-languageserver'; 2 | 3 | import { Analysis, Symbol } from '../analysis'; 4 | import { matchesQuery } from '../utils'; 5 | 6 | export class CompletionService { 7 | private analysis: Analysis; 8 | 9 | public constructor(analysis: Analysis) { 10 | this.analysis = analysis; 11 | } 12 | 13 | public buildCompletions(query: string): CompletionItem[] { 14 | return this.analysis.symbols 15 | .filter(symbol => matchesQuery(query, symbol.name)) 16 | .map(symbol => { 17 | let detail = symbol.display; 18 | 19 | if (!detail) { 20 | if (symbol.isGlobalScope) { 21 | detail = '(global)'; 22 | } 23 | else if (symbol.kind === 'FunctionParameter') { 24 | detail = '(parameter)'; 25 | } 26 | else if (symbol.isOuterScope) { 27 | detail = '(outer)'; 28 | } 29 | else { 30 | detail = '(local)'; 31 | } 32 | } 33 | 34 | return { 35 | label: symbol.name, 36 | kind: this.convertSymbolKindToCompletionKind(symbol), 37 | detail 38 | } as CompletionItem; 39 | }); 40 | } 41 | 42 | private convertSymbolKindToCompletionKind(symbol: Symbol) { 43 | switch (symbol.kind) { 44 | case 'Function': 45 | return CompletionItemKind.Function; 46 | case 'FunctionParameter': 47 | return CompletionItemKind.Property; 48 | case 'Variable': 49 | return CompletionItemKind.Variable; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /server/src/services/documentSymbolService.ts: -------------------------------------------------------------------------------- 1 | import { Analysis } from '../analysis'; 2 | import { SymbolInformation, Location, SymbolKind } from 'vscode-languageserver'; 3 | 4 | export function buildDocumentSymbols(uri: string, analysis: Analysis): SymbolInformation[] { 5 | const symbols: SymbolInformation[] = []; 6 | 7 | for (const symbol of analysis.symbols.filter(sym => sym.isGlobalScope)) { 8 | // Populate the document's functions: 9 | if (symbol.kind === 'Function') { 10 | if (symbol.name === null) { continue; } 11 | 12 | symbols.push({ 13 | name: symbol.name, 14 | containerName: symbol.container || undefined, 15 | kind: SymbolKind.Function, 16 | location: Location.create(uri, symbol.range) 17 | }); 18 | } 19 | // Populate the document's variables: 20 | else if (symbol.kind === 'Variable') { 21 | if (symbol.name === null) { continue; } 22 | 23 | symbols.push({ 24 | name: symbol.name, 25 | kind: SymbolKind.Variable, 26 | location: Location.create(uri, symbol.range) 27 | }); 28 | } 29 | } 30 | 31 | return symbols; 32 | } 33 | -------------------------------------------------------------------------------- /server/src/services/formatService.ts: -------------------------------------------------------------------------------- 1 | import { TextEdit, Range, Position, TextDocument, FormattingOptions } from 'vscode-languageserver'; 2 | import { formatText, producePatch, UserOptions, WriteMode } from 'lua-fmt'; 3 | import { parsePatch } from 'diff'; 4 | import { FormatOptions } from '../server'; 5 | 6 | enum EditAction { 7 | Replace, 8 | Insert, 9 | Delete 10 | } 11 | 12 | class Edit { 13 | public action: EditAction; 14 | public start: Position; 15 | public end: Position; 16 | public text: string = ''; 17 | 18 | public constructor(action: EditAction, start: Position) { 19 | this.action = action; 20 | this.start = start; 21 | this.end = Position.create(0, 0); 22 | } 23 | } 24 | 25 | function getEditsFromFormattedText(documentUri: string, originalText: string, formattedText: string, 26 | startOffset: number = 0): TextEdit[] { 27 | const diff = producePatch(documentUri, originalText, formattedText); 28 | const unifiedDiffs = parsePatch(diff); 29 | 30 | const edits: Edit[] = []; 31 | let currentEdit: Edit | null = null; 32 | 33 | for (const uniDiff of unifiedDiffs) { 34 | for (const hunk of uniDiff.hunks) { 35 | let startLine = hunk.oldStart + startOffset; 36 | 37 | for (const line of hunk.lines) { 38 | switch (line[0]) { 39 | case '-': 40 | if (currentEdit === null) { 41 | currentEdit = new Edit(EditAction.Delete, Position.create(startLine - 1, 0)); 42 | } 43 | currentEdit.end = Position.create(startLine, 0); 44 | startLine++; 45 | break; 46 | 47 | case '+': 48 | if (currentEdit === null) { 49 | currentEdit = new Edit(EditAction.Insert, Position.create(startLine - 1, 0)); 50 | } else if (currentEdit.action === EditAction.Delete) { 51 | currentEdit.action = EditAction.Replace; 52 | } 53 | 54 | currentEdit.text += line.substr(1) + '\n'; 55 | 56 | break; 57 | 58 | case ' ': 59 | startLine++; 60 | if (currentEdit != null) { 61 | edits.push(currentEdit); 62 | } 63 | currentEdit = null; 64 | break; 65 | } 66 | } 67 | } 68 | 69 | if (currentEdit != null) { 70 | edits.push(currentEdit); 71 | } 72 | } 73 | 74 | return edits.map(edit => { 75 | switch (edit.action) { 76 | case EditAction.Replace: 77 | return TextEdit.replace(Range.create(edit.start, edit.end), edit.text); 78 | case EditAction.Insert: 79 | return TextEdit.insert(edit.start, edit.text); 80 | case EditAction.Delete: 81 | return TextEdit.del(Range.create(edit.start, edit.end)); 82 | } 83 | }); 84 | } 85 | 86 | export function buildDocumentFormatEdits(documentUri: string, document: TextDocument, extFormatOptions: FormatOptions, 87 | editorFormatOptions: FormattingOptions): 88 | TextEdit[] { 89 | let documentText = document.getText(); 90 | 91 | const useTabs = extFormatOptions.useTabs || !editorFormatOptions.insertSpaces; 92 | const indentCount = extFormatOptions.indentCount || editorFormatOptions.tabSize; 93 | 94 | const formatOptions: UserOptions = { 95 | writeMode: WriteMode.Diff, 96 | useTabs, 97 | indentCount, 98 | lineWidth: extFormatOptions.lineWidth, 99 | quotemark: extFormatOptions.singleQuote ? 'single' : 'double', 100 | linebreakMultipleAssignments: extFormatOptions.linebreakMultipleAssignments 101 | }; 102 | let formattedText: string; 103 | try { 104 | formattedText = formatText(documentText, formatOptions); 105 | } catch { 106 | // Return an empty array of edits in the case of failure to avoid distracting the user with the Output window 107 | // appearing every time there was an error formatting the document. Fixes #45. 108 | return []; 109 | } 110 | 111 | // Normalize the line endings so jsdiff has a chance at providing minimal edits, otherwise the diffing result will 112 | // be one giant edit, which isn't very friendly. 113 | if (process.platform === 'win32') { 114 | documentText = documentText.split('\r\n').join('\n'); 115 | formattedText = formattedText.split('\r\n').join('\n'); 116 | } 117 | 118 | return getEditsFromFormattedText(documentUri, documentText, formattedText); 119 | } 120 | 121 | export function buildDocumentRangeFormatEdits(_documentUri: string, _document: TextDocument, 122 | _range: Range, _extFormatOptions: FormatOptions, _editorFormatOptions: FormattingOptions): TextEdit[] { 123 | return []; 124 | 125 | // TODO: This feature is dependent on https://github.com/trixnz/lua-fmt/issues/14 to provide a reasonable 126 | // experience to the user. 127 | // 128 | // The code below works, but completely ignores any indentation levels that may exist in the code scope. 129 | // For this reason, it is temporarily disabled until the aforementioned #14 issue is resolved. 130 | 131 | // const documentText = document.getText(); 132 | 133 | // const startOffset = document.offsetAt(range.start); 134 | // const endOffset = document.offsetAt(range.end); 135 | // const text = documentText.substring(startOffset, endOffset); 136 | 137 | // const formatOptions: UserOptions = { 138 | // writeMode: WriteMode.Diff, 139 | // }; 140 | // const formattedText = formatText(text, formatOptions); 141 | 142 | // return getEditsFromFormattedText(documentUri, text, formattedText, range.start.line); 143 | } 144 | -------------------------------------------------------------------------------- /server/src/services/lintingService.ts: -------------------------------------------------------------------------------- 1 | import { Diagnostic, DiagnosticSeverity, Range } from 'vscode-languageserver'; 2 | import { spawnSync } from 'child_process'; 3 | // Arrrgh. This is awful! 4 | import { Settings } from '../server'; 5 | import { dirname } from 'path'; 6 | import Uri from 'vscode-uri'; 7 | 8 | function parseDiagnostics(data: string): Diagnostic[] { 9 | const diagnostics: Diagnostic[] = []; 10 | 11 | const errorRegex = /^.*:(\d+):(\d+)-(\d+): \(([EW]?)(\d+)\) (.*)$/mg; 12 | // file line column endcolumn type code message 13 | 14 | const matches = data.match(errorRegex); 15 | if (!matches) { return []; } 16 | 17 | while (true) { 18 | const m = errorRegex.exec(data); 19 | if (!m) { break; } 20 | 21 | const [, lineStr, columnStr, endColumnStr, type, codeStr, message] = m; 22 | 23 | const line = Number(lineStr) - 1; 24 | const column = Number(columnStr) - 1; 25 | const columnEnd = Number(endColumnStr); 26 | const code = Number(codeStr); 27 | 28 | const mapSeverity = () => { 29 | switch (type) { 30 | case 'E': 31 | return DiagnosticSeverity.Error; 32 | 33 | case 'W': 34 | return DiagnosticSeverity.Warning; 35 | 36 | default: 37 | return DiagnosticSeverity.Information; 38 | } 39 | }; 40 | 41 | diagnostics.push({ 42 | range: Range.create(line, column, line, columnEnd), 43 | severity: mapSeverity(), 44 | code, 45 | source: 'luacheck', 46 | message 47 | }); 48 | } 49 | 50 | return diagnostics; 51 | } 52 | 53 | export function buildLintingErrors(settings: Settings, documentUri: string, documentText: string) { 54 | // If a path to luacheck hasn't been provided, don't bother trying. 55 | if (!settings.luacheckPath) { return []; } 56 | 57 | const uri = Uri.parse(documentUri); 58 | const dir = dirname(uri.fsPath); 59 | 60 | const getLuacheckArgs = () => { 61 | const args = [ 62 | '-', '--no-color', '--ranges', '--codes', `--filename "${uri.fsPath}"` 63 | ]; 64 | 65 | if (settings.linting.luaCheckConfig) { 66 | args.push(`--config "${settings.linting.luaCheckConfig}"`); 67 | } 68 | 69 | args.push(...settings.linting.luaCheckArgs); 70 | 71 | return args; 72 | }; 73 | 74 | const cp = spawnSync( 75 | `"${settings.luacheckPath}"`, 76 | getLuacheckArgs(), 77 | { 78 | cwd: dir, 79 | input: documentText, 80 | shell: true 81 | } 82 | ); 83 | 84 | // From https://luacheck.readthedocs.io/en/stable/cli.html 85 | // Exit code is 0 if no warnings or errors occurred. 86 | // Exit code is 1 if some warnings occurred but there were no syntax errors or invalid inline options. 87 | // Exit code is 2 if there were some syntax errors or invalid inline options. 88 | // Exit code is 3 if some files couldn’t be checked, typically due to an incorrect file name. 89 | // Exit code is 4 if there was a critical error(invalid CLI arguments, config, or cache file). 90 | if (cp.status === 0) { return []; } 91 | 92 | if (cp.status === 1 || cp.status === 2) { 93 | return parseDiagnostics(cp.output.join('\n')); 94 | } 95 | 96 | throw new Error('luacheck failed with error: ' + cp.stderr.toString()); 97 | } 98 | -------------------------------------------------------------------------------- /server/src/services/workspaceSymbolService.ts: -------------------------------------------------------------------------------- 1 | import { Analysis } from '../analysis'; 2 | import { SymbolInformation, SymbolKind, Location } from 'vscode-languageserver'; 3 | import { matchesQuery } from '../utils'; 4 | import Uri from 'vscode-uri'; 5 | 6 | export function buildWorkspaceSymbols(path: string, query: string, analysis: Analysis): SymbolInformation[] { 7 | const symbols: SymbolInformation[] = []; 8 | const uri = Uri.file(path); 9 | 10 | for (const symbol of analysis.symbols.filter(sym => sym.isGlobalScope && matchesQuery(query, sym.name))) { 11 | // Populate the document's functions: 12 | if (symbol.kind === 'Function') { 13 | if (symbol.name === null) { continue; } 14 | 15 | symbols.push({ 16 | name: symbol.name, 17 | containerName: symbol.container || undefined, 18 | kind: SymbolKind.Function, 19 | location: Location.create(uri.toString(), symbol.range) 20 | }); 21 | } 22 | // Populate the document's variables: 23 | else if (symbol.kind === 'Variable') { 24 | if (symbol.name === null) { continue; } 25 | 26 | symbols.push({ 27 | name: symbol.name, 28 | kind: SymbolKind.Variable, 29 | location: Location.create(uri.toString(), symbol.range) 30 | }); 31 | } 32 | } 33 | 34 | return symbols; 35 | } 36 | -------------------------------------------------------------------------------- /server/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { Position, Range } from 'vscode-languageserver'; 2 | import { NodeAdditional } from 'luaparse'; 3 | 4 | export function getCursorWordBoundry(documentText: string, position: Position) { 5 | const line = documentText.split(/\r?\n/g)[position.line]; 6 | 7 | const beginningOfLineWordRegex = /^\w*[a-zA-Z_]+\w*\b/g; 8 | const endOfLineWordRegex = /\b\w*[a-zA-Z_]+\w*$/g; 9 | 10 | const leadingText = line.substring(0, position.character); 11 | const prefix = leadingText.match(endOfLineWordRegex); 12 | const prefixString = prefix ? prefix[0] : ''; 13 | const prefixStartPosition = Position.create(position.line, position.character - prefixString.length); 14 | 15 | const trailingText = line.substring(position.character); 16 | const suffix = trailingText.match(beginningOfLineWordRegex); 17 | const suffixString = suffix ? suffix[0] : ''; 18 | const suffixEndPosition = Position.create(position.line, position.character + suffixString.length); 19 | 20 | return { 21 | prefixStartPosition, 22 | suffixEndPosition 23 | }; 24 | } 25 | 26 | // Convert the node's range into something the vscode language server can work with 27 | export function getNodeRange(node: NodeAdditional): Range { 28 | return { 29 | start: { 30 | character: node.loc.start.column, 31 | line: node.loc.start.line - 1 32 | }, 33 | end: { 34 | character: node.loc.end.column, 35 | line: node.loc.end.line - 1 36 | } 37 | }; 38 | } 39 | 40 | export function matchesQuery(query: string, name: string | null) { 41 | if (query.length === 0) { return true; } 42 | if (name === null) { return false; } 43 | return name.toLowerCase().indexOf(query) !== -1; 44 | } 45 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | 8 | "lib": [ 9 | "es2016" 10 | ], 11 | "outDir": "../out/server", 12 | "typeRoots": [ 13 | "./typings/modules" 14 | ], 15 | "strict": true, 16 | "allowJs": false, 17 | "allowSyntheticDefaultImports": false, 18 | "allowUnreachableCode": false, 19 | "allowUnusedLabels": false, 20 | "experimentalDecorators": true, 21 | "forceConsistentCasingInFileNames": true, 22 | "noEmitOnError": true, 23 | "noFallthroughCasesInSwitch": true, 24 | "noImplicitReturns": true, 25 | "noUnusedLocals": true, 26 | "noUnusedParameters": true, 27 | "removeComments": true, 28 | "skipDefaultLibCheck": true, 29 | "skipLibCheck": true, 30 | "stripInternal": true, 31 | "suppressImplicitAnyIndexErrors": true 32 | }, 33 | "exclude": [ 34 | "node_modules" 35 | ], 36 | "include": [ 37 | "**/*.ts" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /server/typings/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /server/typings/modules/luaparse/extensions.d.ts: -------------------------------------------------------------------------------- 1 | // Extensions to original luaparse types to provide typesafety when dealing with values that are injected by vscode-lua. 2 | import { Scope } from "../../../src/analysis/scope"; 3 | 4 | declare module 'luaparse' { 5 | interface NodeAdditional { 6 | scope: Scope 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /server/typings/modules/luaparse/index.d.ts: -------------------------------------------------------------------------------- 1 | /* luaparse by: https://github.com/oxyc */ 2 | /* typing definition by: https://github.com/hydroper */ 3 | declare module 'luaparse' { 4 | interface NodeAdditional { 5 | type: string; 6 | loc: MarkerLocations; 7 | } 8 | 9 | interface ExpAdditional extends NodeAdditional { 10 | inParens?: boolean; 11 | } 12 | 13 | export type Expression = CallExpression | StringCallExpression | TableCallExpression | 14 | FunctionDeclaration | Identifier | IndexExpression | MemberExpression | 15 | TableConstructorExpression | BooleanLiteral | NilLiteral | NumericLiteral | StringLiteral | 16 | VarargLiteral | BinaryExpression | LogicalExpression | UnaryExpression; 17 | 18 | export type Statement = LabelStatement | BreakStatement | GotoStatement | 19 | ReturnStatement | IfStatement | IfClause | ElseifClause | ElseClause | WhileStatement | 20 | DoStatement | RepeatStatement | LocalStatement | AssignmentStatement | CallStatement | 21 | FunctionDeclaration | ForNumericStatement | ForGenericStatement; 22 | 23 | type Node = Chunk | Expression | Statement | TableKey | TableKeyString | TableValue; 24 | 25 | export interface LabelStatement extends NodeAdditional { 26 | readonly type: "LabelStatement"; 27 | readonly label: Identifier; 28 | } 29 | 30 | export interface BreakStatement extends NodeAdditional { 31 | readonly type: "BreakStatement"; 32 | } 33 | 34 | export interface GotoStatement extends NodeAdditional { 35 | readonly type: "GotoStatement"; 36 | readonly label: Identifier; 37 | } 38 | export interface ReturnStatement extends NodeAdditional { 39 | readonly type: "ReturnStatement"; 40 | readonly arguments: Expression[]; 41 | } 42 | export interface IfStatement extends NodeAdditional { 43 | readonly type: "IfStatement"; 44 | readonly clauses: (IfClause | ElseifClause | ElseClause)[]; 45 | } 46 | export interface IfClause extends NodeAdditional { 47 | readonly type: "IfClause"; 48 | readonly condition: Expression; 49 | readonly body: Statement[]; 50 | } 51 | export interface ElseifClause extends NodeAdditional { 52 | readonly type: "ElseifClause"; 53 | readonly condition: Expression; 54 | readonly body: Statement[]; 55 | } 56 | export interface ElseClause extends NodeAdditional { 57 | readonly type: "ElseClause"; 58 | readonly body: Statement[]; 59 | } 60 | export interface WhileStatement extends NodeAdditional { 61 | readonly type: "WhileStatement"; 62 | readonly condition: Expression; 63 | readonly body: Statement[]; 64 | } 65 | export interface DoStatement extends NodeAdditional { 66 | readonly type: "DoStatement"; 67 | readonly body: Statement[]; 68 | } 69 | export interface RepeatStatement extends NodeAdditional { 70 | readonly type: "RepeatStatement"; 71 | readonly condition: Expression; 72 | readonly body: Statement[]; 73 | } 74 | export interface LocalStatement extends NodeAdditional { 75 | readonly type: "LocalStatement"; 76 | readonly variables: Identifier[]; 77 | readonly init: (Expression | null)[]; 78 | } 79 | export interface AssignmentStatement extends NodeAdditional { 80 | readonly type: "AssignmentStatement"; 81 | readonly variables: (Identifier | IndexExpression | MemberExpression)[]; 82 | readonly init: (Expression | null)[]; 83 | } 84 | export interface CallStatement extends NodeAdditional { 85 | readonly type: "CallStatement"; 86 | readonly expression: Expression; 87 | } 88 | export interface FunctionDeclaration extends ExpAdditional { 89 | readonly type: "FunctionDeclaration"; 90 | readonly identifier: Identifier | MemberExpression | null; 91 | readonly isLocal: boolean; 92 | readonly parameters: (Identifier | VarargLiteral)[]; 93 | readonly body: Statement[]; 94 | } 95 | export interface ForNumericStatement extends NodeAdditional { 96 | readonly type: "ForNumericStatement"; 97 | readonly variable: Identifier; 98 | readonly start: Expression; 99 | readonly end: Expression; 100 | readonly step: Expression; 101 | readonly body: Statement[]; 102 | } 103 | export interface ForGenericStatement extends NodeAdditional { 104 | readonly type: "ForGenericStatement"; 105 | readonly variables: Identifier[]; 106 | readonly iterators: Expression[]; 107 | readonly body: Statement[]; 108 | } 109 | export interface Chunk extends NodeAdditional { 110 | readonly type: "Chunk"; 111 | readonly body: Statement[]; 112 | readonly comments: Comment[]; 113 | readonly globals?: Expression[]; 114 | } 115 | export interface Identifier extends ExpAdditional { 116 | readonly type: "Identifier"; 117 | readonly name: string; 118 | } 119 | export interface BooleanLiteral extends ExpAdditional { 120 | readonly type: "BooleanLiteral"; 121 | readonly raw: string; 122 | readonly value: boolean; 123 | } 124 | export interface NilLiteral extends ExpAdditional { 125 | readonly type: "NilLiteral"; 126 | readonly raw: string; 127 | readonly value: null; 128 | } 129 | export interface NumericLiteral extends ExpAdditional { 130 | readonly type: "NumericLiteral"; 131 | readonly raw: string; 132 | readonly value: number; 133 | } 134 | export interface StringLiteral extends ExpAdditional { 135 | readonly type: "StringLiteral"; 136 | readonly raw: string; 137 | readonly value: string; 138 | } 139 | export interface VarargLiteral extends ExpAdditional { 140 | readonly type: "VarargLiteral"; 141 | readonly raw: string; 142 | readonly value: string; 143 | } 144 | export interface TableKey extends NodeAdditional { 145 | readonly type: "TableKey"; 146 | readonly key: Expression; 147 | readonly value: Expression; 148 | } 149 | export interface TableKeyString extends NodeAdditional { 150 | readonly type: "TableKeyString"; 151 | readonly key: Identifier; 152 | readonly value: Expression; 153 | } 154 | export interface TableValue extends NodeAdditional { 155 | readonly type: "TableValue"; 156 | readonly value: Expression; 157 | } 158 | export interface TableConstructorExpression extends ExpAdditional { 159 | readonly type: "TableConstructorExpression"; 160 | readonly fields: (TableKey | TableKeyString | TableValue)[]; 161 | } 162 | export interface BinaryExpression extends ExpAdditional { 163 | readonly type: "BinaryExpression"; 164 | readonly operator: string; 165 | readonly left: Expression; 166 | readonly right: Expression; 167 | } 168 | export interface LogicalExpression extends ExpAdditional { 169 | readonly type: "LogicalExpression"; 170 | readonly operator: string; 171 | readonly left: Expression; 172 | readonly right: Expression; 173 | } 174 | export interface UnaryExpression extends ExpAdditional { 175 | readonly type: "UnaryExpression"; 176 | readonly operator: string; 177 | readonly argument: string; 178 | } 179 | export interface MemberExpression extends ExpAdditional { 180 | readonly type: "MemberExpression"; 181 | readonly indexer: string; 182 | readonly identifier: Identifier; 183 | readonly base: Expression; 184 | } 185 | export interface IndexExpression extends ExpAdditional { 186 | readonly type: "IndexExpression"; 187 | readonly base: Expression; 188 | readonly index: Expression; 189 | } 190 | export interface CallExpression extends ExpAdditional { 191 | readonly type: "CallExpression"; 192 | readonly base: Expression; 193 | readonly arguments: Expression[]; 194 | } 195 | export interface TableCallExpression extends ExpAdditional { 196 | readonly type: "TableCallExpression"; 197 | readonly base: Expression; 198 | readonly arguments: TableCallExpression; 199 | } 200 | export interface StringCallExpression extends ExpAdditional { 201 | readonly type: "StringCallExpression"; 202 | readonly base: Expression; 203 | readonly argument: StringLiteral; 204 | } 205 | export interface Comment extends NodeAdditional { 206 | readonly type: "Comment"; 207 | readonly raw: string; 208 | readonly value: string; 209 | } 210 | interface MarkerLocation { 211 | line: number; 212 | column: number; 213 | } 214 | interface MarkerLocations { 215 | start: MarkerLocation; 216 | end: MarkerLocation; 217 | } 218 | export module Tokens { 219 | export type EOF = 1; 220 | export type StringLiteral = 2; 221 | export type Identifier = 8; 222 | export type NumericLiteral = 16; 223 | export type Punctuator = 32; 224 | export type BooleanLiteral = 64; 225 | export type NilLiteral = 128; 226 | export type VarargLiteral = 256; 227 | } 228 | export interface Token { 229 | //readonly type: Tokens.EOF | Tokens.StringLiteral | Tokens.Identifier | Tokens.NumericLiteral | 230 | // Tokens.Punctuator | Tokens.BooleanLiteral | Tokens.NilLiteral | Tokens.VarargLiteral; 231 | readonly type: number; 232 | readonly value: string; 233 | readonly line: number; 234 | readonly lineStart: number; 235 | readonly loc?: MarkerLocations; 236 | readonly range: [number, number]; 237 | } 238 | export const defaultOptions: Options; 239 | export const version: string; 240 | 241 | export function end(code: string): Chunk; 242 | export function lex(): Token; 243 | export function parse(code: Options | string, options?: Options | null): Chunk; 244 | export function write(code: string): void; 245 | 246 | interface Options { 247 | wait?: boolean; 248 | comments?: boolean; 249 | scope?: boolean; 250 | locations?: boolean; 251 | ranges?: boolean; 252 | onCreateNode?: (node: Node) => void | null; 253 | onCreateScope?: Function | null; 254 | onDestroyScope?: Function | null; 255 | //luaVersion?: '5.1' | '5.2' | '5.3'; 256 | luaVersion?: string; 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | import * as path from 'path'; 3 | import { VersionSelector } from './versionSelector'; 4 | 5 | import { 6 | LanguageClient, LanguageClientOptions, ServerOptions, 7 | TransportKind 8 | } from 'vscode-languageclient'; 9 | 10 | export function activate(context: vscode.ExtensionContext) { 11 | startLanguageServer(context); 12 | 13 | context.subscriptions.push(new VersionSelector()); 14 | } 15 | 16 | export function deactivate() { 17 | } 18 | 19 | function startLanguageServer(context: vscode.ExtensionContext) { 20 | const serverModule = path.join(__dirname, '../server', 'main.js'); 21 | 22 | const debugOptions = { 23 | execArgv: ['--nolazy', '--inspect=6009'], env: { 24 | NODE_ENV: 'development' 25 | } 26 | }; 27 | 28 | const runOptions = { 29 | env: { 30 | NODE_ENV: 'production' 31 | } 32 | }; 33 | 34 | let serverOptions: ServerOptions = { 35 | run: { module: serverModule, transport: TransportKind.ipc, options: runOptions }, 36 | debug: { 37 | module: serverModule, 38 | transport: TransportKind.ipc, 39 | // The current version of node shipped with VSCode Insiders (as of April 3 2017) seems to have an issue with 40 | // --inspect debugging, so we'll assume that someone debugging the extension has a recent version of node on 41 | // on their PATH. 42 | // If you do not, comment this line out and replace the --inspect above with --debug. 43 | runtime: 'node', 44 | options: debugOptions 45 | } 46 | }; 47 | 48 | const serverCommand = vscode.workspace.getConfiguration().get('lua.server.command') as string; 49 | if (serverCommand) { 50 | const serverArgs = vscode.workspace.getConfiguration().get('lua.server.args') as string[]; 51 | serverOptions = { 52 | command: serverCommand, args: serverArgs 53 | }; 54 | } 55 | 56 | // Options to control the language client 57 | const clientOptions: LanguageClientOptions = { 58 | // Register the server for plain text documents 59 | documentSelector: [ 60 | { language: 'lua', scheme: 'file' }, 61 | { language: 'lua', scheme: 'untitled' } 62 | ], 63 | synchronize: { 64 | configurationSection: [ 65 | 'lua' 66 | ] 67 | } 68 | }; 69 | 70 | // Create the language client and start the client. 71 | const disposable = new LanguageClient('luaLanguageServer', 72 | 'Lua Language Server', serverOptions, clientOptions).start(); 73 | 74 | // Push the disposable to the context's subscriptions so that the 75 | // client can be deactivated on extension deactivation 76 | context.subscriptions.push(disposable); 77 | } 78 | -------------------------------------------------------------------------------- /src/versionSelector.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from 'vscode'; 2 | 3 | export class VersionSelector extends vscode.Disposable { 4 | private statusBarEntry: vscode.StatusBarItem; 5 | private onChangeEditorSubscription: vscode.Disposable; 6 | private onSelectVersionCommand: vscode.Disposable; 7 | private onConfigChangedSubscription: vscode.Disposable; 8 | 9 | private readonly defaultVersion = '5.1'; 10 | private readonly availableVersions = ['5.1', '5.2', '5.3']; 11 | 12 | public constructor() { 13 | super(() => this.dispose()); 14 | 15 | this.statusBarEntry = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, Number.MIN_VALUE); 16 | this.onChangeEditorSubscription = vscode.window.onDidChangeActiveTextEditor(this.updateVisibility, this); 17 | this.onConfigChangedSubscription = vscode.workspace.onDidChangeConfiguration( 18 | () => this.updateTextFromConfiguration()); 19 | 20 | const selectVersionCommand = 'lua.selectVersion'; 21 | this.statusBarEntry.tooltip = 'Select Lua Version'; 22 | this.statusBarEntry.command = selectVersionCommand; 23 | 24 | this.onSelectVersionCommand = vscode.commands.registerCommand(selectVersionCommand, 25 | this.showVersionPicker, this); 26 | 27 | this.updateTextFromConfiguration(); 28 | this.updateVisibility(); 29 | } 30 | 31 | public dispose() { 32 | this.statusBarEntry.dispose(); 33 | this.onChangeEditorSubscription.dispose(); 34 | this.onSelectVersionCommand.dispose(); 35 | this.onConfigChangedSubscription.dispose(); 36 | } 37 | 38 | private updateTextFromConfiguration() { 39 | const targetVersion = vscode.workspace.getConfiguration().get('lua.targetVersion') as string; 40 | 41 | this.statusBarEntry.text = this.availableVersions.includes(targetVersion) 42 | ? targetVersion 43 | : this.defaultVersion; 44 | } 45 | 46 | private updateVisibility() { 47 | if (!this.statusBarEntry) { 48 | return; 49 | } 50 | 51 | if (!vscode.window.activeTextEditor) { 52 | this.statusBarEntry.hide(); 53 | return; 54 | } 55 | 56 | const document = vscode.window.activeTextEditor.document; 57 | if (vscode.languages.match('lua', document)) { 58 | this.statusBarEntry.show(); 59 | } else { 60 | this.statusBarEntry.hide(); 61 | } 62 | } 63 | 64 | private async showVersionPicker() { 65 | const selectedOption = await vscode.window.showQuickPick(this.availableVersions, { 66 | placeHolder: 'Select the version of Lua to target' 67 | }); 68 | 69 | if (!selectedOption) { 70 | return; 71 | } 72 | 73 | await vscode.workspace.getConfiguration().update('lua.targetVersion', selectedOption); 74 | this.updateTextFromConfiguration(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /test.lua: -------------------------------------------------------------------------------- 1 | Test -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es2016" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": ".", 11 | "strict": true, 12 | "allowJs": false, 13 | "allowSyntheticDefaultImports": false, 14 | "allowUnreachableCode": false, 15 | "allowUnusedLabels": false, 16 | "experimentalDecorators": true, 17 | "forceConsistentCasingInFileNames": true, 18 | "noEmitOnError": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "noImplicitReturns": true, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "removeComments": true, 24 | "skipDefaultLibCheck": true, 25 | "skipLibCheck": true, 26 | "stripInternal": true, 27 | "suppressImplicitAnyIndexErrors": true 28 | }, 29 | "exclude": [ 30 | "node_modules", 31 | "server", 32 | "out/server", 33 | ".vscode-test" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "adjacent-overload-signatures": true, 4 | "callable-types": true, 5 | "class-name": true, 6 | "comment-format": [ 7 | true, 8 | "check-space" 9 | ], 10 | "curly": true, 11 | "eofline": true, 12 | "forin": true, 13 | "indent": [ 14 | true, 15 | "spaces" 16 | ], 17 | "interface-over-type-literal": true, 18 | "label-position": true, 19 | "linebreak-style": [ 20 | true, 21 | "LF" 22 | ], 23 | "max-line-length": [ 24 | true, 25 | 120 26 | ], 27 | "member-access": [ 28 | true, 29 | "check-accessor", 30 | "check-constructor" 31 | ], 32 | "new-parens": true, 33 | "no-angle-bracket-type-assertion": true, 34 | "no-arg": true, 35 | "no-bitwise": true, 36 | "no-conditional-assignment": true, 37 | "no-consecutive-blank-lines": [ 38 | true, 39 | 2 40 | ], 41 | "no-construct": true, 42 | "no-default-export": true, 43 | "no-duplicate-variable": true, 44 | "no-eval": true, 45 | "no-internal-module": true, 46 | "no-invalid-this": true, 47 | "no-mergeable-namespace": true, 48 | "no-namespace": [ 49 | true, 50 | "allow-declarations" 51 | ], 52 | "no-parameter-properties": true, 53 | "no-shadowed-variable": true, 54 | "no-string-literal": true, 55 | "no-string-throw": true, 56 | "no-switch-case-fall-through": true, 57 | "no-trailing-whitespace": true, 58 | "no-unsafe-finally": true, 59 | "no-unused-expression": true, 60 | "no-var-keyword": true, 61 | "object-literal-key-quotes": [ 62 | true, 63 | "as-needed" 64 | ], 65 | "object-literal-shorthand": true, 66 | "one-line": [ 67 | true, 68 | "check-open-brace", 69 | "check-whitespace" 70 | ], 71 | "one-variable-per-declaration": [ 72 | true 73 | ], 74 | "only-arrow-functions": [ 75 | true, 76 | "allow-declarations" 77 | ], 78 | "prefer-const": true, 79 | "prefer-for-of": true, 80 | "quotemark": [ 81 | true, 82 | "single", 83 | "jsx-double" 84 | ], 85 | "semicolon": [ 86 | true, 87 | "always" 88 | ], 89 | "triple-equals": [ 90 | true, 91 | "allow-null-check" 92 | ], 93 | "typedef": [ 94 | true, 95 | "parameter" 96 | ], 97 | "use-isnan": true, 98 | "typedef-whitespace": [ 99 | true, 100 | { 101 | "call-signature": "nospace", 102 | "index-signature": "nospace", 103 | "parameter": "nospace", 104 | "property-declaration": "nospace", 105 | "variable-declaration": "nospace" 106 | } 107 | ], 108 | "trailing-comma": [ 109 | true, 110 | { 111 | "multiline": "never", 112 | "singleline": "never" 113 | } 114 | ], 115 | "variable-name": [ 116 | true, 117 | "check-format", 118 | "allow-leading-underscore", 119 | "ban-keywords" 120 | ], 121 | "whitespace": [ 122 | true, 123 | "check-branch", 124 | "check-decl", 125 | "check-operator", 126 | "check-separator", 127 | "check-type" 128 | ] 129 | } 130 | } 131 | --------------------------------------------------------------------------------