Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'
This commit is contained in:
@ -0,0 +1,10 @@
|
||||
.vscode/
|
||||
out/test/
|
||||
out/**/*.js.map
|
||||
src/
|
||||
test/
|
||||
tsconfig.json
|
||||
.gitignore
|
||||
yarn.lock
|
||||
extension.webpack.config.js
|
||||
vscode-json-languageserver-*.tgz
|
34
lib/vscode/extensions/json-language-features/server/.vscode/launch.json
vendored
Normal file
34
lib/vscode/extensions/json-language-features/server/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"version": "0.1.0",
|
||||
// List of configurations. Add new configurations or edit existing ones.
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Attach",
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"port": 6004,
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceFolder}/out/**/*js"],
|
||||
"preLaunchTask": "npm: compile"
|
||||
},
|
||||
{
|
||||
"name": "Unit Tests",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/../../../node_modules/mocha/bin/_mocha",
|
||||
"stopOnEntry": false,
|
||||
"args": [
|
||||
"--timeout",
|
||||
"999999",
|
||||
"--colors"
|
||||
],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"runtimeExecutable": null,
|
||||
"runtimeArgs": [],
|
||||
"env": {},
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceFolder}/out/**/*js"],
|
||||
"preLaunchTask": "npm: compile"
|
||||
}
|
||||
]
|
||||
}
|
20
lib/vscode/extensions/json-language-features/server/.vscode/tasks.json
vendored
Normal file
20
lib/vscode/extensions/json-language-features/server/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "compile",
|
||||
"problemMatcher": "$tsc-watch",
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"reveal": "never"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
241
lib/vscode/extensions/json-language-features/server/README.md
Normal file
241
lib/vscode/extensions/json-language-features/server/README.md
Normal file
@ -0,0 +1,241 @@
|
||||
# VSCode JSON Language Server
|
||||
|
||||
[](https://npmjs.org/package/vscode-json-languageserver)
|
||||
[](https://npmjs.org/package/vscode-json-languageserver)
|
||||
[](https://npmjs.org/package/vscode-json-languageserver)
|
||||
|
||||
The JSON Language server provides language-specific smarts for editing, validating and understanding JSON documents. It runs as a separate executable and implements the [language server protocol](https://microsoft.github.io/language-server-protocol/overview) to be connected by any code editor or IDE.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Server capabilities
|
||||
|
||||
The JSON language server supports requests on documents of language id `json` and `jsonc`.
|
||||
- `json` documents are parsed and validated following the [JSON specification](https://tools.ietf.org/html/rfc7159).
|
||||
- `jsonc` documents additionally accept single line (`//`) and multi-line comments (`/* ... */`). JSONC is a VSCode specific file format, intended for VSCode configuration files, without any aspirations to define a new common file format.
|
||||
|
||||
The server implements the following capabilities of the language server protocol:
|
||||
|
||||
- [Code completion](https://microsoft.github.io/language-server-protocol/specification#textDocument_completion) for JSON properties and values based on the document's [JSON schema](http://json-schema.org/) or based on existing properties and values used at other places in the document. JSON schemas are configured through the server configuration options.
|
||||
- [Hover](https://microsoft.github.io/language-server-protocol/specification#textDocument_hover) for values based on descriptions in the document's [JSON schema](http://json-schema.org/).
|
||||
- [Document Symbols](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) for quick navigation to properties in the document.
|
||||
- [Document Colors](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentColor) for showing color decorators on values representing colors and [Color Presentation](https://microsoft.github.io/language-server-protocol/specification#textDocument_colorPresentation) for color presentation information to support color pickers. The location of colors is defined by the document's [JSON schema](http://json-schema.org/). All values marked with `"format": "color-hex"` (VSCode specific, non-standard JSON Schema extension) are considered color values. The supported color formats are `#rgb[a]` and `#rrggbb[aa]`.
|
||||
- [Code Formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_rangeFormatting) supporting ranges and formatting the whole document.
|
||||
- [Folding Ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange) for all folding ranges in the document.
|
||||
- Semantic Selection for semantic selection for one or multiple cursor positions.
|
||||
- [Goto Definition](https://microsoft.github.io/language-server-protocol/specification#textDocument_definition) for $ref references in JSON schemas
|
||||
- [Diagnostics (Validation)](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics) are pushed for all open documents
|
||||
- syntax errors
|
||||
- structural validation based on the document's [JSON schema](http://json-schema.org/).
|
||||
|
||||
In order to load JSON schemas, the JSON server uses NodeJS `http` and `fs` modules. For all other features, the JSON server only relies on the documents and settings provided by the client through the LSP.
|
||||
|
||||
### Client requirements:
|
||||
|
||||
The JSON language server expects the client to only send requests and notifications for documents of language id `json` and `jsonc`.
|
||||
|
||||
The JSON language server has the following dependencies on the client's capabilities:
|
||||
|
||||
- Code completion requires that the client capability has *snippetSupport*. If not supported by the client, the server will not offer the completion capability.
|
||||
- Formatting support requires the client to support *dynamicRegistration* for *rangeFormatting*. If not supported by the client, the server will not offer the format capability.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Initialization options
|
||||
|
||||
The client can send the following initialization options to the server:
|
||||
|
||||
- `provideFormatter: boolean | undefined`. If defined, the value defines whether the server provides the `documentRangeFormattingProvider` capability on initialization. If undefined, the setting `json.format.enable` is used to determine whether formatting is provided. The formatter will then be registered through dynamic registration. If the client does not support dynamic registration, no formatter will be available.
|
||||
- `handledSchemaProtocols`: The URI schemas handles by the server. See section `Schema configuration` below.
|
||||
- `customCapabilities`: Additional non-LSP client capabilities:
|
||||
- `rangeFormatting: { editLimit: x } }`: For performance reasons, limit the number of edits returned by the range formatter to `x`.
|
||||
|
||||
### Settings
|
||||
|
||||
Clients may send a `workspace/didChangeConfiguration` notification to notify the server of settings changes.
|
||||
The server supports the following settings:
|
||||
|
||||
- http
|
||||
- `proxy`: The URL of the proxy server to use when fetching schema. When undefined or empty, no proxy is used.
|
||||
- `proxyStrictSSL`: Whether the proxy server certificate should be verified against the list of supplied CAs.
|
||||
|
||||
- json
|
||||
- `format`
|
||||
- `enable`: Whether the server should register the formatting support. This option is only applicable if the client supports *dynamicRegistration* for *rangeFormatting* and `initializationOptions.provideFormatter` is not defined.
|
||||
- `schemas`: Configures association of file names to schema URL or schemas and/or associations of schema URL to schema content.
|
||||
- `fileMatch`: an array of file names or paths (separated by `/`). `*` can be used as a wildcard. Exclusion patterns can also be defined and start with '!'. A file matches when there is at least one matching pattern and the last matching pattern is not an exclusion pattern.
|
||||
- `url`: The URL of the schema, optional when also a schema is provided.
|
||||
- `schema`: The schema content.
|
||||
- `resultLimit`: The max number folding ranges and outline symbols to be computed (for performance reasons)
|
||||
|
||||
```json
|
||||
{
|
||||
"http": {
|
||||
"proxy": "",
|
||||
"proxyStrictSSL": true
|
||||
},
|
||||
"json": {
|
||||
"format": {
|
||||
"enable": true
|
||||
},
|
||||
"schemas": [
|
||||
{
|
||||
"fileMatch": [
|
||||
"foo.json",
|
||||
"*.superfoo.json"
|
||||
],
|
||||
"url": "http://json.schemastore.org/foo",
|
||||
"schema": {
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Schema configuration and custom schema content delivery
|
||||
|
||||
[JSON schemas](http://json-schema.org/) are essential for code assist, hovers, color decorators to work and are required for structural validation.
|
||||
|
||||
To find the schema for a given JSON document, the server uses the following mechanisms:
|
||||
- JSON documents can define the schema URL using a `$schema` property
|
||||
- The settings define a schema association based on the documents URL. Settings can either associate a schema URL to a file or path pattern, and they can directly provide a schema.
|
||||
- Additionally, schema associations can also be provided by a custom 'schemaAssociations' configuration call.
|
||||
|
||||
Schemas are identified by URLs. To load the content of a schema, the JSON language server either tries to load from that URI or path itself or delegates to the client.
|
||||
|
||||
The `initializationOptions.handledSchemaProtocols` initialization option defines which URLs are handled by the server. Requests for all other URIs are sent to the client.
|
||||
|
||||
`handledSchemaProtocols` is part of the initialization options and can't be changed while the server is running.
|
||||
|
||||
```ts
|
||||
let clientOptions: LanguageClientOptions = {
|
||||
initializationOptions: {
|
||||
handledSchemaProtocols: ['file'] // language server should only try to load file URLs
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
If `handledSchemaProtocols` is not set, the JSON language server will load the following URLs itself:
|
||||
|
||||
- `http`, `https`: Loaded using NodeJS's HTTP support. Proxies can be configured through the settings.
|
||||
- `file`: Loaded using NodeJS's `fs` support.
|
||||
|
||||
#### Schema content request
|
||||
|
||||
Requests for schemas with URLs not handled by the server are forwarded to the client through an LSP request. This request is a JSON language server-specific, non-standardized, extension to the LSP.
|
||||
|
||||
Request:
|
||||
- method: 'vscode/content'
|
||||
- params: `string` - The schema URL to request.
|
||||
- response: `string` - The content of the schema with the given URL
|
||||
|
||||
#### Schema content change notification
|
||||
|
||||
When the client is aware that a schema content has changed, it will notify the server through a notification. This notification is a JSON language server-specific, non-standardized, extension to the LSP.
|
||||
The server will, as a response, clear the schema content from the cache and reload the schema content when required again.
|
||||
|
||||
#### Schema associations notification
|
||||
|
||||
In addition to the settings, schemas associations can also be provided through a notification from the client to the server. This notification is a JSON language server-specific, non-standardized, extension to the LSP.
|
||||
|
||||
Notification:
|
||||
- method: 'json/schemaAssociations'
|
||||
- params: `ISchemaAssociations` or `ISchemaAssociation[]` defined as follows
|
||||
|
||||
```ts
|
||||
interface ISchemaAssociations {
|
||||
/**
|
||||
* An object where:
|
||||
* - keys are file names or file paths (using `/` as path separator). `*` can be used as a wildcard.
|
||||
* - values are an arrays of schema URIs
|
||||
*/
|
||||
[pattern: string]: string[];
|
||||
}
|
||||
|
||||
interface ISchemaAssociation {
|
||||
/**
|
||||
* The URI of the schema, which is also the identifier of the schema.
|
||||
*/
|
||||
uri: string;
|
||||
|
||||
/**
|
||||
* A list of file path patterns that are associated to the schema. The '*' wildcard can be used. Exclusion patterns starting with '!'.
|
||||
* For example '*.schema.json', 'package.json', '!foo*.schema.json'.
|
||||
* A match succeeds when there is at least one pattern matching and last matching pattern does not start with '!'.
|
||||
*/
|
||||
fileMatch: string[];
|
||||
|
||||
/*
|
||||
* The schema for the given URI.
|
||||
* If no schema is provided, the schema will be fetched with the schema request service (if available).
|
||||
*/
|
||||
schema?: JSONSchema;
|
||||
}
|
||||
|
||||
```
|
||||
`ISchemaAssociations`
|
||||
- keys: a file names or file path (separated by `/`). `*` can be used as a wildcard.
|
||||
- values: An array of schema URLs
|
||||
|
||||
Notification:
|
||||
- method: 'json/schemaContent'
|
||||
- params: `string` the URL of the schema that has changed.
|
||||
|
||||
### Item Limit
|
||||
|
||||
If the setting `resultLimit` is set, the JSON language server will limit the number of folding ranges and document symbols computed.
|
||||
When the limit is reached, a notification `json/resultLimitReached` is sent that can be shown that can be shown to the user.
|
||||
|
||||
Notification:
|
||||
- method: 'json/resultLimitReached'
|
||||
- params: a human readable string to show to the user.
|
||||
|
||||
|
||||
## Try
|
||||
|
||||
The JSON language server is shipped with [Visual Studio Code](https://code.visualstudio.com/) as part of the built-in VSCode extension `json-language-features`. The server is started when the first JSON file is opened. The [VSCode JSON documentation](https://code.visualstudio.com/docs/languages/json) for detailed information on the user experience and has more information on how to configure the language support.
|
||||
|
||||
## Integrate
|
||||
|
||||
If you plan to integrate the JSON language server into an editor and IDE, check out [this page](https://microsoft.github.io/language-server-protocol/implementors/tools/) if there's already an LSP client integration available.
|
||||
|
||||
You can also launch the language server as a command and connect to it.
|
||||
For that, install the `json-language-server` npm module:
|
||||
|
||||
`npm install -g json-language-server`
|
||||
|
||||
Start the language server with the `json-language-server` command. Use a command line argument to specify the preferred communication channel:
|
||||
|
||||
```
|
||||
json-language-server --node-ipc
|
||||
json-language-server --stdio
|
||||
json-language-server --socket=<port>
|
||||
```
|
||||
|
||||
To connect to the server from NodeJS, see Remy Suen's great write-up on [how to communicate with the server](https://github.com/rcjsuen/dockerfile-language-server-nodejs#communicating-with-the-server) through the available communication channels.
|
||||
|
||||
## Participate
|
||||
|
||||
The source code of the JSON language server can be found in the [VSCode repository](https://github.com/microsoft/vscode) at [extensions/json-language-features/server](https://github.com/microsoft/vscode/tree/master/extensions/json-language-features/server).
|
||||
|
||||
File issues and pull requests in the [VSCode GitHub Issues](https://github.com/microsoft/vscode/issues). See the document [How to Contribute](https://github.com/microsoft/vscode/wiki/How-to-Contribute) on how to build and run from source.
|
||||
|
||||
Most of the functionality of the server is located in libraries:
|
||||
- [jsonc-parser](https://github.com/microsoft/node-jsonc-parser) contains the JSON parser and scanner.
|
||||
- [vscode-json-languageservice](https://github.com/microsoft/vscode-json-languageservice) contains the implementation of all features as a re-usable library.
|
||||
- [vscode-languageserver-node](https://github.com/microsoft/vscode-languageserver-node) contains the implementation of language server for NodeJS.
|
||||
|
||||
Help on any of these projects is very welcome.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Licensed under the [MIT](https://github.com/microsoft/vscode/blob/master/LICENSE.txt) License.
|
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
require('../out/node/jsonServerMain');
|
@ -0,0 +1,23 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
//@ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
const withBrowserDefaults = require('../../shared.webpack.config').browser;
|
||||
const path = require('path');
|
||||
|
||||
module.exports = withBrowserDefaults({
|
||||
context: __dirname,
|
||||
entry: {
|
||||
extension: './src/browser/jsonServerMain.ts',
|
||||
},
|
||||
output: {
|
||||
filename: 'jsonServerMain.js',
|
||||
path: path.join(__dirname, 'dist', 'browser'),
|
||||
libraryTarget: 'var'
|
||||
}
|
||||
});
|
@ -0,0 +1,28 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
//@ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
const withDefaults = require('../../shared.webpack.config');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const config = withDefaults({
|
||||
context: path.join(__dirname),
|
||||
entry: {
|
||||
extension: './src/node/jsonServerMain.ts',
|
||||
},
|
||||
output: {
|
||||
filename: 'jsonServerMain.js',
|
||||
path: path.join(__dirname, 'dist', 'node'),
|
||||
}
|
||||
});
|
||||
|
||||
// add plugin, don't replace inherited
|
||||
config.plugins.push(new webpack.IgnorePlugin(/vertx/)); // request-light dependency
|
||||
|
||||
module.exports = config;
|
@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "vscode-json-languageserver",
|
||||
"description": "JSON language server",
|
||||
"version": "1.3.1",
|
||||
"author": "Microsoft Corporation",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"bin": {
|
||||
"vscode-json-languageserver": "./bin/vscode-json-languageserver"
|
||||
},
|
||||
"main": "./out/node/jsonServerMain",
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^2.2.1",
|
||||
"request-light": "^0.3.0",
|
||||
"vscode-json-languageservice": "^3.9.1",
|
||||
"vscode-languageserver": "7.0.0-next.3",
|
||||
"vscode-uri": "^2.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "2.2.33",
|
||||
"@types/node": "^12.11.7"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublishOnly": "npm run clean && npm run compile",
|
||||
"compile": "npx gulp compile-extension:json-language-features-server",
|
||||
"watch": "npx gulp watch-extension:json-language-features-server",
|
||||
"clean": "../../../node_modules/.bin/rimraf out",
|
||||
"install-service-next": "yarn add vscode-json-languageservice@next",
|
||||
"install-service-local": "yarn link vscode-json-languageservice",
|
||||
"install-server-next": "yarn add vscode-languageserver@next",
|
||||
"install-server-local": "yarn link vscode-languageserver-server",
|
||||
"version": "git commit -m \"JSON Language Server $npm_package_version\" package.json"
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createConnection, BrowserMessageReader, BrowserMessageWriter } from 'vscode-languageserver/browser';
|
||||
import { startServer } from '../jsonServer';
|
||||
|
||||
declare let self: any;
|
||||
|
||||
const messageReader = new BrowserMessageReader(self);
|
||||
const messageWriter = new BrowserMessageWriter(self);
|
||||
|
||||
const connection = createConnection(messageReader, messageWriter);
|
||||
|
||||
startServer(connection, {});
|
@ -0,0 +1,497 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import {
|
||||
Connection,
|
||||
TextDocuments, InitializeParams, InitializeResult, NotificationType, RequestType,
|
||||
DocumentRangeFormattingRequest, Disposable, ServerCapabilities, TextDocumentSyncKind, TextEdit
|
||||
} from 'vscode-languageserver';
|
||||
|
||||
import { formatError, runSafe, runSafeAsync } from './utils/runner';
|
||||
import { TextDocument, JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration, ClientCapabilities, Diagnostic, Range, Position } from 'vscode-json-languageservice';
|
||||
import { getLanguageModelCache } from './languageModelCache';
|
||||
import { RequestService, basename, resolvePath } from './requests';
|
||||
|
||||
type ISchemaAssociations = Record<string, string[]>;
|
||||
|
||||
namespace SchemaAssociationNotification {
|
||||
export const type: NotificationType<ISchemaAssociations | SchemaConfiguration[], any> = new NotificationType('json/schemaAssociations');
|
||||
}
|
||||
|
||||
namespace VSCodeContentRequest {
|
||||
export const type: RequestType<string, string, any, any> = new RequestType('vscode/content');
|
||||
}
|
||||
|
||||
namespace SchemaContentChangeNotification {
|
||||
export const type: NotificationType<string, any> = new NotificationType('json/schemaContent');
|
||||
}
|
||||
|
||||
namespace ResultLimitReachedNotification {
|
||||
export const type: NotificationType<string, any> = new NotificationType('json/resultLimitReached');
|
||||
}
|
||||
|
||||
namespace ForceValidateRequest {
|
||||
export const type: RequestType<string, Diagnostic[], any, any> = new RequestType('json/validate');
|
||||
}
|
||||
|
||||
|
||||
const workspaceContext = {
|
||||
resolveRelativePath: (relativePath: string, resource: string) => {
|
||||
const base = resource.substr(0, resource.lastIndexOf('/') + 1);
|
||||
return resolvePath(base, relativePath);
|
||||
}
|
||||
};
|
||||
|
||||
export interface RuntimeEnvironment {
|
||||
file?: RequestService;
|
||||
http?: RequestService
|
||||
configureHttpRequests?(proxy: string, strictSSL: boolean): void;
|
||||
}
|
||||
|
||||
export function startServer(connection: Connection, runtime: RuntimeEnvironment) {
|
||||
|
||||
function getSchemaRequestService(handledSchemas: string[] = ['https', 'http', 'file']) {
|
||||
const builtInHandlers: { [protocol: string]: RequestService | undefined } = {};
|
||||
for (let protocol of handledSchemas) {
|
||||
if (protocol === 'file') {
|
||||
builtInHandlers[protocol] = runtime.file;
|
||||
} else if (protocol === 'http' || protocol === 'https') {
|
||||
builtInHandlers[protocol] = runtime.http;
|
||||
}
|
||||
}
|
||||
return (uri: string): Thenable<string> => {
|
||||
const protocol = uri.substr(0, uri.indexOf(':'));
|
||||
|
||||
const builtInHandler = builtInHandlers[protocol];
|
||||
if (builtInHandler) {
|
||||
return builtInHandler.getContent(uri);
|
||||
}
|
||||
return connection.sendRequest(VSCodeContentRequest.type, uri).then(responseText => {
|
||||
return responseText;
|
||||
}, error => {
|
||||
return Promise.reject(error.message);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// create the JSON language service
|
||||
let languageService = getLanguageService({
|
||||
workspaceContext,
|
||||
contributions: [],
|
||||
clientCapabilities: ClientCapabilities.LATEST
|
||||
});
|
||||
|
||||
// Create a text document manager.
|
||||
const documents = new TextDocuments(TextDocument);
|
||||
|
||||
// Make the text document manager listen on the connection
|
||||
// for open, change and close text document events
|
||||
documents.listen(connection);
|
||||
|
||||
let clientSnippetSupport = false;
|
||||
let dynamicFormatterRegistration = false;
|
||||
let hierarchicalDocumentSymbolSupport = false;
|
||||
|
||||
let foldingRangeLimitDefault = Number.MAX_VALUE;
|
||||
let foldingRangeLimit = Number.MAX_VALUE;
|
||||
let resultLimit = Number.MAX_VALUE;
|
||||
let formatterMaxNumberOfEdits = Number.MAX_VALUE;
|
||||
|
||||
// After the server has started the client sends an initialize request. The server receives
|
||||
// in the passed params the rootPath of the workspace plus the client capabilities.
|
||||
connection.onInitialize((params: InitializeParams): InitializeResult => {
|
||||
|
||||
const handledProtocols = params.initializationOptions?.handledSchemaProtocols;
|
||||
|
||||
languageService = getLanguageService({
|
||||
schemaRequestService: getSchemaRequestService(handledProtocols),
|
||||
workspaceContext,
|
||||
contributions: [],
|
||||
clientCapabilities: params.capabilities
|
||||
});
|
||||
|
||||
function getClientCapability<T>(name: string, def: T) {
|
||||
const keys = name.split('.');
|
||||
let c: any = params.capabilities;
|
||||
for (let i = 0; c && i < keys.length; i++) {
|
||||
if (!c.hasOwnProperty(keys[i])) {
|
||||
return def;
|
||||
}
|
||||
c = c[keys[i]];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
clientSnippetSupport = getClientCapability('textDocument.completion.completionItem.snippetSupport', false);
|
||||
dynamicFormatterRegistration = getClientCapability('textDocument.rangeFormatting.dynamicRegistration', false) && (typeof params.initializationOptions?.provideFormatter !== 'boolean');
|
||||
foldingRangeLimitDefault = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE);
|
||||
hierarchicalDocumentSymbolSupport = getClientCapability('textDocument.documentSymbol.hierarchicalDocumentSymbolSupport', false);
|
||||
formatterMaxNumberOfEdits = params.initializationOptions?.customCapabilities?.rangeFormatting?.editLimit || Number.MAX_VALUE;
|
||||
const capabilities: ServerCapabilities = {
|
||||
textDocumentSync: TextDocumentSyncKind.Incremental,
|
||||
completionProvider: clientSnippetSupport ? {
|
||||
resolveProvider: false, // turn off resolving as the current language service doesn't do anything on resolve. Also fixes #91747
|
||||
triggerCharacters: ['"', ':']
|
||||
} : undefined,
|
||||
hoverProvider: true,
|
||||
documentSymbolProvider: true,
|
||||
documentRangeFormattingProvider: params.initializationOptions?.provideFormatter === true,
|
||||
colorProvider: {},
|
||||
foldingRangeProvider: true,
|
||||
selectionRangeProvider: true,
|
||||
definitionProvider: true
|
||||
};
|
||||
|
||||
return { capabilities };
|
||||
});
|
||||
|
||||
|
||||
|
||||
// The settings interface describes the server relevant settings part
|
||||
interface Settings {
|
||||
json: {
|
||||
schemas: JSONSchemaSettings[];
|
||||
format: { enable: boolean; };
|
||||
resultLimit?: number;
|
||||
};
|
||||
http: {
|
||||
proxy: string;
|
||||
proxyStrictSSL: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface JSONSchemaSettings {
|
||||
fileMatch?: string[];
|
||||
url?: string;
|
||||
schema?: JSONSchema;
|
||||
}
|
||||
|
||||
|
||||
const limitExceededWarnings = function () {
|
||||
const pendingWarnings: { [uri: string]: { features: { [name: string]: string }; timeout?: NodeJS.Timeout; } } = {};
|
||||
|
||||
return {
|
||||
cancel(uri: string) {
|
||||
const warning = pendingWarnings[uri];
|
||||
if (warning && warning.timeout) {
|
||||
clearTimeout(warning.timeout);
|
||||
delete pendingWarnings[uri];
|
||||
}
|
||||
},
|
||||
|
||||
onResultLimitExceeded(uri: string, resultLimit: number, name: string) {
|
||||
return () => {
|
||||
let warning = pendingWarnings[uri];
|
||||
if (warning) {
|
||||
if (!warning.timeout) {
|
||||
// already shown
|
||||
return;
|
||||
}
|
||||
warning.features[name] = name;
|
||||
warning.timeout.refresh();
|
||||
} else {
|
||||
warning = { features: { [name]: name } };
|
||||
warning.timeout = setTimeout(() => {
|
||||
connection.sendNotification(ResultLimitReachedNotification.type, `${basename(uri)}: For performance reasons, ${Object.keys(warning.features).join(' and ')} have been limited to ${resultLimit} items.`);
|
||||
warning.timeout = undefined;
|
||||
}, 2000);
|
||||
pendingWarnings[uri] = warning;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}();
|
||||
|
||||
let jsonConfigurationSettings: JSONSchemaSettings[] | undefined = undefined;
|
||||
let schemaAssociations: ISchemaAssociations | SchemaConfiguration[] | undefined = undefined;
|
||||
let formatterRegistration: Thenable<Disposable> | null = null;
|
||||
|
||||
// The settings have changed. Is send on server activation as well.
|
||||
connection.onDidChangeConfiguration((change) => {
|
||||
let settings = <Settings>change.settings;
|
||||
if (runtime.configureHttpRequests) {
|
||||
runtime.configureHttpRequests(settings.http && settings.http.proxy, settings.http && settings.http.proxyStrictSSL);
|
||||
}
|
||||
jsonConfigurationSettings = settings.json && settings.json.schemas;
|
||||
updateConfiguration();
|
||||
|
||||
foldingRangeLimit = Math.trunc(Math.max(settings.json && settings.json.resultLimit || foldingRangeLimitDefault, 0));
|
||||
resultLimit = Math.trunc(Math.max(settings.json && settings.json.resultLimit || Number.MAX_VALUE, 0));
|
||||
|
||||
// dynamically enable & disable the formatter
|
||||
if (dynamicFormatterRegistration) {
|
||||
const enableFormatter = settings && settings.json && settings.json.format && settings.json.format.enable;
|
||||
if (enableFormatter) {
|
||||
if (!formatterRegistration) {
|
||||
formatterRegistration = connection.client.register(DocumentRangeFormattingRequest.type, { documentSelector: [{ language: 'json' }, { language: 'jsonc' }] });
|
||||
}
|
||||
} else if (formatterRegistration) {
|
||||
formatterRegistration.then(r => r.dispose());
|
||||
formatterRegistration = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// The jsonValidation extension configuration has changed
|
||||
connection.onNotification(SchemaAssociationNotification.type, associations => {
|
||||
schemaAssociations = associations;
|
||||
updateConfiguration();
|
||||
});
|
||||
|
||||
// A schema has changed
|
||||
connection.onNotification(SchemaContentChangeNotification.type, uri => {
|
||||
languageService.resetSchema(uri);
|
||||
});
|
||||
|
||||
// Retry schema validation on all open documents
|
||||
connection.onRequest(ForceValidateRequest.type, uri => {
|
||||
return new Promise<Diagnostic[]>(resolve => {
|
||||
const document = documents.get(uri);
|
||||
if (document) {
|
||||
updateConfiguration();
|
||||
validateTextDocument(document, diagnostics => {
|
||||
resolve(diagnostics);
|
||||
});
|
||||
} else {
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function updateConfiguration() {
|
||||
const languageSettings = {
|
||||
validate: true,
|
||||
allowComments: true,
|
||||
schemas: new Array<SchemaConfiguration>()
|
||||
};
|
||||
if (schemaAssociations) {
|
||||
if (Array.isArray(schemaAssociations)) {
|
||||
Array.prototype.push.apply(languageSettings.schemas, schemaAssociations);
|
||||
} else {
|
||||
for (const pattern in schemaAssociations) {
|
||||
const association = schemaAssociations[pattern];
|
||||
if (Array.isArray(association)) {
|
||||
association.forEach(uri => {
|
||||
languageSettings.schemas.push({ uri, fileMatch: [pattern] });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (jsonConfigurationSettings) {
|
||||
jsonConfigurationSettings.forEach((schema, index) => {
|
||||
let uri = schema.url;
|
||||
if (!uri && schema.schema) {
|
||||
uri = schema.schema.id || `vscode://schemas/custom/${index}`;
|
||||
}
|
||||
if (uri) {
|
||||
languageSettings.schemas.push({ uri, fileMatch: schema.fileMatch, schema: schema.schema });
|
||||
}
|
||||
});
|
||||
}
|
||||
languageService.configure(languageSettings);
|
||||
|
||||
// Revalidate any open text documents
|
||||
documents.all().forEach(triggerValidation);
|
||||
}
|
||||
|
||||
// The content of a text document has changed. This event is emitted
|
||||
// when the text document first opened or when its content has changed.
|
||||
documents.onDidChangeContent((change) => {
|
||||
limitExceededWarnings.cancel(change.document.uri);
|
||||
triggerValidation(change.document);
|
||||
});
|
||||
|
||||
// a document has closed: clear all diagnostics
|
||||
documents.onDidClose(event => {
|
||||
limitExceededWarnings.cancel(event.document.uri);
|
||||
cleanPendingValidation(event.document);
|
||||
connection.sendDiagnostics({ uri: event.document.uri, diagnostics: [] });
|
||||
});
|
||||
|
||||
const pendingValidationRequests: { [uri: string]: NodeJS.Timer; } = {};
|
||||
const validationDelayMs = 300;
|
||||
|
||||
function cleanPendingValidation(textDocument: TextDocument): void {
|
||||
const request = pendingValidationRequests[textDocument.uri];
|
||||
if (request) {
|
||||
clearTimeout(request);
|
||||
delete pendingValidationRequests[textDocument.uri];
|
||||
}
|
||||
}
|
||||
|
||||
function triggerValidation(textDocument: TextDocument): void {
|
||||
cleanPendingValidation(textDocument);
|
||||
pendingValidationRequests[textDocument.uri] = setTimeout(() => {
|
||||
delete pendingValidationRequests[textDocument.uri];
|
||||
validateTextDocument(textDocument);
|
||||
}, validationDelayMs);
|
||||
}
|
||||
|
||||
function validateTextDocument(textDocument: TextDocument, callback?: (diagnostics: Diagnostic[]) => void): void {
|
||||
const respond = (diagnostics: Diagnostic[]) => {
|
||||
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
|
||||
if (callback) {
|
||||
callback(diagnostics);
|
||||
}
|
||||
};
|
||||
if (textDocument.getText().length === 0) {
|
||||
respond([]); // ignore empty documents
|
||||
return;
|
||||
}
|
||||
const jsonDocument = getJSONDocument(textDocument);
|
||||
const version = textDocument.version;
|
||||
|
||||
const documentSettings: DocumentLanguageSettings = textDocument.languageId === 'jsonc' ? { comments: 'ignore', trailingCommas: 'warning' } : { comments: 'error', trailingCommas: 'error' };
|
||||
languageService.doValidation(textDocument, jsonDocument, documentSettings).then(diagnostics => {
|
||||
setImmediate(() => {
|
||||
const currDocument = documents.get(textDocument.uri);
|
||||
if (currDocument && currDocument.version === version) {
|
||||
respond(diagnostics); // Send the computed diagnostics to VSCode.
|
||||
}
|
||||
});
|
||||
}, error => {
|
||||
connection.console.error(formatError(`Error while validating ${textDocument.uri}`, error));
|
||||
});
|
||||
}
|
||||
|
||||
connection.onDidChangeWatchedFiles((change) => {
|
||||
// Monitored files have changed in VSCode
|
||||
let hasChanges = false;
|
||||
change.changes.forEach(c => {
|
||||
if (languageService.resetSchema(c.uri)) {
|
||||
hasChanges = true;
|
||||
}
|
||||
});
|
||||
if (hasChanges) {
|
||||
documents.all().forEach(triggerValidation);
|
||||
}
|
||||
});
|
||||
|
||||
const jsonDocuments = getLanguageModelCache<JSONDocument>(10, 60, document => languageService.parseJSONDocument(document));
|
||||
documents.onDidClose(e => {
|
||||
jsonDocuments.onDocumentRemoved(e.document);
|
||||
});
|
||||
connection.onShutdown(() => {
|
||||
jsonDocuments.dispose();
|
||||
});
|
||||
|
||||
function getJSONDocument(document: TextDocument): JSONDocument {
|
||||
return jsonDocuments.get(document);
|
||||
}
|
||||
|
||||
connection.onCompletion((textDocumentPosition, token) => {
|
||||
return runSafeAsync(async () => {
|
||||
const document = documents.get(textDocumentPosition.textDocument.uri);
|
||||
if (document) {
|
||||
const jsonDocument = getJSONDocument(document);
|
||||
return languageService.doComplete(document, textDocumentPosition.position, jsonDocument);
|
||||
}
|
||||
return null;
|
||||
}, null, `Error while computing completions for ${textDocumentPosition.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onHover((textDocumentPositionParams, token) => {
|
||||
return runSafeAsync(async () => {
|
||||
const document = documents.get(textDocumentPositionParams.textDocument.uri);
|
||||
if (document) {
|
||||
const jsonDocument = getJSONDocument(document);
|
||||
return languageService.doHover(document, textDocumentPositionParams.position, jsonDocument);
|
||||
}
|
||||
return null;
|
||||
}, null, `Error while computing hover for ${textDocumentPositionParams.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onDocumentSymbol((documentSymbolParams, token) => {
|
||||
return runSafe(() => {
|
||||
const document = documents.get(documentSymbolParams.textDocument.uri);
|
||||
if (document) {
|
||||
const jsonDocument = getJSONDocument(document);
|
||||
const onResultLimitExceeded = limitExceededWarnings.onResultLimitExceeded(document.uri, resultLimit, 'document symbols');
|
||||
if (hierarchicalDocumentSymbolSupport) {
|
||||
return languageService.findDocumentSymbols2(document, jsonDocument, { resultLimit, onResultLimitExceeded });
|
||||
} else {
|
||||
return languageService.findDocumentSymbols(document, jsonDocument, { resultLimit, onResultLimitExceeded });
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}, [], `Error while computing document symbols for ${documentSymbolParams.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onDocumentRangeFormatting((formatParams, token) => {
|
||||
return runSafe(() => {
|
||||
const document = documents.get(formatParams.textDocument.uri);
|
||||
if (document) {
|
||||
const edits = languageService.format(document, formatParams.range, formatParams.options);
|
||||
if (edits.length > formatterMaxNumberOfEdits) {
|
||||
const newText = TextDocument.applyEdits(document, edits);
|
||||
return [TextEdit.replace(Range.create(Position.create(0, 0), document.positionAt(document.getText().length)), newText)];
|
||||
}
|
||||
return edits;
|
||||
}
|
||||
return [];
|
||||
}, [], `Error while formatting range for ${formatParams.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onDocumentColor((params, token) => {
|
||||
return runSafeAsync(async () => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
const onResultLimitExceeded = limitExceededWarnings.onResultLimitExceeded(document.uri, resultLimit, 'document colors');
|
||||
const jsonDocument = getJSONDocument(document);
|
||||
return languageService.findDocumentColors(document, jsonDocument, { resultLimit, onResultLimitExceeded });
|
||||
}
|
||||
return [];
|
||||
}, [], `Error while computing document colors for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onColorPresentation((params, token) => {
|
||||
return runSafe(() => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
const jsonDocument = getJSONDocument(document);
|
||||
return languageService.getColorPresentations(document, jsonDocument, params.color, params.range);
|
||||
}
|
||||
return [];
|
||||
}, [], `Error while computing color presentations for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onFoldingRanges((params, token) => {
|
||||
return runSafe(() => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
const onRangeLimitExceeded = limitExceededWarnings.onResultLimitExceeded(document.uri, foldingRangeLimit, 'folding ranges');
|
||||
return languageService.getFoldingRanges(document, { rangeLimit: foldingRangeLimit, onRangeLimitExceeded });
|
||||
}
|
||||
return null;
|
||||
}, null, `Error while computing folding ranges for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
|
||||
connection.onSelectionRanges((params, token) => {
|
||||
return runSafe(() => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
const jsonDocument = getJSONDocument(document);
|
||||
return languageService.getSelectionRanges(document, params.positions, jsonDocument);
|
||||
}
|
||||
return [];
|
||||
}, [], `Error while computing selection ranges for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
connection.onDefinition((params, token) => {
|
||||
return runSafeAsync(async () => {
|
||||
const document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
const jsonDocument = getJSONDocument(document);
|
||||
return languageService.findDefinition(document, params.position, jsonDocument);
|
||||
}
|
||||
return [];
|
||||
}, [], `Error while computing definitions for ${params.textDocument.uri}`, token);
|
||||
});
|
||||
|
||||
// Listen on the connection
|
||||
connection.listen();
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TextDocument } from 'vscode-languageserver';
|
||||
|
||||
export interface LanguageModelCache<T> {
|
||||
get(document: TextDocument): T;
|
||||
onDocumentRemoved(document: TextDocument): void;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export function getLanguageModelCache<T>(maxEntries: number, cleanupIntervalTimeInSec: number, parse: (document: TextDocument) => T): LanguageModelCache<T> {
|
||||
let languageModels: { [uri: string]: { version: number, languageId: string, cTime: number, languageModel: T } } = {};
|
||||
let nModels = 0;
|
||||
|
||||
let cleanupInterval: NodeJS.Timer | undefined = undefined;
|
||||
if (cleanupIntervalTimeInSec > 0) {
|
||||
cleanupInterval = setInterval(() => {
|
||||
let cutoffTime = Date.now() - cleanupIntervalTimeInSec * 1000;
|
||||
let uris = Object.keys(languageModels);
|
||||
for (let uri of uris) {
|
||||
let languageModelInfo = languageModels[uri];
|
||||
if (languageModelInfo.cTime < cutoffTime) {
|
||||
delete languageModels[uri];
|
||||
nModels--;
|
||||
}
|
||||
}
|
||||
}, cleanupIntervalTimeInSec * 1000);
|
||||
}
|
||||
|
||||
return {
|
||||
get(document: TextDocument): T {
|
||||
let version = document.version;
|
||||
let languageId = document.languageId;
|
||||
let languageModelInfo = languageModels[document.uri];
|
||||
if (languageModelInfo && languageModelInfo.version === version && languageModelInfo.languageId === languageId) {
|
||||
languageModelInfo.cTime = Date.now();
|
||||
return languageModelInfo.languageModel;
|
||||
}
|
||||
let languageModel = parse(document);
|
||||
languageModels[document.uri] = { languageModel, version, languageId, cTime: Date.now() };
|
||||
if (!languageModelInfo) {
|
||||
nModels++;
|
||||
}
|
||||
|
||||
if (nModels === maxEntries) {
|
||||
let oldestTime = Number.MAX_VALUE;
|
||||
let oldestUri = null;
|
||||
for (let uri in languageModels) {
|
||||
let languageModelInfo = languageModels[uri];
|
||||
if (languageModelInfo.cTime < oldestTime) {
|
||||
oldestUri = uri;
|
||||
oldestTime = languageModelInfo.cTime;
|
||||
}
|
||||
}
|
||||
if (oldestUri) {
|
||||
delete languageModels[oldestUri];
|
||||
nModels--;
|
||||
}
|
||||
}
|
||||
return languageModel;
|
||||
|
||||
},
|
||||
onDocumentRemoved(document: TextDocument) {
|
||||
let uri = document.uri;
|
||||
if (languageModels[uri]) {
|
||||
delete languageModels[uri];
|
||||
nModels--;
|
||||
}
|
||||
},
|
||||
dispose() {
|
||||
if (typeof cleanupInterval !== 'undefined') {
|
||||
clearInterval(cleanupInterval);
|
||||
cleanupInterval = undefined;
|
||||
languageModels = {};
|
||||
nModels = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createConnection, Connection } from 'vscode-languageserver/node';
|
||||
import { formatError } from '../utils/runner';
|
||||
import { startServer } from '../jsonServer';
|
||||
import { RequestService } from '../requests';
|
||||
|
||||
import { xhr, XHRResponse, configure as configureHttpRequests, getErrorStatusDescription } from 'request-light';
|
||||
import { URI as Uri } from 'vscode-uri';
|
||||
import * as fs from 'fs';
|
||||
|
||||
// Create a connection for the server.
|
||||
const connection: Connection = createConnection();
|
||||
|
||||
console.log = connection.console.log.bind(connection.console);
|
||||
console.error = connection.console.error.bind(connection.console);
|
||||
|
||||
process.on('unhandledRejection', (e: any) => {
|
||||
connection.console.error(formatError(`Unhandled exception`, e));
|
||||
});
|
||||
|
||||
function getHTTPRequestService(): RequestService {
|
||||
return {
|
||||
getContent(uri: string, _encoding?: string) {
|
||||
const headers = { 'Accept-Encoding': 'gzip, deflate' };
|
||||
return xhr({ url: uri, followRedirects: 5, headers }).then(response => {
|
||||
return response.responseText;
|
||||
}, (error: XHRResponse) => {
|
||||
return Promise.reject(error.responseText || getErrorStatusDescription(error.status) || error.toString());
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getFileRequestService(): RequestService {
|
||||
return {
|
||||
getContent(location: string, encoding?: string) {
|
||||
return new Promise((c, e) => {
|
||||
const uri = Uri.parse(location);
|
||||
fs.readFile(uri.fsPath, encoding, (err, buf) => {
|
||||
if (err) {
|
||||
return e(err);
|
||||
}
|
||||
c(buf.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
startServer(connection, { file: getFileRequestService(), http: getHTTPRequestService(), configureHttpRequests });
|
@ -0,0 +1,87 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vscode-uri';
|
||||
|
||||
export interface RequestService {
|
||||
getContent(uri: string, encoding?: string): Promise<string>;
|
||||
}
|
||||
|
||||
export function getScheme(uri: string) {
|
||||
return uri.substr(0, uri.indexOf(':'));
|
||||
}
|
||||
|
||||
export function dirname(uri: string) {
|
||||
const lastIndexOfSlash = uri.lastIndexOf('/');
|
||||
return lastIndexOfSlash !== -1 ? uri.substr(0, lastIndexOfSlash) : '';
|
||||
}
|
||||
|
||||
export function basename(uri: string) {
|
||||
const lastIndexOfSlash = uri.lastIndexOf('/');
|
||||
return uri.substr(lastIndexOfSlash + 1);
|
||||
}
|
||||
|
||||
|
||||
const Slash = '/'.charCodeAt(0);
|
||||
const Dot = '.'.charCodeAt(0);
|
||||
|
||||
export function extname(uri: string) {
|
||||
for (let i = uri.length - 1; i >= 0; i--) {
|
||||
const ch = uri.charCodeAt(i);
|
||||
if (ch === Dot) {
|
||||
if (i > 0 && uri.charCodeAt(i - 1) !== Slash) {
|
||||
return uri.substr(i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (ch === Slash) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function isAbsolutePath(path: string) {
|
||||
return path.charCodeAt(0) === Slash;
|
||||
}
|
||||
|
||||
export function resolvePath(uriString: string, path: string): string {
|
||||
if (isAbsolutePath(path)) {
|
||||
const uri = URI.parse(uriString);
|
||||
const parts = path.split('/');
|
||||
return uri.with({ path: normalizePath(parts) }).toString();
|
||||
}
|
||||
return joinPath(uriString, path);
|
||||
}
|
||||
|
||||
export function normalizePath(parts: string[]): string {
|
||||
const newParts: string[] = [];
|
||||
for (const part of parts) {
|
||||
if (part.length === 0 || part.length === 1 && part.charCodeAt(0) === Dot) {
|
||||
// ignore
|
||||
} else if (part.length === 2 && part.charCodeAt(0) === Dot && part.charCodeAt(1) === Dot) {
|
||||
newParts.pop();
|
||||
} else {
|
||||
newParts.push(part);
|
||||
}
|
||||
}
|
||||
if (parts.length > 1 && parts[parts.length - 1].length === 0) {
|
||||
newParts.push('');
|
||||
}
|
||||
let res = newParts.join('/');
|
||||
if (parts[0].length === 0) {
|
||||
res = '/' + res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
export function joinPath(uriString: string, ...paths: string[]): string {
|
||||
const uri = URI.parse(uriString);
|
||||
const parts = uri.path.split('/');
|
||||
for (let path of paths) {
|
||||
parts.push(...path.split('/'));
|
||||
}
|
||||
return uri.with({ path: normalizePath(parts) }).toString();
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken, ResponseError, ErrorCodes } from 'vscode-languageserver';
|
||||
|
||||
export function formatError(message: string, err: any): string {
|
||||
if (err instanceof Error) {
|
||||
let error = <Error>err;
|
||||
return `${message}: ${error.message}\n${error.stack}`;
|
||||
} else if (typeof err === 'string') {
|
||||
return `${message}: ${err}`;
|
||||
} else if (err) {
|
||||
return `${message}: ${err.toString()}`;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
export function runSafeAsync<T>(func: () => Thenable<T>, errorVal: T, errorMessage: string, token: CancellationToken): Thenable<T | ResponseError<any>> {
|
||||
return new Promise<T | ResponseError<any>>((resolve) => {
|
||||
setImmediate(() => {
|
||||
if (token.isCancellationRequested) {
|
||||
resolve(cancelValue());
|
||||
}
|
||||
return func().then(result => {
|
||||
if (token.isCancellationRequested) {
|
||||
resolve(cancelValue());
|
||||
return;
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
}, e => {
|
||||
console.error(formatError(errorMessage, e));
|
||||
resolve(errorVal);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function runSafe<T, E>(func: () => T, errorVal: T, errorMessage: string, token: CancellationToken): Thenable<T | ResponseError<E>> {
|
||||
return new Promise<T | ResponseError<E>>((resolve) => {
|
||||
setImmediate(() => {
|
||||
if (token.isCancellationRequested) {
|
||||
resolve(cancelValue());
|
||||
} else {
|
||||
try {
|
||||
let result = func();
|
||||
if (token.isCancellationRequested) {
|
||||
resolve(cancelValue());
|
||||
return;
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error(formatError(errorMessage, e));
|
||||
resolve(errorVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cancelValue<E>() {
|
||||
console.log('cancelled');
|
||||
return new ResponseError<E>(ErrorCodes.RequestCancelled, 'Request cancelled');
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Determines if haystack ends with needle.
|
||||
*/
|
||||
export function endsWith(haystack: string, needle: string): boolean {
|
||||
let diff = haystack.length - needle.length;
|
||||
if (diff > 0) {
|
||||
return haystack.lastIndexOf(needle) === diff;
|
||||
} else if (diff === 0) {
|
||||
return haystack === needle;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function convertSimple2RegExpPattern(pattern: string): string {
|
||||
return pattern.replace(/[\-\\\{\}\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&').replace(/[\*]/g, '.*');
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
--ui tdd
|
||||
--useColors true
|
||||
./out/test/**/*.test.js
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../shared.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"sourceMap": true,
|
||||
"sourceRoot": "../src"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
142
lib/vscode/extensions/json-language-features/server/yarn.lock
Normal file
142
lib/vscode/extensions/json-language-features/server/yarn.lock
Normal file
@ -0,0 +1,142 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/mocha@2.2.33":
|
||||
version "2.2.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.33.tgz#d79a0061ec270379f4d9e225f4096fb436669def"
|
||||
integrity sha1-15oAYewnA3n02eIl9AlvtDZmne8=
|
||||
|
||||
"@types/node@^12.11.7":
|
||||
version "12.11.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a"
|
||||
integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==
|
||||
|
||||
agent-base@4:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.1.2.tgz#80fa6cde440f4dcf9af2617cf246099b5d99f0c8"
|
||||
integrity sha512-VE6QoEdaugY86BohRtfGmTDabxdU5sCKOkbcPA6PXKJsRzEi/7A3RCTxJal1ft/4qSfPht5/iQLhMh/wzSkkNw==
|
||||
dependencies:
|
||||
es6-promisify "^5.0.0"
|
||||
|
||||
agent-base@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
|
||||
integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
|
||||
dependencies:
|
||||
es6-promisify "^5.0.0"
|
||||
|
||||
debug@3.1.0, debug@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
es6-promise@^4.0.3:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.1.1.tgz#8811e90915d9a0dba36274f0b242dbda78f9c92a"
|
||||
integrity sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng==
|
||||
|
||||
es6-promisify@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
|
||||
integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
|
||||
dependencies:
|
||||
es6-promise "^4.0.3"
|
||||
|
||||
http-proxy-agent@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
|
||||
integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==
|
||||
dependencies:
|
||||
agent-base "4"
|
||||
debug "3.1.0"
|
||||
|
||||
https-proxy-agent@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
|
||||
integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
|
||||
dependencies:
|
||||
agent-base "^4.3.0"
|
||||
debug "^3.1.0"
|
||||
|
||||
jsonc-parser@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc"
|
||||
integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==
|
||||
|
||||
jsonc-parser@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.1.tgz#59549150b133f2efacca48fe9ce1ec0659af2342"
|
||||
integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
request-light@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.3.0.tgz#04daa783e7f0a70392328dda4b546f3e27845f2d"
|
||||
integrity sha512-xlVlZVT0ZvCT+c3zm3SjeFCzchoQxsUUmx5fkal0I6RIDJK+lmb1UYyKJ7WM4dTfnzHP4ElWwAf8Dli8c0/tVA==
|
||||
dependencies:
|
||||
http-proxy-agent "^2.1.0"
|
||||
https-proxy-agent "^2.2.4"
|
||||
vscode-nls "^4.1.1"
|
||||
|
||||
vscode-json-languageservice@^3.9.1:
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.9.1.tgz#f72b581f8cd2bd9b47445ccf8b0ddcde6aba7483"
|
||||
integrity sha512-oJkknkdCVitQ5XPSRa0weHjUxt8eSCptaL+MBQQlRsa6Nb8XnEY0S5wYnLUFHzEvKzwt01/LKk8LdOixWEXkNA==
|
||||
dependencies:
|
||||
jsonc-parser "^2.3.1"
|
||||
vscode-languageserver-textdocument "^1.0.1"
|
||||
vscode-languageserver-types "3.16.0-next.2"
|
||||
vscode-nls "^5.0.0"
|
||||
vscode-uri "^2.1.2"
|
||||
|
||||
vscode-jsonrpc@6.0.0-next.2:
|
||||
version "6.0.0-next.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0-next.2.tgz#3d73f86d812304cb91b9fb1efee40ec60b09ed7f"
|
||||
integrity sha512-dKQXRYNUY6BHALQJBJlyZyv9oWlYpbJ2vVoQNNVNPLAYQ3hzNp4zy+iSo7zGx1BPXByArJQDWTKLQh8dz3dnNw==
|
||||
|
||||
vscode-languageserver-protocol@3.16.0-next.4:
|
||||
version "3.16.0-next.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0-next.4.tgz#8f8b1b831d4dfd9b26aa1ba3d2a32c427a91c99f"
|
||||
integrity sha512-6GmPUp2MhJy2H1CTWp2B40Pa9BeC9glrXWmQWVG6A/0V9UbcAjVC9m56znm2GL32iyLDIprTBe8gBvvvcjbpaQ==
|
||||
dependencies:
|
||||
vscode-jsonrpc "6.0.0-next.2"
|
||||
vscode-languageserver-types "3.16.0-next.2"
|
||||
|
||||
vscode-languageserver-textdocument@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.1.tgz#178168e87efad6171b372add1dea34f53e5d330f"
|
||||
integrity sha512-UIcJDjX7IFkck7cSkNNyzIz5FyvpQfY7sdzVy+wkKN/BLaD4DQ0ppXQrKePomCxTS7RrolK1I0pey0bG9eh8dA==
|
||||
|
||||
vscode-languageserver-types@3.16.0-next.2:
|
||||
version "3.16.0-next.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.2.tgz#940bd15c992295a65eae8ab6b8568a1e8daa3083"
|
||||
integrity sha512-QjXB7CKIfFzKbiCJC4OWC8xUncLsxo19FzGVp/ADFvvi87PlmBSCAtZI5xwGjF5qE0xkLf0jjKUn3DzmpDP52Q==
|
||||
|
||||
vscode-languageserver@7.0.0-next.3:
|
||||
version "7.0.0-next.3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-7.0.0-next.3.tgz#3833bd09259a4a085baeba90783f1e4d06d81095"
|
||||
integrity sha512-qSt8eb546iFuoFIN+9MPl4Avru6Iz2/JP0UmS/3djf40ICa31Np/yJ7anX2j0Az5rCzb0fak8oeKwDioGeVOYg==
|
||||
dependencies:
|
||||
vscode-languageserver-protocol "3.16.0-next.4"
|
||||
|
||||
vscode-nls@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c"
|
||||
integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A==
|
||||
|
||||
vscode-nls@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840"
|
||||
integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA==
|
||||
|
||||
vscode-uri@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.1.2.tgz#c8d40de93eb57af31f3c715dd650e2ca2c096f1c"
|
||||
integrity sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==
|
Reference in New Issue
Block a user