зеркало из https://github.com/Azure/autorest.git
Enable VSC Language-service (#2676)
* WIP * it works! * more fixes * added script * added vscode interfaces * fixed package.json and a test * removed unnecessary file * trimming fat * manually patch entrypoints and patch npm in core * tweaking * missing loader, remove fat * fixed tests, edge cases
This commit is contained in:
Родитель
7800961841
Коммит
f9eaa7b78d
|
@ -11,6 +11,9 @@ copyDtsFiles = (done) =>
|
|||
.on 'end', () =>
|
||||
source ["#{basefolder}/src/autorest-core/dist/**/*.d.ts","!#{basefolder}/src/autorest-core/dist/test/**" ]
|
||||
.pipe destination "#{basefolder}/src/autorest/dist/lib/core"
|
||||
.on 'end', () =>
|
||||
source ["#{basefolder}/src/autorest/vscode/**/*.d.ts" ]
|
||||
.pipe destination "#{basefolder}/src/autorest/dist/vscode"
|
||||
.on 'end', done
|
||||
return null
|
||||
|
||||
|
@ -64,9 +67,9 @@ task 'build', 'typescript', (done)->
|
|||
|
||||
task 'compile/typescript', fn, deps, (fin) ->
|
||||
copyDtsFiles ->
|
||||
execute "#{basefolder}/node_modules/.bin/tsc --project #{each.path} ", {cwd: each.path }, (code,stdout,stderr) ->
|
||||
execute "npm run build", {cwd: each.path }, (code,stdout,stderr) ->
|
||||
if watch
|
||||
execute "#{basefolder}/node_modules/.bin/tsc --watch --project #{each.path}", (c,o,e) ->
|
||||
execute "npm run watch", {cwd: each.path }, (c,o,e) ->
|
||||
echo "watching #{fn}"
|
||||
, (d) -> echo d.replace(/^src\//mig, "#{basefolder}/src/")
|
||||
fin()
|
||||
|
|
|
@ -8,9 +8,8 @@
|
|||
"name": "run tests",
|
||||
"program": "${workspaceRoot}/src/autorest-core/node_modules/mocha/bin/_mocha",
|
||||
"args": [
|
||||
"dist/test",
|
||||
"-g",
|
||||
"blaming"
|
||||
"dist/test/blaming.js",
|
||||
"--timeout=2000000"
|
||||
],
|
||||
"cwd": "${workspaceRoot}/src/autorest-core"
|
||||
},
|
||||
|
@ -21,7 +20,7 @@
|
|||
"name": "run bootstrapper",
|
||||
"program": "${workspaceRoot}/src/autorest/dist/app.js",
|
||||
"args": [
|
||||
"--latest",
|
||||
"--version=c:/work/github/autorest/autorest/src/autorest-core",
|
||||
"--verbose",
|
||||
"--debug"
|
||||
],
|
||||
|
|
|
@ -6,9 +6,12 @@
|
|||
"src/autorest-core/**/*.js.map": true,
|
||||
"src/autorest/**/*.js": true,
|
||||
"src/autorest/**/*.js.map": true,
|
||||
"src/autorest/**/*.d.ts": true,
|
||||
"src/autorest/*.d.ts": true,
|
||||
"src/autorest/lib/*.d.ts": true,
|
||||
"src/autorest/lib/**/*.d.ts": true,
|
||||
"src/autorest/node_modules/**": true,
|
||||
"src/autorest-core/node_modules/**": true,
|
||||
"src/autorest/lib/vscode/*.d.ts": false,
|
||||
"**/.git": true,
|
||||
"**/.svn": true,
|
||||
"**/.hg": true,
|
||||
|
|
|
@ -1 +1 @@
|
|||
4
|
||||
4
|
|
@ -1,15 +1,15 @@
|
|||
#!/usr/bin/env node
|
||||
// load static module: ${__dirname }/static_modules.fs
|
||||
require('./static-loader.js').load(`${__dirname}/static_modules.fs`)
|
||||
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// enable static modules for autorest-core
|
||||
if ((<any>global).StaticVolumeSet) {
|
||||
(<any>global).StaticVolumeSet.addFileSystem(`${__dirname}/static_modules.fs`)
|
||||
}
|
||||
|
||||
require('events').EventEmitter.defaultMaxListeners = 100;
|
||||
process.env['ELECTRON_RUN_AS_NODE'] = "1";
|
||||
delete process.env['ELECTRON_NO_ATTACH_CONSOLE'];
|
||||
|
||||
// start of autorest-ng
|
||||
// the console app starts for real here.
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
// ---------------------------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
import { JsonPath, SourceMap } from './source-map';
|
||||
|
||||
import { Location, Position } from 'vscode-languageserver';
|
||||
import { value, stringify, parse, nodes, paths, } from "jsonpath";
|
||||
|
||||
/**
|
||||
* This class provides complex analysis for a document in relation to its peers, i.e.
|
||||
* the other documents involved in one AutoRest/validation run (configuration file, OpenAPI documents).
|
||||
* As such, it offers operations like:
|
||||
* - looking up JSON paths/queries among all OpenAPI documents,
|
||||
* - retrieving the data (and corresponding JSON path) that can be found at a certain text location.
|
||||
*
|
||||
* Essentially, it provides useful mappings between logical (JSON path) and physical (line/column) locations in both directions.
|
||||
*/
|
||||
export class DocumentAnalysis {
|
||||
/*
|
||||
public static async Create(host: OpenApiDocumentManager, documentUri: string): Promise<DocumentAnalysis | null> {
|
||||
|
||||
const document = await host.GetFileContent(documentUri);
|
||||
if (!document) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const fullyResolvedAndMergedDefinition = host.GetFullyResolvedAndMergedDefinitionOf(documentUri);
|
||||
if (!fullyResolvedAndMergedDefinition) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DocumentAnalysis(
|
||||
documentUri,
|
||||
document,
|
||||
fullyResolvedAndMergedDefinition.openapiDefinition,
|
||||
new SourceMap(fullyResolvedAndMergedDefinition.openapiDefinitionMap));
|
||||
}*/
|
||||
|
||||
public constructor(
|
||||
private documentUri: string,
|
||||
private document: string,
|
||||
private fullyResolvedAndMergedDefinition: any,
|
||||
private fullyResolvedAndMergedDefinitionMap: SourceMap) { }
|
||||
|
||||
/**
|
||||
* Determines the JSON query found at a given position.
|
||||
* For example, suppressions will use JSON queries to limit the scope of the suppression (e.g. `$..parameters[?(@.name === 'quirkyParam')]`).
|
||||
*
|
||||
* @param position The position to look at for a JSON query.
|
||||
*/
|
||||
public GetJsonQueryAt(position: Position): string | null {
|
||||
const lines = this.document.split("\n");
|
||||
const potentialQuery: string = (lines[position.line].match(/\B\$[.[].+/g) || [])[0];
|
||||
|
||||
try {
|
||||
parse(potentialQuery);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return potentialQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the JSON path equivalent to the JSON reference at a given position.
|
||||
* OpenAPI definitions make use of these excessively.
|
||||
*
|
||||
* @param position The position to look at for a JSON reference.
|
||||
*/
|
||||
public GetJsonPathFromJsonReferenceAt(position: Position): string | null {
|
||||
const fullyResolvedAndMergedDefinitionLocation = this.fullyResolvedAndMergedDefinitionMap.LookupForward(
|
||||
this.documentUri,
|
||||
position.line + 1, // VS Code deviates from the source map standard here... 0 vs. 1 based line numbers
|
||||
position.character)[0];
|
||||
if (fullyResolvedAndMergedDefinitionLocation) {
|
||||
|
||||
const path = fullyResolvedAndMergedDefinitionLocation.path;
|
||||
if (path) {
|
||||
|
||||
// is $ref?
|
||||
if (path.length > 0 && path[path.length - 1] === "$ref") {
|
||||
// lookup object
|
||||
const refValueJsonPointer: string = value(this.fullyResolvedAndMergedDefinition, stringify(path));
|
||||
const refValueJsonPath: JsonPath = refValueJsonPointer.split("/").slice(1).map(part => part.replace(/~1/g, "/").replace(/~0/g, "~"));
|
||||
return stringify(refValueJsonPath);
|
||||
}
|
||||
} // else { console.warn("no object path for that location"); return null; }
|
||||
} // else { console.log("reverse lookup failed (no big deal, may just hover empty space)"); return null; }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all document locations (VS Code understands) corresponding with given JSON query.
|
||||
*/
|
||||
public * GetDocumentLocations(jsonQuery: string): Iterable<Location> {
|
||||
for (const path of paths(this.fullyResolvedAndMergedDefinition, jsonQuery)) {
|
||||
for (const mappingItem of this.fullyResolvedAndMergedDefinitionMap.LookupPath(path.slice(1))) {
|
||||
yield {
|
||||
uri: mappingItem.source,
|
||||
range: {
|
||||
start: {
|
||||
line: mappingItem.originalLine - 1, // VS Code deviates from the source map standard here... 0 vs. 1 based line numbers
|
||||
character: mappingItem.originalColumn
|
||||
},
|
||||
end: {
|
||||
line: mappingItem.originalLine - 1,
|
||||
character: mappingItem.originalColumn // TODO: room for improvement. think there even is extended information in `name`!
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all locations in the entire OpenAPI definition (and corresponding values) matching given JSON query.
|
||||
*/
|
||||
public * GetDefinitionLocations(jsonQuery: string): Iterable<{ value: any, jsonPath: string }> {
|
||||
for (const path of nodes(this.fullyResolvedAndMergedDefinition, jsonQuery)) {
|
||||
yield {
|
||||
value: path.value,
|
||||
jsonPath: stringify(path.path)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,653 @@
|
|||
#!/usr/bin/env node
|
||||
// load static module: ${__dirname }/static_modules.fs
|
||||
require('../static-loader.js').load(`${__dirname}/../static_modules.fs`)
|
||||
|
||||
// Ensure that if we're running in an electron process, that things will work as if it were node.
|
||||
process.env['ELECTRON_RUN_AS_NODE'] = "1";
|
||||
delete process.env['ELECTRON_NO_ATTACH_CONSOLE'];
|
||||
|
||||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { Message, Channel } from "../lib/message"
|
||||
import { JsonPath, SourceMap } from './source-map';
|
||||
import { IFileSystem } from "../lib/file-system";
|
||||
import { Artifact } from "../lib/artifact";
|
||||
import { ResolveUri, FileUriToPath, GetExtension, IsUri } from '../lib/ref/uri';
|
||||
import { From } from "linq-es2015";
|
||||
import { safeDump } from "js-yaml";
|
||||
import { DocumentAnalysis } from "./document-analysis";
|
||||
import { isFile, writeFile, isDirectory, readdir, readFile } from "@microsoft.azure/async-io"
|
||||
import { createHash } from 'crypto';
|
||||
import { Configuration } from "../lib/configuration"
|
||||
|
||||
import {
|
||||
IConnection,
|
||||
TextDocuments, DiagnosticSeverity, InitializedParams, TextDocument,
|
||||
InitializeParams, TextDocumentPositionParams, DidChangeConfigurationParams,
|
||||
Range, Position, DidChangeWatchedFilesParams, TextDocumentChangeEvent, Hover, Location,
|
||||
MarkedString, FileEvent, Diagnostic, createConnection,
|
||||
InitializeResult, DidChangeConfigurationNotification, Proposed, ProposedFeatures,
|
||||
TextDocumentSyncKind, IPCMessageReader, IPCMessageWriter
|
||||
} from 'vscode-languageserver';
|
||||
|
||||
|
||||
|
||||
//TODO: adding URL here temporarily, this should be coming either in the message coming from autorest or the plugin
|
||||
const azureValidatorRulesDocUrl = "https://github.com/Azure/azure-rest-api-specs/blob/current/documentation/openapi-authoring-automated-guidelines.md";
|
||||
|
||||
const md5 = (content: any) => content ? createHash('md5').update(JSON.stringify(content)).digest("hex") : null;
|
||||
|
||||
class Result {
|
||||
private readonly onDispose = new Array<() => void>();
|
||||
private files = new Array<string>();
|
||||
private busy: Promise<void> = Promise.resolve();
|
||||
|
||||
public readonly artifacts: Array<Artifact> = new Array<Artifact>();
|
||||
private readonly AutoRest: AutoRest;
|
||||
private static active = 0;
|
||||
|
||||
private dispose() {
|
||||
for (const each of this.onDispose) {
|
||||
each();
|
||||
}
|
||||
}
|
||||
public cancel: () => Promise<void> = async () => { };
|
||||
public ready = () => { };
|
||||
|
||||
constructor(private readonly service: OpenApiLanugageService, configurationUrl: string) {
|
||||
this.AutoRest = new AutoRest(service, configurationUrl);
|
||||
|
||||
this.onDispose.push(this.AutoRest.GeneratedFile.Subscribe((a, artifact) => this.artifacts.push(artifact)));
|
||||
this.onDispose.push(this.AutoRest.Message.Subscribe((au, message) => {
|
||||
switch (message.Channel) {
|
||||
case Channel.Debug:
|
||||
service.debug(message.Text);
|
||||
break;
|
||||
case Channel.Fatal:
|
||||
service.error(message.Text);
|
||||
break;
|
||||
case Channel.Verbose:
|
||||
service.verbose(message.Text);
|
||||
break;
|
||||
case Channel.Information:
|
||||
service.log(message.Text);
|
||||
break;
|
||||
|
||||
case Channel.Warning:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Warning);
|
||||
break;
|
||||
case Channel.Error:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Error);
|
||||
break;
|
||||
case Channel.Information:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Information);
|
||||
break;
|
||||
case Channel.Hint:
|
||||
service.pushDiagnostic(message, DiagnosticSeverity.Hint);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
|
||||
this.onDispose.push(this.AutoRest.Finished.Subscribe((a, success) => {
|
||||
// anything after it's done?
|
||||
service.debug(`Finished Autorest ${success}`);
|
||||
|
||||
// clear diagnostics for next run
|
||||
for (const f of this.files) {
|
||||
const diagnostics = this.service.getDiagnosticCollection(f);
|
||||
// make sure that the last of the last is sent
|
||||
diagnostics.send();
|
||||
|
||||
// then clear the collection it since we're sure this is the end of the run.
|
||||
diagnostics.clear();
|
||||
}
|
||||
Result.active--;
|
||||
this.updateStatus();
|
||||
this.ready();
|
||||
}));
|
||||
}
|
||||
|
||||
private updateStatus() {
|
||||
if (Result.active === 0) {
|
||||
this.service.setStatus("idle");
|
||||
return;
|
||||
}
|
||||
this.service.setStatus(`active:${Result.active}`);
|
||||
}
|
||||
|
||||
public async process() {
|
||||
Result.active++;
|
||||
this.updateStatus();
|
||||
|
||||
// make sure we're clear to start
|
||||
await this.busy;
|
||||
|
||||
// reset the busy flag
|
||||
this.busy = new Promise((r, j) => this.ready = r);
|
||||
|
||||
// ensure that we have nothing left over from before
|
||||
this.clear();
|
||||
|
||||
// set configuration
|
||||
await this.resetConfiguration(this.service.settings.configuration)
|
||||
|
||||
// get the list of files this is running on
|
||||
this.files = (await this.AutoRest.view).InputFileUris;
|
||||
|
||||
// start it up!
|
||||
const processResult = this.AutoRest.Process();
|
||||
|
||||
this.cancel = async () => {
|
||||
// cancel only once!
|
||||
this.cancel = async () => { };
|
||||
|
||||
// cancel the current process if running.
|
||||
processResult.cancel();
|
||||
};
|
||||
}
|
||||
|
||||
public async resetConfiguration(configuration: any) {
|
||||
// wipe the previous configuration
|
||||
await this.AutoRest.ResetConfiguration();
|
||||
|
||||
// set the basic defaults we need
|
||||
this.AutoRest.AddConfiguration({
|
||||
"output-artifact": ["swagger-document.json", "swagger-document.json.map"]
|
||||
// debug and verbose messages are not sent by default, turn them on so client settings can decide to show or not.
|
||||
, debug: true,
|
||||
verbose: true
|
||||
});
|
||||
|
||||
// apply settings from the client
|
||||
if (configuration) {
|
||||
this.AutoRest.AddConfiguration(configuration);
|
||||
}
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this.artifacts.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
class Diagnostics {
|
||||
// map allows us to hash the diagnostics to filter out duplicates.
|
||||
private diagnostics = new Map<string, Diagnostic>();
|
||||
|
||||
public constructor(private connection: IConnection, private fileUri: string) {
|
||||
}
|
||||
|
||||
public clear(send: boolean = false) {
|
||||
this.diagnostics.clear();
|
||||
if (send) {
|
||||
this.send();
|
||||
}
|
||||
}
|
||||
|
||||
public send() {
|
||||
this.connection.sendDiagnostics({ uri: this.fileUri, diagnostics: [...this.diagnostics.values()] });
|
||||
}
|
||||
|
||||
public push(diagnostic: Diagnostic, send: boolean = true) {
|
||||
const hash = md5(diagnostic) || "";
|
||||
if (!this.diagnostics.has(hash)) {
|
||||
this.diagnostics.set(hash, diagnostic);
|
||||
if (send) {
|
||||
this.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export interface generated {
|
||||
messages: Array<string>;
|
||||
files: Map<string, string>;
|
||||
}
|
||||
|
||||
export class OpenApiLanugageService extends TextDocuments implements IFileSystem {
|
||||
private results = new Map</*configfile*/string, Result>();
|
||||
private diagnostics = new Map</*file*/string, Diagnostics>();
|
||||
private virtualFile = new Map<string, TextDocument>();
|
||||
public settings: any = {};
|
||||
|
||||
public get(uri: string): TextDocument {
|
||||
const content = super.get(uri);
|
||||
if (!content) {
|
||||
const name = decodeURIComponent(uri);
|
||||
for (const each of super.all()) {
|
||||
if (decodeURIComponent(each.uri) === name) {
|
||||
return each;
|
||||
}
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
constructor(private connection: IConnection) {
|
||||
super();
|
||||
|
||||
// track opened, changed, saved, and closed files
|
||||
this.onDidOpen((p) => this.onDocumentChanged(p.document));
|
||||
this.onDidChangeContent((p) => this.onDocumentChanged(p.document));
|
||||
this.onDidClose((p) => this.getDiagnosticCollection(p.document.uri).clear(true));
|
||||
this.onDidSave((p) => this.onSaving(p.document));
|
||||
|
||||
// subscribe to client settings changes
|
||||
connection.onDidChangeConfiguration(config => config.settings && config.settings.autorest ? this.onSettingsChanged(config.settings.autorest) : null)
|
||||
|
||||
// we also get change notifications of files on disk:
|
||||
connection.onDidChangeWatchedFiles((changes) => this.onFileEvents(changes.changes));
|
||||
|
||||
// requests for hover/definitions
|
||||
connection.onHover((position, _cancel) => this.onHover(position));
|
||||
connection.onDefinition((position, _cancel) => this.onDefinition(position));
|
||||
|
||||
connection.onInitialize(params => this.onInitialize(params));
|
||||
|
||||
// connection.onRequest("generate", generateArgs => onGenerate(generateArgs))
|
||||
this.setStatus("Starting Up.");
|
||||
|
||||
// expose the features that we want to give to the client
|
||||
connection.onRequest("generate", (p) => this.generate(p.documentUri, p.language, p.configuration));
|
||||
connection.onRequest("isOpenApiDocument", (p) => this.isOpenApiDocument(p.contentOrUri));
|
||||
connection.onRequest("isConfigurationFile", (p) => this.isConfigurationFile(p.contentOrUri));
|
||||
connection.onRequest("isSupportedFile", (p) => this.isSupportedFile(p.languageId, p.contentOrUri));
|
||||
connection.onRequest("toJSON", (p) => this.toJSON(p.contentOrUri));
|
||||
connection.onRequest("findConfigurationFile", p => this.findConfigurationFile(p.documentUri));
|
||||
|
||||
|
||||
this.listen(connection);
|
||||
}
|
||||
|
||||
public async generate(documentUri: string, language: string, configuration: any): Promise<generated> {
|
||||
const cfgFile = await this.getConfiguration(documentUri);
|
||||
const autorest = new AutoRest(this, cfgFile);
|
||||
const cfg: any = {};
|
||||
cfg[language] = {
|
||||
"output-folder": "/generated"
|
||||
};
|
||||
autorest.AddConfiguration(cfg);
|
||||
autorest.AddConfiguration(configuration);
|
||||
|
||||
const result = {
|
||||
files: <any>{},
|
||||
messages: new Array<string>()
|
||||
};
|
||||
autorest.GeneratedFile.Subscribe((a, artifact) => result.files[artifact.uri] = artifact.content);
|
||||
autorest.Message.Subscribe((a, message) => result.messages.push(JSON.stringify(message, null, 2)));
|
||||
autorest.Finished.Subscribe((a, success) => { });
|
||||
const done = autorest.Process();
|
||||
await done.finish;
|
||||
|
||||
return result;
|
||||
}
|
||||
public async isOpenApiDocument(contentOrUri: string): Promise<boolean> {
|
||||
return IsUri(contentOrUri) ? await AutoRest.IsSwaggerFile(await this.ReadFile(contentOrUri)) : await AutoRest.IsSwaggerFile(contentOrUri);
|
||||
}
|
||||
public async isConfigurationFile(contentOrUri: string): Promise<boolean> {
|
||||
return IsUri(contentOrUri) ? await AutoRest.IsConfigurationFile(await this.ReadFile(contentOrUri)) : await AutoRest.IsConfigurationFile(contentOrUri);
|
||||
}
|
||||
public async isSupportedFile(languageId: string, contentOrUri: string): Promise<boolean> {
|
||||
if (AutoRest.IsSwaggerExtension(languageId) || AutoRest.IsConfigurationExtension(languageId)) {
|
||||
// so far, so good.
|
||||
const content = IsUri(contentOrUri) ? await this.ReadFile(contentOrUri) : contentOrUri;
|
||||
const isSwag = AutoRest.IsSwaggerFile(content);
|
||||
const isConf = AutoRest.IsConfigurationFile(content);
|
||||
return await isSwag || await isConf;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
public async toJSON(contentOrUri: string): Promise<string> {
|
||||
return IsUri(contentOrUri) ? await AutoRest.LiterateToJson(await this.ReadFile(contentOrUri)) : await AutoRest.LiterateToJson(contentOrUri);
|
||||
}
|
||||
public async findConfigurationFile(documentUri: string): Promise<string> {
|
||||
return await AutoRest.DetectConfigurationFile(this, documentUri, true) || "";
|
||||
}
|
||||
|
||||
public setStatus(message: string) {
|
||||
this.connection.sendNotification("status", message);
|
||||
}
|
||||
|
||||
private async onSettingsChanged(serviceSettings: any) {
|
||||
// snapshot the current autorest configuration from the client
|
||||
const hash = md5(this.settings.configuration);
|
||||
this.settings = serviceSettings || {};
|
||||
|
||||
if (hash !== md5(this.settings.configuration)) {
|
||||
// if the configuration change involved a change in the autorest configuration
|
||||
// we should activate all the open documents again.
|
||||
for (const document of this.all()) {
|
||||
this.onDocumentChanged(document);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async onInitialize(params: InitializeParams): Promise<InitializeResult> {
|
||||
await this.onRootUriChanged(params.rootPath || null);
|
||||
|
||||
return {
|
||||
capabilities: {
|
||||
definitionProvider: true,
|
||||
hoverProvider: true,
|
||||
|
||||
// Tell the client that the server works in FULL text document sync mode
|
||||
textDocumentSync: TextDocumentSyncKind.Full,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async onSaving(document: TextDocument) {
|
||||
|
||||
}
|
||||
|
||||
private async getDocumentAnalysis(documentUri: string): Promise<DocumentAnalysis | null> {
|
||||
const config = await this.getConfiguration(documentUri);
|
||||
const result = this.results.get(config);
|
||||
if (result) {
|
||||
await result.ready; // wait for any current process to finish.
|
||||
const outputs = result.artifacts;
|
||||
const openapiDefinition = From(outputs).Where(x => x.type === "swagger-document.json").Select(x => JSON.parse(x.content)).FirstOrDefault();
|
||||
const openapiDefinitionMap = From(outputs).Where(x => x.type === "swagger-document.json.map").Select(x => JSON.parse(x.content)).FirstOrDefault();
|
||||
|
||||
if (openapiDefinition && openapiDefinitionMap) {
|
||||
return new DocumentAnalysis(
|
||||
documentUri,
|
||||
await this.ReadFile(documentUri),
|
||||
openapiDefinition,
|
||||
new SourceMap(openapiDefinitionMap));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*@internal*/ public getDiagnosticCollection(fileUri: string): Diagnostics {
|
||||
const diag = this.diagnostics.get(fileUri) || new Diagnostics(this.connection, fileUri);
|
||||
this.diagnostics.set(fileUri, diag);
|
||||
return diag;
|
||||
}
|
||||
|
||||
public pushDiagnostic(message: Message, severity: DiagnosticSeverity) {
|
||||
let moreInfo = "";
|
||||
if (message.Plugin === "azure-validator") {
|
||||
if (message.Key) {
|
||||
moreInfo = "\n More info: " + azureValidatorRulesDocUrl + "#" + [...message.Key][1].toLowerCase() + "-" + [...message.Key][0].toLowerCase() + "\n";
|
||||
}
|
||||
}
|
||||
if (message.Range) {
|
||||
for (const each of message.Range) {
|
||||
// get the file reference first
|
||||
|
||||
|
||||
const file = this.getDiagnosticCollection(each.document);
|
||||
|
||||
if (file) {
|
||||
file.push({
|
||||
severity: severity,
|
||||
range: Range.create(Position.create(each.start.line - 1, each.start.column), Position.create(each.end.line - 1, each.end.column)),
|
||||
message: message.Text + moreInfo,
|
||||
source: message.Key ? [...message.Key].join("/") : ""
|
||||
});
|
||||
} else {
|
||||
// console.log(each.document)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private * onHoverRef(docAnalysis: DocumentAnalysis, position: Position): Iterable<MarkedString> {
|
||||
const refValueJsonPath = docAnalysis.GetJsonPathFromJsonReferenceAt(position);
|
||||
if (refValueJsonPath) {
|
||||
|
||||
for (const location of docAnalysis.GetDefinitionLocations(refValueJsonPath)) {
|
||||
yield {
|
||||
language: "yaml",
|
||||
value: safeDump(location.value)
|
||||
};
|
||||
}
|
||||
} // else {console.log("found nothing that looks like a JSON reference"); return null; }
|
||||
}
|
||||
|
||||
private * onHoverJsonPath(docAnalysis: DocumentAnalysis, position: Position): Iterable<MarkedString> {
|
||||
const potentialQuery: string = <string>docAnalysis.GetJsonQueryAt(position);
|
||||
if (potentialQuery) {
|
||||
|
||||
const queryNodes = [...docAnalysis.GetDefinitionLocations(potentialQuery)];
|
||||
yield {
|
||||
language: "plaintext",
|
||||
value: `${queryNodes.length} matches\n${queryNodes.map(node => node.jsonPath).join("\n")}`
|
||||
};
|
||||
} // else { console.log("found nothing that looks like a JSON path"); return null; }
|
||||
}
|
||||
|
||||
|
||||
private async onHover(position: TextDocumentPositionParams): Promise<Hover> {
|
||||
const docAnalysis = await this.getDocumentAnalysis(position.textDocument.uri);
|
||||
return docAnalysis ? <Hover>{
|
||||
contents: [
|
||||
...this.onHoverRef(docAnalysis, position.position),
|
||||
...this.onHoverJsonPath(docAnalysis, position.position)
|
||||
]
|
||||
} : <Hover><any>null
|
||||
}
|
||||
|
||||
private onDefinitionRef(docAnalysis: DocumentAnalysis, position: Position): Iterable<Location> {
|
||||
const refValueJsonPath = docAnalysis.GetJsonPathFromJsonReferenceAt(position);
|
||||
if (refValueJsonPath) {
|
||||
return docAnalysis.GetDocumentLocations(refValueJsonPath);
|
||||
} // else { console.log("found nothing that looks like a JSON reference"); }
|
||||
return [];
|
||||
}
|
||||
|
||||
private onDefinitionJsonPath(docAnalysis: DocumentAnalysis, position: Position): Iterable<Location> {
|
||||
const potentialQuery: string = <string>docAnalysis.GetJsonQueryAt(position);
|
||||
if (potentialQuery) {
|
||||
|
||||
return docAnalysis.GetDocumentLocations(potentialQuery);
|
||||
} // else { console.log("found nothing that looks like a JSON path");}
|
||||
return [];
|
||||
}
|
||||
|
||||
private async onDefinition(position: TextDocumentPositionParams): Promise<Location[]> {
|
||||
const docAnalysis = await this.getDocumentAnalysis(position.textDocument.uri);
|
||||
return docAnalysis ? [
|
||||
...this.onDefinitionRef(docAnalysis, position.position),
|
||||
...this.onDefinitionJsonPath(docAnalysis, position.position)
|
||||
] : [];
|
||||
}
|
||||
|
||||
private async onFileEvents(changes: FileEvent[]) {
|
||||
this.debug(`onFileEvents: ${changes}`);
|
||||
for (const each of changes) {
|
||||
|
||||
const doc = this.get(each.uri);
|
||||
if (doc) {
|
||||
this.onDocumentChanged(doc);
|
||||
return;
|
||||
}
|
||||
|
||||
let documentUri = each.uri;
|
||||
const txt = await this.ReadFile(each.uri);
|
||||
if (documentUri.startsWith("file://")) {
|
||||
// fake out a document for us to play with
|
||||
this.onDocumentChanged({
|
||||
uri: each.uri,
|
||||
languageId: "",
|
||||
version: 1,
|
||||
getText: () => txt,
|
||||
positionAt: (offset: number) => <Position>{},
|
||||
offsetAt: (position: Position) => 0,
|
||||
lineCount: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// IFileSystem Implementation
|
||||
public async EnumerateFileUris(folderUri: string): Promise<Array<string>> {
|
||||
if (folderUri && folderUri.startsWith("file:")) {
|
||||
const folderPath = FileUriToPath(folderUri);
|
||||
if (await isDirectory(folderPath)) {
|
||||
const items = await readdir(folderPath);
|
||||
return From<string>(items).Where(each => AutoRest.IsConfigurationExtension(GetExtension(each))).Select(each => ResolveUri(folderUri, each)).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public async ReadFile(fileUri: string): Promise<string> {
|
||||
const doc = this.get(fileUri) || this.virtualFile.get(fileUri);
|
||||
try {
|
||||
if (doc) {
|
||||
return doc.getText();
|
||||
}
|
||||
|
||||
const content = await readFile(FileUriToPath(fileUri));
|
||||
|
||||
return content;
|
||||
} catch {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private async process(configurationUrl: string) {
|
||||
const result = this.results.get(configurationUrl) || new Result(this, configurationUrl);
|
||||
this.results.set(configurationUrl, result);
|
||||
|
||||
// ensure that we are no longer processing a previous run.
|
||||
await result.cancel();
|
||||
|
||||
// process the files.
|
||||
await result.process();
|
||||
}
|
||||
|
||||
private async getConfiguration(documentUri: string): Promise<string> {
|
||||
// let folder = ResolveUri(documentUri, ".");
|
||||
let configFiles = await Configuration.DetectConfigurationFiles(this, documentUri, undefined, true);
|
||||
|
||||
// is the document a config file?
|
||||
if (configFiles.length === 1 && configFiles[0] == documentUri) {
|
||||
return documentUri;
|
||||
}
|
||||
|
||||
// is there a config file that contains the document as an input?
|
||||
for (const configFile of configFiles) {
|
||||
const a = new AutoRest(this, configFile);
|
||||
const inputs = (await a.view).InputFileUris
|
||||
for (const input of inputs) {
|
||||
if (input === documentUri || decodeURIComponent(input) == decodeURIComponent(documentUri)) {
|
||||
return configFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find a match, let's make a dummy one.
|
||||
const configFile = `${documentUri}/readme.md`;
|
||||
if (!this.virtualFile.get(configFile)) {
|
||||
this.virtualFile.set(configFile, {
|
||||
uri: configFile,
|
||||
languageId: "markdown",
|
||||
version: 1,
|
||||
getText: () => "#Fake config file \n> see https://aka.ms/autorest \n``` yaml \ninput-file: \n - " + documentUri,
|
||||
positionAt: (offset: number) => <Position>{},
|
||||
offsetAt: (position: Position) => 0,
|
||||
lineCount: 1
|
||||
});
|
||||
}
|
||||
|
||||
return configFile;
|
||||
}
|
||||
|
||||
private async onDocumentChanged(document: TextDocument) {
|
||||
this.debug(`onDocumentChanged: ${document.uri}`);
|
||||
|
||||
if (AutoRest.IsSwaggerExtension(document.languageId) && await AutoRest.IsSwaggerFile(document.getText())) {
|
||||
// find the configuration file and activate that.
|
||||
this.process(await this.getConfiguration(document.uri));
|
||||
return;
|
||||
}
|
||||
|
||||
// is this a config file?
|
||||
if (AutoRest.IsConfigurationExtension(document.languageId) && await AutoRest.IsConfigurationFile(document.getText())) {
|
||||
this.process(document.uri);
|
||||
return;
|
||||
}
|
||||
|
||||
// neither
|
||||
// clear any results we have for this.
|
||||
const result = this.results.get(document.uri);
|
||||
if (result) {
|
||||
// this used to be a config file
|
||||
result.cancel();
|
||||
result.clear();
|
||||
}
|
||||
|
||||
// let's clear anything we may have sent for this file.
|
||||
this.getDiagnosticCollection(document.uri).clear(true);
|
||||
}
|
||||
|
||||
public async onRootUriChanged(rootUri: string | null) {
|
||||
this.debug(`onRootUriChanged: ${rootUri}`);
|
||||
if (rootUri) {
|
||||
// check this folder for a configuration file
|
||||
const configFile = await Configuration.DetectConfigurationFile(this, rootUri, undefined, false);
|
||||
|
||||
if (configFile) {
|
||||
const content = await this.ReadFile(configFile);
|
||||
const document = {
|
||||
uri: configFile,
|
||||
languageId: "markdown",
|
||||
version: 1,
|
||||
getText: () => content,
|
||||
positionAt: (offset: number) => <Position>{},
|
||||
offsetAt: (position: Position) => 0,
|
||||
lineCount: 1
|
||||
};
|
||||
this.virtualFile.set(configFile, document);
|
||||
this.onDocumentChanged(document);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public error(text: string) {
|
||||
this.connection.console.error(text);
|
||||
}
|
||||
public debug(text: string) {
|
||||
if (this.settings.debug) {
|
||||
this.connection.console.info(text);
|
||||
}
|
||||
}
|
||||
public log(text: string) {
|
||||
this.connection.console.log(text);
|
||||
}
|
||||
public verbose(text: string) {
|
||||
if (this.settings.verbose) {
|
||||
this.connection.console.log(text);
|
||||
}
|
||||
}
|
||||
public verboseDebug(text: string) {
|
||||
if (this.settings.verbose && this.settings.debug) {
|
||||
this.connection.console.info(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the IPC Channel for the lanaguage service.
|
||||
let connection: IConnection = createConnection(new IPCMessageReader(process), new IPCMessageWriter(process));
|
||||
let languageService = new OpenApiLanugageService(connection);
|
||||
|
||||
process.on("unhandledRejection", function (err) {
|
||||
//
|
||||
// @Future_Garrett - only turn this on as a desperate move of last resort.
|
||||
// You'll be sorry, and you will waste another day going down this rat hole
|
||||
// looking for the reason something is failing only to find out that it's only
|
||||
// during the detection if a file is swagger or not, and then you'll
|
||||
// realize why I wrote this message. Don't say I didn't warn you.
|
||||
// -- @Past_Garrett
|
||||
//
|
||||
// languageService.verboseDebug(`Unhandled Rejection Suppressed: ${err}`);
|
||||
});
|
||||
|
||||
|
||||
// Listen on the connection
|
||||
connection.listen();
|
|
@ -0,0 +1,83 @@
|
|||
// ---------------------------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
import { RawSourceMap, SourceMapConsumer } from "source-map";
|
||||
|
||||
export type JsonPath = (number | string)[];
|
||||
|
||||
export class SourceMap {
|
||||
private consumer: SourceMapConsumer;
|
||||
|
||||
public constructor(map: RawSourceMap) {
|
||||
this.consumer = new SourceMapConsumer(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the source map to determine which mappings are associated with a certain JSON path.
|
||||
* @param path The JSON path to lookup.
|
||||
*/
|
||||
public LookupPath(path: JsonPath): sourceMap.MappingItem[] {
|
||||
const result: sourceMap.MappingItem[] = [];
|
||||
this.consumer.eachMapping(mi => {
|
||||
const itemPath = this.ExtractJsonPath(mi);
|
||||
if (itemPath && itemPath.length === path.length && itemPath.every((part, index) => itemPath[index].toString() === path[index].toString())) {
|
||||
result.push(mi);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the source map to determine which locations in the generated file where influenced by given location in a source file.
|
||||
* @param file Source file having influenced the generated file.
|
||||
* @param line Line in the source file having influenced the generated file.
|
||||
* @param column Column in the source file having influenced the generated file.
|
||||
*/
|
||||
public LookupForward(file: string, line: number, column: number): { line: number, column: number, path: JsonPath | null }[] {
|
||||
const sameLineResults: sourceMap.MappingItem[] = [];
|
||||
this.consumer.eachMapping(mi => {
|
||||
if (((mi.source === file) || (decodeURIComponent(mi.source) === decodeURIComponent(file))) && mi.originalLine === line && mi.originalColumn <= column) {
|
||||
sameLineResults.push(mi);
|
||||
}
|
||||
});
|
||||
const maxColumn = sameLineResults.map(mi => mi.originalColumn).reduce((a, b) => Math.max(a, b), 0);
|
||||
return sameLineResults
|
||||
.filter(mi => mi.originalColumn === maxColumn)
|
||||
.map(mi => { return { line: mi.generatedLine, column: mi.generatedColumn, path: this.ExtractJsonPath(mi) }; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the source map to determine which locations in the source files where influenced by given location in the generated file.
|
||||
* @param line Line in the generated file having influenced the generated file.
|
||||
* @param column Column in the generated file having influenced the generated file.
|
||||
*/
|
||||
public LookupBackwards(line: number, column: number): { file: string, line: number, column: number, path: JsonPath | null }[] {
|
||||
const sameLineResults: sourceMap.MappingItem[] = [];
|
||||
this.consumer.eachMapping(mi => {
|
||||
if (mi.generatedLine === line && mi.generatedColumn <= column) {
|
||||
sameLineResults.push(mi);
|
||||
}
|
||||
});
|
||||
const maxColumn = sameLineResults.map(mi => mi.generatedColumn).reduce((a, b) => Math.max(a, b), 0);
|
||||
return sameLineResults
|
||||
.filter(mi => mi.generatedColumn === maxColumn)
|
||||
.map(mi => { return { file: mi.source, line: mi.originalLine, column: mi.originalColumn, path: this.ExtractJsonPath(mi) }; });
|
||||
}
|
||||
|
||||
/**
|
||||
* AutoRest stores rich information in the "name" field available in source maps.
|
||||
* This function tries to extract a JSON path from a mapping.
|
||||
* @param mi The mapping to extract the JSON path from.
|
||||
*/
|
||||
private ExtractJsonPath(mi: sourceMap.MappingItem): JsonPath | null {
|
||||
try {
|
||||
const pathPart = mi.name.split("\n")[0];
|
||||
return JSON.parse(pathPart);
|
||||
} catch (e) {
|
||||
console.warn("Failed obtaining object path from mapping item", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -88,8 +88,8 @@ export class AutoRest extends EventEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
public static async DetectConfigurationFile(fileSystem: IFileSystem, documentPath?: string): Promise<string | null> {
|
||||
return Configuration.DetectConfigurationFile(fileSystem, (documentPath || null));
|
||||
public static async DetectConfigurationFile(fileSystem: IFileSystem, documentPath?: string, walkUpFolders?: boolean): Promise<string | null> {
|
||||
return Configuration.DetectConfigurationFile(fileSystem, (documentPath || null), undefined, walkUpFolders);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,6 +141,10 @@ export class AutoRest extends EventEmitter {
|
|||
return this._view = await new Configuration(this.fileSystem, this.configFileOrFolderUri).CreateView(messageEmitter, includeDefault, ...this._configurations);
|
||||
}
|
||||
|
||||
public static async Shutdown() {
|
||||
await Configuration.shutdown();
|
||||
}
|
||||
|
||||
public Invalidate() {
|
||||
if (this._view) {
|
||||
this._view.messageEmitter.removeAllListeners();
|
||||
|
|
|
@ -27,6 +27,7 @@ import { BlameTree } from './source-map/blaming';
|
|||
import { MergeOverwriteOrAppend, resolveRValue } from './source-map/merging';
|
||||
import { TryDecodeEnhancedPositionFromName } from './source-map/source-map';
|
||||
import { safeEval } from './ref/safe-eval';
|
||||
import { OutstandingTaskAwaiter } from "./outstanding-task-awaiter"
|
||||
|
||||
const untildify: (path: string) => string = require("untildify");
|
||||
|
||||
|
@ -240,7 +241,7 @@ export class ConfigurationView {
|
|||
this.config = this.rawConfig;
|
||||
}
|
||||
this.suppressor = new Suppressor(this);
|
||||
this.Message({ Channel: Channel.Debug, Text: `Creating ConfigurationView : ${configs.length} sections.` });
|
||||
// this.Message({ Channel: Channel.Debug, Text: `Creating ConfigurationView : ${configs.length} sections.` });
|
||||
}
|
||||
|
||||
public get Keys(): Array<string> {
|
||||
|
@ -393,16 +394,23 @@ export class ConfigurationView {
|
|||
let blameTree: BlameTree | null = null;
|
||||
|
||||
try {
|
||||
const originalPath = JSON.stringify(s.Position.path);
|
||||
let shouldComplain = false;
|
||||
while (blameTree === null) {
|
||||
try {
|
||||
blameTree = this.DataStore.Blame(s.document, s.Position);
|
||||
} catch (e) {
|
||||
const path = s.Position.path as string[];
|
||||
if (path) {
|
||||
if (shouldComplain) {
|
||||
this.Message({
|
||||
Channel: Channel.Verbose,
|
||||
Text: `Could not find the exact path ${JSON.stringify(path)} for ${JSON.stringify(m.Text)}`
|
||||
Text: `\nDEVELOPER-WARNING: Path '${originalPath}' was corrected to ${JSON.stringify(s.Position.path)} on MESSAGE '${JSON.stringify(m.Text)}'\n`
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (!shouldComplain) {
|
||||
shouldComplain = true;
|
||||
}
|
||||
const path = s.Position.path as string[];
|
||||
if (path) {
|
||||
if (path.length === 0) {
|
||||
throw e;
|
||||
}
|
||||
|
@ -593,6 +601,17 @@ export class Configuration {
|
|||
return Promise.all(configs.map(c => this.DesugarRawConfig(c)));
|
||||
}
|
||||
|
||||
public static async shutdown() {
|
||||
for (const each in loadedExtensions) {
|
||||
const ext = loadedExtensions[each];
|
||||
if (ext.autorestExtension.hasValue) {
|
||||
const extension = await ext.autorestExtension;
|
||||
extension.kill();
|
||||
delete loadedExtensions[each];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async CreateView(messageEmitter: MessageEmitter, includeDefault: boolean, ...configs: Array<any>): Promise<ConfigurationView> {
|
||||
const configFileUri = this.fileSystem && this.configFileOrFolderUri
|
||||
? await Configuration.DetectConfigurationFile(this.fileSystem, this.configFileOrFolderUri, messageEmitter)
|
||||
|
@ -746,64 +765,60 @@ export class Configuration {
|
|||
|
||||
return createView().Indexer;
|
||||
}
|
||||
|
||||
public static async DetectConfigurationFile(fileSystem: IFileSystem, configFileOrFolderUri: string | null, messageEmitter?: MessageEmitter, walkUpFolders: boolean = false): Promise<string | null> {
|
||||
const files = await this.DetectConfigurationFiles(fileSystem, configFileOrFolderUri, messageEmitter, walkUpFolders);
|
||||
|
||||
return From<string>(files).FirstOrDefault(each => each.toLowerCase().endsWith("/" + Constants.DefaultConfiguration)) ||
|
||||
From<string>(files).OrderBy(each => each.length).FirstOrDefault() || null;
|
||||
}
|
||||
|
||||
public static async DetectConfigurationFiles(fileSystem: IFileSystem, configFileOrFolderUri: string | null, messageEmitter?: MessageEmitter, walkUpFolders: boolean = false): Promise<Array<string>> {
|
||||
const results = new Array<string>();
|
||||
const originalConfigFileOrFolderUri = configFileOrFolderUri;
|
||||
|
||||
//
|
||||
if (!configFileOrFolderUri || configFileOrFolderUri.endsWith(".md")) {
|
||||
return configFileOrFolderUri;
|
||||
// null means null!
|
||||
if (!configFileOrFolderUri) {
|
||||
return results;
|
||||
}
|
||||
|
||||
// try querying the Uri directly
|
||||
if (ExistsUri(configFileOrFolderUri)) {
|
||||
try {
|
||||
const content = await fileSystem.ReadFile(configFileOrFolderUri);
|
||||
try {
|
||||
const content = await fileSystem.ReadFile(configFileOrFolderUri);
|
||||
if (content.indexOf(Constants.MagicString) > -1) {
|
||||
// the file name was passed in!
|
||||
return [configFileOrFolderUri];
|
||||
}
|
||||
// this *was* an actual file passed in, not a folder. don't make this harder than it has to be.
|
||||
return results;
|
||||
} catch {
|
||||
// didn't get the file successfully, move on.
|
||||
}
|
||||
|
||||
// scan the filesystem items for configurations.
|
||||
for (const name of await fileSystem.EnumerateFileUris(EnsureIsFolderUri(configFileOrFolderUri))) {
|
||||
if (name.endsWith(".md")) {
|
||||
const content = await fileSystem.ReadFile(name);
|
||||
if (content.indexOf(Constants.MagicString) > -1) {
|
||||
return configFileOrFolderUri;
|
||||
results.push(name);
|
||||
}
|
||||
} catch (e) {
|
||||
// that didn't work... try next
|
||||
}
|
||||
}
|
||||
|
||||
// search for a config file, walking up the folder tree
|
||||
while (configFileOrFolderUri !== null) {
|
||||
// scan the filesystem items for the configuration.
|
||||
const configFiles = new Map<string, string>();
|
||||
|
||||
for (const name of await fileSystem.EnumerateFileUris(EnsureIsFolderUri(configFileOrFolderUri))) {
|
||||
if (name.endsWith(".md")) {
|
||||
const content = await fileSystem.ReadFile(name);
|
||||
if (content.indexOf(Constants.MagicString) > -1) {
|
||||
configFiles.set(name, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configFiles.size > 0) {
|
||||
// it's the readme.md or the shortest filename.
|
||||
const found =
|
||||
From<string>(configFiles.keys()).FirstOrDefault(each => each.toLowerCase().endsWith("/" + Constants.DefaultConfiguration)) ||
|
||||
From<string>(configFiles.keys()).OrderBy(each => each.length).First();
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
if (walkUpFolders) {
|
||||
// walk up
|
||||
const newUriToConfigFileOrWorkingFolder = ResolveUri(configFileOrFolderUri, "..");
|
||||
configFileOrFolderUri = !walkUpFolders || newUriToConfigFileOrWorkingFolder === configFileOrFolderUri
|
||||
? null
|
||||
: newUriToConfigFileOrWorkingFolder;
|
||||
if (newUriToConfigFileOrWorkingFolder !== configFileOrFolderUri) {
|
||||
results.push(... await this.DetectConfigurationFiles(fileSystem, newUriToConfigFileOrWorkingFolder, messageEmitter, walkUpFolders))
|
||||
}
|
||||
} else {
|
||||
if (messageEmitter && results.length === 0) {
|
||||
messageEmitter.Message.Dispatch({
|
||||
Channel: Channel.Warning,
|
||||
Text: `No configuration found at '${originalConfigFileOrFolderUri}'.`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (messageEmitter) {
|
||||
messageEmitter.Message.Dispatch({
|
||||
Channel: Channel.Warning,
|
||||
Text: `No configuration found at '${originalConfigFileOrFolderUri}'.`
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
return results;
|
||||
}
|
||||
}
|
|
@ -30,6 +30,10 @@ export class LazyPromise<T> implements PromiseLike<T> {
|
|||
return this.promise;
|
||||
}
|
||||
|
||||
public get hasValue(): boolean {
|
||||
return this.promise !== null;
|
||||
}
|
||||
|
||||
then<TResult1, TResult2>(
|
||||
onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>,
|
||||
onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2> {
|
||||
|
|
|
@ -12,6 +12,7 @@ export enum Channel {
|
|||
Debug = <any>"debug",
|
||||
Verbose = <any>"verbose",
|
||||
Fatal = <any>"fatal",
|
||||
Hint = <any>"hint",
|
||||
}
|
||||
|
||||
export interface SourceLocation {
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
|
||||
import { OutstandingTaskAlreadyCompletedException } from "./exception";
|
||||
|
||||
|
||||
export class OutstandingTaskAwaiter {
|
||||
private locked: boolean = false;
|
||||
private outstandingTasks: Promise<any>[] = [];
|
||||
|
||||
|
||||
public async Wait(): Promise<void> {
|
||||
this.locked = true;
|
||||
await Promise.all(this.outstandingTasks);
|
||||
|
|
|
@ -361,6 +361,7 @@ export async function RunPipeline(configView: ConfigurationView, fileSystem: IFi
|
|||
// execute pipeline
|
||||
const barrier = new OutstandingTaskAwaiter();
|
||||
const barrierRobust = new OutstandingTaskAwaiter();
|
||||
|
||||
for (const name of Object.keys(pipeline.pipeline)) {
|
||||
const task = getTask(name);
|
||||
const taskx: { _state: "running" | "failed" | "complete", _result: () => DataHandle[], _finishedAt: number } = task as any;
|
||||
|
@ -372,14 +373,18 @@ export async function RunPipeline(configView: ConfigurationView, fileSystem: IFi
|
|||
taskx._finishedAt = Date.now();
|
||||
}).catch(() => taskx._state = "failed");
|
||||
barrier.Await(task);
|
||||
barrierRobust.Await(task.catch(() => null));
|
||||
barrierRobust.Await(task.catch(() => { }));
|
||||
}
|
||||
|
||||
try {
|
||||
await barrier.Wait();
|
||||
} catch (e) {
|
||||
// wait for outstanding nodes
|
||||
await barrierRobust.Wait();
|
||||
try {
|
||||
await barrierRobust.Wait();
|
||||
} catch {
|
||||
// wait for others to fail or whatever...
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
|
@ -35,13 +35,17 @@ export class AutoRestExtension extends EventEmitter {
|
|||
private static lastSessionId: number = 0;
|
||||
private static CreateSessionId(): string { return `session_${++AutoRestExtension.lastSessionId}`; }
|
||||
|
||||
public kill() {
|
||||
this.childProcess.kill();
|
||||
}
|
||||
|
||||
public static async FromModule(modulePath: string): Promise<AutoRestExtension> {
|
||||
const childProc = fork(modulePath, [], <any>{ silent: true });
|
||||
return AutoRestExtension.FromChildProcess(modulePath, childProc);
|
||||
}
|
||||
|
||||
public static async FromChildProcess(extensionName: string, childProc: ChildProcess): Promise<AutoRestExtension> {
|
||||
const plugin = new AutoRestExtension(extensionName, childProc.stdout, childProc.stdin);
|
||||
const plugin = new AutoRestExtension(extensionName, childProc.stdout, childProc.stdin, childProc);
|
||||
childProc.stderr.pipe(process.stderr);
|
||||
|
||||
// poke the extension to detect trivial issues like process startup failure or protocol violations, ...
|
||||
|
@ -55,7 +59,7 @@ export class AutoRestExtension extends EventEmitter {
|
|||
// Exposed through __status and consumed by tools like autorest-interactive.
|
||||
private __inspectTraffic: [number, boolean /*outgoing (core => ext)*/, string][] = [];
|
||||
|
||||
public constructor(private extensionName: string, reader: Readable, writer: Writable) {
|
||||
public constructor(private extensionName: string, reader: Readable, writer: Writable, private childProcess: ChildProcess) {
|
||||
super();
|
||||
|
||||
// hook in inspectors
|
||||
|
@ -148,7 +152,8 @@ export class AutoRestExtension extends EventEmitter {
|
|||
});
|
||||
|
||||
// name transformation
|
||||
const friendly2internal: (name: string) => Promise<string | undefined> = async name => ((await inputFileHandles).filter(h => h.Description === name)[0] || {}).key;
|
||||
// decodeUriComponent horsehockey is there because we may have an over-decoded URI from the plugin.
|
||||
const friendly2internal: (name: string) => Promise<string | undefined> = async name => ((await inputFileHandles).filter(h => h.Description === name || decodeURIComponent(h.Description) === decodeURIComponent(name))[0] || {}).key;
|
||||
const internal2friendly: (name: string) => Promise<string | undefined> = async key => (await inputScope.Read(key) || <any>{}).Description;
|
||||
|
||||
let finishNotifications: Promise<void> = Promise.resolve();
|
||||
|
|
|
@ -13,7 +13,7 @@ export function IsUri(uri: string): boolean {
|
|||
import * as promisify from "pify";
|
||||
import { Readable } from "stream";
|
||||
import { parse } from "url";
|
||||
import { sep } from "path";
|
||||
import { sep, extname } from "path";
|
||||
|
||||
const stripBom: (text: string) => string = require("strip-bom");
|
||||
const getUri = require("get-uri");
|
||||
|
@ -162,6 +162,9 @@ export function ResolveUri(baseUri: string, pathOrUri: string): string {
|
|||
try {
|
||||
const base = new URI(baseUri);
|
||||
const relative = new URI(pathOrUri);
|
||||
if (baseUri.startsWith("untitled:///") && pathOrUri.startsWith("untitled:")) {
|
||||
return pathOrUri;
|
||||
}
|
||||
const result = relative.absoluteTo(base);
|
||||
// GitHub simple token forwarding, for when you pass a URI to a private repo file with `?token=` query parameter.
|
||||
// this may be easier for quick testing than getting and passing an OAuth token.
|
||||
|
@ -281,4 +284,30 @@ import { rmdir } from "@microsoft.azure/async-io";
|
|||
export async function ClearFolder(folderUri: string): Promise<void> {
|
||||
const path = FileUriToLocalPath(folderUri);
|
||||
return rmdir(path);
|
||||
}
|
||||
|
||||
export function FileUriToPath(fileUri: string): string {
|
||||
const uri = parse(fileUri);
|
||||
if (uri.protocol !== "file:") {
|
||||
throw `Protocol '${uri.protocol}' not supported for writing.`;
|
||||
}
|
||||
// convert to path
|
||||
let p = uri.path;
|
||||
if (p === undefined) {
|
||||
throw `Cannot write to '${uri}'. Path not found.`;
|
||||
}
|
||||
if (sep === "\\") {
|
||||
p = p.substr(p.startsWith("/") ? 1 : 0);
|
||||
p = p.replace(/\//g, "\\");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
export function GetExtension(name: string) {
|
||||
let ext = extname(name);
|
||||
if (ext) {
|
||||
return ext.substr(1).toLowerCase();
|
||||
}
|
||||
return ext;
|
||||
}
|
|
@ -3,10 +3,8 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// enable static modules for autorest-core
|
||||
if ((<any>global).StaticVolumeSet) {
|
||||
(<any>global).StaticVolumeSet.addFileSystem(`${__dirname}/static_modules.fs`)
|
||||
}
|
||||
// load static module: ${__dirname }/static_modules.fs
|
||||
require('./static-loader.js').load(`${__dirname}/static_modules.fs`)
|
||||
|
||||
export { IFileSystem } from "./lib/file-system"
|
||||
export { Message, Channel } from "./lib/message"
|
||||
|
|
|
@ -19,57 +19,52 @@
|
|||
},
|
||||
"homepage": "https://github.com/Azure/autorest/readme.md",
|
||||
"main": "./dist/main.js",
|
||||
"bin": {
|
||||
"autorest-core": "./dist/app.js",
|
||||
"autorest-language-service": "dist/language-service/language-service.js"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "./node_modules/.bin/mocha ./dist/test --timeout 0",
|
||||
"prepare": "shx mkdir -p ./dist/ && cd ./static_modules && npm install",
|
||||
"build": "tsc -p . && static-link",
|
||||
"static-link": "static-link",
|
||||
"postinstall": "static-link --force || exit 0",
|
||||
"prepublishonly": "gulp build"
|
||||
},
|
||||
"typings": "./dist/main.d.ts",
|
||||
"devDependencies": {
|
||||
"@microsoft.azure/async-io": "~1.0.22",
|
||||
"@microsoft.azure/extension": "~1.2.12",
|
||||
"@types/commonmark": "^0.27.0",
|
||||
"@types/js-yaml": "^3.5.31",
|
||||
"@types/jsonpath": "^0.1.29",
|
||||
"@types/node": "^8.0.28",
|
||||
"@types/pify": "0.0.28",
|
||||
"@types/source-map": "^0.5.0",
|
||||
"@types/yargs": "^8.0.2",
|
||||
"commonmark": "^0.27.0",
|
||||
"file-url": "^2.0.2",
|
||||
"get-uri": "^2.0.0",
|
||||
"jsonpath": "^0.2.11",
|
||||
"linq-es2015": "^2.4.25",
|
||||
"mocha": "3.4.2",
|
||||
"mocha-typescript": "1.1.5",
|
||||
"pify": "^3.0.0",
|
||||
"safe-eval": "^0.3.0",
|
||||
"source-map": "^0.5.6",
|
||||
"source-map-support": "^0.4.15",
|
||||
"strip-bom": "^3.0.0",
|
||||
"typescript": "2.5.3",
|
||||
"untildify": "^3.0.2",
|
||||
"urijs": "^1.18.10",
|
||||
"shx": "^0.2.2",
|
||||
"vscode-jsonrpc": "^3.3.1",
|
||||
"yaml-ast-parser": "https://github.com/olydis/yaml-ast-parser/releases/download/0.0.34/yaml-ast-parser-0.0.34.tgz",
|
||||
"yargs": "^8.0.2"
|
||||
"mocha": "^4.0.1",
|
||||
"mocha-typescript": "^1.1.7",
|
||||
"static-link": "^0.2.0"
|
||||
},
|
||||
"staticDependencies": {
|
||||
"@microsoft.azure/async-io": "~1.0.22",
|
||||
"@microsoft.azure/extension": "~1.2.12",
|
||||
"commonmark": "^0.27.0",
|
||||
"file-url": "^2.0.2",
|
||||
"get-uri": "^2.0.0",
|
||||
"jsonpath": "^0.2.11",
|
||||
"linq-es2015": "^2.4.25",
|
||||
"pify": "^3.0.0",
|
||||
"safe-eval": "^0.3.0",
|
||||
"source-map": "^0.5.6",
|
||||
"strip-bom": "^3.0.0",
|
||||
"untildify": "^3.0.2",
|
||||
"urijs": "^1.18.10",
|
||||
"vscode-jsonrpc": "^3.3.1",
|
||||
"yaml-ast-parser": "https://github.com/olydis/yaml-ast-parser/releases/download/0.0.34/yaml-ast-parser-0.0.34.tgz",
|
||||
"yargs": "^8.0.2"
|
||||
"static-link": {
|
||||
"entrypoints": [],
|
||||
"dependencies": {
|
||||
"@microsoft.azure/async-io": "~1.0.22",
|
||||
"@microsoft.azure/extension": "~1.2.12",
|
||||
"vscode-languageserver": "3.4.3",
|
||||
"commonmark": "^0.27.0",
|
||||
"file-url": "^2.0.2",
|
||||
"js-yaml": "^3.8.4",
|
||||
"get-uri": "^2.0.0",
|
||||
"jsonpath": "^0.2.11",
|
||||
"linq-es2015": "^2.4.25",
|
||||
"pify": "^3.0.0",
|
||||
"safe-eval": "^0.3.0",
|
||||
"source-map": "^0.5.6",
|
||||
"strip-bom": "^3.0.0",
|
||||
"untildify": "^3.0.2",
|
||||
"urijs": "^1.18.10",
|
||||
"vscode-jsonrpc": "^3.3.1",
|
||||
"yaml-ast-parser": "https://github.com/olydis/yaml-ast-parser/releases/download/0.0.34/yaml-ast-parser-0.0.34.tgz",
|
||||
"yargs": "^8.0.2"
|
||||
},
|
||||
"patch": "const fs = require(`fs`); let txt = fs.readFileSync('./node_modules/npm/lib/install/action/extract.js','utf8').replace(`const ENABLE_WORKERS = process.platform === 'darwin'`, `const ENABLE_WORKERS = false;`); fs.writeFileSync('./node_modules/npm/lib/install/action/extract.js', txt ); txt = fs.readFileSync(`./node_modules/npm/lib/npm.js`,`utf8`).replace(`var j = parseJSON(fs.readFileSync(`, `var j = require(path.join(__dirname, '../package.json'));` ).replace(`path.join(__dirname, '../package.json')) + '')`,``); fs.writeFileSync(`./node_modules/npm/lib/npm.js`, txt ); "
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
const fs = require("fs");
|
||||
|
||||
// patch const ENABLE_WORKERS = process.platform === 'darwin'
|
||||
// in .\node_modules\npm\lib\install\action\extract.js
|
||||
|
||||
let txt = fs.readFileSync('./node_modules/npm/lib/install/action/extract.js',"utf8").replace("const ENABLE_WORKERS = process.platform === 'darwin'", "const ENABLE_WORKERS = false;");
|
||||
fs.writeFileSync('./node_modules/npm/lib/install/action/extract.js', txt );
|
||||
|
||||
function getFileNames(path, result) {
|
||||
const files = fs.readdirSync(path);
|
||||
for (const file of files) {
|
||||
const full = `${path}/${file}`;
|
||||
const stat = fs.statSync(full);
|
||||
if ( stat.isDirectory()) {
|
||||
getFileNames(full, result)
|
||||
} else {
|
||||
result[full] = stat;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const intBuffer = Buffer.alloc(6);
|
||||
function writeIntAt(fd, num, offset) {
|
||||
intBuffer.writeIntBE(num, 0, 6 );
|
||||
writeBufferAt(fd, intBuffer,offset);
|
||||
}
|
||||
|
||||
function writeBufferAt(fd,buffer,offset) {
|
||||
// return new Promise((r,j)=> fs.write(fd,buffer,0,buffer.length,offset,(err,bytes)=> err ? j(err, console.log("BAD")): r(bytes)));
|
||||
fs.writeSync( fd, buffer, 0, buffer.length, offset);
|
||||
}
|
||||
|
||||
// async function main() {
|
||||
const files = getFileNames(`./node_modules`,{});
|
||||
const fd = fs.openSync("../dist/static_modules.fs","w");
|
||||
|
||||
// write payload offset
|
||||
writeIntAt(fd,0,0);
|
||||
|
||||
let tablesize = 6;
|
||||
|
||||
// create a static fs
|
||||
for(const each in files) {
|
||||
|
||||
const name = Buffer.from(each.replace(/^./, ''), 'utf-8');
|
||||
const size = files[each].size;
|
||||
writeIntAt(fd, name.length,tablesize); // size of name
|
||||
writeIntAt(fd, files[each].size,tablesize+6); // size of file
|
||||
writeBufferAt(fd, name,tablesize+12); // actual name
|
||||
|
||||
tablesize+=12 + name.length;
|
||||
}
|
||||
// write end of table
|
||||
writeIntAt(fd,0,tablesize);
|
||||
tablesize+=6;
|
||||
|
||||
// write data offset start
|
||||
writeIntAt(fd, tablesize,0);
|
||||
|
||||
|
||||
datasize = tablesize;
|
||||
|
||||
// write files out
|
||||
for(const each in files) {
|
||||
const buf = fs.readFileSync(each);
|
||||
// console.log(`${each} => ( @${datasize} , ${files[each].size}, ) `);
|
||||
writeBufferAt(fd, buf,datasize);
|
||||
datasize += files[each].size;
|
||||
}
|
||||
fs.close(fd,()=> console.log('done'));
|
||||
// }
|
||||
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
{
|
||||
"name": "static_modules",
|
||||
"version": "2.0.0",
|
||||
"description": "builds the static_modules file",
|
||||
"scripts": {
|
||||
"postinstall": "node ./create-static-fs"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@microsoft.azure/extension": "~1.2.12",
|
||||
"@microsoft.azure/async-io": "~1.0.22",
|
||||
"commonmark": "^0.27.0",
|
||||
"file-url": "^2.0.2",
|
||||
"get-uri": "^2.0.0",
|
||||
"jsonpath": "^0.2.11",
|
||||
"linq-es2015": "^2.4.25",
|
||||
"pify": "^3.0.0",
|
||||
"safe-eval": "^0.3.0",
|
||||
"semver-regex": "^1.0.0",
|
||||
"source-map": "^0.5.6",
|
||||
"strip-bom": "^3.0.0",
|
||||
"untildify": "^3.0.2",
|
||||
"urijs": "^1.18.10",
|
||||
"vscode-jsonrpc": "^3.3.1",
|
||||
"yaml-ast-parser": "https://github.com/olydis/yaml-ast-parser/releases/download/0.0.34/yaml-ast-parser-0.0.34.tgz",
|
||||
"yargs": "^8.0.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/olydis/dotnet-2.0.0.git"
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import * as assert from "assert";
|
|||
|
||||
import { CreateFolderUri, ResolveUri } from "../lib/ref/uri";
|
||||
import { parse } from "../lib/ref/jsonpath";
|
||||
import { Configuration } from "../lib/configuration";
|
||||
|
||||
@suite class Blaming {
|
||||
|
||||
|
@ -92,4 +93,8 @@ import { parse } from "../lib/ref/jsonpath";
|
|||
assert.equal(await autoRest.Process().finish, true);
|
||||
assert.notEqual(messages.length, 0);
|
||||
}
|
||||
|
||||
static after() {
|
||||
Configuration.shutdown()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import { AutoRest } from "../lib/autorest-core";
|
|||
import { RealFileSystem } from "../lib/file-system";
|
||||
import { CreateFolderUri, ResolveUri } from "../lib/ref/uri";
|
||||
import { Message } from "../lib/message";
|
||||
import { Configuration } from "../lib/configuration";
|
||||
|
||||
/*@suite */ class Cancellation {
|
||||
private async CreateLongRunningAutoRest(): Promise<AutoRest> {
|
||||
|
@ -54,4 +55,8 @@ import { Message } from "../lib/message";
|
|||
@test async "after 8s"() { await this.TestCancellationAfter(8000); }
|
||||
@test async "after 10s"() { await this.TestCancellationAfter(10000); }
|
||||
@test async "after 15s"() { await this.TestCancellationAfter(15000); }
|
||||
|
||||
static after() {
|
||||
Configuration.shutdown()
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import * as AutoRest from "../lib/autorest-core"
|
|||
let f = new MemoryFileSystem(new Map<string, string>([
|
||||
['readme.md', `
|
||||
# this is a test
|
||||
see https://aka.ms/autorest
|
||||
> see https://aka.ms/autorest
|
||||
~~~ yaml
|
||||
my-value: $(sample-value)
|
||||
sample-value: one
|
||||
|
|
|
@ -11,6 +11,7 @@ import { Message, Channel } from "../lib/message";
|
|||
import { AutoRest } from "../lib/autorest-core";
|
||||
import { MemoryFileSystem } from "../lib/file-system";
|
||||
import { Parse } from "../lib/parsing/literate-yaml";
|
||||
import { Configuration } from "../lib/configuration";
|
||||
|
||||
@suite class SyntaxValidation {
|
||||
private async GetLoaderErrors(swagger: string): Promise<Message[]> {
|
||||
|
@ -51,4 +52,8 @@ import { Parse } from "../lib/parsing/literate-yaml";
|
|||
assert.deepStrictEqual(((await this.GetLoaderErrors("{ a 3 }"))[0] as any).Source[0].Position, { line: 1, column: 5 });
|
||||
assert.deepStrictEqual(((await this.GetLoaderErrors("a: [3"))[0] as any).Source[0].Position, { line: 1, column: 6 });
|
||||
}
|
||||
|
||||
static after() {
|
||||
Configuration.shutdown();
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ import * as cp from 'child_process';
|
|||
import * as rpc from 'vscode-jsonrpc';
|
||||
import { suite, test, slow, timeout, skip, only } from "mocha-typescript";
|
||||
|
||||
|
||||
async function connect() {
|
||||
let childProcess = cp.spawn("dotnet", [`${__dirname}/../../../core/AutoRest/bin/netcoreapp1.0/AutoRest.dll`, "--server"]);
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#!/usr/bin/env node
|
||||
// load static module: ${__dirname }/static_modules.fs
|
||||
require('./static-loader.js').load(`${__dirname}/static_modules.fs`)
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
if (process.argv.indexOf("--no-static-loader") == -1) {
|
||||
require("./static-loader").initialize();
|
||||
}
|
||||
|
||||
if (process.argv.indexOf("--no-upgrade-check") != -1) {
|
||||
process.argv.push("--skip-upgrade-check");
|
||||
|
|
|
@ -7,7 +7,7 @@ import { Enumerable as IEnumerable, From } from "./lib/ref/linq";
|
|||
import { Exception, LazyPromise } from "@microsoft.azure/polyfill";
|
||||
|
||||
import * as semver from "semver";
|
||||
import * as asyncIO from "@microsoft.azure/async-io";
|
||||
import { isFile, mkdir, isDirectory } from "@microsoft.azure/async-io";
|
||||
|
||||
export const pkgVersion: string = require(`${__dirname}/../package.json`).version;
|
||||
const home: string = process.env["autorest.home"] || homedir();
|
||||
|
@ -64,22 +64,58 @@ export function resolvePathForLocalVersion(requestedVersion: string | null): str
|
|||
}
|
||||
|
||||
export async function tryRequire(localPath: string | null, entrypoint: string): Promise<any> {
|
||||
try {
|
||||
return require(await resolveEntrypoint(localPath, entrypoint))
|
||||
} catch{ }
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function resolveEntrypoint(localPath: string | null, entrypoint: string): Promise<string | null> {
|
||||
try {
|
||||
// did they specify the package directory directly
|
||||
if (await asyncIO.isDirectory(localPath)) {
|
||||
if (require(`${localPath}/package.json`).name === corePackage) {
|
||||
console.trace(`Using core from: '${localPath}'`);
|
||||
return require(`${localPath}/dist/${entrypoint}`);
|
||||
if (await isDirectory(localPath)) {
|
||||
const pkg = require(`${localPath}/package.json`);
|
||||
|
||||
if (pkg.name === corePackage) {
|
||||
switch (entrypoint) {
|
||||
case 'main':
|
||||
case 'main.js':
|
||||
entrypoint = pkg.main;
|
||||
break;
|
||||
|
||||
case 'language-service':
|
||||
case 'language-service.js':
|
||||
case 'autorest-language-service':
|
||||
entrypoint = pkg.bin["autorest-language-service"];
|
||||
break;
|
||||
|
||||
case 'autorest':
|
||||
case 'autorest-core':
|
||||
case 'app.js':
|
||||
case 'app':
|
||||
entrypoint = pkg.bin["autorest-core"];
|
||||
break;
|
||||
|
||||
case 'module':
|
||||
// special case: look for the main entrypoint
|
||||
// but return the module folder
|
||||
if (await isFile(`${localPath}/${pkg.main}`)) {
|
||||
return localPath;
|
||||
}
|
||||
}
|
||||
const path = `${localPath}/${entrypoint}`;
|
||||
if (await isFile(path)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function ensureAutorestHome() {
|
||||
await asyncIO.mkdir(rootFolder);
|
||||
await mkdir(rootFolder);
|
||||
}
|
||||
|
||||
export async function selectVersion(requestedVersion: string, force: boolean, minimumVersion?: string) {
|
||||
|
@ -111,7 +147,7 @@ export async function selectVersion(requestedVersion: string, force: boolean, mi
|
|||
}
|
||||
|
||||
// if it's not a file, and the network isn't available, we can't continue.
|
||||
if (!await asyncIO.isFile(requestedVersion) && !(await networkEnabled)) {
|
||||
if (!await isFile(requestedVersion) && !(await networkEnabled)) {
|
||||
// no network enabled.
|
||||
throw new Exception(`Network access is not available, requested version '${requestedVersion}' is not installed. `);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
|
||||
// enable the static module loader
|
||||
require("./static-loader").initialize();
|
||||
// load static module: ${__dirname }/static_modules.fs
|
||||
// require('./static-loader.js').load(`${__dirname}/static_modules.fs`)
|
||||
|
||||
// everything else.
|
||||
import { networkEnabled, rootFolder, extensionManager, availableVersions, corePackage, installedCores, tryRequire, resolvePathForLocalVersion, ensureAutorestHome, selectVersion, pkgVersion } from "./autorest-as-a-service"
|
||||
import { networkEnabled, rootFolder, extensionManager, availableVersions, corePackage, installedCores, tryRequire, resolveEntrypoint, resolvePathForLocalVersion, ensureAutorestHome, selectVersion, pkgVersion } from "./autorest-as-a-service"
|
||||
import { DocumentPatterns } from './lib/core/lib/document-type';
|
||||
import { resolve } from 'path';
|
||||
import { BaseLanguageClient as LanguageClient, TextDocument } from "./vscode/client";
|
||||
|
||||
// exports the public AutoRest definitions
|
||||
export { IFileSystem, Message } from './lib/core/main';
|
||||
|
@ -32,15 +32,32 @@ export const AutoRest: Promise<typeof IAutoRest> = new Promise((r, j) => {
|
|||
reject_autorest = j;
|
||||
});
|
||||
|
||||
let coreModule: any = undefined;
|
||||
let busy = false;
|
||||
let loaded = false;
|
||||
let modulePath: string | undefined = undefined;
|
||||
|
||||
export async function getLanguageServiceEntrypoint(requestedVersion: string = "latest-installed", minimumVersion?: string): Promise<string> {
|
||||
if (!modulePath && !busy) {
|
||||
// if we haven't already got autorest-core, let's do that now with the default settings.
|
||||
await initialize(requestedVersion, minimumVersion);
|
||||
}
|
||||
return resolveEntrypoint(modulePath, "language-service");
|
||||
}
|
||||
|
||||
export async function getApplicationEntrypoint(requestedVersion: string = "latest-installed", minimumVersion?: string): Promise<string> {
|
||||
if (!modulePath && !busy) {
|
||||
// if we haven't already got autorest-core, let's do that now with the default settings.
|
||||
await initialize(requestedVersion, minimumVersion);
|
||||
}
|
||||
return resolveEntrypoint(modulePath, "app");
|
||||
}
|
||||
|
||||
export async function initialize(requestedVersion: string = "latest-installed", minimumVersion?: string) {
|
||||
if (loaded) {
|
||||
if (modulePath) {
|
||||
return;
|
||||
}
|
||||
if (busy) {
|
||||
throw new Error("initialize is already called.")
|
||||
throw new Error("initialize is already in progress.")
|
||||
}
|
||||
|
||||
busy = true;
|
||||
|
@ -53,36 +70,95 @@ export async function initialize(requestedVersion: string = "latest-installed",
|
|||
const localVersion = resolve(requestedVersion);
|
||||
|
||||
// try to use a specified folder
|
||||
const module = await tryRequire(localVersion, "main.js")
|
||||
if (module) {
|
||||
// assign the type to the Async Class Identity
|
||||
resolve_autorest(module.AutoRest)
|
||||
loaded = true;
|
||||
modulePath = await resolveEntrypoint(localVersion, "module");
|
||||
|
||||
if (modulePath) {
|
||||
return;
|
||||
}
|
||||
} catch (E) {
|
||||
// no local version
|
||||
}
|
||||
|
||||
// logic to resolve and optionally install a autorest core package.
|
||||
// will throw if it's not doable.
|
||||
let selectedVersion = await selectVersion(requestedVersion, false, minimumVersion);
|
||||
|
||||
const module = await tryRequire(await selectedVersion.modulePath, "main.js");
|
||||
if (!module) {
|
||||
modulePath = await resolveEntrypoint(await selectedVersion.modulePath, "module");
|
||||
if (!modulePath) {
|
||||
reject_autorest(new Error(`Unable to start AutoRest Core from ${requestedVersion}/${await selectedVersion.modulePath}`));
|
||||
throw new Error(`Unable to start AutoRest Core from ${requestedVersion}/${await selectedVersion.modulePath}`);
|
||||
}
|
||||
|
||||
// assign the type to the Async Class Identity
|
||||
resolve_autorest(module.AutoRest)
|
||||
loaded = true;
|
||||
|
||||
} finally {
|
||||
busy = false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function create(fileSystem?: IFileSystem, configFileOrFolderUri?: string): Promise<AutoRest> {
|
||||
if (!modulePath && !busy) {
|
||||
// if we haven't already got autorest-core, let's do that now with the default settings.
|
||||
await initialize();
|
||||
}
|
||||
|
||||
if (modulePath && !coreModule) {
|
||||
// get the library entrypoint
|
||||
coreModule = tryRequire(modulePath, "main");
|
||||
|
||||
// assign the type to the Async Class Identity
|
||||
resolve_autorest(coreModule.AutoRest)
|
||||
}
|
||||
|
||||
// wait for class definition
|
||||
const CAutoRest = <any>(await AutoRest);
|
||||
|
||||
// return new instance of the AutoRest interface.
|
||||
return new CAutoRest(fileSystem, configFileOrFolderUri);
|
||||
}
|
||||
|
||||
export interface generated {
|
||||
messages: Array<string>;
|
||||
files: any;
|
||||
}
|
||||
|
||||
export class AutoRestLanguageService {
|
||||
|
||||
public constructor(private languageClient: LanguageClient) {
|
||||
|
||||
}
|
||||
|
||||
public async generate(documentUri: string, language: string, configuration: any): Promise<generated> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
return await this.languageClient.sendRequest<generated>("generate", { documentUri: documentUri, language: language, configuration: configuration });
|
||||
}
|
||||
|
||||
public async isOpenApiDocument(contentOrUri: string): Promise<boolean> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
|
||||
return await this.languageClient.sendRequest<boolean>("isOpenApiDocument", { contentOrUri: contentOrUri });
|
||||
}
|
||||
public async isConfigurationFile(contentOrUri: string): Promise<boolean> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
|
||||
return await this.languageClient.sendRequest<boolean>("isConfigurationFile", { contentOrUri: contentOrUri });
|
||||
}
|
||||
public async toJSON(contentOrUri: string): Promise<string> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
|
||||
return await this.languageClient.sendRequest<string>("toJSON", { contentOrUri: contentOrUri });
|
||||
}
|
||||
public async findConfigurationFile(documentUri: string): Promise<string> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
|
||||
return await this.languageClient.sendRequest<string>("findConfigurationFile", { documentUri: documentUri });
|
||||
}
|
||||
|
||||
public async isSupportedFile(languageId: string, contentOrUri: string): Promise<boolean> {
|
||||
// don't call before the client is ready.
|
||||
await this.languageClient.onReady();
|
||||
|
||||
return await this.languageClient.sendRequest<boolean>("isSupportedFile", { languageId: languageId, contentOrUri: contentOrUri });
|
||||
}
|
||||
}
|
|
@ -28,8 +28,11 @@
|
|||
"scripts": {
|
||||
"start": "node ./dist/app.js",
|
||||
"test": "./node_modules/.bin/mocha ./dist/test",
|
||||
"restore": "yarn install --no-lockfile && static-link --force",
|
||||
"build": "tsc -p . && static-link",
|
||||
"static-link": "static-link",
|
||||
"postinstall": "static-link --force || exit 0",
|
||||
"preinstall": "node ./preinstall-check",
|
||||
"prepare": "shx mkdir -p ./dist/ && shx cp -R ./node_modules/fs-monkey/lib/ ./dist/fs-monkey/ && cd ./static_modules && npm install",
|
||||
"prepublishonly": "gulp build"
|
||||
},
|
||||
"typings": "./dist/main.d.ts",
|
||||
|
@ -43,25 +46,24 @@
|
|||
"mocha-typescript": "1.0.22",
|
||||
"source-map": "^0.5.6",
|
||||
"source-map-support": "^0.4.14",
|
||||
"typescript": "2.3.3",
|
||||
"typescript": "2.5.3",
|
||||
"@types/jsonpath": "^0.1.29",
|
||||
"vscode-languageserver-protocol": "3.4.4",
|
||||
"vscode-jsonrpc": "^3.1.0",
|
||||
"shx": "^0.2.2",
|
||||
"fs-monkey": "https://github.com/fearthecowboy/fs-monkey/releases/download/0.2.2/fs-monkey-0.2.2.tgz",
|
||||
"@microsoft.azure/async-io": "~1.0.22",
|
||||
"@microsoft.azure/console": "~1.0.31",
|
||||
"@microsoft.azure/extension": "~1.2.12",
|
||||
"@microsoft.azure/polyfill": "~1.0.17",
|
||||
"linq-es2015": "^2.4.24",
|
||||
"semver": "^5.3.0",
|
||||
"static-link": "^0.2.0",
|
||||
"yaml-ast-parser": "https://github.com/olydis/yaml-ast-parser/releases/download/0.0.34/yaml-ast-parser-0.0.34.tgz"
|
||||
},
|
||||
"staticDependencies": {
|
||||
"@microsoft.azure/async-io": "~1.0.22",
|
||||
"@microsoft.azure/console": "~1.0.31",
|
||||
"@microsoft.azure/extension": "~1.2.12",
|
||||
"@microsoft.azure/polyfill": "~1.0.17",
|
||||
"linq-es2015": "^2.4.24",
|
||||
"semver": "^5.3.0"
|
||||
"static-link": {
|
||||
"entrypoints": [],
|
||||
"dependencies": {
|
||||
"@microsoft.azure/async-io": "~1.0.22",
|
||||
"@microsoft.azure/console": "~1.0.31",
|
||||
"@microsoft.azure/extension": "~1.2.12",
|
||||
"@microsoft.azure/polyfill": "~1.0.17",
|
||||
"linq-es2015": "^2.4.24",
|
||||
"semver": "^5.3.0"
|
||||
},
|
||||
"patch": "const fs = require(`fs`); let txt = fs.readFileSync('./node_modules/npm/lib/install/action/extract.js','utf8').replace(`const ENABLE_WORKERS = process.platform === 'darwin'`, `const ENABLE_WORKERS = false;`); fs.writeFileSync('./node_modules/npm/lib/install/action/extract.js', txt ); txt = fs.readFileSync(`./node_modules/npm/lib/npm.js`,`utf8`).replace(`var j = parseJSON(fs.readFileSync(`, `var j = require(path.join(__dirname, '../package.json'));` ).replace(`path.join(__dirname, '../package.json')) + '')`,``); fs.writeFileSync(`./node_modules/npm/lib/npm.js`, txt ); "
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
import { initialize } from "./static-loader";
|
||||
|
||||
initialize();
|
||||
require('./app');
|
|
@ -1,188 +0,0 @@
|
|||
import { dirname } from 'path';
|
||||
import { Stats } from 'fs';
|
||||
|
||||
const fs_readFileSync = require("fs").readFileSync;
|
||||
const fs_openSync = require("fs").openSync;
|
||||
const fs_readSync = require("fs").readSync;
|
||||
const fs_statSync = require("fs").statSync;
|
||||
const fs_realpathSync = require("fs").realpathSync;
|
||||
const fs_closeSync = require("fs").closeSync;
|
||||
|
||||
const correctPath = require("./fs-monkey/correctPath.js").correctPath;
|
||||
|
||||
interface Index {
|
||||
[filepath: string]: Stats;
|
||||
}
|
||||
|
||||
function addParentPaths(name: string, index: any): any {
|
||||
const parent = dirname(name);
|
||||
if (parent && !index[parent]) {
|
||||
index[parent] = <Stats>{
|
||||
size: 0,
|
||||
isDirectory: () => true,
|
||||
isSymbolicLink: () => false,
|
||||
isBlockDevice: () => false,
|
||||
isCharacterDevice: () => false,
|
||||
isFile: () => false,
|
||||
isFIFO: () => false,
|
||||
isSocket: () => false,
|
||||
dev: 0,
|
||||
ino: 0,
|
||||
mode: 0,
|
||||
nlink: 0,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
rdev: 0,
|
||||
|
||||
blksize: 1,
|
||||
blocks: 0,
|
||||
atimeMs: 1,
|
||||
mtimeMs: 1,
|
||||
ctimeMs: 1,
|
||||
birthtimeMs: 1,
|
||||
atime: new Date(),
|
||||
mtime: new Date(),
|
||||
ctime: new Date(),
|
||||
birthtime: new Date(),
|
||||
}
|
||||
return addParentPaths(parent, index);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
class StaticFileSystem {
|
||||
private intBuffer = Buffer.alloc(6);
|
||||
private buf = Buffer.alloc(1024 * 128); // 128k by default.
|
||||
index: Index = {};
|
||||
private fd: number;
|
||||
|
||||
private readBuffer(buffer: Buffer, length?: number): number {
|
||||
return fs_readSync(this.fd, buffer, 0, length || buffer.length, null);
|
||||
}
|
||||
|
||||
private readInt(): number {
|
||||
fs_readSync(this.fd, this.intBuffer, 0, 6, null);
|
||||
return this.intBuffer.readIntBE(0, 6);
|
||||
}
|
||||
|
||||
public shutdown() {
|
||||
fs_closeSync(this.fd);
|
||||
this.index = <Index>{};
|
||||
}
|
||||
|
||||
readFile(filepath: string): string | undefined {
|
||||
const item = this.index[filepath];
|
||||
if (item && item.isFile()) {
|
||||
// realloc if necessary
|
||||
while (this.buf.length < item.size) {
|
||||
this.buf = Buffer.alloc(this.buf.length * 2);
|
||||
}
|
||||
|
||||
// read the content and return a string
|
||||
fs_readSync(this.fd, this.buf, 0, item.size, item.ino);
|
||||
return this.buf.toString("utf-8", 0, item.size);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public constructor(private sourcePath: string) {
|
||||
// read the index
|
||||
this.fd = fs_openSync(sourcePath, 'r');
|
||||
// close on process exit.
|
||||
let dataOffset = this.readInt();
|
||||
|
||||
do {
|
||||
const nameSz = this.readInt();
|
||||
if (nameSz == 0) {
|
||||
break;
|
||||
}
|
||||
const dataSz = this.readInt();
|
||||
while (nameSz > this.buf.length) {
|
||||
this.buf = Buffer.alloc(this.buf.length * 2);
|
||||
}
|
||||
this.readBuffer(this.buf, nameSz);
|
||||
const name = this.buf.toString('utf-8', 0, nameSz);
|
||||
|
||||
// add entry for file into index
|
||||
this.index[name] = <Stats>{
|
||||
ino: dataOffset,
|
||||
size: dataSz,
|
||||
isDirectory: () => false,
|
||||
isSymbolicLink: () => false,
|
||||
isBlockDevice: () => false,
|
||||
isCharacterDevice: () => false,
|
||||
isFile: () => true,
|
||||
isFIFO: () => false,
|
||||
isSocket: () => false,
|
||||
}
|
||||
// ensure parent path has a directory entry
|
||||
addParentPaths(name, this.index);
|
||||
dataOffset += dataSz;
|
||||
} while (true)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export class StaticVolumeSet {
|
||||
private fileSystems: Array<StaticFileSystem> = [];
|
||||
|
||||
public shutdown() {
|
||||
for (const fsystem of this.fileSystems) {
|
||||
fsystem.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public constructor(sourcePath: string, private fallbackToDisk: boolean = false) {
|
||||
this.addFileSystem(sourcePath);
|
||||
}
|
||||
|
||||
public addFileSystem(sourcePath: string): StaticVolumeSet {
|
||||
this.fileSystems.push(new StaticFileSystem(sourcePath));
|
||||
return this;
|
||||
}
|
||||
|
||||
public readFileSync(filepath: string, options: any): string | Buffer {
|
||||
|
||||
const targetPath: string = correctPath(filepath);
|
||||
|
||||
for (const fsystem of this.fileSystems) {
|
||||
const result = fsystem.readFile(targetPath);
|
||||
if (result != undefined) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fallbackToDisk) {
|
||||
return fs_readFileSync(filepath, options);
|
||||
}
|
||||
|
||||
throw new Error(`statSync - no file found ${filepath}`);
|
||||
}
|
||||
|
||||
public realpathSync(filepath: string): string {
|
||||
const targetPath: string = correctPath(filepath);
|
||||
for (const fsystem of this.fileSystems) {
|
||||
const result = fsystem.index[targetPath];
|
||||
if (result) {
|
||||
return targetPath;
|
||||
}
|
||||
}
|
||||
return fs_realpathSync(filepath);
|
||||
};
|
||||
|
||||
public statSync(filepath: string): Stats {
|
||||
const targetPath: string = correctPath(filepath);
|
||||
|
||||
for (const fsystem of this.fileSystems) {
|
||||
const result = fsystem.index[targetPath];
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (this.fallbackToDisk) {
|
||||
return fs_statSync(filepath);
|
||||
}
|
||||
|
||||
throw new Error(`statSync - no file found ${filepath}`);
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
import { StaticVolumeSet } from './static-fs'
|
||||
|
||||
export function initialize(): StaticVolumeSet {
|
||||
// only do this once, ever.
|
||||
if ((<any>global).StaticVolumeSet) {
|
||||
return (<any>global).StaticVolumeSet;
|
||||
}
|
||||
|
||||
// get patchRequire
|
||||
const patchRequire = require("./fs-monkey/index.js").patchRequire;
|
||||
const patchFs = require("./fs-monkey/index.js").patchFs;
|
||||
|
||||
// create the static volume set
|
||||
const staticVolume = new StaticVolumeSet(`${__dirname}/static_modules.fs`, true);
|
||||
|
||||
// patch require
|
||||
patchRequire(staticVolume);
|
||||
|
||||
// patch the fs too (fixes readFileSync)
|
||||
patchFs(staticVolume);
|
||||
|
||||
// cheat: add static volume instance to the global namespace so that autorest core can add to it.
|
||||
(<any>global).StaticVolumeSet = staticVolume;
|
||||
|
||||
// hot-patch process.exit so that when it's called we shutdown the patcher early
|
||||
const process_exit = process.exit;
|
||||
process.exit = (n): never => {
|
||||
staticVolume.shutdown();
|
||||
return process_exit(n);
|
||||
}
|
||||
|
||||
return staticVolume;
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
const fs = require("fs");
|
||||
|
||||
let txt = fs.readFileSync('./node_modules/npm/lib/install/action/extract.js',"utf8").replace("const ENABLE_WORKERS = process.platform === 'darwin'", "const ENABLE_WORKERS = false;");
|
||||
fs.writeFileSync('./node_modules/npm/lib/install/action/extract.js', txt );
|
||||
|
||||
|
||||
function getFileNames(path, result) {
|
||||
const files = fs.readdirSync(path);
|
||||
for (const file of files) {
|
||||
const full = `${path}/${file}`;
|
||||
const stat = fs.statSync(full);
|
||||
if ( stat.isDirectory()) {
|
||||
getFileNames(full, result)
|
||||
} else {
|
||||
result[full] = stat;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const intBuffer = Buffer.alloc(6);
|
||||
function writeIntAt(fd, num, offset) {
|
||||
intBuffer.writeIntBE(num, 0, 6 );
|
||||
writeBufferAt(fd, intBuffer,offset);
|
||||
}
|
||||
|
||||
function writeBufferAt(fd,buffer,offset) {
|
||||
// return new Promise((r,j)=> fs.write(fd,buffer,0,buffer.length,offset,(err,bytes)=> err ? j(err, console.log("BAD")): r(bytes)));
|
||||
fs.writeSync( fd, buffer, 0, buffer.length, offset);
|
||||
}
|
||||
|
||||
// async function main() {
|
||||
const files = getFileNames(`./node_modules`,{});
|
||||
const fd = fs.openSync("../dist/static_modules.fs","w");
|
||||
|
||||
// write payload offset
|
||||
writeIntAt(fd,0,0);
|
||||
|
||||
let tablesize = 6;
|
||||
|
||||
// create a static fs
|
||||
for(const each in files) {
|
||||
|
||||
const name = Buffer.from(each.replace(/^./, ''), 'utf-8');
|
||||
const size = files[each].size;
|
||||
writeIntAt(fd, name.length,tablesize); // size of name
|
||||
writeIntAt(fd, files[each].size,tablesize+6); // size of file
|
||||
writeBufferAt(fd, name,tablesize+12); // actual name
|
||||
|
||||
tablesize+=12 + name.length;
|
||||
}
|
||||
// write end of table
|
||||
writeIntAt(fd,0,tablesize);
|
||||
tablesize+=6;
|
||||
|
||||
// write data offset start
|
||||
writeIntAt(fd, tablesize,0);
|
||||
|
||||
|
||||
datasize = tablesize;
|
||||
|
||||
// write files out
|
||||
for(const each in files) {
|
||||
const buf = fs.readFileSync(each);
|
||||
// console.log(`${each} => ( @${datasize} , ${files[each].size}, ) `);
|
||||
writeBufferAt(fd, buf,datasize);
|
||||
datasize += files[each].size;
|
||||
}
|
||||
fs.close(fd,()=> console.log('done'));
|
||||
// }
|
||||
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"name": "static_modules",
|
||||
"version": "2.0.0",
|
||||
"description": "builds the static_modules file",
|
||||
"scripts": {
|
||||
"postinstall": "node ./create-static-fs"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@microsoft.azure/async-io": "~1.0.22",
|
||||
"@microsoft.azure/console": "~1.0.31",
|
||||
"@microsoft.azure/extension": "~1.2.12",
|
||||
"@microsoft.azure/polyfill": "~1.0.17",
|
||||
"linq-es2015": "^2.4.24",
|
||||
"semver": "^5.3.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/olydis/dotnet-2.0.0.git"
|
||||
}
|
||||
}
|
|
@ -20,6 +20,6 @@
|
|||
"exclude": [
|
||||
"dist",
|
||||
"node_modules",
|
||||
"nm"
|
||||
"lib/core/language-service"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,359 @@
|
|||
import { TextDocumentChangeEvent, TextDocument, Disposable, OutputChannel, FileSystemWatcher as VFileSystemWatcher, DiagnosticCollection, ProviderResult, CancellationToken, Position as VPosition, Location as VLocation, Range as VRange, CompletionItem as VCompletionItem, CompletionList as VCompletionList, SignatureHelp as VSignatureHelp, Definition as VDefinition, DocumentHighlight as VDocumentHighlight, SymbolInformation as VSymbolInformation, CodeActionContext as VCodeActionContext, Command as VCommand, CodeLens as VCodeLens, FormattingOptions as VFormattingOptions, TextEdit as VTextEdit, WorkspaceEdit as VWorkspaceEdit, Hover as VHover, DocumentLink as VDocumentLink, TextDocumentWillSaveEvent, WorkspaceFolder as VWorkspaceFolder } from './vscode';
|
||||
import { Message, RPCMessageType, ResponseError, RequestType, RequestType0, RequestHandler, RequestHandler0, GenericRequestHandler, NotificationType, NotificationType0, NotificationHandler, NotificationHandler0, GenericNotificationHandler, MessageReader, MessageWriter, Trace, Event, ClientCapabilities, InitializeParams, InitializeResult, InitializeError, ServerCapabilities, DocumentSelector } from 'vscode-languageserver-protocol';
|
||||
import * as c2p from './codeConverter';
|
||||
import * as p2c from './protocolConverter';
|
||||
export { Converter as Code2ProtocolConverter } from './codeConverter';
|
||||
export { Converter as Protocol2CodeConverter } from './protocolConverter';
|
||||
export * from 'vscode-languageserver-protocol';
|
||||
export interface ExecutableOptions {
|
||||
cwd?: string;
|
||||
stdio?: string | string[];
|
||||
env?: any;
|
||||
detached?: boolean;
|
||||
}
|
||||
export interface Executable {
|
||||
command: string;
|
||||
args?: string[];
|
||||
options?: ExecutableOptions;
|
||||
}
|
||||
export interface ForkOptions {
|
||||
cwd?: string;
|
||||
env?: any;
|
||||
encoding?: string;
|
||||
execArgv?: string[];
|
||||
}
|
||||
export declare enum TransportKind {
|
||||
stdio = 0,
|
||||
ipc = 1,
|
||||
pipe = 2,
|
||||
}
|
||||
export interface NodeModule {
|
||||
module: string;
|
||||
transport?: TransportKind;
|
||||
args?: string[];
|
||||
runtime?: string;
|
||||
options?: ForkOptions;
|
||||
}
|
||||
/**
|
||||
* An action to be performed when the connection is producing errors.
|
||||
*/
|
||||
export declare enum ErrorAction {
|
||||
/**
|
||||
* Continue running the server.
|
||||
*/
|
||||
Continue = 1,
|
||||
/**
|
||||
* Shutdown the server.
|
||||
*/
|
||||
Shutdown = 2,
|
||||
}
|
||||
/**
|
||||
* An action to be performed when the connection to a server got closed.
|
||||
*/
|
||||
export declare enum CloseAction {
|
||||
/**
|
||||
* Don't restart the server. The connection stays closed.
|
||||
*/
|
||||
DoNotRestart = 1,
|
||||
/**
|
||||
* Restart the server.
|
||||
*/
|
||||
Restart = 2,
|
||||
}
|
||||
/**
|
||||
* A pluggable error handler that is invoked when the connection is either
|
||||
* producing errors or got closed.
|
||||
*/
|
||||
export interface ErrorHandler {
|
||||
/**
|
||||
* An error has occurred while writing or reading from the connection.
|
||||
*
|
||||
* @param error - the error received
|
||||
* @param message - the message to be delivered to the server if know.
|
||||
* @param count - a count indicating how often an error is received. Will
|
||||
* be reset if a message got successfully send or received.
|
||||
*/
|
||||
error(error: Error, message: Message, count: number): ErrorAction;
|
||||
/**
|
||||
* The connection to the server got closed.
|
||||
*/
|
||||
closed(): CloseAction;
|
||||
}
|
||||
export interface InitializationFailedHandler {
|
||||
(error: ResponseError<InitializeError> | Error | any): boolean;
|
||||
}
|
||||
export interface SynchronizeOptions {
|
||||
configurationSection?: string | string[];
|
||||
fileEvents?: VFileSystemWatcher | VFileSystemWatcher[];
|
||||
}
|
||||
export declare enum RevealOutputChannelOn {
|
||||
Info = 1,
|
||||
Warn = 2,
|
||||
Error = 3,
|
||||
Never = 4,
|
||||
}
|
||||
export interface ProvideCompletionItemsSignature {
|
||||
(document: TextDocument, position: VPosition, token: CancellationToken): ProviderResult<VCompletionItem[] | VCompletionList>;
|
||||
}
|
||||
export interface ResolveCompletionItemSignature {
|
||||
(item: VCompletionItem, token: CancellationToken): ProviderResult<VCompletionItem>;
|
||||
}
|
||||
export interface ProvideHoverSignature {
|
||||
(document: TextDocument, position: VPosition, token: CancellationToken): ProviderResult<VHover>;
|
||||
}
|
||||
export interface ProvideSignatureHelpSignature {
|
||||
(document: TextDocument, position: VPosition, token: CancellationToken): ProviderResult<VSignatureHelp>;
|
||||
}
|
||||
export interface ProvideDefinitionSignature {
|
||||
(document: TextDocument, position: VPosition, token: CancellationToken): ProviderResult<VDefinition>;
|
||||
}
|
||||
export interface ProvideReferencesSignature {
|
||||
(document: TextDocument, position: VPosition, options: {
|
||||
includeDeclaration: boolean;
|
||||
}, token: CancellationToken): ProviderResult<VLocation[]>;
|
||||
}
|
||||
export interface ProvideDocumentHighlightsSignature {
|
||||
(document: TextDocument, position: VPosition, token: CancellationToken): ProviderResult<VDocumentHighlight[]>;
|
||||
}
|
||||
export interface ProvideDocumentSymbolsSignature {
|
||||
(document: TextDocument, token: CancellationToken): ProviderResult<VSymbolInformation[]>;
|
||||
}
|
||||
export interface ProvideWorkspaceSymbolsSignature {
|
||||
(query: string, token: CancellationToken): ProviderResult<VSymbolInformation[]>;
|
||||
}
|
||||
export interface ProvideCodeActionsSignature {
|
||||
(document: TextDocument, range: VRange, context: VCodeActionContext, token: CancellationToken): ProviderResult<VCommand[]>;
|
||||
}
|
||||
export interface ProvideCodeLensesSignature {
|
||||
(document: TextDocument, token: CancellationToken): ProviderResult<VCodeLens[]>;
|
||||
}
|
||||
export interface ResolveCodeLensSignature {
|
||||
(codeLens: VCodeLens, token: CancellationToken): ProviderResult<VCodeLens>;
|
||||
}
|
||||
export interface ProvideDocumentFormattingEditsSignature {
|
||||
(document: TextDocument, options: VFormattingOptions, token: CancellationToken): ProviderResult<VTextEdit[]>;
|
||||
}
|
||||
export interface ProvideDocumentRangeFormattingEditsSignature {
|
||||
(document: TextDocument, range: VRange, options: VFormattingOptions, token: CancellationToken): ProviderResult<VTextEdit[]>;
|
||||
}
|
||||
export interface ProvideOnTypeFormattingEditsSignature {
|
||||
(document: TextDocument, position: VPosition, ch: string, options: VFormattingOptions, token: CancellationToken): ProviderResult<VTextEdit[]>;
|
||||
}
|
||||
export interface ProvideRenameEditsSignature {
|
||||
(document: TextDocument, position: VPosition, newName: string, token: CancellationToken): ProviderResult<VWorkspaceEdit>;
|
||||
}
|
||||
export interface ProvideDocumentLinksSignature {
|
||||
(document: TextDocument, token: CancellationToken): ProviderResult<VDocumentLink[]>;
|
||||
}
|
||||
export interface ResolveDocumentLinkSignature {
|
||||
(link: VDocumentLink, token: CancellationToken): ProviderResult<VDocumentLink>;
|
||||
}
|
||||
export interface NextSignature<P, R> {
|
||||
(data: P, next: (data: P) => R): R;
|
||||
}
|
||||
export interface DidChangeConfigurationSignature {
|
||||
(sections: string[] | undefined): void;
|
||||
}
|
||||
export interface WorkspaceMiddleware {
|
||||
didChangeConfiguration?: (sections: string[] | undefined, next: DidChangeConfigurationSignature) => void;
|
||||
}
|
||||
export interface Middleware {
|
||||
didOpen?: NextSignature<TextDocument, void>;
|
||||
didChange?: NextSignature<TextDocumentChangeEvent, void>;
|
||||
willSave?: NextSignature<TextDocumentWillSaveEvent, void>;
|
||||
willSaveWaitUntil?: NextSignature<TextDocumentWillSaveEvent, Thenable<VTextEdit[]>>;
|
||||
didSave?: NextSignature<TextDocument, void>;
|
||||
didClose?: NextSignature<TextDocument, void>;
|
||||
provideCompletionItem?: (document: TextDocument, position: VPosition, token: CancellationToken, next: ProvideCompletionItemsSignature) => ProviderResult<VCompletionItem[] | VCompletionList>;
|
||||
resolveCompletionItem?: (item: VCompletionItem, token: CancellationToken, next: ResolveCompletionItemSignature) => ProviderResult<VCompletionItem>;
|
||||
provideHover?: (document: TextDocument, position: VPosition, token: CancellationToken, next: ProvideHoverSignature) => ProviderResult<VHover>;
|
||||
provideSignatureHelp?: (document: TextDocument, position: VPosition, token: CancellationToken, next: ProvideSignatureHelpSignature) => ProviderResult<VSignatureHelp>;
|
||||
provideDefinition?: (document: TextDocument, position: VPosition, token: CancellationToken, next: ProvideDefinitionSignature) => ProviderResult<VDefinition>;
|
||||
provideReferences?: (document: TextDocument, position: VPosition, options: {
|
||||
includeDeclaration: boolean;
|
||||
}, token: CancellationToken, next: ProvideReferencesSignature) => ProviderResult<VLocation[]>;
|
||||
provideDocumentHighlights?: (document: TextDocument, position: VPosition, token: CancellationToken, next: ProvideDocumentHighlightsSignature) => ProviderResult<VDocumentHighlight[]>;
|
||||
provideDocumentSymbols?: (document: TextDocument, token: CancellationToken, next: ProvideDocumentSymbolsSignature) => ProviderResult<VSymbolInformation[]>;
|
||||
provideWorkspaceSymbols?: (query: string, token: CancellationToken, next: ProvideWorkspaceSymbolsSignature) => ProviderResult<VSymbolInformation[]>;
|
||||
provideCodeActions?: (document: TextDocument, range: VRange, context: VCodeActionContext, token: CancellationToken, next: ProvideCodeActionsSignature) => ProviderResult<VCommand[]>;
|
||||
provideCodeLenses?: (document: TextDocument, token: CancellationToken, next: ProvideCodeLensesSignature) => ProviderResult<VCodeLens[]>;
|
||||
resolveCodeLens?: (codeLens: VCodeLens, token: CancellationToken, next: ResolveCodeLensSignature) => ProviderResult<VCodeLens>;
|
||||
provideDocumentFormattingEdits?: (document: TextDocument, options: VFormattingOptions, token: CancellationToken, next: ProvideDocumentFormattingEditsSignature) => ProviderResult<VTextEdit[]>;
|
||||
provideDocumentRangeFormattingEdits?: (document: TextDocument, range: VRange, options: VFormattingOptions, token: CancellationToken, next: ProvideDocumentRangeFormattingEditsSignature) => ProviderResult<VTextEdit[]>;
|
||||
provideOnTypeFormattingEdits?: (document: TextDocument, position: VPosition, ch: string, options: VFormattingOptions, token: CancellationToken, next: ProvideOnTypeFormattingEditsSignature) => ProviderResult<VTextEdit[]>;
|
||||
provideRenameEdits?: (document: TextDocument, position: VPosition, newName: string, token: CancellationToken, next: ProvideRenameEditsSignature) => ProviderResult<VWorkspaceEdit>;
|
||||
provideDocumentLinks?: (document: TextDocument, token: CancellationToken, next: ProvideDocumentLinksSignature) => ProviderResult<VDocumentLink[]>;
|
||||
resolveDocumentLink?: (link: VDocumentLink, token: CancellationToken, next: ResolveDocumentLinkSignature) => ProviderResult<VDocumentLink>;
|
||||
workspace?: WorkspaceMiddleware;
|
||||
}
|
||||
export interface LanguageClientOptions {
|
||||
documentSelector?: DocumentSelector | string[];
|
||||
synchronize?: SynchronizeOptions;
|
||||
diagnosticCollectionName?: string;
|
||||
outputChannel?: OutputChannel;
|
||||
outputChannelName?: string;
|
||||
revealOutputChannelOn?: RevealOutputChannelOn;
|
||||
/**
|
||||
* The encoding use to read stdout and stderr. Defaults
|
||||
* to 'utf8' if ommitted.
|
||||
*/
|
||||
stdioEncoding?: string;
|
||||
initializationOptions?: any | (() => any);
|
||||
initializationFailedHandler?: InitializationFailedHandler;
|
||||
errorHandler?: ErrorHandler;
|
||||
middleware?: Middleware;
|
||||
uriConverters?: {
|
||||
code2Protocol: c2p.URIConverter;
|
||||
protocol2Code: p2c.URIConverter;
|
||||
};
|
||||
workspaceFolder?: VWorkspaceFolder;
|
||||
}
|
||||
export declare enum State {
|
||||
Stopped = 1,
|
||||
Running = 2,
|
||||
}
|
||||
export interface StateChangeEvent {
|
||||
oldState: State;
|
||||
newState: State;
|
||||
}
|
||||
/**
|
||||
* A static feature. A static feature can't be dynamically activate via the
|
||||
* server. It is wired during the initialize sequence.
|
||||
*/
|
||||
export interface StaticFeature {
|
||||
/**
|
||||
* Called to fill the initialize params.
|
||||
*
|
||||
* @params the initialize params.
|
||||
*/
|
||||
fillInitializeParams?: (params: InitializeParams) => void;
|
||||
/**
|
||||
* Called to fill in the client capabilities this feature implements.
|
||||
*
|
||||
* @param capabilities The client capabilities to fill.
|
||||
*/
|
||||
fillClientCapabilities(capabilities: ClientCapabilities): void;
|
||||
/**
|
||||
* Initialize the feature. This method is called on a feature instance
|
||||
* when the client has successfully received the initalize request from
|
||||
* the server and before the client sends the initialized notification
|
||||
* to the server.
|
||||
*
|
||||
* @param capabilities the server capabilities
|
||||
* @param documentSelector the document selector pass to the client's constuctor.
|
||||
* May be `undefined` if the client was created without a selector.
|
||||
*/
|
||||
initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector | undefined): void;
|
||||
}
|
||||
export interface RegistrationData<T> {
|
||||
id: string;
|
||||
registerOptions: T;
|
||||
}
|
||||
export interface DynamicFeature<T> {
|
||||
/**
|
||||
* The message for which this features support dynamic activation / registration.
|
||||
*/
|
||||
messages: RPCMessageType | RPCMessageType[];
|
||||
/**
|
||||
* Called to fill the initialize params.
|
||||
*
|
||||
* @params the initialize params.
|
||||
*/
|
||||
fillInitializeParams?: (params: InitializeParams) => void;
|
||||
/**
|
||||
* Called to fill in the client capabilities this feature implements.
|
||||
*
|
||||
* @param capabilities The client capabilities to fill.
|
||||
*/
|
||||
fillClientCapabilities(capabilities: ClientCapabilities): void;
|
||||
/**
|
||||
* Initialize the feature. This method is called on a feature instance
|
||||
* when the client has successfully received the initalize request from
|
||||
* the server and before the client sends the initialized notification
|
||||
* to the server.
|
||||
*
|
||||
* @param capabilities the server capabilities.
|
||||
* @param documentSelector the document selector pass to the client's constuctor.
|
||||
* May be `undefined` if the client was created without a selector.
|
||||
*/
|
||||
initialize(capabilities: ServerCapabilities, documentSelector: DocumentSelector | undefined): void;
|
||||
/**
|
||||
* Is called when the server send a register request for the given message.
|
||||
*
|
||||
* @param message the message to register for.
|
||||
* @param data additional registration data as defined in the protocol.
|
||||
*/
|
||||
register(message: RPCMessageType, data: RegistrationData<T>): void;
|
||||
/**
|
||||
* Is called when the server wants to unregister a feature.
|
||||
*
|
||||
* @param id the id used when registering the feature.
|
||||
*/
|
||||
unregister(id: string): void;
|
||||
/**
|
||||
* Called when the client is stopped to dispose this feature. Usually a feature
|
||||
* unregisters listeners registerd hooked up with the VS Code extension host.
|
||||
*/
|
||||
dispose(): void;
|
||||
}
|
||||
export interface MessageTransports {
|
||||
reader: MessageReader;
|
||||
writer: MessageWriter;
|
||||
}
|
||||
export declare namespace MessageTransports {
|
||||
function is(value: any): value is MessageTransports;
|
||||
}
|
||||
export declare abstract class BaseLanguageClient {
|
||||
constructor(id: string, name: string, clientOptions: LanguageClientOptions);
|
||||
readonly initializeResult: InitializeResult | undefined;
|
||||
sendRequest<R, E, RO>(type: RequestType0<R, E, RO>, token?: CancellationToken): Thenable<R>;
|
||||
sendRequest<P, R, E, RO>(type: RequestType<P, R, E, RO>, params: P, token?: CancellationToken): Thenable<R>;
|
||||
sendRequest<R>(method: string, token?: CancellationToken): Thenable<R>;
|
||||
sendRequest<R>(method: string, param: any, token?: CancellationToken): Thenable<R>;
|
||||
onRequest<R, E, RO>(type: RequestType0<R, E, RO>, handler: RequestHandler0<R, E>): void;
|
||||
onRequest<P, R, E, RO>(type: RequestType<P, R, E, RO>, handler: RequestHandler<P, R, E>): void;
|
||||
onRequest<R, E>(method: string, handler: GenericRequestHandler<R, E>): void;
|
||||
sendNotification<RO>(type: NotificationType0<RO>): void;
|
||||
sendNotification<P, RO>(type: NotificationType<P, RO>, params?: P): void;
|
||||
sendNotification(method: string): void;
|
||||
sendNotification(method: string, params: any): void;
|
||||
onNotification<RO>(type: NotificationType0<RO>, handler: NotificationHandler0): void;
|
||||
onNotification<P, RO>(type: NotificationType<P, RO>, handler: NotificationHandler<P>): void;
|
||||
onNotification(method: string, handler: GenericNotificationHandler): void;
|
||||
readonly clientOptions: LanguageClientOptions;
|
||||
readonly protocol2CodeConverter: p2c.Converter;
|
||||
readonly code2ProtocolConverter: c2p.Converter;
|
||||
readonly onTelemetry: Event<any>;
|
||||
readonly onDidChangeState: Event<StateChangeEvent>;
|
||||
readonly outputChannel: OutputChannel;
|
||||
readonly diagnostics: DiagnosticCollection | undefined;
|
||||
createDefaultErrorHandler(): ErrorHandler;
|
||||
trace: Trace;
|
||||
info(message: string, data?: any): void;
|
||||
warn(message: string, data?: any): void;
|
||||
error(message: string, data?: any): void;
|
||||
needsStart(): boolean;
|
||||
needsStop(): boolean;
|
||||
onReady(): Promise<void>;
|
||||
start(): Disposable;
|
||||
stop(): Thenable<void>;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
registerFeatures(features: (StaticFeature | DynamicFeature<any>)[]): void;
|
||||
registerFeature(feature: StaticFeature | DynamicFeature<any>): void;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
logFailedRequest(type: RPCMessageType, error: any): void;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
import * as code from './vscode';
|
||||
import * as proto from 'vscode-languageserver-protocol';
|
||||
export interface Converter {
|
||||
asUri(uri: code.Uri): string;
|
||||
asTextDocumentIdentifier(textDocument: code.TextDocument): proto.TextDocumentIdentifier;
|
||||
asOpenTextDocumentParams(textDocument: code.TextDocument): proto.DidOpenTextDocumentParams;
|
||||
asChangeTextDocumentParams(textDocument: code.TextDocument): proto.DidChangeTextDocumentParams;
|
||||
asChangeTextDocumentParams(event: code.TextDocumentChangeEvent): proto.DidChangeTextDocumentParams;
|
||||
asCloseTextDocumentParams(textDocument: code.TextDocument): proto.DidCloseTextDocumentParams;
|
||||
asSaveTextDocumentParams(textDocument: code.TextDocument, includeContent?: boolean): proto.DidSaveTextDocumentParams;
|
||||
asWillSaveTextDocumentParams(event: code.TextDocumentWillSaveEvent): proto.WillSaveTextDocumentParams;
|
||||
asTextDocumentPositionParams(textDocument: code.TextDocument, position: code.Position): proto.TextDocumentPositionParams;
|
||||
asWorkerPosition(position: code.Position): proto.Position;
|
||||
asPosition(value: code.Position): proto.Position;
|
||||
asPosition(value: undefined): undefined;
|
||||
asPosition(value: null): null;
|
||||
asPosition(value: code.Position | undefined | null): proto.Position | undefined | null;
|
||||
asRange(value: code.Range): proto.Range;
|
||||
asRange(value: undefined): undefined;
|
||||
asRange(value: null): null;
|
||||
asRange(value: code.Range | undefined | null): proto.Range | undefined | null;
|
||||
asDiagnosticSeverity(value: code.DiagnosticSeverity): number;
|
||||
asDiagnostic(item: code.Diagnostic): proto.Diagnostic;
|
||||
asDiagnostics(items: code.Diagnostic[]): proto.Diagnostic[];
|
||||
asCompletionItem(item: code.CompletionItem): proto.CompletionItem;
|
||||
asTextEdit(edit: code.TextEdit): proto.TextEdit;
|
||||
asReferenceParams(textDocument: code.TextDocument, position: code.Position, options: {
|
||||
includeDeclaration: boolean;
|
||||
}): proto.ReferenceParams;
|
||||
asCodeActionContext(context: code.CodeActionContext): proto.CodeActionContext;
|
||||
asCommand(item: code.Command): proto.Command;
|
||||
asCodeLens(item: code.CodeLens): proto.CodeLens;
|
||||
asFormattingOptions(item: code.FormattingOptions): proto.FormattingOptions;
|
||||
asDocumentSymbolParams(textDocument: code.TextDocument): proto.DocumentSymbolParams;
|
||||
asCodeLensParams(textDocument: code.TextDocument): proto.CodeLensParams;
|
||||
asDocumentLink(item: code.DocumentLink): proto.DocumentLink;
|
||||
asDocumentLinkParams(textDocument: code.TextDocument): proto.DocumentLinkParams;
|
||||
}
|
||||
export interface URIConverter {
|
||||
(value: code.Uri): string;
|
||||
}
|
||||
export declare function createConverter(uriConverter?: URIConverter): Converter;
|
|
@ -0,0 +1,5 @@
|
|||
import * as code from './vscode';
|
||||
export default class ProtocolCodeLens extends code.CodeLens {
|
||||
data: any;
|
||||
constructor(range: code.Range);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import * as code from './vscode';
|
||||
export default class ProtocolCompletionItem extends code.CompletionItem {
|
||||
data: any;
|
||||
fromEdit: boolean;
|
||||
constructor(label: string);
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
import * as code from './vscode';
|
||||
import * as ls from 'vscode-languageserver-protocol';
|
||||
import ProtocolCompletionItem from './protocolCompletionItem';
|
||||
export interface Converter {
|
||||
asUri(value: string): code.Uri;
|
||||
asDiagnostic(diagnostic: ls.Diagnostic): code.Diagnostic;
|
||||
asDiagnostics(diagnostics: ls.Diagnostic[]): code.Diagnostic[];
|
||||
asPosition(value: undefined | null): undefined;
|
||||
asPosition(value: ls.Position): code.Position;
|
||||
asPosition(value: ls.Position | undefined | null): code.Position | undefined;
|
||||
asRange(value: undefined | null): undefined;
|
||||
asRange(value: ls.Range): code.Range;
|
||||
asRange(value: ls.Range | undefined | null): code.Range | undefined;
|
||||
asDiagnosticSeverity(value: number | undefined | null): code.DiagnosticSeverity;
|
||||
asHover(hover: ls.Hover): code.Hover;
|
||||
asHover(hover: undefined | null): undefined;
|
||||
asHover(hover: ls.Hover | undefined | null): code.Hover | undefined;
|
||||
asCompletionResult(result: ls.CompletionList): code.CompletionList;
|
||||
asCompletionResult(result: ls.CompletionItem[]): code.CompletionItem[];
|
||||
asCompletionResult(result: undefined | null): undefined;
|
||||
asCompletionResult(result: ls.CompletionItem[] | ls.CompletionList | undefined | null): code.CompletionItem[] | code.CompletionList | undefined;
|
||||
asCompletionItem(item: ls.CompletionItem): ProtocolCompletionItem;
|
||||
asTextEdit(edit: undefined | null): undefined;
|
||||
asTextEdit(edit: ls.TextEdit): code.TextEdit;
|
||||
asTextEdits(items: ls.TextEdit[]): code.TextEdit[];
|
||||
asTextEdits(items: undefined | null): undefined;
|
||||
asTextEdits(items: ls.TextEdit[] | undefined | null): code.TextEdit[] | undefined;
|
||||
asSignatureHelp(item: undefined | null): undefined;
|
||||
asSignatureHelp(item: ls.SignatureHelp): code.SignatureHelp;
|
||||
asSignatureHelp(item: ls.SignatureHelp | undefined | null): code.SignatureHelp | undefined;
|
||||
asSignatureInformation(item: ls.SignatureInformation): code.SignatureInformation;
|
||||
asSignatureInformations(items: ls.SignatureInformation[]): code.SignatureInformation[];
|
||||
asParameterInformation(item: ls.ParameterInformation): code.ParameterInformation;
|
||||
asParameterInformations(item: ls.ParameterInformation[]): code.ParameterInformation[];
|
||||
asDefinitionResult(item: ls.Definition): code.Definition;
|
||||
asDefinitionResult(item: undefined | null): undefined;
|
||||
asDefinitionResult(item: ls.Definition | undefined | null): code.Definition | undefined;
|
||||
asLocation(item: ls.Location): code.Location;
|
||||
asLocation(item: undefined | null): undefined;
|
||||
asLocation(item: ls.Location | undefined | null): code.Location | undefined;
|
||||
asReferences(values: ls.Location[]): code.Location[];
|
||||
asReferences(values: undefined | null): code.Location[] | undefined;
|
||||
asReferences(values: ls.Location[] | undefined | null): code.Location[] | undefined;
|
||||
asDocumentHighlightKind(item: number): code.DocumentHighlightKind;
|
||||
asDocumentHighlight(item: ls.DocumentHighlight): code.DocumentHighlight;
|
||||
asDocumentHighlights(values: ls.DocumentHighlight[]): code.DocumentHighlight[];
|
||||
asDocumentHighlights(values: undefined | null): undefined;
|
||||
asDocumentHighlights(values: ls.DocumentHighlight[] | undefined | null): code.DocumentHighlight[] | undefined;
|
||||
asSymbolInformation(item: ls.SymbolInformation, uri?: code.Uri): code.SymbolInformation;
|
||||
asSymbolInformations(values: ls.SymbolInformation[], uri?: code.Uri): code.SymbolInformation[];
|
||||
asSymbolInformations(values: undefined | null, uri?: code.Uri): undefined;
|
||||
asSymbolInformations(values: ls.SymbolInformation[] | undefined | null, uri?: code.Uri): code.SymbolInformation[] | undefined;
|
||||
asCommand(item: ls.Command): code.Command;
|
||||
asCommands(items: ls.Command[]): code.Command[];
|
||||
asCommands(items: undefined | null): undefined;
|
||||
asCommands(items: ls.Command[] | undefined | null): code.Command[] | undefined;
|
||||
asCodeLens(item: ls.CodeLens): code.CodeLens;
|
||||
asCodeLens(item: undefined | null): undefined;
|
||||
asCodeLens(item: ls.CodeLens | undefined | null): code.CodeLens | undefined;
|
||||
asCodeLenses(items: ls.CodeLens[]): code.CodeLens[];
|
||||
asCodeLenses(items: undefined | null): undefined;
|
||||
asCodeLenses(items: ls.CodeLens[] | undefined | null): code.CodeLens[] | undefined;
|
||||
asWorkspaceEdit(item: ls.WorkspaceEdit): code.WorkspaceEdit;
|
||||
asWorkspaceEdit(item: undefined | null): undefined;
|
||||
asWorkspaceEdit(item: ls.WorkspaceEdit | undefined | null): code.WorkspaceEdit | undefined;
|
||||
asDocumentLink(item: ls.DocumentLink): code.DocumentLink;
|
||||
asDocumentLinks(items: ls.DocumentLink[]): code.DocumentLink[];
|
||||
asDocumentLinks(items: undefined | null): undefined;
|
||||
asDocumentLinks(items: ls.DocumentLink[] | undefined | null): code.DocumentLink[] | undefined;
|
||||
}
|
||||
export interface URIConverter {
|
||||
(value: string): code.Uri;
|
||||
}
|
||||
export declare function createConverter(uriConverter?: URIConverter): Converter;
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,24 @@
|
|||
import { WorkspaceFoldersChangeEvent as VWorkspaceFoldersChangeEvent } from './vscode';
|
||||
import { DynamicFeature, RegistrationData, BaseLanguageClient, NextSignature } from './client';
|
||||
import { ClientCapabilities, InitializedParams, Proposed, RPCMessageType } from 'vscode-languageserver-protocol';
|
||||
export interface WorkspaceFolderMiddleware {
|
||||
workspace?: {
|
||||
workspaceFolders?: Proposed.WorkspaceFoldersRequest.MiddlewareSignature;
|
||||
didChangeWorkspaceFolders?: NextSignature<VWorkspaceFoldersChangeEvent, void>;
|
||||
};
|
||||
}
|
||||
export declare class WorkspaceFoldersFeature implements DynamicFeature<undefined> {
|
||||
private _client;
|
||||
private _listeners;
|
||||
constructor(_client: BaseLanguageClient);
|
||||
readonly messages: RPCMessageType;
|
||||
fillInitializeParams(params: InitializedParams): void;
|
||||
fillClientCapabilities(capabilities: ClientCapabilities): void;
|
||||
initialize(): void;
|
||||
register(_message: RPCMessageType, data: RegistrationData<undefined>): void;
|
||||
unregister(id: string): void;
|
||||
dispose(): void;
|
||||
private asProtocol(workspaceFolder);
|
||||
private asProtocol(workspaceFolder);
|
||||
private getWorkspaceFolderMiddleware();
|
||||
}
|
Загрузка…
Ссылка в новой задаче