Skip to content

Commit

Permalink
load schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
Cammisuli committed Aug 3, 2022
1 parent 2479121 commit 087b243
Show file tree
Hide file tree
Showing 11 changed files with 287 additions and 365 deletions.
36 changes: 19 additions & 17 deletions apps/lsp/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
import {
ClientCapabilities,
getLanguageService,
JSONDocument,
TextDocument,
} from 'vscode-json-languageservice';
import {
Expand All @@ -16,8 +15,9 @@ import {
TextDocuments,
TextDocumentSyncKind,
} from 'vscode-languageserver/node';
import { Utils, URI } from 'vscode-uri';
import { URI, Utils } from 'vscode-uri';
import { jsonDocumentsMapper } from './json-documents';
import { getSchemaRequestService } from './runtime';

const workspaceContext = {
resolveRelativePath: (relativePath: string, resource: string) => {
Expand Down Expand Up @@ -50,13 +50,14 @@ documents.onDidClose((e) => {
});

connection.onInitialize(async (params) => {
debugger;
// TODO: add capability checks
const capabilities = params.capabilities;

const { workspacePath, projects } = params.initializationOptions ?? {};

languageService = getLanguageService({
// schemaRequestService: getSchemaRequestService(handledProtocols),
schemaRequestService: getSchemaRequestService(['file']),
workspaceContext,
contributions: [],
clientCapabilities: params.capabilities,
Expand All @@ -66,18 +67,18 @@ connection.onInitialize(async (params) => {
const collections = await getExecutors(workspacePath, projects, false);
const workspaceSchema = getWorkspaceJsonSchema(collections);
const projectSchema = getProjectJsonSchema(collections);

console.log(projectSchema);
languageService.configure({
schemas: [
{
uri: 'nx://schemas/workspace',
fileMatch: ['**/workspace.json'],
schema: JSON.parse(workspaceSchema),
fileMatch: ['**/workspace.json', '**/angular.json'],
schema: workspaceSchema,
},
{
uri: 'nx://schemas/project',
fileMatch: ['**/project.json'],
schema: JSON.parse(projectSchema),
schema: projectSchema,
},
],
});
Expand All @@ -87,6 +88,7 @@ connection.onInitialize(async (params) => {
textDocumentSync: TextDocumentSyncKind.Incremental,
completionProvider: {
resolveProvider: false,
triggerCharacters: ['"', ':'],
},
},
};
Expand All @@ -96,18 +98,18 @@ connection.onInitialize(async (params) => {

connection.onCompletion(async (completionParams) => {
const document = documents.get(completionParams.textDocument.uri);
if (document) {
const jsonDocument = getJsonDocument(document);
const completionList = await languageService.doComplete(
document,
completionParams.position,
jsonDocument
);
console.log(completionList);
return completionList;
if (!document) {
return null;
}

return null;
const jsonDocument = getJsonDocument(document);
const completionList = await languageService.doComplete(
document,
completionParams.position,
jsonDocument
);
console.log(completionList);
return completionList;
});

function getJsonDocument(document: TextDocument) {
Expand Down
71 changes: 71 additions & 0 deletions apps/lsp/src/runtime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {
xhr,
XHRResponse,
configure as configureHttpRequests,
getErrorStatusDescription,
} from 'request-light';
import { URI } from 'vscode-uri';
import * as fs from 'fs';

export interface RequestService {
getContent(uri: string): Promise<string>;
}

function getHTTPRequestService(): RequestService {
return {
getContent(uri: string, _encoding?: string) {
const headers = { 'Accept-Encoding': 'gzip, deflate' };
return xhr({ url: uri, followRedirects: 5, headers }).then(
(response) => {
return response.responseText;
},
(error: XHRResponse) => {
return Promise.reject(
error.responseText ||
getErrorStatusDescription(error.status) ||
error.toString()
);
}
);
},
};
}

function getFileRequestService(): RequestService {
return {
getContent(location: string, encoding?: BufferEncoding) {
return new Promise((c, e) => {
const uri = URI.parse(location);
fs.readFile(uri.fsPath, encoding, (err, buf) => {
if (err) {
return e(err);
}
c(buf.toString());
});
});
},
};
}

export function getSchemaRequestService(
handledSchemas: string[] = ['https', 'http', 'file']
) {
const builtInHandlers: { [protocol: string]: RequestService | undefined } =
{};
for (const protocol of handledSchemas) {
if (protocol === 'file') {
builtInHandlers[protocol] = getFileRequestService();
} else if (protocol === 'http' || protocol === 'https') {
builtInHandlers[protocol] = getHTTPRequestService();
}
}
return (uri: string): Thenable<string> => {
const protocol = uri.substr(0, uri.indexOf(':'));

const builtInHandler = builtInHandlers[protocol];
if (builtInHandler) {
return builtInHandler.getContent(uri);
}
return Promise.reject('Unable to retrieve schema');
};
}
12 changes: 0 additions & 12 deletions apps/vscode/src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -884,18 +884,6 @@
]
},
"jsonValidation": [
{
"fileMatch": "workspace.json",
"url": "./workspace-schema.json"
},
{
"fileMatch": "angular.json",
"url": "./workspace-schema.json"
},
{
"fileMatch": "project.json",
"url": "./project-schema.json"
},
{
"fileMatch": "nx.json",
"url": "./nx-schema.json"
Expand Down
60 changes: 60 additions & 0 deletions libs/json-schema/src/lib/create-builders-and-executors-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { CollectionInfo } from '@nx-console/schema';
import { JSONSchema } from 'vscode-json-languageservice';

type BuildersSchema = JSONSchema;
type ExecutorsSchema = JSONSchema;

/**
* Builds the schema for builders and executors.
*
* @param collections
* @returns [BuildersSchema[], ExecutorsSchema[]]
*/
export function createBuildersAndExecutorsSchema(
collections: CollectionInfo[]
): [BuildersSchema[], ExecutorsSchema[]] {
return collections.reduce<[BuildersSchema[], ExecutorsSchema[]]>(
(acc, collection) => {
acc[0].push({
if: {
properties: { builder: { const: collection.name } },
required: ['builder'],
},
then: {
properties: {
options: {
$ref: `file://${collection.path}`,
},
configurations: {
additionalProperties: {
$ref: `file://${collection.path}`,
required: [],
},
},
},
},
});
acc[1].push({
if: {
properties: { executor: { const: collection.name } },
required: ['executor'],
},
then: {
properties: {
options: {
$ref: `file://${collection.path}`,
},
configurations: {
additionalProperties: {
$ref: `file://${collection.path}`,
required: [],
},
},
},
},
});
return acc;
},
[[], []]
);
}
121 changes: 31 additions & 90 deletions libs/json-schema/src/lib/project-json-schema.ts
Original file line number Diff line number Diff line change
@@ -1,100 +1,41 @@
import { CollectionInfo } from '@nx-console/schema';
import { JSONSchema } from 'vscode-json-languageservice';
import { createBuildersAndExecutorsSchema } from './create-builders-and-executors-schema';

export function getProjectJsonSchema(collections: CollectionInfo[]) {
const [builders, executors] = createBuildersAndExecutorsSchema(collections);
const contents = createJsonSchema(builders, executors);
const [, executors] = createBuildersAndExecutorsSchema(collections);
const contents = createJsonSchema(executors);
return contents;
}

function createBuildersAndExecutorsSchema(
collections: CollectionInfo[]
): [string, string] {
const builders = collections
.map(
(collection) => `
{
"if": {
"properties": { "builder": { "const": "${collection.name}" } },
"required": ["builder"]
},
"then": {
"properties": {
"options": {
"$ref": "${collection.path}"
},
"configurations": {
"additionalProperties": {
"$ref": "${collection.path}",
"required": []
}
}
}
}
}
`
)
.join(',');

const executors = collections
.map(
(collection) => `
{
"if": {
"properties": { "executor": { "const": "${collection.name}" } },
"required": ["executor"]
},
"then": {
"properties": {
"options": {
"$ref": "${collection.path}"
},
"configurations": {
"additionalProperties": {
"$ref": "${collection.path}",
"required": []
}
}
}
}
}
`
)
.join(',');

return [builders, executors];
}

function createJsonSchema(builders: string, executors: string) {
return `
{
"title": "JSON schema for Nx projects",
"id": "https://nx.dev/project-schema",
"type": "object",
"properties": {
"targets": {
"description": "Configures all the targets which define what tasks you can run against the project",
"additionalProperties": {
"type": "object",
"properties": {
"executor": {
"description": "The function that Nx will invoke when you run this target",
"type": "string"
function createJsonSchema(executors: JSONSchema[]): JSONSchema {
return {
title: 'JSON schema for Nx projects',
id: 'https://nx.dev/project-schema',
type: 'object',
properties: {
targets: {
description:
'Configures all the targets which define what tasks you can run against the project',
additionalProperties: {
type: 'object',
properties: {
executor: {
description:
'The function that Nx will invoke when you run this target',
type: 'string',
},
"options": {
"type": "object"
configurations: {
description:
'provides extra sets of values that will be merged into the options map',
additionalProperties: {
type: 'object',
},
},
"configurations": {
"description": "provides extra sets of values that will be merged into the options map",
"additionalProperties": {
"type": "object"
}
}
},
"allOf": [
${executors}
]
}
}
}
}`;
allOf: executors,
},
},
},
};
}
Loading

0 comments on commit 087b243

Please sign in to comment.