Adding 0.0.4
This commit is contained in:
parent
1c06163b28
commit
fec35ea067
9 changed files with 523 additions and 365 deletions
32
.vsixmanifest
Normal file
32
.vsixmanifest
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
|
||||
<Metadata>
|
||||
<Identity Language="en-US" Id="pocketmine-ide" Version="0.0.1" Publisher="Ad5001"/>
|
||||
<DisplayName>PocketMine IDE</DisplayName>
|
||||
<Description xml:space="preserve">Implementation of external PocketMine/PHP libs for Visual Studio Code</Description>
|
||||
<Tags>PocketMine,IDE,PHP,Lib,php</Tags>
|
||||
<Categories>Other</Categories>
|
||||
<GalleryFlags>Public</GalleryFlags>
|
||||
<Badges></Badges>
|
||||
<Properties>
|
||||
<Property Id="Microsoft.VisualStudio.Code.Engine" Value="^1.5.0" />
|
||||
<Property Id="Microsoft.VisualStudio.Code.ExtensionDependencies" Value="" />
|
||||
|
||||
|
||||
<Property Id="Microsoft.VisualStudio.Services.Links.Learn" Value="https://github.com/Ad5001/PocketMine-IDE" />
|
||||
|
||||
|
||||
<Property Id="Microsoft.VisualStudio.Services.GitHubFlavoredMarkdown" Value="true" />
|
||||
</Properties>
|
||||
|
||||
<Icon>extension/icon.png</Icon>
|
||||
</Metadata>
|
||||
<Installation>
|
||||
<InstallationTarget Id="Microsoft.VisualStudio.Code"/>
|
||||
</Installation>
|
||||
<Dependencies/>
|
||||
<Assets>
|
||||
<Asset Type="Microsoft.VisualStudio.Code.Manifest" Path="extension/package.json" Addressable="true" />
|
||||
<Asset Type="Microsoft.VisualStudio.Services.Content.Details" Path="extension/README.md" Addressable="true" /><Asset Type="Microsoft.VisualStudio.Services.Icons.Default" Path="extension/icon.png" Addressable="true" />
|
||||
</Assets>
|
||||
</PackageManifest>
|
13
README.md
13
README.md
|
@ -1,6 +1,6 @@
|
|||
# PocketMine-IDE
|
||||
|
||||
Add all pocketmine functions & classes from a src. Based on [https://github.com/bschulte/PHP-Autocomplete](https://github.com/bschulte/PHP-Autocomplete)
|
||||
Add all pocketmine functions & classes from a src.
|
||||
|
||||
## Features
|
||||
|
||||
|
@ -22,6 +22,17 @@ None so far
|
|||
|
||||
## Release Notes
|
||||
|
||||
## 0.0.4
|
||||
|
||||
Rewriting original extension from (almost) stratch providing an easier reading.
|
||||
Introducing Properties (class properties, static properties and constants).
|
||||
Fixed anyoing method duplication.
|
||||
|
||||
## 0.0.3
|
||||
|
||||
Fixed bugs on Windows
|
||||
Fixed bug with autocompleting class not carring about uses.
|
||||
|
||||
## 0.0.2
|
||||
|
||||
Fixing compatibility bug with original extension.
|
||||
|
|
BIN
icon.png
BIN
icon.png
Binary file not shown.
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
BIN
icon.xcf
Normal file
BIN
icon.xcf
Normal file
Binary file not shown.
|
@ -1,22 +1,30 @@
|
|||
/**
|
||||
* Main file for extension
|
||||
* Almost entiry rewritten by (C) Ad5001 2017
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
// The module 'vscode' contains the VS Code extensibility API
|
||||
// Import the module and reference it with the alias vscode in your code below
|
||||
const vscode = require('vscode');
|
||||
const phpFunctionSuggestions_1 = require('./phpFunctionSuggestions');
|
||||
exports.phpFileFunctions = {};
|
||||
exports.phpFileStaticFunctions = {};
|
||||
exports.phpFileUses = {};
|
||||
// const phpFuncSuggestion = require('./phpFunctionSuggestions');
|
||||
const Indexer = (require('./phpCompletionItem')).Indexer;
|
||||
exports.PHP_MODE = { language: 'php', scheme: 'file' };
|
||||
// this method is called when your extension is activated
|
||||
// your extension is activated the very first time the command is executed
|
||||
exports.currentPath = "";
|
||||
|
||||
|
||||
/**
|
||||
* Initial extension activation
|
||||
*
|
||||
* @param {*} context
|
||||
*/
|
||||
function activate(context) {
|
||||
// Do the initial indexing
|
||||
indexPhpFiles();
|
||||
console.log(exports.phpFileFunctions);
|
||||
console.log(Object.keys(exports.phpFileUses));
|
||||
Indexer.indexPhpFiles();
|
||||
|
||||
// require("fs").appendFileSync("/home/ad5001/echo.txt", JSON.stringify(Indexer.phpFileProperties))
|
||||
vscode.workspace.onDidSaveTextDocument(function (document) {
|
||||
indexPhpFiles();
|
||||
Indexer.indexPhpFiles();
|
||||
});
|
||||
|
||||
// Setup our class as a compvarion item provider for function autocompvare
|
||||
context.subscriptions.push(vscode.languages.registerCompletionItemProvider(exports.PHP_MODE, {
|
||||
provideCompletionItems(document, position, token) {
|
||||
|
@ -30,290 +38,73 @@ function activate(context) {
|
|||
currentWord = word.substr(0, position.character - wordAtPosition.start.character);
|
||||
}
|
||||
|
||||
// Checking for commun regexps
|
||||
var clas = /new\s+(\\)?(\w+)(\\\w+)*/.exec(lineText);
|
||||
var use = /use\s+(\w+)(\\\w+)*/.exec(lineText);
|
||||
var execute = /->(\w+)/.exec(lineText);
|
||||
var executeStatic = /::(\w+)/.exec(lineText);
|
||||
var classInFunc = /(\(|,\s*)((\\\w+)+)/.exec(lineText);
|
||||
|
||||
// Check through the list of functions that are included in this file and see if any match
|
||||
// the starting varter of the word we have so far
|
||||
var suggestions = [];
|
||||
|
||||
// Check what files the current document includes/requires
|
||||
var currentFileName = document.uri.fsPath.replace(vscode.workspace.rootPath, '').slice(1);
|
||||
var currentPath = document.uri.fsPath.replace(vscode.workspace.rootPath, '').replace("src/", "");
|
||||
|
||||
// Look through all included/required files for the current document
|
||||
for (var f in exports.phpFileFunctions) {
|
||||
for (var f in Indexer.phpFileFunctions) {
|
||||
// Checking normal functions
|
||||
if (execute)
|
||||
for (var func in exports.phpFileFunctions[f]) {
|
||||
func = exports.phpFileFunctions[f][func];
|
||||
if (func.function.indexOf(currentWord) > 0 && execute[1] == currentWord && (func.functionModifiers["public"] || f == currentPath)) {
|
||||
var newSuggestion = new vscode.CompletionItem(func.function, vscode.CompletionItemKind.Function);
|
||||
params = func.params;
|
||||
var parameters = [];
|
||||
params.forEach(function(value, key) {
|
||||
if (value) {
|
||||
params[key] = "$" + value[1];
|
||||
parameters[key] = (typeof value[2] !== "undefined" ? value[2] + " " : "") + value[1];
|
||||
parameters[key] += typeof value[3] !== "undefined" ? " = " + value[3] : "";
|
||||
if (execute) {
|
||||
suggestions = Indexer.getFunctionsFromFile(f, suggestions, currentWord, execute);
|
||||
suggestions = Indexer.getPropertiesFromFile(f, suggestions, currentWord, execute);
|
||||
}
|
||||
});
|
||||
newSuggestion.insertText = func.function+"(" + params.join(", ") + ")";
|
||||
newSuggestion.documentation = func.comment;
|
||||
newSuggestion.detail = "(" + parameters.join(", ") + ")";
|
||||
suggestions.push(newSuggestion);
|
||||
}
|
||||
};
|
||||
|
||||
// Checking static functions
|
||||
if (executeStatic)
|
||||
for (var func in exports.phpFileStaticFunctions[f]) {
|
||||
func = exports.phpFileStaticFunctions[f][func];
|
||||
if (func.function.indexOf(currentWord) > 0 && executeStatic[1] == currentWord) {
|
||||
var newSuggestion = new vscode.CompletionItem(func.function, vscode.CompletionItemKind.Function);
|
||||
var params = func.params;
|
||||
var parameters = [];
|
||||
params.forEach(function(value, key) {
|
||||
if (value) {
|
||||
params[key] = "$" + value[1];
|
||||
parameters[key] = (typeof value[2] !== "undefined" ? value[2] + " " : "") + value[1];
|
||||
parameters[key] += typeof value[3] !== "undefined" ? " = " + value[3] : "";
|
||||
if (executeStatic) {
|
||||
suggestions = Indexer.getStaticFunctionsFromFile(f, suggestions, currentWord, executeStatic);
|
||||
suggestions = Indexer.getStaticPropertiesFromFile(f, suggestions, currentWord, executeStatic);
|
||||
}
|
||||
})
|
||||
newSuggestion.insertText = func.function+"(" + params.join(", ") + ")";
|
||||
newSuggestion.documentation = func.comment;
|
||||
newSuggestion.detail = "(" + parameters.join(", ") + ")";
|
||||
suggestions.push(newSuggestion);
|
||||
}
|
||||
};
|
||||
|
||||
// Checking for class name
|
||||
if (f.indexOf(currentWord) > 0) {
|
||||
if (clas && (clas[2] == currentWord || clas[3] == "\\" + currentWord)) { // New instance
|
||||
var currentClass = f.substr(0, f.length - 4).replace(new RegExp("\/", "g"), "\\");
|
||||
var params = [];
|
||||
if (typeof exports.phpFileFunctions[f]["__construct"] !== "undefined") {
|
||||
params = exports.phpFileFunctions[f]["__construct"].params;
|
||||
}
|
||||
params.forEach(function(value, key) {
|
||||
if (value) params[key] = "$" + value[1];
|
||||
});
|
||||
if (currentClass.startsWith("\\")) currentClass = currentClass.substr(1);
|
||||
var newSuggestion = new vscode.CompletionItem(currentClass, vscode.CompletionItemKind.Class);
|
||||
if (typeof clas[1] == "undefined" && typeof exports.phpFileUses[currentPath] !== "undefined" && typeof exports.phpFileUses[currentPath][currentClass] !== "undefined") {
|
||||
newSuggestion.insertText = currentClass.split("\\")[currentClass.split("\\").length - 1] + "(" + params.join(", ") + ");";
|
||||
} else {
|
||||
newSuggestion.insertText = "\\" + currentClass + "(" + params.join(", ") + ");";
|
||||
}
|
||||
newSuggestion.detail = "Class " + currentClass;
|
||||
suggestions.push(newSuggestion);
|
||||
// New instance
|
||||
if (clas && (clas[2] == currentWord || clas[3] == "\\" + currentWord)) {
|
||||
suggestions = Indexer.getClassNew(f, suggestions, currentPath, clas);
|
||||
} else if (use && (use[1] == currentWord || use[2] == "\\" + currentWord)) { // Use
|
||||
var currentClass = f.substr(0, f.length - 4);
|
||||
currentClass = currentClass.replace(new RegExp("\/", "g"), "\\");
|
||||
if (currentClass.startsWith("\\")) currentClass = currentClass.substr(1);
|
||||
var newSuggestion = new vscode.CompletionItem(currentClass, vscode.CompletionItemKind.Class);
|
||||
newSuggestion.detail = "Class " + currentClass;
|
||||
newSuggestion.insertText = currentClass + ";\n";
|
||||
suggestions.push(newSuggestion);
|
||||
suggestions = Indexer.getClassUse(f, suggestions);
|
||||
} else if (!(execute && execute[1] == currentWord) && !(executeStatic && executeStatic[1] == currentWord)) { // static classes
|
||||
var currentClass = f.substr(0, f.length - 4);
|
||||
currentClass = currentClass.replace(new RegExp("\/", "g"), "\\");
|
||||
if (currentClass.startsWith("\\")) currentClass = currentClass.substr(1);
|
||||
var newSuggestion = new vscode.CompletionItem(currentClass, vscode.CompletionItemKind.Class);
|
||||
newSuggestion.detail = "Class " + currentClass;
|
||||
if (typeof exports.phpFileUses[currentPath] !== "undefined" && typeof exports.phpFileUses[currentPath][currentClass] !== "undefined") {
|
||||
newSuggestion.insertText = currentClass.split("\\")[currentClass.split("\\").length - 1] + "::";
|
||||
} else {
|
||||
newSuggestion.insertText = "\\" + currentClass + "::";
|
||||
}
|
||||
suggestions.push(newSuggestion);
|
||||
suggestions = Indexer.getClassNormal(f, suggestions, currentPath);
|
||||
}
|
||||
}
|
||||
};
|
||||
Indexer.done = {};// Reseting cache
|
||||
return suggestions;
|
||||
}
|
||||
}));
|
||||
|
||||
// Setup our plugin to help with function signatures
|
||||
context.subscriptions.push(vscode.languages.registerSignatureHelpProvider(exports.PHP_MODE, new phpFunctionSuggestions_1.PhpSignatureHelpProvider(vscode.workspace.getConfiguration('php')['docsTool']), '(', ','));
|
||||
// The command has been defined in the package.json file
|
||||
// Now provide the implementation of the command with registerCommand
|
||||
// The commandId parameter must match the command field in package.json
|
||||
var indexDisposable = vscode.commands.registerCommand('pmide.indexPhpFiles', () => {
|
||||
// The code you place here will be executed every time your command is executed
|
||||
indexPhpFiles();
|
||||
// context.subscriptions.push(vscode.languages.registerSignatureHelpProvider(exports.PHP_MODE, new phpFuncSuggestion.PhpSignatureHelpProvider(vscode.workspace.getConfiguration('php')['docsTool']), '(', ','));
|
||||
|
||||
// Commands registered by plugin
|
||||
/**
|
||||
* Reindex php files command
|
||||
*/
|
||||
var indexDisposable = vscode.commands.registerCommand('pmide.indexPhpFiles', function () {
|
||||
Indexer.indexPhpFiles();
|
||||
});
|
||||
var printDisposable = vscode.commands.registerCommand('pmide.printPhpFiles', () => {
|
||||
console.log(Object.keys(exports.phpFileFunctions).length);
|
||||
console.log(exports.phpFileUses);
|
||||
/**
|
||||
* Prints everything about PHP files.
|
||||
*/
|
||||
var printDisposable = vscode.commands.registerCommand('pmide.printPhpFiles', function () {
|
||||
console.log(Object.keys(Indexer.phpFileFunctions).length);
|
||||
console.log(Indexer.phpFileUses);
|
||||
});
|
||||
context.subscriptions.push(indexDisposable);
|
||||
context.subscriptions.push(printDisposable);
|
||||
}
|
||||
exports.activate = activate;
|
||||
// this method is called when your extension is deactivated
|
||||
function deactivate() {}
|
||||
exports.deactivate = deactivate;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Function to handle the indexing of PHP files
|
||||
function indexPhpFiles() {
|
||||
// Clear out the cached data
|
||||
exports.phpFileUses = {};
|
||||
exports.phpFileFunctions = {};
|
||||
var indexResult = vscode.workspace.findFiles("**/*.php", "", 1000).then(function(list) {
|
||||
if (list) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
list.forEach((phpFile) => {
|
||||
var path = phpFile.fsPath;
|
||||
var fileName = path.replace(vscode.workspace.rootPath, "").replace("src/", "").slice(1);
|
||||
if (!(fileName in exports.phpFileFunctions)) {
|
||||
exports.phpFileFunctions[fileName] = [];
|
||||
}
|
||||
if (!(fileName in exports.phpFileStaticFunctions)) {
|
||||
exports.phpFileStaticFunctions[fileName] = [];
|
||||
}
|
||||
// Read through the PHP file for includes/requires and function definitions
|
||||
var read = require('fs').readFileSync(path, 'utf8');
|
||||
var lineReader = read.split("\n");
|
||||
try {
|
||||
lineReader.forEach(function(line) {
|
||||
// Thats a bit messy for this one so: $2 = optionnal description comment, $4 = functions specifications (static, public, abstract, final,...), $7 = function name, $8 = arguments, $14 = return of function
|
||||
var functionRegex = /(\/\*\*?((\s|.|\n)+)\*\/)?\s*(((abstract|public|protected|private|final|static)\s*)*)function\s+(\w+)\(((\s*\w+)?\s*\$\w+\s*(,(\s*\w+)?\s*\$\w+\s*)*\s*)?\)\s*(:\s*(\w+)\s*)?({|;)/mig
|
||||
var match = functionRegex.exec(line);
|
||||
if (match) {
|
||||
// Matching function modifiers
|
||||
var functionModifiersLitteral = match[4].replace(/\s/, " ").split(" ");
|
||||
var functionModifiers = {
|
||||
"abstract": false,
|
||||
"public": false,
|
||||
"protected": false,
|
||||
"private": false,
|
||||
"final": false,
|
||||
"static": false
|
||||
};
|
||||
functionModifiersLitteral.forEach(function(modifier) {
|
||||
functionModifiers[modifier] = true;
|
||||
})
|
||||
var comment = typeof match[3] !== "undefined" ? match[3].replace(/[*]/gim, "") : "From " + fileName;
|
||||
// Parameters
|
||||
var params = [];
|
||||
if (typeof match[8] !== "undefined") match[8].replace(/\s*,\s*/, ",").split(",").forEach(function(m) {
|
||||
var paramers = /((\w+)\s+)?(\$\w+)(\s*\=[^,)]+)?/.exec(m)
|
||||
if (typeof paramers !== "undefined" && paramers !== null) params.push([paramers[0], paramers[3], paramers[2], paramers[5]]); // Later use of knowning which equals to what.
|
||||
});
|
||||
// Exporting function
|
||||
if (!functionModifiers.static) {
|
||||
exports.phpFileFunctions[fileName][match[7]] = {
|
||||
function: match[7],
|
||||
params: params,
|
||||
functionModifiers: functionModifiers,
|
||||
comment: comment
|
||||
};
|
||||
} else {
|
||||
exports.phpFileStaticFunctions[fileName][match[7]] = {
|
||||
function: match[7],
|
||||
params: params,
|
||||
functionModifiers: functionModifiers,
|
||||
comment: comment
|
||||
};
|
||||
}
|
||||
}
|
||||
// Check for uses
|
||||
var includeRegex = /use\s+((\w+\\)*)(\w+)(\s+as\s+(\w+)\s*)?;/;
|
||||
match = includeRegex.exec(line);
|
||||
if (match) {
|
||||
if (!(fileName in exports.phpFileUses)) {
|
||||
exports.phpFileUses[fileName] = [];
|
||||
}
|
||||
// Check if there is a match of "as" to set it.
|
||||
var classType = '';
|
||||
if (typeof match[4] !== "undefined") {
|
||||
classType = match[5];
|
||||
} else {
|
||||
classType = match[3];
|
||||
}
|
||||
exports.phpFileUses[fileName][match[1] + match[3]] = classType;
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
})
|
||||
} else {
|
||||
console.log("No workspace defined");
|
||||
}
|
||||
}, function(reason) {
|
||||
console.log("Error: " + reason);
|
||||
});
|
||||
|
||||
// Libraries
|
||||
if (require('fs').existsSync(vscode.workspace.getConfiguration('php')['pocketMinePath'])) {
|
||||
var libraryResult = require("child_process").execSync("find " + vscode.workspace.getConfiguration('php')['pocketMinePath'] + " -maxdepth 10 -type f | fgrep .php").toString().split("\n");
|
||||
if (libraryResult) {
|
||||
libraryResult.forEach(function(path) {
|
||||
if (require('fs').existsSync(path)) {
|
||||
var fileName = path.replace(vscode.workspace.getConfiguration('php')['pocketMinePath'], "").slice(1);
|
||||
if (!(fileName in exports.phpFileFunctions)) {
|
||||
exports.phpFileFunctions[fileName] = {};
|
||||
}
|
||||
if (!(fileName in exports.phpFileStaticFunctions)) {
|
||||
exports.phpFileStaticFunctions[fileName] = [];
|
||||
}
|
||||
// Read through the PHP file for includes/requires and function definitions
|
||||
var read = require('fs').readFileSync(path, 'utf8');
|
||||
try {
|
||||
var lineReader = read.split("\n");
|
||||
lineReader.forEach(function(line) {
|
||||
// Thats a bit messy for this one so: $2 = optionnal description comment, $4 = functions specifications (static, public, abstract, final,...), $7 = function name, $8 = arguments, $14 = return of function
|
||||
var functionRegex = /(\/\*\*?((\s|.|\n)+)\*\/)?\s*(((abstract|public|protected|private|final|static)\s*)*)function\s+(\w+)\(((\s*\w+)?\s*\$\w+\s*(,(\s*\w+)?\s*\$\w+\s*)*\s*)?\)\s*(:\s*(\w+)\s*)?({|;)/mig
|
||||
var match = functionRegex.exec(line);
|
||||
if (match) {
|
||||
// Matching function modifiers
|
||||
var functionModifiersLitteral = match[4].replace(/\s/, " ").split(" ");
|
||||
var functionModifiers = {
|
||||
"abstract": false,
|
||||
"public": false,
|
||||
"protected": false,
|
||||
"private": false,
|
||||
"final": false,
|
||||
"static": false
|
||||
};
|
||||
functionModifiersLitteral.forEach(function(modifier) {
|
||||
functionModifiers[modifier] = true;
|
||||
})
|
||||
var comment = typeof match[3] !== "undefined" ? match[3].replace(/[*]/gim, "") : "From " + fileName;
|
||||
// Parameters
|
||||
var params = [];
|
||||
if (typeof match[8] !== "undefined") match[8].replace(/\s*,\s*/, ",").split(",").forEach(function(m) {
|
||||
var paramers = /((\w+)\s+)?(\$\w+)(\s*\=[^,)]+)?/.exec(m)
|
||||
if (typeof paramers !== "undefined" && paramers !== null) params.push([paramers[0], paramers[3], paramers[2], paramers[5]]); // Later use of knowning which equals to what.
|
||||
});
|
||||
// Exporting function
|
||||
if (!functionModifiers.static) {
|
||||
exports.phpFileFunctions[fileName][match[7]] = {
|
||||
function: match[7],
|
||||
params: params,
|
||||
functionModifiers: functionModifiers,
|
||||
comment: comment
|
||||
};
|
||||
} else {
|
||||
exports.phpFileStaticFunctions[fileName][match[7]] = {
|
||||
function: match[7],
|
||||
params: params,
|
||||
functionModifiers: functionModifiers,
|
||||
comment: comment
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err); // Fails silently later
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log("No workspace defined");
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=extension.js.map
|
||||
exports.deactivate = function () { };
|
417
out/src/phpCompletionItem.js
Normal file
417
out/src/phpCompletionItem.js
Normal file
|
@ -0,0 +1,417 @@
|
|||
const vscode = require("vscode");
|
||||
const ext = require("./extension");
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const PROPERTY_NORMAL = 0;
|
||||
const PROPERTY_STATIC = 1;
|
||||
const PROPERTY_CONST = 2;
|
||||
|
||||
exports.Indexer = {
|
||||
|
||||
/** @var {Object} */
|
||||
phpFileUses: {},
|
||||
/** @var {Object} */
|
||||
phpFileFunctions: {},
|
||||
/** @var {Object} */
|
||||
phpFileStaticFunctions: {},
|
||||
/** @var {Object} */
|
||||
phpFileProperties: {},
|
||||
/** @var {Object} */
|
||||
done: {},
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets all functions in a completion item form
|
||||
*
|
||||
* @param {String} file
|
||||
* @param {vscode.CompletionItem[]} suggestions
|
||||
* @param {String} currentWord
|
||||
* @param {String} execute
|
||||
* @return {vscode.CompletionItem[]}
|
||||
*/
|
||||
getFunctionsFromFile(file, suggestions, currentWord, execute) {
|
||||
for (var func in exports.Indexer.phpFileFunctions[file]) {
|
||||
func = exports.Indexer.phpFileFunctions[file][func];
|
||||
if (func.function.startsWith(currentWord) && execute[1] == currentWord && (func.functionModifiers["public"] || file == ext.currentPath)) {
|
||||
if(typeof exports.Indexer.done[func.function] == "undefined" /*|| exports.Indexer.done[func.function].params !== func.params */) { // Preventing from spamming same method over and over
|
||||
var newSuggestion = new vscode.CompletionItem(func.function, vscode.CompletionItemKind.Function);
|
||||
params = func.params;
|
||||
var parameters = [];
|
||||
params.forEach(function (value, key) {
|
||||
if (value) {
|
||||
params[key] = "$" + value[1];
|
||||
parameters[key] = (typeof value[2] !== "undefined" ? value[2] + " " : "") + value[1];
|
||||
parameters[key] += typeof value[3] !== "undefined" ? " = " + value[3] : "";
|
||||
}
|
||||
});
|
||||
newSuggestion.insertText = func.function + "(" + params.join(", ") + ")";
|
||||
newSuggestion.documentation = func.comment;
|
||||
newSuggestion.detail = "(function) (" + parameters.join(", ") + ")";
|
||||
suggestions.push(newSuggestion);
|
||||
exports.Indexer.done[func.function] = func;
|
||||
}
|
||||
}
|
||||
};
|
||||
return suggestions;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns all indexed static functions of file
|
||||
*
|
||||
* @param {string} file
|
||||
* @param {vscode.CompletionItem[]} suggestions
|
||||
* @param {String} currentWord
|
||||
* @param {String} executeStatic
|
||||
* @return {vscode.CompletionItem[]}
|
||||
*/
|
||||
getStaticFunctionsFromFile(file, suggestions, currentWord, executeStatic) {
|
||||
|
||||
for (var func in exports.Indexer.phpFileStaticFunctions[file]) {
|
||||
func = exports.Indexer.phpFileStaticFunctions[file][func];
|
||||
if (func.function.startsWith(currentWord) && executeStatic[1] == currentWord) {
|
||||
if(typeof exports.Indexer.done[func.function] == "undefined" /*|| exports.Indexer.done[func.function].params !== func.params*/) { // Preventing from spamming same method over and over
|
||||
var newSuggestion = new vscode.CompletionItem(func.function, vscode.CompletionItemKind.Function);
|
||||
var params = func.params;
|
||||
var parameters = [];
|
||||
params.forEach(function (value, key) {
|
||||
if (value) {
|
||||
params[key] = "$" + value[1];
|
||||
parameters[key] = (typeof value[2] !== "undefined" ? value[2] + " " : "") + value[1];
|
||||
parameters[key] += typeof value[3] !== "undefined" ? " = " + value[3] : "";
|
||||
}
|
||||
})
|
||||
newSuggestion.insertText = func.function + "(" + params.join(", ") + ")";
|
||||
newSuggestion.documentation = func.comment;
|
||||
newSuggestion.detail = "(function) (" + parameters.join(", ") + ")";
|
||||
suggestions.push(newSuggestion);
|
||||
exports.Indexer.done[func.function] = func;
|
||||
}
|
||||
}
|
||||
};
|
||||
return suggestions;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Gets all properties in a completion item form
|
||||
*
|
||||
* @param {String} file
|
||||
* @param {vscode.CompletionItem[]} suggestions
|
||||
* @param {String} currentWord
|
||||
* @param {String} execute
|
||||
* @return {vscode.CompletionItem[]}
|
||||
*/
|
||||
getPropertiesFromFile(file, suggestions, currentWord, execute) {
|
||||
|
||||
for (var func in exports.Indexer.phpFileProperties[file]) {
|
||||
func = exports.Indexer.phpFileProperties[file][func];
|
||||
if (func[0].startsWith(currentWord) && execute[1] == currentWord && func[1] == PROPERTY_NORMAL) {
|
||||
if(typeof exports.Indexer.done[func[0]] == "undefined") { // Preventing from spamming same method over and over
|
||||
var newSuggestion = new vscode.CompletionItem(func[0], vscode.CompletionItemKind.Property);
|
||||
newSuggestion.insertText = func[0];
|
||||
newSuggestion.detail = "(property) " + file.substr(0, file.length - 4).replace(new RegExp("\/", "g"), "\\");
|
||||
suggestions.push(newSuggestion);
|
||||
exports.Indexer.done[func[0]] = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
return suggestions;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns all indexed static properties of file
|
||||
*
|
||||
* @param {string} file
|
||||
* @param {vscode.CompletionItem[]} suggestions
|
||||
* @param {String} currentWord
|
||||
* @param {String} executeStatic
|
||||
* @return {vscode.CompletionItem[]}
|
||||
*/
|
||||
getStaticPropertiesFromFile(file, suggestions, currentWord, executeStatic) {
|
||||
|
||||
for (var func in exports.Indexer.phpFileProperties[file]) {
|
||||
func = exports.Indexer.phpFileProperties[file][func];
|
||||
if (func[0].startsWith(currentWord) && executeStatic[1] == currentWord) {
|
||||
if(typeof exports.Indexer.done[func[0]] == "undefined") { // Preventing from spamming same method over and over
|
||||
if(func[1] == PROPERTY_STATIC){
|
||||
var newSuggestion = new vscode.CompletionItem("$" + func[0], vscode.CompletionItemKind.Property);
|
||||
newSuggestion.insertText = "$" + func[0];
|
||||
newSuggestion.detail = "(property) " + file.substr(0, file.length - 4).replace(new RegExp("\/", "g"), "\\");
|
||||
exports.Indexer.done[func[0]] = true;
|
||||
} else if(func[1] == PROPERTY_CONST){
|
||||
var newSuggestion = new vscode.CompletionItem(func[0], vscode.CompletionItemKind.Constant);
|
||||
newSuggestion.insertText = func[0];
|
||||
newSuggestion.detail = "(constant) " + file.substr(0, file.length - 4).replace(new RegExp("\/", "g"), "\\");
|
||||
exports.Indexer.done[func[0]] = true;
|
||||
}
|
||||
if(newSuggestion) suggestions.push(newSuggestion);
|
||||
}
|
||||
}
|
||||
};
|
||||
return suggestions;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets completion class for a file in format "use ns\class;"
|
||||
*
|
||||
* @param {string} file
|
||||
* @param {vscode.CompletionItem[]} suggestions
|
||||
* @return {vscode.CompletionItem[]}
|
||||
*/
|
||||
getClassUse(file, suggestions) {
|
||||
var currentClass = file.substr(0, file.length - 4);
|
||||
currentClass = currentClass.replace(new RegExp("\/", "g"), "\\");
|
||||
if (currentClass.startsWith("\\")) currentClass = currentClass.substr(1);
|
||||
var newSuggestion = new vscode.CompletionItem(currentClass, vscode.CompletionItemKind.Class);
|
||||
newSuggestion.detail = "(class) " + currentClass;
|
||||
newSuggestion.insertText = currentClass + ";\n";
|
||||
suggestions.push(newSuggestion);
|
||||
return suggestions;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a class completion (new instance) item from it's class name
|
||||
*
|
||||
* @param {string} file
|
||||
* @param {vscode.CompletionItem[]} suggestions
|
||||
* @param {string} currentPath
|
||||
* @param {array} clas
|
||||
* @return {vscode.CompletionItem[]}
|
||||
*
|
||||
*/
|
||||
getClassNew(file, suggestions, currentPath, clas) {
|
||||
var currentClass = file.substr(0, file.length - 4).replace(new RegExp("\/", "g"), "\\");
|
||||
var params = [];
|
||||
if (typeof exports.Indexer.phpFileFunctions[file]["__construct"] !== "undefined") {
|
||||
params = exports.Indexer.phpFileFunctions[file]["__construct"].params;
|
||||
}
|
||||
params.forEach(function (value, key) {
|
||||
if (value) params[key] = "$" + value[2];
|
||||
});
|
||||
if (currentClass.startsWith("\\")) currentClass = currentClass.substr(1);
|
||||
var newSuggestion = new vscode.CompletionItem(currentClass, vscode.CompletionItemKind.Class);
|
||||
if (typeof clas[1] == "undefined" &&
|
||||
typeof exports.Indexer.phpFileUses[currentPath] !== "undefined" &&
|
||||
typeof exports.Indexer.phpFileUses[currentPath][currentClass] !== "undefined") {
|
||||
newSuggestion.insertText = currentClass.split("\\")[currentClass.split("\\").length - 1] + "(" + params.join(", ") + ");";
|
||||
} else {
|
||||
newSuggestion.insertText = "\\" + currentClass + "(" + params.join(", ") + ");";
|
||||
}
|
||||
newSuggestion.detail = "(class) " + currentClass;
|
||||
suggestions.push(newSuggestion);
|
||||
return suggestions;
|
||||
},
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets a class completion (static class) item from it's class name
|
||||
*
|
||||
* @param {string} file
|
||||
* @param {vscode.CompletionItem[]} suggestions
|
||||
* @param {string} currentPath
|
||||
* @return {vscode.CompletionItem[]}
|
||||
*
|
||||
*/
|
||||
getClassNormal(file, suggestions, currentPath) {
|
||||
var currentClass = file.substr(0, file.length - 4).replace(new RegExp("\/", "g"), "\\");
|
||||
var currentPath2 = currentPath.substr(1);
|
||||
currentClass = currentClass.replace(new RegExp("\/", "g"), "\\");
|
||||
if (currentClass.startsWith("\\")) currentClass = currentClass.substr(1);
|
||||
var newSuggestion = new vscode.CompletionItem(currentClass, vscode.CompletionItemKind.Class);
|
||||
newSuggestion.detail = "(class) " + currentClass;
|
||||
if (typeof exports.Indexer.phpFileUses[currentPath] !== "undefined" &&
|
||||
typeof exports.Indexer.phpFileUses[currentPath][currentClass] !== "undefined") {
|
||||
newSuggestion.insertText = currentClass.split("\\")[currentClass.split("\\").length - 1];
|
||||
} else {
|
||||
newSuggestion.insertText = "\\" + currentClass;
|
||||
}
|
||||
suggestions.push(newSuggestion);
|
||||
return suggestions;
|
||||
},
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Funcion that handles PHP file registering.
|
||||
*
|
||||
* @return {Void}
|
||||
*/
|
||||
indexPhpFiles() {
|
||||
// Clear out the cached data
|
||||
exports.Indexer.phpFileUses = {};
|
||||
exports.Indexer.phpFileFunctions = {};
|
||||
exports.Indexer.phpFileStaticFunctions = {};
|
||||
exports.Indexer.phpFileProperties = {};
|
||||
var libraryResult = [];
|
||||
if (fs.existsSync(vscode.workspace.getConfiguration('php')['pocketMinePath'])) {
|
||||
libraryResult = exports.Indexer.findFilesInDir(vscode.workspace.getConfiguration('php')['pocketMinePath'], ".php");
|
||||
}
|
||||
if (vscode.workspace.rootPath !== undefined) {
|
||||
var c = exports.Indexer.findFilesInDir(vscode.workspace.rootPath, ".php");
|
||||
libraryResult = libraryResult.concat(c);
|
||||
}
|
||||
libraryResult.forEach(function (path) {
|
||||
if (fs.existsSync(path)) {
|
||||
var fileName = path.replace(vscode.workspace.rootPath, "").replace(vscode.workspace.getConfiguration('php')['pocketMinePath'], "").replace("src", "").slice(1);
|
||||
if (typeof exports.Indexer.phpFileFunctions[fileName] == "undefined") {
|
||||
exports.Indexer.phpFileFunctions[fileName] = {};
|
||||
}
|
||||
if (typeof exports.Indexer.phpFileStaticFunctions[fileName] == "undefined") {
|
||||
exports.Indexer.phpFileStaticFunctions[fileName] = {};
|
||||
}
|
||||
if (typeof exports.Indexer.phpFileUses[fileName] == "undefined") {
|
||||
exports.Indexer.phpFileUses[fileName] = {};
|
||||
}
|
||||
if (typeof exports.Indexer.phpFileProperties[fileName] == "undefined") {
|
||||
exports.Indexer.phpFileProperties[fileName] = {};
|
||||
}
|
||||
// Read through the PHP file for includes/requires and function definitions
|
||||
var read = fs.readFileSync(path, 'utf8');
|
||||
// Parsing class regexr
|
||||
var fileBaseName = (path.indexOf("/") ? path.split("/") : (path.indexOf("\\") ? path.split("\\") : [path]));
|
||||
fileBaseName = fileBaseName[fileBaseName.length - 1].replace(/\.php$/, "");
|
||||
if(!read.match(new RegExp("(class|interface)\\s+" + fileBaseName, "mi"))) return;
|
||||
// var classRegexr = new RegExp("(class|interface)\\s+" + fileBaseName + "(\\s+extends ([\w_]+))?(\\s+implements ([\w_\\\\]+))?", "mi");
|
||||
try {
|
||||
var lineReader = read.split("\n");
|
||||
lineReader.forEach(function (line) {
|
||||
// Parsing functions:
|
||||
exports.Indexer.parseFunction(line, fileName);
|
||||
// Parsing properties:
|
||||
exports.Indexer.parseProperty(line, fileName);
|
||||
// Check for uses
|
||||
exports.Indexer.parseUse(line, fileName);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Find all files recursively in specific folder with specific extension, e.g:
|
||||
* findFilesInDir('./project/src', '.html') ==> ['./project/src/a.html','./project/src/build/index.html']
|
||||
* @param {String} startPath Path relative to exports.Indexer file or other file which requires exports.Indexer files
|
||||
* @param {String} filter Extension name, e.g: '.html'
|
||||
* @return {Array} Result files with path string in an array
|
||||
*/
|
||||
findFilesInDir(startPath, filter) {
|
||||
|
||||
var results = [];
|
||||
|
||||
if (!fs.existsSync(startPath)) {
|
||||
console.log("no dir ", startPath);
|
||||
return;
|
||||
}
|
||||
|
||||
var files = fs.readdirSync(startPath);
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var filename = path.join(startPath, files[i]);
|
||||
var stat = fs.lstatSync(filename);
|
||||
if (stat.isDirectory()) {
|
||||
results = results.concat(exports.Indexer.findFilesInDir(filename, filter)); //recurse
|
||||
}
|
||||
else if (filename.indexOf(filter) >= 0) {
|
||||
results.push(filename);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Parses and exports.Indexer functions from a line.
|
||||
* @param {String} line
|
||||
* @param {String} fileName
|
||||
*/
|
||||
parseFunction(line, fileName) {
|
||||
// Thats a bit messy for exports.Indexer one so: $2 = optionnal description comment, $4 = functions specifications (static, public, abstract, final,...), $7 = function name, $8 = arguments, $14 = return of function
|
||||
var functionRegex = /(\/\*\*?((\s|.|\n)+)\*\/)?\s*(((abstract|public|protected|private|final|static)\s*)*)function\s+(\w+)\(((\s*\w+)?\s*\$\w+\s*(,(\s*\w+)?\s*\$\w+\s*)*\s*)?\)\s*(:\s*(\w+)\s*)?({|;)/mig
|
||||
var match = functionRegex.exec(line);
|
||||
if (match) {
|
||||
// Matching function modifiers
|
||||
var functionModifiersLitteral = match[4].replace(/\s/, " ").split(" ");
|
||||
var functionModifiers = {
|
||||
"abstract": false,
|
||||
"public": false,
|
||||
"protected": false,
|
||||
"private": false,
|
||||
"final": false,
|
||||
"static": false
|
||||
};
|
||||
functionModifiersLitteral.forEach(function (modifier) {
|
||||
functionModifiers[modifier] = true;
|
||||
})
|
||||
var comment = typeof match[3] !== "undefined" ? match[3].replace(/[*]/gim, "") : "From " + fileName;
|
||||
// Parameters
|
||||
var params = [];
|
||||
if (typeof match[8] !== "undefined") match[8].replace(/\s*,\s*/, ",").split(",").forEach(function (m) {
|
||||
var paramers = /((\w+)\s+)?(\$\w+)(\s*\=[^,)]+)?/.exec(m)
|
||||
if (typeof paramers !== "undefined" && paramers !== null) params.push([paramers[0], paramers[3], paramers[2], paramers[5]]); // Later use of knowning which equals to what.
|
||||
});
|
||||
// Exporting function
|
||||
if (!functionModifiers.static) {
|
||||
exports.Indexer.phpFileFunctions[fileName][match[7]] = {
|
||||
function: match[7],
|
||||
params: params,
|
||||
functionModifiers: functionModifiers,
|
||||
comment: comment
|
||||
};
|
||||
} else {
|
||||
exports.Indexer.phpFileStaticFunctions[fileName][match[7]] = {
|
||||
function: match[7],
|
||||
params: params,
|
||||
functionModifiers: functionModifiers,
|
||||
comment: comment
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Parses and exports.Indexer uses from a line.
|
||||
* @param {String} line
|
||||
* @param {String} fileName
|
||||
*/
|
||||
parseUse(line, fileName) {
|
||||
var includeRegex = /use\s+((\w+\\)*)(\w+)(\s+as\s+(\w+)\s*)?;/;
|
||||
match = includeRegex.exec(line);
|
||||
if (match) {
|
||||
// Check if there is a match of "as" to set it.
|
||||
var classType = '';
|
||||
if (typeof match[4] !== "undefined") {
|
||||
classType = match[5];
|
||||
} else {
|
||||
classType = match[3];
|
||||
}
|
||||
exports.Indexer.phpFileUses[fileName][match[1] + match[3]] = classType;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Parses and exports Indexer properties (also static one) from a line.
|
||||
* @param {String} line
|
||||
* @param {String} fileName
|
||||
*/
|
||||
parseProperty(line, fileName) {
|
||||
var propertiesRegexr = /(protected|private|public|static|const)\s+(\$)?([\w_]+)\s*(;|=)/;
|
||||
match = propertiesRegexr.exec(line);
|
||||
if (match) {
|
||||
if(match[1] == "static" && match[2] == "$") {
|
||||
exports.Indexer.phpFileProperties[fileName][match[3]] = [match[3], PROPERTY_STATIC];
|
||||
} else if(match[1] == "const") {
|
||||
exports.Indexer.phpFileProperties[fileName][match[3]] = [match[3], PROPERTY_CONST];
|
||||
} else {
|
||||
exports.Indexer.phpFileProperties[fileName][match[3]] = [match[3], PROPERTY_NORMAL];
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
|
@ -150,4 +150,3 @@ class GoDefinitionProvider {
|
|||
}
|
||||
}
|
||||
exports.GoDefinitionProvider = GoDefinitionProvider;
|
||||
//# sourceMappingURL=phpDeclaration.js.map
|
|
@ -1,91 +0,0 @@
|
|||
'use strict';
|
||||
const vscode = require('vscode');
|
||||
const vscode_1 = require('vscode');
|
||||
// import { definitionLocation } from './phpDeclaration';
|
||||
// import { parameters } from './util';
|
||||
const extension_1 = require('./extension');
|
||||
class PhpSignatureHelpProvider {
|
||||
constructor(toolForDocs) {
|
||||
this.toolForDocs = 'phpdoc';
|
||||
this.toolForDocs = toolForDocs;
|
||||
}
|
||||
provideSignatureHelp(document, position, token) {
|
||||
let theCall = this.walkBackwardsToBeginningOfCall(document, position);
|
||||
if (theCall == null) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
// Find the name of the function that's being called
|
||||
let functionNameRange = this.previousTokenPosition(document, theCall.openParen);
|
||||
let functionName = document.getText(functionNameRange);
|
||||
let result = new vscode_1.SignatureHelp();
|
||||
let declarationText, sig;
|
||||
let si;
|
||||
let currentFileName = document.uri.fsPath.replace(vscode.workspace.rootPath, '').slice(1).replace('\\', '/');
|
||||
if (currentFileName in extension_1.phpFileIncludes) {
|
||||
extension_1.phpFileIncludes[currentFileName].forEach(function (file) {
|
||||
if (file in extension_1.phpFileFunctions) {
|
||||
// Look through all the functions declared in the included/required file
|
||||
extension_1.phpFileFunctions[file].forEach(function (func) {
|
||||
// If the included/required function starts with the letter of our current word then add it to the set of suggestions
|
||||
if (func.function == functionName) {
|
||||
si = new vscode_1.SignatureInformation(func.function);
|
||||
si.parameters = [];
|
||||
func.params.forEach(function (param) {
|
||||
si.parameters.push(param);
|
||||
});
|
||||
// Set the documentation of the SignatureInformation to be the full function signature
|
||||
si.documentation = file + " : " + func.function + "(" + si.parameters.join(',') + ')';
|
||||
result.signatures = [si];
|
||||
result.activeSignature = 0;
|
||||
result.activeParameter = Math.min(theCall.commas.length, si.parameters.length - 1);
|
||||
result.signatures[0].label = functionName + ": " + result.signatures[0].parameters[result.activeParameter];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// console.log("Result: ", result);
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
else {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
}
|
||||
previousTokenPosition(document, position) {
|
||||
while (position.character > 0) {
|
||||
let word = document.getWordRangeAtPosition(position);
|
||||
if (word) {
|
||||
return word;
|
||||
}
|
||||
position = position.translate(0, -1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
walkBackwardsToBeginningOfCall(document, position) {
|
||||
let currentLine = document.lineAt(position.line).text.substring(0, position.character);
|
||||
let parenBalance = 0;
|
||||
let commas = [];
|
||||
for (let char = position.character; char >= 0; char--) {
|
||||
switch (currentLine[char]) {
|
||||
case '(':
|
||||
parenBalance--;
|
||||
if (parenBalance < 0) {
|
||||
return {
|
||||
openParen: new vscode_1.Position(position.line, char),
|
||||
commas: commas
|
||||
};
|
||||
}
|
||||
break;
|
||||
case ')':
|
||||
parenBalance++;
|
||||
break;
|
||||
case ',':
|
||||
if (parenBalance === 0) {
|
||||
commas.push(new vscode_1.Position(position.line, char));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
exports.PhpSignatureHelpProvider = PhpSignatureHelpProvider;
|
||||
//# sourceMappingURL=phpFunctionSuggestions.js.map
|
|
@ -2,7 +2,7 @@
|
|||
"name": "pocketmine-ide",
|
||||
"displayName": "PocketMine IDE",
|
||||
"description": "Implementation of external PocketMine/PHP libs for Visual Studio Code",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.4",
|
||||
"publisher": "Ad5001",
|
||||
"homepage": "https://github.com/Ad5001/PocketMine-IDE",
|
||||
"keywords": [
|
||||
|
@ -55,7 +55,6 @@
|
|||
"postinstall": "node ./node_modules/vscode/bin/install"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^2.0.3",
|
||||
"vscode": "^1.0.0",
|
||||
"mocha": "^2.3.3",
|
||||
"@types/node": "^6.0.40",
|
||||
|
|
Loading…
Reference in a new issue