mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
Move bower/package.json dependency completions to javascript extension
This commit is contained in:
parent
4fe233c752
commit
235cbcdf9d
29
extensions/javascript/.vscode/launch.json
vendored
Normal file
29
extensions/javascript/.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceRoot}"
|
||||
],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outDir": "${workspaceRoot}/out",
|
||||
"preLaunchTask": "npm"
|
||||
},
|
||||
{
|
||||
"name": "Launch Tests",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ],
|
||||
"stopOnEntry": false,
|
||||
"sourceMaps": true,
|
||||
"outDir": "${workspaceRoot}/out/test",
|
||||
"preLaunchTask": "npm"
|
||||
}
|
||||
]
|
||||
}
|
30
extensions/javascript/.vscode/tasks.json
vendored
Normal file
30
extensions/javascript/.vscode/tasks.json
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Available variables which can be used inside of strings.
|
||||
// ${workspaceRoot}: the root folder of the team
|
||||
// ${file}: the current opened file
|
||||
// ${fileBasename}: the current opened file's basename
|
||||
// ${fileDirname}: the current opened file's dirname
|
||||
// ${fileExtname}: the current opened file's extension
|
||||
// ${cwd}: the current working directory of the spawned process
|
||||
|
||||
// A task runner that calls a custom npm script that compiles the extension.
|
||||
{
|
||||
"version": "0.1.0",
|
||||
|
||||
// we want to run npm
|
||||
"command": "npm",
|
||||
|
||||
// the command is a shell script
|
||||
"isShellCommand": true,
|
||||
|
||||
// show the output window only if unrecognized errors occur.
|
||||
"showOutput": "silent",
|
||||
|
||||
// we run the custom script "compile" as defined in package.json
|
||||
"args": ["run", "compile"],
|
||||
|
||||
// The tsc compiler is started in watching mode
|
||||
"isWatching": true,
|
||||
|
||||
// use the standard tsc in watch mode problem matcher to find compile problems in the output.
|
||||
"problemMatcher": "$tsc-watch"
|
||||
}
|
|
@ -2,8 +2,19 @@
|
|||
"name": "javascript",
|
||||
"version": "0.1.0",
|
||||
"publisher": "vscode",
|
||||
"engines": {
|
||||
"vscode": "*"
|
||||
"engines": { "vscode": "0.10.x" },
|
||||
"activationEvents": [
|
||||
"onLanguage:javascript", "onLanguage:json"
|
||||
],
|
||||
"main": "./out/javascriptMain",
|
||||
"dependencies": {
|
||||
"vscode-nls": "^1.0.4",
|
||||
"request-light": "^0.0.3",
|
||||
"jsonc-parser": "^0.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:javascript",
|
||||
"watch": "gulp watch-extension:javascript"
|
||||
},
|
||||
"contributes": {
|
||||
"languages": [
|
||||
|
|
177
extensions/javascript/src/features/bowerJSONContribution.ts
Normal file
177
extensions/javascript/src/features/bowerJSONContribution.ts
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {MarkedString, CompletionItemKind, CompletionItem, DocumentSelector} from 'vscode';
|
||||
import {IJSONContribution, ISuggestionsCollector} from './jsonContributions';
|
||||
import {XHRRequest} from 'request-light';
|
||||
import {Location} from 'jsonc-parser';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class BowerJSONContribution implements IJSONContribution {
|
||||
|
||||
private topRanked = ['twitter','bootstrap','angular-1.1.6','angular-latest','angulerjs','d3','myjquery','jq','abcdef1234567890','jQuery','jquery-1.11.1','jquery',
|
||||
'sushi-vanilla-x-data','font-awsome','Font-Awesome','font-awesome','fontawesome','html5-boilerplate','impress.js','homebrew',
|
||||
'backbone','moment1','momentjs','moment','linux','animate.css','animate-css','reveal.js','jquery-file-upload','blueimp-file-upload','threejs','express','chosen',
|
||||
'normalize-css','normalize.css','semantic','semantic-ui','Semantic-UI','modernizr','underscore','underscore1',
|
||||
'material-design-icons','ionic','chartjs','Chart.js','nnnick-chartjs','select2-ng','select2-dist','phantom','skrollr','scrollr','less.js','leancss','parser-lib',
|
||||
'hui','bootstrap-languages','async','gulp','jquery-pjax','coffeescript','hammer.js','ace','leaflet','jquery-mobile','sweetalert','typeahead.js','soup','typehead.js',
|
||||
'sails','codeigniter2'];
|
||||
|
||||
public constructor(private xhr: XHRRequest) {
|
||||
}
|
||||
|
||||
public getDocumentSelector(): DocumentSelector {
|
||||
return [{ language: 'json', pattern: '**/bower.json' }, { language: 'json', pattern: '**/.bower.json' }];
|
||||
}
|
||||
|
||||
public collectDefaultSuggestions(resource: string, collector: ISuggestionsCollector): Thenable<any> {
|
||||
let defaultValue = {
|
||||
'name': '{{name}}',
|
||||
'description': '{{description}}',
|
||||
'authors': [ '{{author}}' ],
|
||||
'version': '{{1.0.0}}',
|
||||
'main': '{{pathToMain}}',
|
||||
'dependencies': {}
|
||||
};
|
||||
let proposal = new CompletionItem(localize('json.bower.default', 'Default bower.json'));
|
||||
proposal.kind = CompletionItemKind.Class;
|
||||
proposal.insertText = JSON.stringify(defaultValue, null, '\t');
|
||||
collector.add(proposal);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
public collectPropertySuggestions(resource: string, location: Location, currentWord: string, addValue: boolean, isLast:boolean, collector: ISuggestionsCollector) : Thenable<any> {
|
||||
if ((location.matches(['dependencies']) || location.matches(['devDependencies']))) {
|
||||
if (currentWord.length > 0) {
|
||||
let queryUrl = 'https://bower.herokuapp.com/packages/search/' + encodeURIComponent(currentWord);
|
||||
|
||||
return this.xhr({
|
||||
url : queryUrl
|
||||
}).then((success) => {
|
||||
if (success.status === 200) {
|
||||
try {
|
||||
let obj = JSON.parse(success.responseText);
|
||||
if (Array.isArray(obj)) {
|
||||
let results = <{name:string; description:string;}[]> obj;
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let name = results[i].name;
|
||||
let description = results[i].description || '';
|
||||
let insertText = JSON.stringify(name);
|
||||
if (addValue) {
|
||||
insertText += ': "{{latest}}"';
|
||||
if (!isLast) {
|
||||
insertText += ',';
|
||||
}
|
||||
}
|
||||
let proposal = new CompletionItem(name);
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = insertText;
|
||||
proposal.documentation = description;
|
||||
collector.add(proposal);
|
||||
}
|
||||
collector.setAsIncomplete();
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
} else {
|
||||
collector.error(localize('json.bower.error.repoaccess', 'Request to the bower repository failed: {0}', success.responseText));
|
||||
return 0;
|
||||
}
|
||||
}, (error) => {
|
||||
collector.error(localize('json.bower.error.repoaccess', 'Request to the bower repository failed: {0}', error.responseText));
|
||||
return 0;
|
||||
});
|
||||
} else {
|
||||
this.topRanked.forEach((name) => {
|
||||
let insertText = JSON.stringify(name);
|
||||
if (addValue) {
|
||||
insertText += ': "{{latest}}"';
|
||||
if (!isLast) {
|
||||
insertText += ',';
|
||||
}
|
||||
}
|
||||
|
||||
let proposal = new CompletionItem(name);
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = insertText;
|
||||
proposal.documentation = '';
|
||||
collector.add(proposal);
|
||||
});
|
||||
collector.setAsIncomplete();
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public collectValueSuggestions(resource: string, location: Location, collector: ISuggestionsCollector): Thenable<any> {
|
||||
// not implemented. Could be do done calling the bower command. Waiting for web API: https://github.com/bower/registry/issues/26
|
||||
let proposal = new CompletionItem(localize('json.bower.latest.version', 'latest'));
|
||||
proposal.insertText = '"{{latest}}"';
|
||||
proposal.kind = CompletionItemKind.Value;
|
||||
proposal.documentation = 'The latest version of the package';
|
||||
collector.add(proposal);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
public resolveSuggestion(item: CompletionItem) : Thenable<CompletionItem> {
|
||||
if (item.kind === CompletionItemKind.Property && item.documentation === '') {
|
||||
return this.getInfo(item.label).then(documentation => {
|
||||
if (documentation) {
|
||||
item.documentation = documentation;
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
private getInfo(pack: string): Thenable<string> {
|
||||
let queryUrl = 'https://bower.herokuapp.com/packages/' + encodeURIComponent(pack);
|
||||
|
||||
return this.xhr({
|
||||
url : queryUrl
|
||||
}).then((success) => {
|
||||
try {
|
||||
let obj = JSON.parse(success.responseText);
|
||||
if (obj && obj.url) {
|
||||
let url : string = obj.url;
|
||||
if (url.indexOf('git://') === 0) {
|
||||
url = url.substring(6);
|
||||
}
|
||||
if (url.lastIndexOf('.git') === url.length - 4) {
|
||||
url = url.substring(0, url.length - 4);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return void 0;
|
||||
}, (error) => {
|
||||
return void 0;
|
||||
});
|
||||
}
|
||||
|
||||
public getInfoContribution(resource: string, location: Location): Thenable<MarkedString[]> {
|
||||
if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']))) {
|
||||
let pack = location.segments[location.segments.length - 1];
|
||||
let htmlContent : MarkedString[] = [];
|
||||
htmlContent.push(localize('json.bower.package.hover', '{0}', pack));
|
||||
return this.getInfo(pack).then(documentation => {
|
||||
if (documentation) {
|
||||
htmlContent.push(documentation);
|
||||
}
|
||||
return htmlContent;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
154
extensions/javascript/src/features/jsonContributions.ts
Normal file
154
extensions/javascript/src/features/jsonContributions.ts
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {Location, getLocation, createScanner, SyntaxKind} from 'jsonc-parser';
|
||||
import {basename} from 'path';
|
||||
import {BowerJSONContribution} from './bowerJSONContribution';
|
||||
import {PackageJSONContribution} from './packageJSONContribution';
|
||||
import {XHRRequest} from 'request-light';
|
||||
|
||||
import {CompletionItem, CompletionItemProvider, CompletionList, TextDocument, Position, Hover, HoverProvider,
|
||||
CancellationToken, Range, TextEdit, MarkedString, DocumentSelector, languages} from 'vscode';
|
||||
|
||||
export interface ISuggestionsCollector {
|
||||
add(suggestion: CompletionItem): void;
|
||||
error(message:string): void;
|
||||
log(message:string): void;
|
||||
setAsIncomplete(): void;
|
||||
}
|
||||
|
||||
export interface IJSONContribution {
|
||||
getDocumentSelector(): DocumentSelector;
|
||||
getInfoContribution(fileName: string, location: Location) : Thenable<MarkedString[]>;
|
||||
collectPropertySuggestions(fileName: string, location: Location, currentWord: string, addValue: boolean, isLast:boolean, result: ISuggestionsCollector) : Thenable<any>;
|
||||
collectValueSuggestions(fileName: string, location: Location, result: ISuggestionsCollector): Thenable<any>;
|
||||
collectDefaultSuggestions(fileName: string, result: ISuggestionsCollector): Thenable<any>;
|
||||
resolveSuggestion?(item: CompletionItem): Thenable<CompletionItem>;
|
||||
}
|
||||
|
||||
export function addJSONProviders(xhr: XHRRequest, subscriptions: { dispose(): any }[]) {
|
||||
let contributions = [new PackageJSONContribution(xhr), new BowerJSONContribution(xhr)];
|
||||
contributions.forEach(contribution => {
|
||||
let selector = contribution.getDocumentSelector();
|
||||
subscriptions.push(languages.registerCompletionItemProvider(selector, new JSONCompletionItemProvider(contribution), '.', '$'));
|
||||
subscriptions.push(languages.registerHoverProvider(selector, new JSONHoverProvider(contribution)));
|
||||
});
|
||||
}
|
||||
|
||||
export class JSONHoverProvider implements HoverProvider {
|
||||
|
||||
constructor(private jsonContribution: IJSONContribution) {
|
||||
}
|
||||
|
||||
public provideHover(document: TextDocument, position: Position, token: CancellationToken): Thenable<Hover> {
|
||||
let fileName = basename(document.fileName);
|
||||
let offset = document.offsetAt(position);
|
||||
let location = getLocation(document.getText(), offset);
|
||||
let node = location.previousNode;
|
||||
if (node && node.offset <= offset && offset <= node.offset + node.length) {
|
||||
let promise = this.jsonContribution.getInfoContribution(fileName, location);
|
||||
if (promise) {
|
||||
return promise.then(htmlContent => {
|
||||
let range = new Range(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
|
||||
let result: Hover = {
|
||||
contents: htmlContent,
|
||||
range: range
|
||||
};
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export class JSONCompletionItemProvider implements CompletionItemProvider {
|
||||
|
||||
constructor(private jsonContribution: IJSONContribution) {
|
||||
}
|
||||
|
||||
public resolveCompletionItem(item: CompletionItem, token: CancellationToken) : Thenable<CompletionItem> {
|
||||
if (this.jsonContribution.resolveSuggestion) {
|
||||
let resolver = this.jsonContribution.resolveSuggestion(item);
|
||||
if (resolver) {
|
||||
return resolver;
|
||||
}
|
||||
}
|
||||
return Promise.resolve(item);
|
||||
}
|
||||
|
||||
public provideCompletionItems(document: TextDocument, position: Position, token: CancellationToken): Thenable<CompletionList> {
|
||||
|
||||
let fileName = basename(document.fileName);
|
||||
|
||||
let currentWord = this.getCurrentWord(document, position);
|
||||
let overwriteRange = null;
|
||||
let items: CompletionItem[] = [];
|
||||
let isIncomplete = false;
|
||||
|
||||
let offset = document.offsetAt(position);
|
||||
let location = getLocation(document.getText(), offset);
|
||||
|
||||
let node = location.previousNode;
|
||||
if (node && node.offset <= offset && offset <= node.offset + node.length && (node.type === 'property' || node.type === 'string' || node.type === 'number' || node.type === 'boolean' || node.type === 'null')) {
|
||||
overwriteRange = new Range(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
|
||||
} else {
|
||||
overwriteRange = new Range(document.positionAt(offset - currentWord.length), position);
|
||||
}
|
||||
|
||||
let proposed: { [key: string]: boolean } = {};
|
||||
let collector: ISuggestionsCollector = {
|
||||
add: (suggestion: CompletionItem) => {
|
||||
if (!proposed[suggestion.label]) {
|
||||
proposed[suggestion.label] = true;
|
||||
if (overwriteRange) {
|
||||
suggestion.textEdit = TextEdit.replace(overwriteRange, suggestion.insertText);
|
||||
}
|
||||
|
||||
items.push(suggestion);
|
||||
}
|
||||
},
|
||||
setAsIncomplete: () => isIncomplete = true,
|
||||
error: (message: string) => console.error(message),
|
||||
log: (message: string) => console.log(message)
|
||||
};
|
||||
|
||||
let collectPromise : Thenable<any> = null;
|
||||
|
||||
if (location.completeProperty) {
|
||||
let addValue = !location.previousNode || !location.previousNode.columnOffset;
|
||||
let scanner = createScanner(document.getText(), true);
|
||||
scanner.setPosition(offset);
|
||||
scanner.scan();
|
||||
let isLast = scanner.getToken() === SyntaxKind.CloseBraceToken || scanner.getToken() === SyntaxKind.EOF;
|
||||
collectPromise = this.jsonContribution.collectPropertySuggestions(fileName, location, currentWord, addValue, isLast, collector);
|
||||
} else {
|
||||
if (location.segments.length === 0) {
|
||||
collectPromise = this.jsonContribution.collectDefaultSuggestions(fileName, collector);
|
||||
} else {
|
||||
collectPromise = this.jsonContribution.collectValueSuggestions(fileName, location, collector);
|
||||
}
|
||||
}
|
||||
if (collectPromise) {
|
||||
return collectPromise.then(() => {
|
||||
if (items.length > 0) {
|
||||
return new CompletionList(items, isIncomplete);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private getCurrentWord(document: TextDocument, position: Position) {
|
||||
var i = position.character - 1;
|
||||
var text = document.lineAt(position.line).text;
|
||||
while (i >= 0 && ' \t\n\r\v":{[,'.indexOf(text.charAt(i)) === -1) {
|
||||
i--;
|
||||
}
|
||||
return text.substring(i+1, position.character);
|
||||
}
|
||||
}
|
220
extensions/javascript/src/features/packageJSONContribution.ts
Normal file
220
extensions/javascript/src/features/packageJSONContribution.ts
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {MarkedString, CompletionItemKind, CompletionItem, DocumentSelector} from 'vscode';
|
||||
import {IJSONContribution, ISuggestionsCollector} from './jsonContributions';
|
||||
import {XHRRequest} from 'request-light';
|
||||
import {Location} from 'jsonc-parser';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
let LIMIT = 40;
|
||||
|
||||
export class PackageJSONContribution implements IJSONContribution {
|
||||
|
||||
private mostDependedOn = [ 'lodash', 'async', 'underscore', 'request', 'commander', 'express', 'debug', 'chalk', 'colors', 'q', 'coffee-script',
|
||||
'mkdirp', 'optimist', 'through2', 'yeoman-generator', 'moment', 'bluebird', 'glob', 'gulp-util', 'minimist', 'cheerio', 'jade', 'redis', 'node-uuid',
|
||||
'socket', 'io', 'uglify-js', 'winston', 'through', 'fs-extra', 'handlebars', 'body-parser', 'rimraf', 'mime', 'semver', 'mongodb', 'jquery',
|
||||
'grunt', 'connect', 'yosay', 'underscore', 'string', 'xml2js', 'ejs', 'mongoose', 'marked', 'extend', 'mocha', 'superagent', 'js-yaml', 'xtend',
|
||||
'shelljs', 'gulp', 'yargs', 'browserify', 'minimatch', 'react', 'less', 'prompt', 'inquirer', 'ws', 'event-stream', 'inherits', 'mysql', 'esprima',
|
||||
'jsdom', 'stylus', 'when', 'readable-stream', 'aws-sdk', 'concat-stream', 'chai', 'Thenable', 'wrench'];
|
||||
|
||||
public getDocumentSelector(): DocumentSelector {
|
||||
return [{ language: 'json', pattern: '**/package.json' }];
|
||||
}
|
||||
|
||||
public constructor(private xhr: XHRRequest) {
|
||||
}
|
||||
|
||||
public collectDefaultSuggestions(fileName: string, result: ISuggestionsCollector): Thenable<any> {
|
||||
let defaultValue = {
|
||||
'name': '{{name}}',
|
||||
'description': '{{description}}',
|
||||
'author': '{{author}}',
|
||||
'version': '{{1.0.0}}',
|
||||
'main': '{{pathToMain}}',
|
||||
'dependencies': {}
|
||||
};
|
||||
let proposal = new CompletionItem(localize('json.package.default', 'Default package.json'));
|
||||
proposal.kind = CompletionItemKind.Module;
|
||||
proposal.insertText = JSON.stringify(defaultValue, null, '\t');
|
||||
result.add(proposal);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
public collectPropertySuggestions(resource: string, location: Location, currentWord: string, addValue: boolean, isLast:boolean, collector: ISuggestionsCollector) : Thenable<any> {
|
||||
if ((location.matches(['dependencies']) || location.matches(['devDependencies']) || location.matches(['optionalDependencies']) || location.matches(['peerDependencies']))) {
|
||||
let queryUrl : string;
|
||||
if (currentWord.length > 0) {
|
||||
queryUrl = 'https://skimdb.npmjs.com/registry/_design/app/_view/browseAll?group_level=1&limit=' + LIMIT + '&start_key=%5B%22' + encodeURIComponent(currentWord) + '%22%5D&end_key=%5B%22'+ encodeURIComponent(currentWord + 'z') + '%22,%7B%7D%5D';
|
||||
|
||||
return this.xhr({
|
||||
url : queryUrl
|
||||
}).then((success) => {
|
||||
if (success.status === 200) {
|
||||
try {
|
||||
let obj = JSON.parse(success.responseText);
|
||||
if (obj && Array.isArray(obj.rows)) {
|
||||
let results = <{ key: string[]; }[]> obj.rows;
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let keys = results[i].key;
|
||||
if (Array.isArray(keys) && keys.length > 0) {
|
||||
let name = keys[0];
|
||||
let insertText = JSON.stringify(name);
|
||||
if (addValue) {
|
||||
insertText += ': "{{*}}"';
|
||||
if (!isLast) {
|
||||
insertText += ',';
|
||||
}
|
||||
}
|
||||
let proposal = new CompletionItem(name);
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = insertText;
|
||||
proposal.documentation = '';
|
||||
collector.add(proposal);
|
||||
}
|
||||
}
|
||||
if (results.length === LIMIT) {
|
||||
collector.setAsIncomplete();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
} else {
|
||||
collector.error(localize('json.npm.error.repoaccess', 'Request to the NPM repository failed: {0}', success.responseText));
|
||||
return 0;
|
||||
}
|
||||
}, (error) => {
|
||||
collector.error(localize('json.npm.error.repoaccess', 'Request to the NPM repository failed: {0}', error.responseText));
|
||||
return 0;
|
||||
});
|
||||
} else {
|
||||
this.mostDependedOn.forEach((name) => {
|
||||
let insertText = JSON.stringify(name);
|
||||
if (addValue) {
|
||||
insertText += ': "{{*}}"';
|
||||
if (!isLast) {
|
||||
insertText += ',';
|
||||
}
|
||||
}
|
||||
let proposal = new CompletionItem(name);
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = insertText;
|
||||
proposal.documentation = '';
|
||||
collector.add(proposal);
|
||||
});
|
||||
collector.setAsIncomplete();
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public collectValueSuggestions(fileName: string, location: Location, result: ISuggestionsCollector): Thenable<any> {
|
||||
if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) {
|
||||
let currentKey = location.segments[location.segments.length - 1];
|
||||
let queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(currentKey) + '/latest';
|
||||
|
||||
return this.xhr({
|
||||
url : queryUrl
|
||||
}).then((success) => {
|
||||
try {
|
||||
let obj = JSON.parse(success.responseText);
|
||||
if (obj && obj.version) {
|
||||
let version = obj.version;
|
||||
let name = JSON.stringify(version);
|
||||
let proposal = new CompletionItem(name);
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = name;
|
||||
proposal.documentation = localize('json.npm.latestversion', 'The currently latest version of the package');
|
||||
result.add(proposal);
|
||||
|
||||
name = JSON.stringify('^' + version);
|
||||
proposal = new CompletionItem(name);
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = name;
|
||||
proposal.documentation = localize('json.npm.majorversion', 'Matches the most recent major version (1.x.x)');
|
||||
result.add(proposal);
|
||||
|
||||
name = JSON.stringify('~' + version);
|
||||
proposal = new CompletionItem(name);
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = name;
|
||||
proposal.documentation = localize('json.npm.minorversion', 'Matches the most recent minor version (1.2.x)');
|
||||
result.add(proposal);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return 0;
|
||||
}, (error) => {
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public resolveSuggestion(item: CompletionItem) : Thenable<CompletionItem> {
|
||||
if (item.kind === CompletionItemKind.Property && item.documentation === '') {
|
||||
return this.getInfo(item.label).then(infos => {
|
||||
if (infos.length > 0) {
|
||||
item.documentation = infos[0];
|
||||
if (infos.length > 1) {
|
||||
item.detail = infos[1];
|
||||
}
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
private getInfo(pack: string): Thenable<string[]> {
|
||||
let queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(pack) + '/latest';
|
||||
|
||||
return this.xhr({
|
||||
url : queryUrl
|
||||
}).then((success) => {
|
||||
try {
|
||||
let obj = JSON.parse(success.responseText);
|
||||
if (obj) {
|
||||
let result = [];
|
||||
if (obj.description) {
|
||||
result.push(obj.description);
|
||||
}
|
||||
if (obj.version) {
|
||||
result.push(localize('json.npm.version.hover', 'Latest version: {0}', obj.version));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return [];
|
||||
}, (error) => {
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
public getInfoContribution(fileName: string, location: Location): Thenable<MarkedString[]> {
|
||||
if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) {
|
||||
let pack = location.segments[location.segments.length - 1];
|
||||
|
||||
let htmlContent : MarkedString[] = [];
|
||||
htmlContent.push(localize('json.npm.package.hover', '{0}', pack));
|
||||
return this.getInfo(pack).then(infos => {
|
||||
infos.forEach(info => {
|
||||
htmlContent.push(info);
|
||||
});
|
||||
return htmlContent;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
27
extensions/javascript/src/javascriptMain.ts
Normal file
27
extensions/javascript/src/javascriptMain.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import {addJSONProviders} from './features/jsonContributions';
|
||||
import * as httpRequest from 'request-light';
|
||||
|
||||
import {ExtensionContext, env, workspace} from 'vscode';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
export function activate(context: ExtensionContext): any {
|
||||
nls.config({locale: env.language});
|
||||
|
||||
configureHttpRequest();
|
||||
workspace.onDidChangeConfiguration(e => configureHttpRequest());
|
||||
|
||||
addJSONProviders(httpRequest.xhr, context.subscriptions);
|
||||
}
|
||||
|
||||
function configureHttpRequest() {
|
||||
let httpSettings = workspace.getConfiguration('http');
|
||||
httpRequest.configure(httpSettings.get<string>('proxy'), httpSettings.get<boolean>('proxyStrictSSL'));
|
||||
}
|
|
@ -3,18 +3,8 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module 'http-proxy-agent' {
|
||||
|
||||
interface IHttpProxyAgentOptions {
|
||||
host: string;
|
||||
port: number;
|
||||
auth?: string;
|
||||
}
|
||||
|
||||
class HttpProxyAgent {
|
||||
constructor(proxy: string);
|
||||
constructor(opts: IHttpProxyAgentOptions);
|
||||
}
|
||||
|
||||
export = HttpProxyAgent;
|
||||
}
|
||||
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
||||
/// <reference path='../../../../src/typings/mocha.d.ts'/>
|
||||
/// <reference path='../../../../extensions/node.d.ts'/>
|
||||
/// <reference path='../../../../extensions/lib.core.d.ts'/>
|
||||
/// <reference path='../../../../extensions/declares.d.ts'/>
|
11
extensions/javascript/tsconfig.json
Normal file
11
extensions/javascript/tsconfig.json
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"noLib": true,
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"outDir": "./out"
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
|
@ -8,8 +8,8 @@
|
|||
"node": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"http-proxy-agent": "^0.2.6",
|
||||
"https-proxy-agent": "^0.3.5",
|
||||
"request-light": "^0.0.3",
|
||||
"jsonc-parser": "^0.0.1",
|
||||
"vscode-languageserver": "^1.3.0",
|
||||
"vscode-nls": "^1.0.4"
|
||||
},
|
||||
|
|
|
@ -1,980 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
export enum ScanError {
|
||||
None,
|
||||
UnexpectedEndOfComment,
|
||||
UnexpectedEndOfString,
|
||||
UnexpectedEndOfNumber,
|
||||
InvalidUnicode,
|
||||
InvalidEscapeCharacter
|
||||
}
|
||||
|
||||
export enum SyntaxKind {
|
||||
Unknown = 0,
|
||||
OpenBraceToken,
|
||||
CloseBraceToken,
|
||||
OpenBracketToken,
|
||||
CloseBracketToken,
|
||||
CommaToken,
|
||||
ColonToken,
|
||||
NullKeyword,
|
||||
TrueKeyword,
|
||||
FalseKeyword,
|
||||
StringLiteral,
|
||||
NumericLiteral,
|
||||
LineCommentTrivia,
|
||||
BlockCommentTrivia,
|
||||
LineBreakTrivia,
|
||||
Trivia,
|
||||
EOF
|
||||
}
|
||||
|
||||
export interface JSONScanner {
|
||||
scan(): SyntaxKind;
|
||||
getPosition(): number;
|
||||
getToken(): SyntaxKind;
|
||||
getTokenValue(): string;
|
||||
getTokenOffset(): number;
|
||||
getTokenLength(): number;
|
||||
getTokenError(): ScanError;
|
||||
}
|
||||
|
||||
export function createScanner(text:string, ignoreTrivia:boolean = false):JSONScanner {
|
||||
|
||||
var pos = 0,
|
||||
len = text.length,
|
||||
value:string = '',
|
||||
tokenOffset = 0,
|
||||
token:SyntaxKind = SyntaxKind.Unknown,
|
||||
scanError:ScanError = ScanError.None;
|
||||
|
||||
function scanHexDigits(count: number, exact?: boolean): number {
|
||||
var digits = 0;
|
||||
var value = 0;
|
||||
while (digits < count || !exact) {
|
||||
var ch = text.charCodeAt(pos);
|
||||
if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) {
|
||||
value = value * 16 + ch - CharacterCodes._0;
|
||||
}
|
||||
else if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) {
|
||||
value = value * 16 + ch - CharacterCodes.A + 10;
|
||||
}
|
||||
else if (ch >= CharacterCodes.a && ch <= CharacterCodes.f) {
|
||||
value = value * 16 + ch - CharacterCodes.a + 10;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
digits++;
|
||||
}
|
||||
if (digits < count) {
|
||||
value = -1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function scanNumber(): string {
|
||||
var start = pos;
|
||||
if (text.charCodeAt(pos) === CharacterCodes._0) {
|
||||
pos++;
|
||||
} else {
|
||||
pos++;
|
||||
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
if (pos < text.length && text.charCodeAt(pos) === CharacterCodes.dot) {
|
||||
pos++;
|
||||
if (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
||||
pos++;
|
||||
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
||||
pos++;
|
||||
}
|
||||
} else {
|
||||
scanError = ScanError.UnexpectedEndOfNumber;
|
||||
return text.substring(start, end);
|
||||
}
|
||||
}
|
||||
var end = pos;
|
||||
if (pos < text.length && (text.charCodeAt(pos) === CharacterCodes.E || text.charCodeAt(pos) === CharacterCodes.e)) {
|
||||
pos++;
|
||||
if (pos < text.length && text.charCodeAt(pos) === CharacterCodes.plus || text.charCodeAt(pos) === CharacterCodes.minus) {
|
||||
pos++;
|
||||
}
|
||||
if (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
||||
pos++;
|
||||
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
||||
pos++;
|
||||
}
|
||||
end = pos;
|
||||
} else {
|
||||
scanError = ScanError.UnexpectedEndOfNumber;
|
||||
}
|
||||
}
|
||||
return text.substring(start, end);
|
||||
}
|
||||
|
||||
function scanString(): string {
|
||||
|
||||
var result = '',
|
||||
start = pos;
|
||||
|
||||
while (true) {
|
||||
if (pos >= len) {
|
||||
result += text.substring(start, pos);
|
||||
scanError = ScanError.UnexpectedEndOfString;
|
||||
break;
|
||||
}
|
||||
var ch = text.charCodeAt(pos);
|
||||
if (ch === CharacterCodes.doubleQuote) {
|
||||
result += text.substring(start, pos);
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
if (ch === CharacterCodes.backslash) {
|
||||
result += text.substring(start, pos);
|
||||
pos++;
|
||||
if (pos >= len) {
|
||||
scanError = ScanError.UnexpectedEndOfString;
|
||||
break;
|
||||
}
|
||||
ch = text.charCodeAt(pos++);
|
||||
switch (ch) {
|
||||
case CharacterCodes.doubleQuote:
|
||||
result += '\"';
|
||||
break;
|
||||
case CharacterCodes.backslash:
|
||||
result += '\\';
|
||||
break;
|
||||
case CharacterCodes.slash:
|
||||
result += '/';
|
||||
break;
|
||||
case CharacterCodes.b:
|
||||
result += '\b';
|
||||
break;
|
||||
case CharacterCodes.f:
|
||||
result += '\f';
|
||||
break;
|
||||
case CharacterCodes.n:
|
||||
result += '\n';
|
||||
break;
|
||||
case CharacterCodes.r:
|
||||
result += '\r';
|
||||
break;
|
||||
case CharacterCodes.t:
|
||||
result += '\t';
|
||||
break;
|
||||
case CharacterCodes.u:
|
||||
var ch = scanHexDigits(4, true);
|
||||
if (ch >= 0) {
|
||||
result += String.fromCharCode(ch);
|
||||
} else {
|
||||
scanError = ScanError.InvalidUnicode;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
scanError = ScanError.InvalidEscapeCharacter;
|
||||
}
|
||||
start = pos;
|
||||
continue;
|
||||
}
|
||||
if (isLineBreak(ch)) {
|
||||
result += text.substring(start, pos);
|
||||
scanError = ScanError.UnexpectedEndOfString;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function scanNext():SyntaxKind {
|
||||
|
||||
value = '';
|
||||
scanError = ScanError.None;
|
||||
|
||||
tokenOffset = pos;
|
||||
|
||||
if(pos >= len) {
|
||||
// at the end
|
||||
tokenOffset = len;
|
||||
return token = SyntaxKind.EOF;
|
||||
}
|
||||
|
||||
var code = text.charCodeAt(pos);
|
||||
// trivia: whitespace
|
||||
if (isWhiteSpace(code)) {
|
||||
do {
|
||||
pos++;
|
||||
value += String.fromCharCode(code);
|
||||
code = text.charCodeAt(pos);
|
||||
} while (isWhiteSpace(code));
|
||||
|
||||
return token = SyntaxKind.Trivia;
|
||||
}
|
||||
|
||||
// trivia: newlines
|
||||
if (isLineBreak(code)) {
|
||||
pos++;
|
||||
value += String.fromCharCode(code);
|
||||
if (code === CharacterCodes.carriageReturn && text.charCodeAt(pos) === CharacterCodes.lineFeed) {
|
||||
pos++;
|
||||
value += '\n';
|
||||
}
|
||||
return token = SyntaxKind.LineBreakTrivia;
|
||||
}
|
||||
|
||||
switch(code) {
|
||||
// tokens: []{}:,
|
||||
case CharacterCodes.openBrace:
|
||||
pos++;
|
||||
return token = SyntaxKind.OpenBraceToken;
|
||||
case CharacterCodes.closeBrace:
|
||||
pos++;
|
||||
return token = SyntaxKind.CloseBraceToken;
|
||||
case CharacterCodes.openBracket:
|
||||
pos++;
|
||||
return token = SyntaxKind.OpenBracketToken;
|
||||
case CharacterCodes.closeBracket:
|
||||
pos++;
|
||||
return token = SyntaxKind.CloseBracketToken;
|
||||
case CharacterCodes.colon:
|
||||
pos++;
|
||||
return token = SyntaxKind.ColonToken;
|
||||
case CharacterCodes.comma:
|
||||
pos++;
|
||||
return token = SyntaxKind.CommaToken;
|
||||
|
||||
// strings
|
||||
case CharacterCodes.doubleQuote:
|
||||
pos++;
|
||||
value = scanString();
|
||||
return token = SyntaxKind.StringLiteral;
|
||||
|
||||
// comments
|
||||
case CharacterCodes.slash:
|
||||
var start = pos - 1;
|
||||
// Single-line comment
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.slash) {
|
||||
pos += 2;
|
||||
|
||||
while (pos < len) {
|
||||
if (isLineBreak(text.charCodeAt(pos))) {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
|
||||
}
|
||||
value = text.substring(start, pos);
|
||||
return token = SyntaxKind.LineCommentTrivia;
|
||||
}
|
||||
|
||||
// Multi-line comment
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) {
|
||||
pos += 2;
|
||||
|
||||
var safeLength = len - 1; // For lookahead.
|
||||
var commentClosed = false;
|
||||
while (pos < safeLength) {
|
||||
var ch = text.charCodeAt(pos);
|
||||
|
||||
if (ch === CharacterCodes.asterisk && text.charCodeAt(pos + 1) === CharacterCodes.slash) {
|
||||
pos += 2;
|
||||
commentClosed = true;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (!commentClosed) {
|
||||
pos++;
|
||||
scanError = ScanError.UnexpectedEndOfComment;
|
||||
}
|
||||
|
||||
value = text.substring(start, pos);
|
||||
return token = SyntaxKind.BlockCommentTrivia;
|
||||
}
|
||||
// just a single slash
|
||||
value += String.fromCharCode(code);
|
||||
pos++;
|
||||
return token = SyntaxKind.Unknown;
|
||||
|
||||
// numbers
|
||||
case CharacterCodes.minus:
|
||||
value += String.fromCharCode(code);
|
||||
pos++;
|
||||
if (pos === len || !isDigit(text.charCodeAt(pos))) {
|
||||
return token = SyntaxKind.Unknown;
|
||||
}
|
||||
// found a minus, followed by a number so
|
||||
// we fall through to proceed with scanning
|
||||
// numbers
|
||||
case CharacterCodes._0:
|
||||
case CharacterCodes._1:
|
||||
case CharacterCodes._2:
|
||||
case CharacterCodes._3:
|
||||
case CharacterCodes._4:
|
||||
case CharacterCodes._5:
|
||||
case CharacterCodes._6:
|
||||
case CharacterCodes._7:
|
||||
case CharacterCodes._8:
|
||||
case CharacterCodes._9:
|
||||
value += scanNumber();
|
||||
return token = SyntaxKind.NumericLiteral;
|
||||
// literals and unknown symbols
|
||||
default:
|
||||
// is a literal? Read the full word.
|
||||
while (pos < len && isUnknownContentCharacter(code)) {
|
||||
pos++;
|
||||
code = text.charCodeAt(pos);
|
||||
}
|
||||
if (tokenOffset !== pos) {
|
||||
value = text.substring(tokenOffset, pos);
|
||||
// keywords: true, false, null
|
||||
switch (value) {
|
||||
case 'true': return token = SyntaxKind.TrueKeyword;
|
||||
case 'false': return token = SyntaxKind.FalseKeyword;
|
||||
case 'null': return token = SyntaxKind.NullKeyword;
|
||||
}
|
||||
return token = SyntaxKind.Unknown;
|
||||
}
|
||||
// some
|
||||
value += String.fromCharCode(code);
|
||||
pos++;
|
||||
return token = SyntaxKind.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
function isUnknownContentCharacter(code: CharacterCodes) {
|
||||
if (isWhiteSpace(code) || isLineBreak(code)) {
|
||||
return false;
|
||||
}
|
||||
switch (code) {
|
||||
case CharacterCodes.closeBrace:
|
||||
case CharacterCodes.closeBracket:
|
||||
case CharacterCodes.openBrace:
|
||||
case CharacterCodes.openBracket:
|
||||
case CharacterCodes.doubleQuote:
|
||||
case CharacterCodes.colon:
|
||||
case CharacterCodes.comma:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function scanNextNonTrivia():SyntaxKind {
|
||||
var result : SyntaxKind;
|
||||
do {
|
||||
result = scanNext();
|
||||
} while (result >= SyntaxKind.LineCommentTrivia && result <= SyntaxKind.Trivia);
|
||||
return result;
|
||||
}
|
||||
|
||||
return {
|
||||
getPosition: () => pos,
|
||||
scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
|
||||
getToken: () => token,
|
||||
getTokenValue: () => value,
|
||||
getTokenOffset: () => tokenOffset,
|
||||
getTokenLength: () => pos - tokenOffset,
|
||||
getTokenError: () => scanError
|
||||
};
|
||||
}
|
||||
|
||||
function isWhiteSpace(ch: number): boolean {
|
||||
return ch === CharacterCodes.space || ch === CharacterCodes.tab || ch === CharacterCodes.verticalTab || ch === CharacterCodes.formFeed ||
|
||||
ch === CharacterCodes.nonBreakingSpace || ch === CharacterCodes.ogham || ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace ||
|
||||
ch === CharacterCodes.narrowNoBreakSpace || ch === CharacterCodes.mathematicalSpace || ch === CharacterCodes.ideographicSpace || ch === CharacterCodes.byteOrderMark;
|
||||
}
|
||||
|
||||
function isLineBreak(ch: number): boolean {
|
||||
return ch === CharacterCodes.lineFeed || ch === CharacterCodes.carriageReturn || ch === CharacterCodes.lineSeparator || ch === CharacterCodes.paragraphSeparator;
|
||||
}
|
||||
|
||||
function isDigit(ch: number): boolean {
|
||||
return ch >= CharacterCodes._0 && ch <= CharacterCodes._9;
|
||||
}
|
||||
|
||||
export function isLetter(ch: number): boolean {
|
||||
return ch >= CharacterCodes.a && ch <= CharacterCodes.z || ch >= CharacterCodes.A && ch <= CharacterCodes.Z;
|
||||
}
|
||||
|
||||
enum CharacterCodes {
|
||||
nullCharacter = 0,
|
||||
maxAsciiCharacter = 0x7F,
|
||||
|
||||
lineFeed = 0x0A, // \n
|
||||
carriageReturn = 0x0D, // \r
|
||||
lineSeparator = 0x2028,
|
||||
paragraphSeparator = 0x2029,
|
||||
|
||||
// REVIEW: do we need to support this? The scanner doesn't, but our IText does. This seems
|
||||
// like an odd disparity? (Or maybe it's completely fine for them to be different).
|
||||
nextLine = 0x0085,
|
||||
|
||||
// Unicode 3.0 space characters
|
||||
space = 0x0020, // " "
|
||||
nonBreakingSpace = 0x00A0, //
|
||||
enQuad = 0x2000,
|
||||
emQuad = 0x2001,
|
||||
enSpace = 0x2002,
|
||||
emSpace = 0x2003,
|
||||
threePerEmSpace = 0x2004,
|
||||
fourPerEmSpace = 0x2005,
|
||||
sixPerEmSpace = 0x2006,
|
||||
figureSpace = 0x2007,
|
||||
punctuationSpace = 0x2008,
|
||||
thinSpace = 0x2009,
|
||||
hairSpace = 0x200A,
|
||||
zeroWidthSpace = 0x200B,
|
||||
narrowNoBreakSpace = 0x202F,
|
||||
ideographicSpace = 0x3000,
|
||||
mathematicalSpace = 0x205F,
|
||||
ogham = 0x1680,
|
||||
|
||||
_ = 0x5F,
|
||||
$ = 0x24,
|
||||
|
||||
_0 = 0x30,
|
||||
_1 = 0x31,
|
||||
_2 = 0x32,
|
||||
_3 = 0x33,
|
||||
_4 = 0x34,
|
||||
_5 = 0x35,
|
||||
_6 = 0x36,
|
||||
_7 = 0x37,
|
||||
_8 = 0x38,
|
||||
_9 = 0x39,
|
||||
|
||||
a = 0x61,
|
||||
b = 0x62,
|
||||
c = 0x63,
|
||||
d = 0x64,
|
||||
e = 0x65,
|
||||
f = 0x66,
|
||||
g = 0x67,
|
||||
h = 0x68,
|
||||
i = 0x69,
|
||||
j = 0x6A,
|
||||
k = 0x6B,
|
||||
l = 0x6C,
|
||||
m = 0x6D,
|
||||
n = 0x6E,
|
||||
o = 0x6F,
|
||||
p = 0x70,
|
||||
q = 0x71,
|
||||
r = 0x72,
|
||||
s = 0x73,
|
||||
t = 0x74,
|
||||
u = 0x75,
|
||||
v = 0x76,
|
||||
w = 0x77,
|
||||
x = 0x78,
|
||||
y = 0x79,
|
||||
z = 0x7A,
|
||||
|
||||
A = 0x41,
|
||||
B = 0x42,
|
||||
C = 0x43,
|
||||
D = 0x44,
|
||||
E = 0x45,
|
||||
F = 0x46,
|
||||
G = 0x47,
|
||||
H = 0x48,
|
||||
I = 0x49,
|
||||
J = 0x4A,
|
||||
K = 0x4B,
|
||||
L = 0x4C,
|
||||
M = 0x4D,
|
||||
N = 0x4E,
|
||||
O = 0x4F,
|
||||
P = 0x50,
|
||||
Q = 0x51,
|
||||
R = 0x52,
|
||||
S = 0x53,
|
||||
T = 0x54,
|
||||
U = 0x55,
|
||||
V = 0x56,
|
||||
W = 0x57,
|
||||
X = 0x58,
|
||||
Y = 0x59,
|
||||
Z = 0x5a,
|
||||
|
||||
ampersand = 0x26, // &
|
||||
asterisk = 0x2A, // *
|
||||
at = 0x40, // @
|
||||
backslash = 0x5C, // \
|
||||
bar = 0x7C, // |
|
||||
caret = 0x5E, // ^
|
||||
closeBrace = 0x7D, // }
|
||||
closeBracket = 0x5D, // ]
|
||||
closeParen = 0x29, // )
|
||||
colon = 0x3A, // :
|
||||
comma = 0x2C, // ,
|
||||
dot = 0x2E, // .
|
||||
doubleQuote = 0x22, // "
|
||||
equals = 0x3D, // =
|
||||
exclamation = 0x21, // !
|
||||
greaterThan = 0x3E, // >
|
||||
lessThan = 0x3C, // <
|
||||
minus = 0x2D, // -
|
||||
openBrace = 0x7B, // {
|
||||
openBracket = 0x5B, // [
|
||||
openParen = 0x28, // (
|
||||
percent = 0x25, // %
|
||||
plus = 0x2B, // +
|
||||
question = 0x3F, // ?
|
||||
semicolon = 0x3B, // ;
|
||||
singleQuote = 0x27, // '
|
||||
slash = 0x2F, // /
|
||||
tilde = 0x7E, // ~
|
||||
|
||||
backspace = 0x08, // \b
|
||||
formFeed = 0x0C, // \f
|
||||
byteOrderMark = 0xFEFF,
|
||||
tab = 0x09, // \t
|
||||
verticalTab = 0x0B, // \v
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Takes JSON with JavaScript-style comments and remove
|
||||
* them. Optionally replaces every none-newline character
|
||||
* of comments with a replaceCharacter
|
||||
*/
|
||||
export function stripComments(text:string, replaceCh?:string):string {
|
||||
|
||||
var _scanner = createScanner(text),
|
||||
parts: string[] = [],
|
||||
kind:SyntaxKind,
|
||||
offset = 0,
|
||||
pos:number;
|
||||
|
||||
do {
|
||||
pos = _scanner.getPosition();
|
||||
kind = _scanner.scan();
|
||||
switch (kind) {
|
||||
case SyntaxKind.LineCommentTrivia:
|
||||
case SyntaxKind.BlockCommentTrivia:
|
||||
case SyntaxKind.EOF:
|
||||
if(offset !== pos) {
|
||||
parts.push(text.substring(offset, pos));
|
||||
}
|
||||
if(replaceCh !== void 0) {
|
||||
parts.push(_scanner.getTokenValue().replace(/[^\r\n]/g, replaceCh));
|
||||
}
|
||||
offset = _scanner.getPosition();
|
||||
break;
|
||||
}
|
||||
} while(kind !== SyntaxKind.EOF);
|
||||
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
export enum ParseErrorCode {
|
||||
InvalidSymbol,
|
||||
InvalidNumberFormat,
|
||||
PropertyNameExpected,
|
||||
ValueExpected,
|
||||
ColonExpected,
|
||||
CommaExpected,
|
||||
CloseBraceExpected,
|
||||
CloseBracketExpected,
|
||||
EndOfFileExpected
|
||||
}
|
||||
|
||||
export function getParseErrorMessage(errorCode: ParseErrorCode) : string {
|
||||
switch (errorCode) {
|
||||
case ParseErrorCode.InvalidSymbol: return 'Invalid symbol';
|
||||
case ParseErrorCode.InvalidNumberFormat: return 'Invalid number format';
|
||||
case ParseErrorCode.PropertyNameExpected: return 'Property name expected';
|
||||
case ParseErrorCode.ValueExpected: return 'Value expected';
|
||||
case ParseErrorCode.ColonExpected: return 'Colon expected';
|
||||
case ParseErrorCode.CommaExpected: return 'Comma expected';
|
||||
case ParseErrorCode.CloseBraceExpected: return 'Closing brace expected';
|
||||
case ParseErrorCode.CloseBracketExpected: return 'Closing bracket expected';
|
||||
case ParseErrorCode.EndOfFileExpected: return 'End of file expected';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export type NodeType = "object" | "array" | "property" | "string" | "number" | "null";
|
||||
|
||||
|
||||
export interface Node {
|
||||
type: NodeType;
|
||||
value: any;
|
||||
offset: number;
|
||||
length: number;
|
||||
columnOffset?: number;
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
previousNode: Node;
|
||||
segments: string[];
|
||||
completeProperty: boolean;
|
||||
}
|
||||
|
||||
export function getLocation(text:string, position: number) : Location {
|
||||
let segments: string[] = [];
|
||||
let earlyReturnException = new Object();
|
||||
let previousNode : Node = {
|
||||
value: void 0,
|
||||
offset: void 0,
|
||||
length: void 0,
|
||||
type: void 0
|
||||
};
|
||||
let completeProperty = false;
|
||||
let hasComma = false;
|
||||
try {
|
||||
function setNode(value: string, offset: number, length: number, type: NodeType) {
|
||||
previousNode.value = value;
|
||||
previousNode.offset = offset;
|
||||
previousNode.length = length;
|
||||
previousNode.type = type;
|
||||
previousNode.columnOffset = void 0;
|
||||
}
|
||||
visit(text, {
|
||||
onObjectBegin: (offset: number, length: number) => {
|
||||
if (position <= offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
setNode(void 0, void 0, void 0, void 0);
|
||||
completeProperty = position > offset;
|
||||
hasComma = false;
|
||||
},
|
||||
onObjectProperty: (name: string, offset: number, length: number) => {
|
||||
if (position < offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
setNode(name, offset, length, 'property');
|
||||
hasComma = false;
|
||||
segments.push(name);
|
||||
if (position <= offset + length) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
},
|
||||
onObjectEnd: (offset: number, length: number) => {
|
||||
if (position <= offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
setNode(void 0, void 0, void 0, void 0);
|
||||
if (!hasComma) {
|
||||
segments.pop();
|
||||
}
|
||||
hasComma = false;
|
||||
},
|
||||
onArrayBegin: (offset: number, length: number) => {
|
||||
if (position <= offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
setNode(void 0, void 0, void 0, void 0);
|
||||
segments.push('[0]');
|
||||
hasComma = false;
|
||||
},
|
||||
onArrayEnd: (offset: number, length: number) => {
|
||||
if (position <= offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
setNode(void 0, void 0, void 0, void 0);
|
||||
if (!hasComma) {
|
||||
segments.pop();
|
||||
}
|
||||
hasComma = false;
|
||||
},
|
||||
onLiteralValue: (value: any, offset: number, length: number) => {
|
||||
if (position < offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
setNode(value, offset, length, value === null ? 'null' : (typeof value === 'string' ? 'string' : 'number'));
|
||||
if (position <= offset + length) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
},
|
||||
onSeparator: (sep: string, offset: number, length: number) => {
|
||||
if (position <= offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
if (sep === ':' && previousNode.type === 'property') {
|
||||
previousNode.columnOffset = offset;
|
||||
completeProperty = false;
|
||||
setNode(void 0, void 0, void 0, void 0);
|
||||
} else if (sep === ',') {
|
||||
let last = segments.pop();
|
||||
if (last[0] === '[' && last[last.length - 1] === ']') {
|
||||
segments.push('[' + (parseInt(last.substr(1, last.length - 2)) + 1) + ']');
|
||||
} else {
|
||||
completeProperty = true;
|
||||
}
|
||||
setNode(void 0, void 0, void 0, void 0);
|
||||
hasComma = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (e !== earlyReturnException) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return {
|
||||
segments,
|
||||
previousNode,
|
||||
completeProperty
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function parse(text:string, errors: { error:ParseErrorCode; }[] = []) : any {
|
||||
let currentProperty : string = null;
|
||||
let currentParent : any = [];
|
||||
let previousParents : any[] = [];
|
||||
|
||||
function onValue(value: any) {
|
||||
if (Array.isArray(currentParent)) {
|
||||
(<any[]> currentParent).push(value);
|
||||
} else if (currentProperty) {
|
||||
currentParent[currentProperty] = value;
|
||||
}
|
||||
}
|
||||
|
||||
let visitor = {
|
||||
onObjectBegin: () => {
|
||||
let object = {};
|
||||
onValue(object);
|
||||
previousParents.push(currentParent);
|
||||
currentParent = object;
|
||||
currentProperty = null;
|
||||
},
|
||||
onObjectProperty: (name: string) => {
|
||||
currentProperty = name;
|
||||
},
|
||||
onObjectEnd: () => {
|
||||
currentParent = previousParents.pop();
|
||||
},
|
||||
onArrayBegin: () => {
|
||||
let array = [];
|
||||
onValue(array);
|
||||
previousParents.push(currentParent);
|
||||
currentParent = array;
|
||||
currentProperty = null;
|
||||
},
|
||||
onArrayEnd: () => {
|
||||
currentParent = previousParents.pop();
|
||||
},
|
||||
onLiteralValue: onValue,
|
||||
onError:(error:ParseErrorCode) => {
|
||||
errors.push({error: error});
|
||||
}
|
||||
};
|
||||
visit(text, visitor);
|
||||
return currentParent[0];
|
||||
}
|
||||
|
||||
export function visit(text:string, visitor: JSONVisitor) : any {
|
||||
var _scanner = createScanner(text, true);
|
||||
|
||||
function toNoArgVisit(visitFunction: (offset: number, length: number) => void) : () => void {
|
||||
return visitFunction ? () => visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength()) : () => true;
|
||||
}
|
||||
function toOneArgVisit<T>(visitFunction: (arg: T, offset: number, length: number) => void) : (arg: T) => void {
|
||||
return visitFunction ? (arg: T) => visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength()) : () => true;
|
||||
}
|
||||
|
||||
let onObjectBegin = toNoArgVisit(visitor.onObjectBegin),
|
||||
onObjectProperty = toOneArgVisit(visitor.onObjectProperty),
|
||||
onObjectEnd = toNoArgVisit(visitor.onObjectEnd),
|
||||
onArrayBegin = toNoArgVisit(visitor.onArrayBegin),
|
||||
onArrayEnd = toNoArgVisit(visitor.onArrayEnd),
|
||||
onLiteralValue = toOneArgVisit(visitor.onLiteralValue),
|
||||
onSeparator = toOneArgVisit(visitor.onSeparator),
|
||||
onError = toOneArgVisit(visitor.onError);
|
||||
|
||||
function scanNext() : SyntaxKind {
|
||||
var token = _scanner.scan();
|
||||
while (token === SyntaxKind.Unknown) {
|
||||
handleError(ParseErrorCode.InvalidSymbol);
|
||||
token = _scanner.scan();
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
function handleError(error:ParseErrorCode, skipUntilAfter: SyntaxKind[] = [], skipUntil: SyntaxKind[] = []) : void {
|
||||
onError(error);
|
||||
if (skipUntilAfter.length + skipUntil.length > 0) {
|
||||
var token = _scanner.getToken();
|
||||
while (token !== SyntaxKind.EOF) {
|
||||
if (skipUntilAfter.indexOf(token) !== -1) {
|
||||
scanNext();
|
||||
break;
|
||||
} else if (skipUntil.indexOf(token) !== -1) {
|
||||
break;
|
||||
}
|
||||
token = scanNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseString(isValue: boolean) : boolean {
|
||||
if (_scanner.getToken() !== SyntaxKind.StringLiteral) {
|
||||
return false;
|
||||
}
|
||||
var value = _scanner.getTokenValue();
|
||||
if (isValue) {
|
||||
onLiteralValue(value);
|
||||
} else {
|
||||
onObjectProperty(value);
|
||||
}
|
||||
scanNext();
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseLiteral() : boolean {
|
||||
switch (_scanner.getToken()) {
|
||||
case SyntaxKind.NumericLiteral:
|
||||
let value = 0;
|
||||
try {
|
||||
value = JSON.parse(_scanner.getTokenValue());
|
||||
if (typeof value !== 'number') {
|
||||
handleError(ParseErrorCode.InvalidNumberFormat);
|
||||
value = 0;
|
||||
}
|
||||
} catch (e) {
|
||||
handleError(ParseErrorCode.InvalidNumberFormat);
|
||||
}
|
||||
onLiteralValue(value);
|
||||
break;
|
||||
case SyntaxKind.NullKeyword:
|
||||
onLiteralValue(null);
|
||||
break;
|
||||
case SyntaxKind.TrueKeyword:
|
||||
onLiteralValue(true);
|
||||
break;
|
||||
case SyntaxKind.FalseKeyword:
|
||||
onLiteralValue(false);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
scanNext();
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseProperty() : boolean {
|
||||
if (!parseString(false)) {
|
||||
handleError(ParseErrorCode.PropertyNameExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
|
||||
return false;
|
||||
}
|
||||
if (_scanner.getToken() === SyntaxKind.ColonToken) {
|
||||
onSeparator(':');
|
||||
scanNext(); // consume colon
|
||||
|
||||
if (!parseValue()) {
|
||||
handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
|
||||
}
|
||||
} else {
|
||||
handleError(ParseErrorCode.ColonExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseObject() : boolean {
|
||||
if (_scanner.getToken() !== SyntaxKind.OpenBraceToken) {
|
||||
return false;
|
||||
}
|
||||
onObjectBegin();
|
||||
scanNext(); // consume open brace
|
||||
|
||||
var needsComma = false;
|
||||
while (_scanner.getToken() !== SyntaxKind.CloseBraceToken && _scanner.getToken() !== SyntaxKind.EOF) {
|
||||
if (_scanner.getToken() === SyntaxKind.CommaToken) {
|
||||
if (!needsComma) {
|
||||
handleError(ParseErrorCode.ValueExpected, [], [] );
|
||||
}
|
||||
onSeparator(',');
|
||||
scanNext(); // consume comma
|
||||
} else if (needsComma) {
|
||||
handleError(ParseErrorCode.CommaExpected, [], [] );
|
||||
}
|
||||
if (!parseProperty()) {
|
||||
handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBraceToken, SyntaxKind.CommaToken] );
|
||||
}
|
||||
needsComma = true;
|
||||
}
|
||||
onObjectEnd();
|
||||
if (_scanner.getToken() !== SyntaxKind.CloseBraceToken) {
|
||||
handleError(ParseErrorCode.CloseBraceExpected, [SyntaxKind.CloseBraceToken], []);
|
||||
} else {
|
||||
scanNext(); // consume close brace
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseArray() : boolean {
|
||||
if (_scanner.getToken() !== SyntaxKind.OpenBracketToken) {
|
||||
return false;
|
||||
}
|
||||
onArrayBegin();
|
||||
scanNext(); // consume open bracket
|
||||
|
||||
var needsComma = false;
|
||||
while (_scanner.getToken() !== SyntaxKind.CloseBracketToken && _scanner.getToken() !== SyntaxKind.EOF) {
|
||||
if (_scanner.getToken() === SyntaxKind.CommaToken) {
|
||||
if (!needsComma) {
|
||||
handleError(ParseErrorCode.ValueExpected, [], [] );
|
||||
}
|
||||
onSeparator(',');
|
||||
scanNext(); // consume comma
|
||||
} else if (needsComma) {
|
||||
handleError(ParseErrorCode.CommaExpected, [], [] );
|
||||
}
|
||||
if (!parseValue()) {
|
||||
handleError(ParseErrorCode.ValueExpected, [], [SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken] );
|
||||
}
|
||||
needsComma = true;
|
||||
}
|
||||
onArrayEnd();
|
||||
if (_scanner.getToken() !== SyntaxKind.CloseBracketToken) {
|
||||
handleError(ParseErrorCode.CloseBracketExpected, [SyntaxKind.CloseBracketToken], []);
|
||||
} else {
|
||||
scanNext(); // consume close bracket
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseValue() : boolean {
|
||||
return parseArray() || parseObject() || parseString(true) || parseLiteral();
|
||||
}
|
||||
|
||||
scanNext();
|
||||
if (!parseValue()) {
|
||||
handleError(ParseErrorCode.ValueExpected, [], []);
|
||||
return false;
|
||||
}
|
||||
if (_scanner.getToken() !== SyntaxKind.EOF) {
|
||||
handleError(ParseErrorCode.EndOfFileExpected, [], []);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export interface JSONVisitor {
|
||||
onObjectBegin?: (offset:number, length:number) => void;
|
||||
onObjectProperty?: (property: string, offset:number, length:number) => void;
|
||||
|
||||
onObjectEnd?: (offset:number, length:number) => void;
|
||||
|
||||
onArrayBegin?: (offset:number, length:number) => void;
|
||||
onArrayEnd?: (offset:number, length:number) => void;
|
||||
|
||||
onLiteralValue?: (value: any, offset:number, length:number) => void;
|
||||
|
||||
onSeparator?: (charcter: string, offset:number, length:number) => void;
|
||||
|
||||
onError?: (error: ParseErrorCode, offset:number, length:number) => void;
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Parser = require('./jsonParser');
|
||||
import SchemaService = require('./jsonSchemaService');
|
||||
import JsonSchema = require('./json-toolbox/jsonSchema');
|
||||
import JsonSchema = require('./jsonSchema');
|
||||
import {IJSONWorkerContribution} from './jsonContributions';
|
||||
|
||||
import {CompletionItem, CompletionItemKind, CompletionList, ITextDocument, TextDocumentPosition, Range, TextEdit, RemoteConsole} from 'vscode-languageserver';
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import Json = require('./json-toolbox/json');
|
||||
import Json = require('jsonc-parser');
|
||||
import {ITextDocument, Range, Position, FormattingOptions, TextEdit} from 'vscode-languageserver';
|
||||
|
||||
export function format(document: ITextDocument, range: Range, options: FormattingOptions): TextEdit[] {
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import Json = require('./json-toolbox/json');
|
||||
import JsonSchema = require('./json-toolbox/jsonSchema');
|
||||
import Json = require('jsonc-parser');
|
||||
import JsonSchema = require('./jsonSchema');
|
||||
import {JSONLocation} from './jsonLocation';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
|
@ -898,7 +898,7 @@ export function parse(text: string, config = new JSONDocumentConfig()): JSONDocu
|
|||
if (_scanner.getToken() === Json.SyntaxKind.Unknown) {
|
||||
// give a more helpful error message
|
||||
let value = _scanner.getTokenValue();
|
||||
if (value.length > 0 && (value.charAt(0) === '\'' || Json.isLetter(value.charAt(0).charCodeAt(0)))) {
|
||||
if (value.match(/^['\w]/)) {
|
||||
_error(localize('DoubleQuotesExpected', 'Property keys must be doublequoted'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import Json = require('./json-toolbox/json');
|
||||
import {IJSONSchema} from './json-toolbox/jsonSchema';
|
||||
import {IXHROptions, IXHRResponse, getErrorStatusDescription} from './utils/httpRequest';
|
||||
import Json = require('jsonc-parser');
|
||||
import {IJSONSchema} from './jsonSchema';
|
||||
import {XHROptions, XHRResponse, getErrorStatusDescription} from 'request-light';
|
||||
import URI from './utils/uri';
|
||||
import Strings = require('./utils/strings');
|
||||
import Parser = require('./jsonParser');
|
||||
|
@ -208,7 +208,7 @@ export interface IWorkspaceContextService {
|
|||
}
|
||||
|
||||
export interface IRequestService {
|
||||
(options: IXHROptions): Thenable<IXHRResponse>;
|
||||
(options: XHROptions): Thenable<XHRResponse>;
|
||||
}
|
||||
|
||||
export class JSONSchemaService implements IJSONSchemaService {
|
||||
|
@ -362,7 +362,7 @@ export class JSONSchemaService implements IJSONSchemaService {
|
|||
let errors = jsonErrors.length ? [localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': {1}.', toDisplayString(url), jsonErrors[0])] : [];
|
||||
return new UnresolvedSchema(schemaContent, errors);
|
||||
},
|
||||
(error: IXHRResponse) => {
|
||||
(error: XHRResponse) => {
|
||||
let errorMessage = localize('json.schema.unabletoload', 'Unable to load schema from \'{0}\': {1}', toDisplayString(url), error.responseText || getErrorStatusDescription(error.status) || error.toString());
|
||||
return new UnresolvedSchema(<IJSONSchema>{}, [errorMessage]);
|
||||
}
|
||||
|
|
|
@ -1,144 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {MarkedString, CompletionItemKind} from 'vscode-languageserver';
|
||||
import Strings = require('../utils/strings');
|
||||
import {IJSONWorkerContribution, ISuggestionsCollector} from '../jsonContributions';
|
||||
import {IRequestService} from '../jsonSchemaService';
|
||||
import {JSONLocation} from '../jsonLocation';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class BowerJSONContribution implements IJSONWorkerContribution {
|
||||
|
||||
private requestService : IRequestService;
|
||||
|
||||
private topRanked = ['twitter','bootstrap','angular-1.1.6','angular-latest','angulerjs','d3','myjquery','jq','abcdef1234567890','jQuery','jquery-1.11.1','jquery',
|
||||
'sushi-vanilla-x-data','font-awsome','Font-Awesome','font-awesome','fontawesome','html5-boilerplate','impress.js','homebrew',
|
||||
'backbone','moment1','momentjs','moment','linux','animate.css','animate-css','reveal.js','jquery-file-upload','blueimp-file-upload','threejs','express','chosen',
|
||||
'normalize-css','normalize.css','semantic','semantic-ui','Semantic-UI','modernizr','underscore','underscore1',
|
||||
'material-design-icons','ionic','chartjs','Chart.js','nnnick-chartjs','select2-ng','select2-dist','phantom','skrollr','scrollr','less.js','leancss','parser-lib',
|
||||
'hui','bootstrap-languages','async','gulp','jquery-pjax','coffeescript','hammer.js','ace','leaflet','jquery-mobile','sweetalert','typeahead.js','soup','typehead.js',
|
||||
'sails','codeigniter2'];
|
||||
|
||||
public constructor(requestService: IRequestService) {
|
||||
this.requestService = requestService;
|
||||
}
|
||||
|
||||
private isBowerFile(resource: string): boolean {
|
||||
return Strings.endsWith(resource, '/bower.json') || Strings.endsWith(resource, '/.bower.json');
|
||||
}
|
||||
|
||||
public collectDefaultSuggestions(resource: string, result: ISuggestionsCollector): Thenable<any> {
|
||||
if (this.isBowerFile(resource)) {
|
||||
let defaultValue = {
|
||||
'name': '{{name}}',
|
||||
'description': '{{description}}',
|
||||
'authors': [ '{{author}}' ],
|
||||
'version': '{{1.0.0}}',
|
||||
'main': '{{pathToMain}}',
|
||||
'dependencies': {}
|
||||
};
|
||||
result.add({ kind: CompletionItemKind.Class, label: localize('json.bower.default', 'Default bower.json'), insertText: JSON.stringify(defaultValue, null, '\t'), documentation: '' });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public collectPropertySuggestions(resource: string, location: JSONLocation, currentWord: string, addValue: boolean, isLast:boolean, result: ISuggestionsCollector) : Thenable<any> {
|
||||
if (this.isBowerFile(resource) && (location.matches(['dependencies']) || location.matches(['devDependencies']))) {
|
||||
if (currentWord.length > 0) {
|
||||
let queryUrl = 'https://bower.herokuapp.com/packages/search/' + encodeURIComponent(currentWord);
|
||||
|
||||
return this.requestService({
|
||||
url : queryUrl
|
||||
}).then((success) => {
|
||||
if (success.status === 200) {
|
||||
try {
|
||||
let obj = JSON.parse(success.responseText);
|
||||
if (Array.isArray(obj)) {
|
||||
let results = <{name:string; description:string;}[]> obj;
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let name = results[i].name;
|
||||
let description = results[i].description || '';
|
||||
let insertText = JSON.stringify(name);
|
||||
if (addValue) {
|
||||
insertText += ': "{{*}}"';
|
||||
if (!isLast) {
|
||||
insertText += ',';
|
||||
}
|
||||
}
|
||||
result.add({ kind: CompletionItemKind.Property, label: name, insertText: insertText, documentation: description });
|
||||
}
|
||||
result.setAsIncomplete();
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
} else {
|
||||
result.error(localize('json.bower.error.repoaccess', 'Request to the bower repository failed: {0}', success.responseText));
|
||||
return 0;
|
||||
}
|
||||
}, (error) => {
|
||||
result.error(localize('json.bower.error.repoaccess', 'Request to the bower repository failed: {0}', error.responseText));
|
||||
return 0;
|
||||
});
|
||||
} else {
|
||||
this.topRanked.forEach((name) => {
|
||||
let insertText = JSON.stringify(name);
|
||||
if (addValue) {
|
||||
insertText += ': "{{*}}"';
|
||||
if (!isLast) {
|
||||
insertText += ',';
|
||||
}
|
||||
}
|
||||
result.add({ kind: CompletionItemKind.Property, label: name, insertText: insertText, documentation: '' });
|
||||
});
|
||||
result.setAsIncomplete();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public collectValueSuggestions(resource: string, location: JSONLocation, currentKey: string, result: ISuggestionsCollector): Thenable<any> {
|
||||
// not implemented. Could be do done calling the bower command. Waiting for web API: https://github.com/bower/registry/issues/26
|
||||
return null;
|
||||
}
|
||||
|
||||
public getInfoContribution(resource: string, location: JSONLocation): Thenable<MarkedString[]> {
|
||||
if (this.isBowerFile(resource) && (location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']))) {
|
||||
let pack = location.getSegments()[location.getSegments().length - 1];
|
||||
let htmlContent : MarkedString[] = [];
|
||||
htmlContent.push(localize('json.bower.package.hover', '{0}', pack));
|
||||
|
||||
let queryUrl = 'https://bower.herokuapp.com/packages/' + encodeURIComponent(pack);
|
||||
|
||||
return this.requestService({
|
||||
url : queryUrl
|
||||
}).then((success) => {
|
||||
try {
|
||||
let obj = JSON.parse(success.responseText);
|
||||
if (obj && obj.url) {
|
||||
let url = obj.url;
|
||||
if (Strings.startsWith(url, 'git://')) {
|
||||
url = url.substring(6);
|
||||
}
|
||||
if (Strings.endsWith(url, '.git')) {
|
||||
url = url.substring(0, url.length - 4);
|
||||
}
|
||||
htmlContent.push(url);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return htmlContent;
|
||||
}, (error) => {
|
||||
return htmlContent;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {MarkedString, CompletionItemKind} from 'vscode-languageserver';
|
||||
import Strings = require('../utils/strings');
|
||||
import {IJSONWorkerContribution, ISuggestionsCollector} from '../jsonContributions';
|
||||
import {IRequestService} from '../jsonSchemaService';
|
||||
import {JSONLocation} from '../jsonLocation';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
let LIMIT = 40;
|
||||
|
||||
export class PackageJSONContribution implements IJSONWorkerContribution {
|
||||
|
||||
private mostDependedOn = [ 'lodash', 'async', 'underscore', 'request', 'commander', 'express', 'debug', 'chalk', 'colors', 'q', 'coffee-script',
|
||||
'mkdirp', 'optimist', 'through2', 'yeoman-generator', 'moment', 'bluebird', 'glob', 'gulp-util', 'minimist', 'cheerio', 'jade', 'redis', 'node-uuid',
|
||||
'socket', 'io', 'uglify-js', 'winston', 'through', 'fs-extra', 'handlebars', 'body-parser', 'rimraf', 'mime', 'semver', 'mongodb', 'jquery',
|
||||
'grunt', 'connect', 'yosay', 'underscore', 'string', 'xml2js', 'ejs', 'mongoose', 'marked', 'extend', 'mocha', 'superagent', 'js-yaml', 'xtend',
|
||||
'shelljs', 'gulp', 'yargs', 'browserify', 'minimatch', 'react', 'less', 'prompt', 'inquirer', 'ws', 'event-stream', 'inherits', 'mysql', 'esprima',
|
||||
'jsdom', 'stylus', 'when', 'readable-stream', 'aws-sdk', 'concat-stream', 'chai', 'Thenable', 'wrench'];
|
||||
|
||||
private requestService : IRequestService;
|
||||
|
||||
private isPackageJSONFile(resource: string): boolean {
|
||||
return Strings.endsWith(resource, '/package.json');
|
||||
}
|
||||
|
||||
public constructor(requestService: IRequestService) {
|
||||
this.requestService = requestService;
|
||||
}
|
||||
|
||||
public collectDefaultSuggestions(resource: string, result: ISuggestionsCollector): Thenable<any> {
|
||||
if (this.isPackageJSONFile(resource)) {
|
||||
let defaultValue = {
|
||||
'name': '{{name}}',
|
||||
'description': '{{description}}',
|
||||
'author': '{{author}}',
|
||||
'version': '{{1.0.0}}',
|
||||
'main': '{{pathToMain}}',
|
||||
'dependencies': {}
|
||||
};
|
||||
result.add({ kind: CompletionItemKind.Module, label: localize('json.package.default', 'Default package.json'), insertText: JSON.stringify(defaultValue, null, '\t'), documentation: '' });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public collectPropertySuggestions(resource: string, location: JSONLocation, currentWord: string, addValue: boolean, isLast:boolean, result: ISuggestionsCollector) : Thenable<any> {
|
||||
if (this.isPackageJSONFile(resource) && (location.matches(['dependencies']) || location.matches(['devDependencies']) || location.matches(['optionalDependencies']) || location.matches(['peerDependencies']))) {
|
||||
let queryUrl : string;
|
||||
if (currentWord.length > 0) {
|
||||
queryUrl = 'https://skimdb.npmjs.com/registry/_design/app/_view/browseAll?group_level=1&limit=' + LIMIT + '&start_key=%5B%22' + encodeURIComponent(currentWord) + '%22%5D&end_key=%5B%22'+ encodeURIComponent(currentWord + 'z') + '%22,%7B%7D%5D';
|
||||
|
||||
return this.requestService({
|
||||
url : queryUrl
|
||||
}).then((success) => {
|
||||
if (success.status === 200) {
|
||||
try {
|
||||
let obj = JSON.parse(success.responseText);
|
||||
if (obj && Array.isArray(obj.rows)) {
|
||||
let results = <{ key: string[]; }[]> obj.rows;
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let keys = results[i].key;
|
||||
if (Array.isArray(keys) && keys.length > 0) {
|
||||
let name = keys[0];
|
||||
let insertText = JSON.stringify(name);
|
||||
if (addValue) {
|
||||
insertText += ': "{{*}}"';
|
||||
if (!isLast) {
|
||||
insertText += ',';
|
||||
}
|
||||
}
|
||||
result.add({ kind: CompletionItemKind.Property, label: name, insertText: insertText, documentation: '' });
|
||||
}
|
||||
}
|
||||
if (results.length === LIMIT) {
|
||||
result.setAsIncomplete();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
} else {
|
||||
result.error(localize('json.npm.error.repoaccess', 'Request to the NPM repository failed: {0}', success.responseText));
|
||||
return 0;
|
||||
}
|
||||
}, (error) => {
|
||||
result.error(localize('json.npm.error.repoaccess', 'Request to the NPM repository failed: {0}', error.responseText));
|
||||
return 0;
|
||||
});
|
||||
} else {
|
||||
this.mostDependedOn.forEach((name) => {
|
||||
let insertText = JSON.stringify(name);
|
||||
if (addValue) {
|
||||
insertText += ': "{{*}}"';
|
||||
if (!isLast) {
|
||||
insertText += ',';
|
||||
}
|
||||
}
|
||||
result.add({ kind: CompletionItemKind.Property, label: name, insertText: insertText, documentation: '' });
|
||||
});
|
||||
result.setAsIncomplete();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public collectValueSuggestions(resource: string, location: JSONLocation, currentKey: string, result: ISuggestionsCollector): Thenable<any> {
|
||||
if (this.isPackageJSONFile(resource) && (location.matches(['dependencies']) || location.matches(['devDependencies']) || location.matches(['optionalDependencies']) || location.matches(['peerDependencies']))) {
|
||||
let queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(currentKey) + '/latest';
|
||||
|
||||
return this.requestService({
|
||||
url : queryUrl
|
||||
}).then((success) => {
|
||||
try {
|
||||
let obj = JSON.parse(success.responseText);
|
||||
if (obj && obj.version) {
|
||||
let version = obj.version;
|
||||
let name = JSON.stringify(version);
|
||||
result.add({ kind: CompletionItemKind.Class, label: name, insertText: name, documentation: localize('json.npm.latestversion', 'The currently latest version of the package') });
|
||||
name = JSON.stringify('^' + version);
|
||||
result.add({ kind: CompletionItemKind.Class, label: name, insertText: name, documentation: localize('json.npm.majorversion', 'Matches the most recent major version (1.x.x)') });
|
||||
name = JSON.stringify('~' + version);
|
||||
result.add({ kind: CompletionItemKind.Class, label: name, insertText: name, documentation: localize('json.npm.minorversion', 'Matches the most recent minor version (1.2.x)') });
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return 0;
|
||||
}, (error) => {
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public getInfoContribution(resource: string, location: JSONLocation): Thenable<MarkedString[]> {
|
||||
if (this.isPackageJSONFile(resource) && (location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) {
|
||||
let pack = location.getSegments()[location.getSegments().length - 1];
|
||||
|
||||
let htmlContent : MarkedString[] = [];
|
||||
htmlContent.push(localize('json.npm.package.hover', '{0}', pack));
|
||||
|
||||
let queryUrl = 'http://registry.npmjs.org/' + encodeURIComponent(pack) + '/latest';
|
||||
|
||||
return this.requestService({
|
||||
url : queryUrl
|
||||
}).then((success) => {
|
||||
try {
|
||||
let obj = JSON.parse(success.responseText);
|
||||
if (obj) {
|
||||
if (obj.description) {
|
||||
htmlContent.push(obj.description);
|
||||
}
|
||||
if (obj.version) {
|
||||
htmlContent.push(localize('json.npm.version.hover', 'Latest version: {0}', obj.version));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
return htmlContent;
|
||||
}, (error) => {
|
||||
return htmlContent;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import {MarkedString, CompletionItemKind, CompletionItem} from 'vscode-languageserver';
|
||||
import Strings = require('../utils/strings');
|
||||
import {IXHRResponse, getErrorStatusDescription} from '../utils/httpRequest';
|
||||
import {XHRResponse, getErrorStatusDescription} from 'request-light';
|
||||
import {IJSONWorkerContribution, ISuggestionsCollector} from '../jsonContributions';
|
||||
import {IRequestService} from '../jsonSchemaService';
|
||||
import {JSONLocation} from '../jsonLocation';
|
||||
|
@ -131,7 +131,7 @@ export class ProjectJSONContribution implements IJSONWorkerContribution {
|
|||
}
|
||||
}
|
||||
return Promise.reject<T>(localize('json.nugget.error.indexaccess', 'Request to {0} failed: {1}', url, success.responseText));
|
||||
}, (error: IXHRResponse) => {
|
||||
}, (error: XHRResponse) => {
|
||||
return Promise.reject<T>(localize('json.nugget.error.access', 'Request to {0} failed: {1}', url, getErrorStatusDescription(error.status)));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
DocumentRangeFormattingParams, NotificationType, RequestType
|
||||
} from 'vscode-languageserver';
|
||||
|
||||
import {xhr, IXHROptions, IXHRResponse, configure as configureHttpRequests} from './utils/httpRequest';
|
||||
import {xhr, XHROptions, XHRResponse, configure as configureHttpRequests} from 'request-light';
|
||||
import path = require('path');
|
||||
import fs = require('fs');
|
||||
import URI from './utils/uri';
|
||||
|
@ -22,12 +22,10 @@ import {JSONSchemaService, ISchemaAssociations} from './jsonSchemaService';
|
|||
import {parse as parseJSON, ObjectASTNode, JSONDocument} from './jsonParser';
|
||||
import {JSONCompletion} from './jsonCompletion';
|
||||
import {JSONHover} from './jsonHover';
|
||||
import {IJSONSchema} from './json-toolbox/jsonSchema';
|
||||
import {IJSONSchema} from './jsonSchema';
|
||||
import {JSONDocumentSymbols} from './jsonDocumentSymbols';
|
||||
import {format as formatJSON} from './jsonFormatter';
|
||||
import {schemaContributions} from './configuration';
|
||||
import {BowerJSONContribution} from './jsoncontributions/bowerJSONContribution';
|
||||
import {PackageJSONContribution} from './jsoncontributions/packageJSONContribution';
|
||||
import {ProjectJSONContribution} from './jsoncontributions/projectJSONContribution';
|
||||
import {GlobPatternContribution} from './jsoncontributions/globPatternContribution';
|
||||
import {FileAssociationContribution} from './jsoncontributions/fileAssociationContribution';
|
||||
|
@ -94,10 +92,10 @@ let telemetry = {
|
|||
}
|
||||
};
|
||||
|
||||
let request = (options: IXHROptions): Thenable<IXHRResponse> => {
|
||||
let request = (options: XHROptions): Thenable<XHRResponse> => {
|
||||
if (Strings.startsWith(options.url, 'file://')) {
|
||||
let fsPath = URI.parse(options.url).fsPath;
|
||||
return new Promise<IXHRResponse>((c, e) => {
|
||||
return new Promise<XHRResponse>((c, e) => {
|
||||
fs.readFile(fsPath, 'UTF-8', (err, result) => {
|
||||
err ? e({ responseText: '', status: 404 }) : c({ responseText: result.toString(), status: 200 });
|
||||
});
|
||||
|
@ -120,8 +118,6 @@ let request = (options: IXHROptions): Thenable<IXHRResponse> => {
|
|||
|
||||
let contributions = [
|
||||
new ProjectJSONContribution(request),
|
||||
new PackageJSONContribution(request),
|
||||
new BowerJSONContribution(request),
|
||||
new GlobPatternContribution(),
|
||||
filesAssociationContribution
|
||||
];
|
||||
|
|
|
@ -7,17 +7,17 @@
|
|||
import assert = require('assert');
|
||||
import Parser = require('../jsonParser');
|
||||
import SchemaService = require('../jsonSchemaService');
|
||||
import JsonSchema = require('../json-toolbox/jsonSchema');
|
||||
import JsonSchema = require('../jsonSchema');
|
||||
import {JSONCompletion} from '../jsonCompletion';
|
||||
import {IXHROptions, IXHRResponse} from '../utils/httpRequest';
|
||||
import {XHROptions, XHRResponse} from 'request-light';
|
||||
|
||||
import {CompletionItem, CompletionItemKind, CompletionOptions, ITextDocument, TextDocumentIdentifier, TextDocumentPosition, Range, Position, TextEdit} from 'vscode-languageserver';
|
||||
import {applyEdits} from './textEditSupport';
|
||||
|
||||
suite('JSON Completion', () => {
|
||||
|
||||
var requestService = function(options: IXHROptions): Promise<IXHRResponse> {
|
||||
return Promise.reject<IXHRResponse>({ responseText: '', status: 404 });
|
||||
var requestService = function(options: XHROptions): Promise<XHRResponse> {
|
||||
return Promise.reject<XHRResponse>({ responseText: '', status: 404 });
|
||||
}
|
||||
|
||||
var assertSuggestion = function(completions: CompletionItem[], label: string, documentation?: string, document?: ITextDocument, resultText?: string) {
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
import assert = require('assert');
|
||||
import Parser = require('../jsonParser');
|
||||
import SchemaService = require('../jsonSchemaService');
|
||||
import JsonSchema = require('../json-toolbox/jsonSchema');
|
||||
import JsonSchema = require('../jsonSchema');
|
||||
import {JSONCompletion} from '../jsonCompletion';
|
||||
import {IXHROptions, IXHRResponse} from '../utils/httpRequest';
|
||||
import {JSONDocumentSymbols} from '../jsonDocumentSymbols';
|
||||
|
||||
import {SymbolInformation, SymbolKind, TextDocumentIdentifier, ITextDocument, TextDocumentPosition, Range, Position, TextEdit} from 'vscode-languageserver';
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import Json = require('../json-toolbox/json');
|
||||
import Json = require('jsonc-parser');
|
||||
import {ITextDocument, DocumentFormattingParams, Range, Position, FormattingOptions, TextEdit} from 'vscode-languageserver';
|
||||
import Formatter = require('../jsonFormatter');
|
||||
import assert = require('assert');
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
import assert = require('assert');
|
||||
import Parser = require('../jsonParser');
|
||||
import SchemaService = require('../jsonSchemaService');
|
||||
import JsonSchema = require('../json-toolbox/jsonSchema');
|
||||
import JsonSchema = require('../jsonSchema');
|
||||
import {JSONCompletion} from '../jsonCompletion';
|
||||
import {IXHROptions, IXHRResponse} from '../utils/httpRequest';
|
||||
import {XHROptions, XHRResponse} from 'request-light';
|
||||
import {JSONHover} from '../jsonHover';
|
||||
|
||||
import {Hover, ITextDocument, TextDocumentIdentifier, TextDocumentPosition, Range, Position, TextEdit} from 'vscode-languageserver';
|
||||
|
@ -30,8 +30,8 @@ suite('JSON Hover', () => {
|
|||
return hoverProvider.doHover(document, textDocumentLocation, jsonDoc);
|
||||
}
|
||||
|
||||
var requestService = function(options: IXHROptions): Promise<IXHRResponse> {
|
||||
return Promise.reject<IXHRResponse>({ responseText: '', status: 404 });
|
||||
var requestService = function(options: XHROptions): Promise<XHRResponse> {
|
||||
return Promise.reject<XHRResponse>({ responseText: '', status: 404 });
|
||||
}
|
||||
|
||||
test('Simple schema', function(testDone) {
|
||||
|
|
|
@ -1,226 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { SyntaxKind, createScanner, parse, getLocation, ParseErrorCode, getParseErrorMessage } from '../json-toolbox/json';
|
||||
|
||||
function assertKinds(text:string, ...kinds:SyntaxKind[]):void {
|
||||
var _json = createScanner(text);
|
||||
var kind: SyntaxKind;
|
||||
while((kind = _json.scan()) !== SyntaxKind.EOF) {
|
||||
assert.equal(kind, kinds.shift());
|
||||
}
|
||||
assert.equal(kinds.length, 0);
|
||||
}
|
||||
|
||||
|
||||
function assertValidParse(input:string, expected:any) : void {
|
||||
var errors : {error: ParseErrorCode}[] = [];
|
||||
var actual = parse(input, errors);
|
||||
|
||||
if (errors.length !== 0) {
|
||||
assert(false, getParseErrorMessage(errors[0].error));
|
||||
}
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
function assertInvalidParse(input:string, expected:any) : void {
|
||||
var errors : {error: ParseErrorCode}[] = [];
|
||||
var actual = parse(input, errors);
|
||||
|
||||
assert(errors.length > 0);
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
function assertLocation(input:string, expectedSegments: string[], expectedNodeType: string, expectedCompleteProperty: boolean) : void {
|
||||
var errors : {error: ParseErrorCode}[] = [];
|
||||
var offset = input.indexOf('|');
|
||||
input = input.substring(0, offset) + input.substring(offset+1, input.length);
|
||||
var actual = getLocation(input, offset);
|
||||
assert(actual);
|
||||
assert.deepEqual(actual.segments, expectedSegments, input);
|
||||
assert.equal(actual.previousNode && actual.previousNode.type, expectedNodeType, input);
|
||||
assert.equal(actual.completeProperty, expectedCompleteProperty, input);
|
||||
}
|
||||
|
||||
suite('JSON', () => {
|
||||
test('tokens', () => {
|
||||
assertKinds('{', SyntaxKind.OpenBraceToken);
|
||||
assertKinds('}', SyntaxKind.CloseBraceToken);
|
||||
assertKinds('[', SyntaxKind.OpenBracketToken);
|
||||
assertKinds(']', SyntaxKind.CloseBracketToken);
|
||||
assertKinds(':', SyntaxKind.ColonToken);
|
||||
assertKinds(',', SyntaxKind.CommaToken);
|
||||
});
|
||||
|
||||
test('comments', () => {
|
||||
assertKinds('// this is a comment', SyntaxKind.LineCommentTrivia);
|
||||
assertKinds('// this is a comment\n', SyntaxKind.LineCommentTrivia, SyntaxKind.LineBreakTrivia);
|
||||
assertKinds('/* this is a comment*/', SyntaxKind.BlockCommentTrivia);
|
||||
assertKinds('/* this is a \r\ncomment*/', SyntaxKind.BlockCommentTrivia);
|
||||
assertKinds('/* this is a \ncomment*/', SyntaxKind.BlockCommentTrivia);
|
||||
|
||||
// unexpected end
|
||||
assertKinds('/* this is a', SyntaxKind.BlockCommentTrivia);
|
||||
assertKinds('/* this is a \ncomment', SyntaxKind.BlockCommentTrivia);
|
||||
|
||||
// broken comment
|
||||
assertKinds('/ ttt', SyntaxKind.Unknown, SyntaxKind.Trivia, SyntaxKind.Unknown);
|
||||
});
|
||||
|
||||
test('strings', () => {
|
||||
assertKinds('"test"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\""', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\/"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\b"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\f"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\n"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\r"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\t"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\v"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\u88ff"', SyntaxKind.StringLiteral);
|
||||
|
||||
// unexpected end
|
||||
assertKinds('"test', SyntaxKind.StringLiteral);
|
||||
assertKinds('"test\n"', SyntaxKind.StringLiteral, SyntaxKind.LineBreakTrivia, SyntaxKind.StringLiteral);
|
||||
});
|
||||
|
||||
test('numbers', () => {
|
||||
assertKinds('0', SyntaxKind.NumericLiteral);
|
||||
assertKinds('0.1', SyntaxKind.NumericLiteral);
|
||||
assertKinds('-0.1', SyntaxKind.NumericLiteral);
|
||||
assertKinds('-1', SyntaxKind.NumericLiteral);
|
||||
assertKinds('1', SyntaxKind.NumericLiteral);
|
||||
assertKinds('123456789', SyntaxKind.NumericLiteral);
|
||||
assertKinds('10', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90E+123', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90e+123', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90e-123', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90E-123', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90E123', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90e123', SyntaxKind.NumericLiteral);
|
||||
|
||||
// zero handling
|
||||
assertKinds('01', SyntaxKind.NumericLiteral, SyntaxKind.NumericLiteral);
|
||||
assertKinds('-01', SyntaxKind.NumericLiteral, SyntaxKind.NumericLiteral);
|
||||
|
||||
// unexpected end
|
||||
assertKinds('-', SyntaxKind.Unknown);
|
||||
assertKinds('.0', SyntaxKind.Unknown);
|
||||
});
|
||||
|
||||
test('keywords: true, false, null', () => {
|
||||
assertKinds('true', SyntaxKind.TrueKeyword);
|
||||
assertKinds('false', SyntaxKind.FalseKeyword);
|
||||
assertKinds('null', SyntaxKind.NullKeyword);
|
||||
|
||||
|
||||
assertKinds('true false null',
|
||||
SyntaxKind.TrueKeyword,
|
||||
SyntaxKind.Trivia,
|
||||
SyntaxKind.FalseKeyword,
|
||||
SyntaxKind.Trivia,
|
||||
SyntaxKind.NullKeyword);
|
||||
|
||||
// invalid words
|
||||
assertKinds('nulllll', SyntaxKind.Unknown);
|
||||
assertKinds('True', SyntaxKind.Unknown);
|
||||
assertKinds('foo-bar', SyntaxKind.Unknown);
|
||||
assertKinds('foo bar', SyntaxKind.Unknown, SyntaxKind.Trivia, SyntaxKind.Unknown);
|
||||
});
|
||||
|
||||
test('trivia', () => {
|
||||
assertKinds(' ', SyntaxKind.Trivia);
|
||||
assertKinds(' \t ', SyntaxKind.Trivia);
|
||||
assertKinds(' \t \n \t ', SyntaxKind.Trivia, SyntaxKind.LineBreakTrivia, SyntaxKind.Trivia);
|
||||
assertKinds('\r\n', SyntaxKind.LineBreakTrivia);
|
||||
assertKinds('\r', SyntaxKind.LineBreakTrivia);
|
||||
assertKinds('\n', SyntaxKind.LineBreakTrivia);
|
||||
assertKinds('\n\r', SyntaxKind.LineBreakTrivia, SyntaxKind.LineBreakTrivia);
|
||||
assertKinds('\n \n', SyntaxKind.LineBreakTrivia, SyntaxKind.Trivia, SyntaxKind.LineBreakTrivia);
|
||||
});
|
||||
|
||||
test('parse: literals', () => {
|
||||
|
||||
assertValidParse('true', true);
|
||||
assertValidParse('false', false);
|
||||
assertValidParse('null', null);
|
||||
assertValidParse('"foo"', 'foo');
|
||||
assertValidParse('"\\"-\\\\-\\/-\\b-\\f-\\n-\\r-\\t"', '"-\\-/-\b-\f-\n-\r-\t');
|
||||
assertValidParse('"\\u00DC"', 'Ü');
|
||||
assertValidParse('9', 9);
|
||||
assertValidParse('-9', -9);
|
||||
assertValidParse('0.129', 0.129);
|
||||
assertValidParse('23e3', 23e3);
|
||||
assertValidParse('1.2E+3', 1.2E+3);
|
||||
assertValidParse('1.2E-3', 1.2E-3);
|
||||
|
||||
});
|
||||
|
||||
test('parse: objects', () => {
|
||||
assertValidParse('{}', {});
|
||||
assertValidParse('{ "foo": true }', { foo: true });
|
||||
assertValidParse('{ "bar": 8, "xoo": "foo" }', { bar: 8, xoo: 'foo' });
|
||||
assertValidParse('{ "hello": [], "world": {} }', { hello: [], world: {} });
|
||||
assertValidParse('{ "a": false, "b": true, "c": [ 7.4 ] }', { a: false, b: true, c: [ 7.4 ]});
|
||||
assertValidParse('{ "lineComment": "//", "blockComment": ["/*", "*/"], "brackets": [ ["{", "}"], ["[", "]"], ["(", ")"] ] }', { lineComment: '//', blockComment: ["/*", "*/"], brackets: [ ["{", "}"], ["[", "]"], ["(", ")"] ] });
|
||||
assertValidParse('{ "hello": [], "world": {} }', { hello: [], world: {} });
|
||||
assertValidParse('{ "hello": { "again": { "inside": 5 }, "world": 1 }}', { hello: { again: { inside: 5 }, world: 1 }});
|
||||
});
|
||||
|
||||
test('parse: arrays', () => {
|
||||
assertValidParse('[]', []);
|
||||
assertValidParse('[ [], [ [] ]]', [[], [[]]]);
|
||||
assertValidParse('[ 1, 2, 3 ]', [ 1, 2, 3 ]);
|
||||
assertValidParse('[ { "a": null } ]', [ { a: null } ]);
|
||||
});
|
||||
|
||||
test('parse: objects with errors', () => {
|
||||
assertInvalidParse('{,}', {});
|
||||
assertInvalidParse('{ "foo": true, }', { foo: true });
|
||||
assertInvalidParse('{ "bar": 8 "xoo": "foo" }', { bar: 8, xoo: 'foo' });
|
||||
assertInvalidParse('{ ,"bar": 8 }', { bar: 8 });
|
||||
assertInvalidParse('{ ,"bar": 8, "foo" }', { bar: 8 });
|
||||
assertInvalidParse('{ "bar": 8, "foo": }', { bar: 8 });
|
||||
assertInvalidParse('{ 8, "foo": 9 }', { foo: 9 });
|
||||
});
|
||||
|
||||
test('parse: array with errors', () => {
|
||||
assertInvalidParse('[,]', []);
|
||||
assertInvalidParse('[ 1, 2, ]', [ 1, 2]);
|
||||
assertInvalidParse('[ 1 2, 3 ]', [ 1, 2, 3 ]);
|
||||
assertInvalidParse('[ ,1, 2, 3 ]', [ 1, 2, 3 ]);
|
||||
assertInvalidParse('[ ,1, 2, 3, ]', [ 1, 2, 3 ]);
|
||||
});
|
||||
|
||||
test('location: properties', () => {
|
||||
assertLocation('|{ "foo": "bar" }', [], void 0, false);
|
||||
assertLocation('{| "foo": "bar" }', [], void 0, true);
|
||||
assertLocation('{ |"foo": "bar" }', ["foo" ], "property", true);
|
||||
assertLocation('{ "foo|": "bar" }', [ "foo" ], "property", true);
|
||||
assertLocation('{ "foo"|: "bar" }', ["foo" ], "property", true);
|
||||
assertLocation('{ "foo": "bar"| }', ["foo" ], "string", false);
|
||||
assertLocation('{ "foo":| "bar" }', ["foo" ], void 0, false);
|
||||
assertLocation('{ "foo": {"bar|": 1, "car": 2 } }', ["foo", "bar" ], "property", true);
|
||||
assertLocation('{ "foo": {"bar": 1|, "car": 3 } }', ["foo", "bar" ], "number", false);
|
||||
assertLocation('{ "foo": {"bar": 1,| "car": 4 } }', ["foo"], void 0, true);
|
||||
assertLocation('{ "foo": {"bar": 1, "ca|r": 5 } }', ["foo", "car" ], "property", true);
|
||||
assertLocation('{ "foo": {"bar": 1, "car": 6| } }', ["foo", "car" ], "number", false);
|
||||
assertLocation('{ "foo": {"bar": 1, "car": 7 }| }', ["foo"], void 0, false);
|
||||
assertLocation('{ "foo": {"bar": 1, "car": 8 },| "goo": {} }', [], void 0, true);
|
||||
assertLocation('{ "foo": {"bar": 1, "car": 9 }, "go|o": {} }', ["goo" ], "property", true);
|
||||
});
|
||||
|
||||
test('location: arrays', () => {
|
||||
assertLocation('|["foo", null ]', [], void 0, false);
|
||||
assertLocation('[|"foo", null ]', ["[0]"], "string", false);
|
||||
assertLocation('["foo"|, null ]', ["[0]"], "string", false);
|
||||
assertLocation('["foo",| null ]', ["[1]"], void 0, false);
|
||||
assertLocation('["foo", |null ]', ["[1]"], "null", false);
|
||||
assertLocation('["foo", null,| ]', ["[2]"], void 0, false);
|
||||
});
|
||||
});
|
|
@ -7,7 +7,7 @@
|
|||
import assert = require('assert');
|
||||
import Parser = require('../jsonParser');
|
||||
import SchemaService = require('../jsonSchemaService');
|
||||
import JsonSchema = require('../json-toolbox/jsonSchema');
|
||||
import JsonSchema = require('../jsonSchema');
|
||||
|
||||
suite('JSON Parser', () => {
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
|
||||
import assert = require('assert');
|
||||
import SchemaService = require('../jsonSchemaService');
|
||||
import JsonSchema = require('../json-toolbox/jsonSchema');
|
||||
import Json = require('../json-toolbox/json');
|
||||
import JsonSchema = require('../jsonSchema');
|
||||
import Json = require('jsonc-parser');
|
||||
import Parser = require('../jsonParser');
|
||||
import fs = require('fs');
|
||||
import path = require('path');
|
||||
import {IXHROptions, IXHRResponse} from '../utils/httpRequest';
|
||||
import {XHROptions, XHRResponse} from 'request-light';
|
||||
|
||||
|
||||
suite('JSON Schema', () => {
|
||||
|
@ -26,21 +26,21 @@ suite('JSON Schema', () => {
|
|||
'http://schema.management.azure.com/schemas/2015-08-01/Microsoft.Compute.json': 'Microsoft.Compute.json'
|
||||
}
|
||||
|
||||
var requestServiceMock = function (options:IXHROptions) : Promise<IXHRResponse> {
|
||||
var requestServiceMock = function (options:XHROptions) : Promise<XHRResponse> {
|
||||
var uri = options.url;
|
||||
if (uri.length && uri[uri.length - 1] === '#') {
|
||||
uri = uri.substr(0, uri.length - 1);
|
||||
}
|
||||
var fileName = fixureDocuments[uri];
|
||||
if (fileName) {
|
||||
return new Promise<IXHRResponse>((c, e) => {
|
||||
return new Promise<XHRResponse>((c, e) => {
|
||||
var fixturePath = path.join(__dirname, '../../src/test/fixtures', fileName);
|
||||
fs.readFile(fixturePath, 'UTF-8', (err, result) => {
|
||||
err ? e({ responseText: '', status: 404 }) : c({ responseText: result.toString(), status: 200 })
|
||||
});
|
||||
});
|
||||
}
|
||||
return Promise.reject<IXHRResponse>({ responseText: '', status: 404 });
|
||||
return Promise.reject<XHRResponse>({ responseText: '', status: 404 });
|
||||
}
|
||||
|
||||
test('Resolving $refs', function(testDone) {
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module 'https-proxy-agent' {
|
||||
|
||||
import * as tls from 'tls';
|
||||
|
||||
interface IHttpsProxyAgentOptions extends tls.ConnectionOptions {
|
||||
host: string;
|
||||
port: number;
|
||||
auth?: string;
|
||||
secureProxy?: boolean;
|
||||
secureEndpoint?: boolean;
|
||||
}
|
||||
|
||||
class HttpsProxyAgent {
|
||||
constructor(proxy: string);
|
||||
constructor(opts: IHttpsProxyAgentOptions);
|
||||
}
|
||||
|
||||
export = HttpsProxyAgent;
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { parse as parseUrl } from 'url';
|
||||
import { getProxyAgent } from './proxy';
|
||||
import https = require('https');
|
||||
import http = require('http');
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export interface IXHROptions {
|
||||
type?: string;
|
||||
url?: string;
|
||||
user?: string;
|
||||
password?: string;
|
||||
headers?: any;
|
||||
timeout?: number;
|
||||
data?: any;
|
||||
agent?: any;
|
||||
strictSSL?: boolean;
|
||||
responseType?: string;
|
||||
followRedirects?: number;
|
||||
}
|
||||
|
||||
export interface IXHRResponse {
|
||||
responseText: string;
|
||||
status: number;
|
||||
}
|
||||
|
||||
let proxyUrl: string = null;
|
||||
let strictSSL: boolean = true;
|
||||
|
||||
function assign(destination: any, ...sources: any[]): any {
|
||||
sources.forEach(source => Object.keys(source).forEach((key) => destination[key] = source[key]));
|
||||
return destination;
|
||||
}
|
||||
|
||||
export function configure(_proxyUrl: string, _strictSSL: boolean): void {
|
||||
proxyUrl = _proxyUrl;
|
||||
strictSSL = _strictSSL;
|
||||
}
|
||||
|
||||
export function xhr(options: IXHROptions): Promise<IXHRResponse> {
|
||||
const agent = getProxyAgent(options.url, { proxyUrl, strictSSL });
|
||||
options = assign({}, options);
|
||||
options = assign(options, { agent, strictSSL });
|
||||
if (typeof options.followRedirects !== 'number') {
|
||||
options.followRedirects = 5;
|
||||
}
|
||||
|
||||
return request(options).then(result => new Promise<IXHRResponse>((c, e) => {
|
||||
let res = result.res;
|
||||
let data: string[] = [];
|
||||
res.on('data', c => data.push(c));
|
||||
res.on('end', () => {
|
||||
if (options.followRedirects > 0 && (res.statusCode >= 300 && res.statusCode <= 303 || res.statusCode === 307)) {
|
||||
let location = res.headers['location'];
|
||||
if (location) {
|
||||
let newOptions = {
|
||||
type: options.type, url: location, user: options.user, password: options.password, responseType: options.responseType, headers: options.headers,
|
||||
timeout: options.timeout, followRedirects: options.followRedirects - 1, data: options.data
|
||||
};
|
||||
xhr(newOptions).then(c, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let response: IXHRResponse = {
|
||||
responseText: data.join(''),
|
||||
status: res.statusCode
|
||||
};
|
||||
|
||||
if ((res.statusCode >= 200 && res.statusCode < 300) || res.statusCode === 1223) {
|
||||
c(response);
|
||||
} else {
|
||||
e(response);
|
||||
}
|
||||
});
|
||||
}), err => {
|
||||
let message: string;
|
||||
|
||||
if (agent) {
|
||||
message = 'Unable to to connect to ' + options.url + ' through a proxy . Error: ' + err.message;
|
||||
} else {
|
||||
message = 'Unable to to connect to ' + options.url + '. Error: ' + err.message;
|
||||
}
|
||||
|
||||
return Promise.reject<IXHRResponse>({
|
||||
responseText: message,
|
||||
status: 404
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
interface IRequestResult {
|
||||
req: http.ClientRequest;
|
||||
res: http.ClientResponse;
|
||||
}
|
||||
|
||||
function request(options: IXHROptions): Promise<IRequestResult> {
|
||||
let req: http.ClientRequest;
|
||||
|
||||
return new Promise<IRequestResult>((c, e) => {
|
||||
let endpoint = parseUrl(options.url);
|
||||
|
||||
let opts: https.RequestOptions = {
|
||||
hostname: endpoint.hostname,
|
||||
port: endpoint.port ? parseInt(endpoint.port) : (endpoint.protocol === 'https:' ? 443 : 80),
|
||||
path: endpoint.path,
|
||||
method: options.type || 'GET',
|
||||
headers: options.headers,
|
||||
agent: options.agent,
|
||||
rejectUnauthorized: (typeof options.strictSSL === 'boolean') ? options.strictSSL : true
|
||||
};
|
||||
|
||||
if (options.user && options.password) {
|
||||
opts.auth = options.user + ':' + options.password;
|
||||
}
|
||||
|
||||
let protocol = endpoint.protocol === 'https:' ? https : http;
|
||||
req = protocol.request(opts, (res: http.ClientResponse) => {
|
||||
if (res.statusCode >= 300 && res.statusCode < 400 && options.followRedirects && options.followRedirects > 0 && res.headers['location']) {
|
||||
c(<any> request(assign({}, options, {
|
||||
url: res.headers['location'],
|
||||
followRedirects: options.followRedirects - 1
|
||||
})));
|
||||
} else {
|
||||
c({ req, res });
|
||||
}
|
||||
});
|
||||
req.on('error', e);
|
||||
|
||||
if (options.timeout) {
|
||||
req.setTimeout(options.timeout);
|
||||
}
|
||||
if (options.data) {
|
||||
req.write(options.data);
|
||||
}
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
export function getErrorStatusDescription(status: number) : string {
|
||||
if (status < 400) {
|
||||
return void 0;
|
||||
}
|
||||
switch (status) {
|
||||
case 400: return localize('status.400', 'Bad request. The request cannot be fulfilled due to bad syntax.');
|
||||
case 401: return localize('status.401', 'Unauthorized. The server is refusing to respond.');
|
||||
case 403: return localize('status.403', 'Forbidden. The server is refusing to respond.');
|
||||
case 404: return localize('status.404', 'Not Found. The requested location could not be found.');
|
||||
case 405: return localize('status.405', 'Method not allowed. A request was made using a request method not supported by that location.');
|
||||
case 406: return localize('status.406', 'Not Acceptable. The server can only generate a response that is not accepted by the client.');
|
||||
case 407: return localize('status.407', 'Proxy Authentication Required. The client must first authenticate itself with the proxy.');
|
||||
case 408: return localize('status.408', 'Request Timeout. The server timed out waiting for the request.');
|
||||
case 409: return localize('status.409', 'Conflict. The request could not be completed because of a conflict in the request.');
|
||||
case 410: return localize('status.410', 'Gone. The requested page is no longer available.');
|
||||
case 411: return localize('status.411', 'Length Required. The "Content-Length" is not defined.');
|
||||
case 412: return localize('status.412', 'Precondition Failed. The precondition given in the request evaluated to false by the server.');
|
||||
case 413: return localize('status.413', 'Request Entity Too Large. The server will not accept the request, because the request entity is too large.');
|
||||
case 414: return localize('status.414', 'Request-URI Too Long. The server will not accept the request, because the URL is too long.');
|
||||
case 415: return localize('status.415', 'Unsupported Media Type. The server will not accept the request, because the media type is not supported.');
|
||||
case 500: return localize('status.500', 'Internal Server Error.');
|
||||
case 501: return localize('status.501', 'Not Implemented. The server either does not recognize the request method, or it lacks the ability to fulfill the request.');
|
||||
case 503: return localize('status.503', 'Service Unavailable. The server is currently unavailable (overloaded or down).');
|
||||
default: return localize('status.416', 'HTTP status code {0}', status);
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
export function localize2(key: string, message: string, ...formatArgs: any[]) {
|
||||
if (formatArgs.length > 0) {
|
||||
return message.replace(/\{(\d+)\}/g, function(match, rest) {
|
||||
var index = rest[0];
|
||||
return typeof formatArgs[index] !== 'undefined' ? formatArgs[index] : match;
|
||||
});
|
||||
}
|
||||
return message;
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { Url, parse as parseUrl } from 'url';
|
||||
import HttpProxyAgent = require('http-proxy-agent');
|
||||
import HttpsProxyAgent = require('https-proxy-agent');
|
||||
|
||||
function getSystemProxyURI(requestURL: Url): string {
|
||||
if (requestURL.protocol === 'http:') {
|
||||
return process.env.HTTP_PROXY || process.env.http_proxy || null;
|
||||
} else if (requestURL.protocol === 'https:') {
|
||||
return process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy || null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
proxyUrl?: string;
|
||||
strictSSL?: boolean;
|
||||
}
|
||||
|
||||
export function getProxyAgent(rawRequestURL: string, options: IOptions = {}): any {
|
||||
const requestURL = parseUrl(rawRequestURL);
|
||||
const proxyURL = options.proxyUrl || getSystemProxyURI(requestURL);
|
||||
|
||||
if (!proxyURL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const proxyEndpoint = parseUrl(proxyURL);
|
||||
|
||||
if (!/^https?:$/.test(proxyEndpoint.protocol)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const opts = {
|
||||
host: proxyEndpoint.hostname,
|
||||
port: Number(proxyEndpoint.port),
|
||||
auth: proxyEndpoint.auth,
|
||||
rejectUnauthorized: (typeof options.strictSSL === 'boolean') ? options.strictSSL : true
|
||||
};
|
||||
|
||||
return requestURL.protocol === 'http:' ? new HttpProxyAgent(opts) : new HttpsProxyAgent(opts);
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
"scripts": {
|
||||
"test": "mocha",
|
||||
"preinstall": "node build/npm/preinstall.js",
|
||||
"postinstall": "npm --prefix extensions/vscode-api-tests/ install extensions/vscode-api-tests/ && npm --prefix extensions/vscode-colorize-tests/ install extensions/vscode-colorize-tests/ && npm --prefix extensions/json/ install extensions/json/ && npm --prefix extensions/typescript/ install extensions/typescript/ && npm --prefix extensions/php/ install extensions/php/",
|
||||
"postinstall": "npm --prefix extensions/vscode-api-tests/ install extensions/vscode-api-tests/ && npm --prefix extensions/vscode-colorize-tests/ install extensions/vscode-colorize-tests/ && npm --prefix extensions/json/ install extensions/json/ && npm --prefix extensions/typescript/ install extensions/typescript/ && npm --prefix extensions/php/ install extensions/php/ && npm --prefix extensions/javascript/ install extensions/javascript/",
|
||||
"watch": "gulp watch"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
Loading…
Reference in a new issue