Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 9 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"ajv-draft-04": "^1.0.0",
"prettier": "^3.8.1",
"request-light": "^0.5.7",
"vscode-json-languageservice": "4.1.8",
"vscode-json-languageservice": "5.7.2",
"vscode-languageserver": "^9.0.0",
"vscode-languageserver-textdocument": "^1.0.1",
"vscode-languageserver-types": "^3.16.0",
Expand Down
67 changes: 37 additions & 30 deletions src/languageservice/services/yamlSchemaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
UnresolvedSchema,
ResolvedSchema,
JSONSchemaService,
SchemaDependencies,
ISchemaContributions,
SchemaHandle,
} from 'vscode-json-languageservice/lib/umd/services/jsonSchemaService';
Expand Down Expand Up @@ -153,7 +152,7 @@ export class YAMLSchemaService extends JSONSchemaService {
const result: JSONSchemaDescriptionExt[] = [];
const schemaUris = new Set<string>();
for (const filePattern of this.filePatternAssociations) {
const schemaUri = filePattern.uris[0];
const schemaUri = filePattern.getURIs()[0];
if (schemaUris.has(schemaUri)) {
continue;
}
Expand Down Expand Up @@ -198,12 +197,13 @@ export class YAMLSchemaService extends JSONSchemaService {
return Object.values(map);
}

async resolveSchemaContent(
schemaToResolve: UnresolvedSchema,
schemaURL: string,
dependencies: SchemaDependencies
): Promise<ResolvedSchema> {
const resolveErrors: string[] = schemaToResolve.errors.slice(0);
async resolveSchemaContent(schemaToResolve: UnresolvedSchema, handle: SchemaHandle): Promise<ResolvedSchema> {
const schemaURL: string = handle.uri;
const dependencies: Set<string> = handle.dependencies;
const resolveErrors: (string | { message: string; code: number })[] = schemaToResolve.errors.slice(0);
// Normalize errors: upstream v5.x expects { message, code } objects, but our code pushes strings
const _toDiagErrors = (errors: (string | { message: string; code: number })[]): { message: string; code: number }[] =>
errors.map((e) => (typeof e === 'string' ? { message: e, code: 0x10000 } : e));
const loc = toDisplayString(schemaURL);

const raw: unknown = schemaToResolve.schema;
Expand All @@ -212,7 +212,7 @@ export class YAMLSchemaService extends JSONSchemaService {
resolveErrors.push(
l10n.t("Schema '{0}' is not valid: {1}", loc, `expected a JSON Schema object or boolean, got "${got}".`)
);
return new ResolvedSchema({}, resolveErrors);
return new ResolvedSchema({}, _toDiagErrors(resolveErrors));
}

const _cloneSchema = (
Expand Down Expand Up @@ -532,7 +532,7 @@ export class YAMLSchemaService extends JSONSchemaService {
uri: string,
linkPath: string,
parentSchemaURL: string,
parentSchemaDependencies: SchemaDependencies,
parentSchemaDependencies: Set<string>,
resolutionStack: Set<string>,
recursiveAnchorBase: string,
inheritedDynamicScope: Map<string, JSONSchema[]>
Expand All @@ -543,14 +543,14 @@ export class YAMLSchemaService extends JSONSchemaService {
schemaRoot: JSONSchema,
schemaUri: string,
linkPath: string,
parentSchemaDependencies: SchemaDependencies,
resolveRefDependencies: SchemaDependencies,
parentSchemaDependencies: Set<string>,
resolveRefDependencies: Set<string>,
resolutionStack: Set<string>,
recursiveAnchorBase: string,
inheritedDynamicScope: Map<string, JSONSchema[]>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<any> => {
parentSchemaDependencies[schemaUri] = true;
parentSchemaDependencies.add(schemaUri);
_merge(node, schemaRoot, schemaUri, linkPath, !!inheritedDynamicScope || !!recursiveAnchorBase);
if (!recursiveAnchorBase || !node._baseUrl) node._baseUrl = schemaUri;
node.url = schemaUri;
Expand Down Expand Up @@ -590,15 +590,20 @@ export class YAMLSchemaService extends JSONSchemaService {
const referencedHandle = this.getOrAddSchemaHandle(targetUri);
return referencedHandle.getUnresolvedSchema().then(async (unresolvedSchema) => {
if (
unresolvedSchema.errors?.some((error) => error.toLowerCase().includes('unable to load schema from')) &&
unresolvedSchema.errors?.some((error) => {
const msg = typeof error === 'string' ? error : (error?.message ?? '');
return msg.toLowerCase().includes('unable to load schema from');
}) &&
index + 1 < targetUris.length
) {
return _resolveByUri(targetUris, index + 1);
}

if (unresolvedSchema.errors.length) {
const loc = linkPath ? targetUri + '#' + linkPath : targetUri;
resolveErrors.push(l10n.t("Problems loading reference '{0}': {1}", loc, unresolvedSchema.errors[0]));
const firstError = unresolvedSchema.errors[0];
const errorMsg = typeof firstError === 'string' ? firstError : (firstError?.message ?? String(firstError));
resolveErrors.push(l10n.t("Problems loading reference '{0}': {1}", loc, errorMsg));
}
// index resources for the newly loaded schema
await _indexSchemaResources(unresolvedSchema.schema, targetUri);
Expand Down Expand Up @@ -626,7 +631,7 @@ export class YAMLSchemaService extends JSONSchemaService {
node: JSONSchema,
parentSchema: JSONSchema,
parentSchemaURL: string,
parentSchemaDependencies: SchemaDependencies,
parentSchemaDependencies: Set<string>,
resolutionStack: Set<string>,
recursiveAnchorBase?: string,
inheritedDynamicScope?: Map<string, JSONSchema[]>
Expand Down Expand Up @@ -939,7 +944,7 @@ export class YAMLSchemaService extends JSONSchemaService {
const rootResource = schema._baseUrl || schemaURL;
if (rootResource) resolutionStack.add(rootResource);
await resolveRefs(schema, schema, schemaURL, dependencies, resolutionStack);
return new ResolvedSchema(schema, resolveErrors);
return new ResolvedSchema(schema, _toDiagErrors(resolveErrors));
}

public getSchemaForResource(resource: string, doc: JSONDocument): Promise<ResolvedSchema> {
Expand Down Expand Up @@ -973,7 +978,7 @@ export class YAMLSchemaService extends JSONSchemaService {
const resolveSchemaForResource = (schemas: string[]): Promise<ResolvedSchema> => {
const schemaHandle = super.createCombinedSchema(resource, schemas);
return schemaHandle.getResolvedSchema().then((schema) => {
return this.finalizeResolvedSchema(schema, schemaHandle.url, doc, false);
return this.finalizeResolvedSchema(schema, schemaHandle.uri, doc, false);
});
};

Expand Down Expand Up @@ -1038,14 +1043,11 @@ export class YAMLSchemaService extends JSONSchemaService {
})
).then(
(schemas) => {
return {
errors: [],
schema: {
allOf: schemas.map((schemaObj) => {
return schemaObj.schema;
}),
},
};
return new ResolvedSchema({
allOf: schemas.map((schemaObj) => {
return schemaObj.schema;
}),
});
},
() => {
return resolveSchema();
Expand Down Expand Up @@ -1130,7 +1132,8 @@ export class YAMLSchemaService extends JSONSchemaService {

private async resolveCustomSchema(schemaUri, doc): ResolvedSchema {
const unresolvedSchema = await this.loadSchema(schemaUri);
const schema = await this.resolveSchemaContent(unresolvedSchema, schemaUri, []);
const schemaHandle = this.getOrAddSchemaHandle(schemaUri);
const schema = await this.resolveSchemaContent(unresolvedSchema, schemaHandle);
return this.finalizeResolvedSchema(schema, schemaUri, doc, true);
}

Expand Down Expand Up @@ -1259,10 +1262,13 @@ export class YAMLSchemaService extends JSONSchemaService {
return requestService(schemaUri).then(
(content) => {
if (!content) {
const errorDetails = unresolvedJsonSchema.errors
.map((e) => (typeof e === 'string' ? e : (e?.message ?? String(e))))
.join(', ');
const errorMessage = l10n.t(
"Unable to load schema from '{0}': No content. {1}",
toDisplayString(schemaUri),
unresolvedJsonSchema.errors
errorDetails
);
return new UnresolvedSchema(<JSONSchema>{}, [errorMessage]);
}
Expand Down Expand Up @@ -1294,7 +1300,8 @@ export class YAMLSchemaService extends JSONSchemaService {
unresolvedJsonSchema.schema.description = description ?? unresolvedJsonSchema.schema.description;
unresolvedJsonSchema.schema.versions = versions ?? unresolvedJsonSchema.schema.versions;
} else if (unresolvedJsonSchema.errors && unresolvedJsonSchema.errors.length > 0) {
let errorMessage: string = unresolvedJsonSchema.errors[0];
const firstError = unresolvedJsonSchema.errors[0];
let errorMessage: string = typeof firstError === 'string' ? firstError : (firstError?.message ?? String(firstError));
if (errorMessage.toLowerCase().indexOf('load') !== -1) {
errorMessage = l10n.t("Unable to load schema from '{0}': No content.", toDisplayString(schemaUri));
} else if (errorMessage.toLowerCase().indexOf('parse') !== -1) {
Expand Down Expand Up @@ -1329,7 +1336,7 @@ export class YAMLSchemaService extends JSONSchemaService {
if (name || description) {
this.schemaUriToNameAndDescription.set(uri, { name, description, versions });
}
return super.registerExternalSchema(uri, filePatterns, unresolvedSchema);
return super.registerExternalSchema({ uri, fileMatch: filePatterns, schema: unresolvedSchema });
}

clearExternalSchemas(): void {
Expand Down
4 changes: 2 additions & 2 deletions test/autoCompletion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2131,7 +2131,7 @@ describe('Auto Completion Tests', () => {
textDocument: testTextDocument,
});
assert.strictEqual(result.items.length, 1, `Expecting 1 item in completion but found ${result.items.length}`);
assert.strictEqual(result.items[0].label, 'http://google.com');
assert.strictEqual(result.items[0].label, 'http://google.com/');
});

it('should provide schema id completion in modeline for any line', async () => {
Expand All @@ -2144,7 +2144,7 @@ describe('Auto Completion Tests', () => {
textDocument: testTextDocument,
});
assert.strictEqual(result.items.length, 1, `Expecting 1 item in completion but found ${result.items.length}`);
assert.strictEqual(result.items[0].label, 'http://google.com');
assert.strictEqual(result.items[0].label, 'http://google.com/');
});
});

Expand Down
7 changes: 5 additions & 2 deletions test/jsonParser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { JSONDocument } from '../src/languageservice/parser/jsonDocument';
import { getNodeValue } from '../src/languageservice/parser/astNodeUtils';
import * as JsonSchema from './../src/languageservice/jsonSchema';
import { ASTNode, ObjectASTNode } from './../src/languageservice/jsonASTTypes';
import { ErrorCode, getLanguageService } from 'vscode-json-languageservice';
import { ErrorCode, getLanguageService, type JSONSchema } from 'vscode-json-languageservice';
import { Diagnostic, TextDocument, Range } from 'vscode-languageserver-types';

describe('JSON Parser', () => {
Expand Down Expand Up @@ -1422,6 +1422,7 @@ describe('JSON Parser', () => {

it('items as array', function () {
const schema: JsonSchema.JSONSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'array',
items: [
{
Expand Down Expand Up @@ -1457,6 +1458,7 @@ describe('JSON Parser', () => {

it('additionalItems', function () {
let schema: JsonSchema.JSONSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'array',
items: [
{
Expand Down Expand Up @@ -1484,6 +1486,7 @@ describe('JSON Parser', () => {
assert.strictEqual(semanticErrors.length, 1);
}
schema = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'array',
items: [
{
Expand Down Expand Up @@ -1927,7 +1930,7 @@ describe('JSON Parser', () => {
res = await ls.doValidation(textDoc, jsonDoc, { trailingCommas: 'ignore' });
assert.strictEqual(res.length, 0);

const schema: JsonSchema.JSONSchema = { type: 'object', required: ['foo'] };
const schema: JSONSchema = { type: 'object', required: ['foo'] };
res = await ls.doValidation(textDoc, jsonDoc, { trailingCommas: 'ignore' }, schema);
assert.strictEqual(res.length, 1);
assert.strictEqual(res[0].message, 'Missing property "foo".');
Expand Down
1 change: 1 addition & 0 deletions test/schemaValidation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ describe('Validation Tests', () => {

afterEach(() => {
schemaProvider.deleteSchema(SCHEMA_ID);
telemetry.clearMessages();
});

describe('Boolean tests', () => {
Expand Down
4 changes: 2 additions & 2 deletions test/yamlLanguageService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('getLanguageService()', () => {
});

describe('minimal language service hover happy path', () => {
const schemaUri = 'my.schema.uri';
const schemaUri = 'https://example.com/my.schema.json';
const schemaContentMap: { [uri: string]: string } = {};

let schemaRequestService: SchemaRequestService;
Expand Down Expand Up @@ -79,7 +79,7 @@ describe('getLanguageService()', () => {
assert.deepEqual(result, {
contents: {
kind: 'markdown',
value: "The person's first name.\n\nSource: [my.schema.uri](my.schema.uri)",
value: "The person's first name.\n\nSource: [my.schema.json](https://example.com/my.schema.json)",
},
range: {
start: {
Expand Down