Skip to content

Commit 3ae9936

Browse files
committed
refactor: replace AJV with @hyperjump/json-schema
Replace AJV dependencies with @hyperjump/json-schema to reduce bundle size and prepare for JSON Schema 2019-09/2020-12 support. Simplifies schema meta-validation while maintaining backward compatibility.
1 parent 3821411 commit 3ae9936

File tree

4 files changed

+166
-91
lines changed

4 files changed

+166
-91
lines changed

package-lock.json

Lines changed: 111 additions & 63 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@
2727
"url": "git+https://github.com/redhat-developer/yaml-language-server.git"
2828
},
2929
"dependencies": {
30+
"@hyperjump/json-schema": "^1.16.2",
3031
"@vscode/l10n": "^0.0.18",
31-
"ajv": "^8.17.1",
32-
"ajv-draft-04": "^1.0.0",
3332
"lodash": "4.17.21",
3433
"prettier": "^3.5.0",
3534
"request-light": "^0.5.7",
@@ -99,4 +98,4 @@
9998
],
10099
"all": true
101100
}
102-
}
101+
}

src/languageservice/services/yamlSchemaService.ts

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,8 @@ import { SchemaVersions } from '../yamlTypes';
2727

2828
import { parse } from 'yaml';
2929
import * as Json from 'jsonc-parser';
30-
import Ajv, { DefinedError } from 'ajv';
31-
import Ajv4 from 'ajv-draft-04';
3230
import { getSchemaTitle } from '../utils/schemaUtils';
3331

34-
const ajv = new Ajv();
35-
const ajv4 = new Ajv4();
36-
37-
// load JSON Schema 07 def to validate loaded schemas
38-
// eslint-disable-next-line @typescript-eslint/no-var-requires
39-
const jsonSchema07 = require('ajv/dist/refs/json-schema-draft-07.json');
40-
const schema07Validator = ajv.compile(jsonSchema07);
41-
42-
// eslint-disable-next-line @typescript-eslint/no-var-requires
43-
const jsonSchema04 = require('ajv-draft-04/dist/refs/json-schema-draft-04.json');
44-
const schema04Validator = ajv4.compile(jsonSchema04);
45-
const SCHEMA_04_URI_WITH_HTTPS = ajv4.defaultMeta().replace('http://', 'https://');
46-
4732
export declare type CustomSchemaProvider = (uri: string) => Promise<string | string[]>;
4833

4934
export enum MODIFICATION_ACTIONS {
@@ -169,16 +154,12 @@ export class YAMLSchemaService extends JSONSchemaService {
169154
let schema: JSONSchema = schemaToResolve.schema;
170155
const contextService = this.contextService;
171156

172-
const validator =
173-
this.normalizeId(schema.$schema) === ajv4.defaultMeta() || this.normalizeId(schema.$schema) === SCHEMA_04_URI_WITH_HTTPS
174-
? schema04Validator
175-
: schema07Validator;
176-
if (!validator(schema)) {
177-
const errs: string[] = [];
178-
for (const err of validator.errors as DefinedError[]) {
179-
errs.push(`${err.instancePath} : ${err.message}`);
180-
}
181-
resolveErrors.push(`Schema '${getSchemaTitle(schemaToResolve.schema, schemaURL)}' is not valid:\n${errs.join('\n')}`);
157+
// Basic schema validation - check if schema is a valid object
158+
if (typeof schema !== 'object' || schema === null || Array.isArray(schema)) {
159+
const invalidSchemaType = Array.isArray(schema) ? 'array' : typeof schema;
160+
resolveErrors.push(
161+
`Schema '${getSchemaTitle(schemaToResolve.schema, schemaURL)}' is not valid:\nWrong schema: "${invalidSchemaType}", it MUST be an Object or Boolean`
162+
);
182163
}
183164

184165
const findSection = (schema: JSONSchema, path: string): JSONSchema => {

test/yamlSchemaService.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* Copyright (c) Red Hat. All rights reserved.
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
5+
import { readFile } from 'fs/promises';
56
import * as sinon from 'sinon';
67
import * as chai from 'chai';
78
import * as sinonChai from 'sinon-chai';
@@ -67,6 +68,52 @@ describe('YAML Schema Service', () => {
6768
expect(schema.schema.type).eqls('array');
6869
});
6970

71+
it('should handle schemas that use draft-04', async () => {
72+
const content = `openapi: "3.0.0"
73+
info:
74+
version: 1.0.0
75+
title: Minimal ping API server
76+
paths:
77+
/ping:
78+
get:
79+
responses:
80+
'200':
81+
description: pet response
82+
content:
83+
application/json:
84+
schema:
85+
$ref: '#/components/schemas/Pong'
86+
components:
87+
schemas:
88+
# base types
89+
Pong:
90+
type: object
91+
required:
92+
- ping
93+
properties:
94+
ping:
95+
type: string
96+
example: pong`;
97+
98+
const yamlDock = parse(content);
99+
// eslint-disable-next-line @typescript-eslint/no-var-requires
100+
const openapiV3Schema = await readFile(path.join(__dirname, './fixtures/sample-openapiv3.0.0-schema.json'), {
101+
encoding: 'utf-8',
102+
});
103+
104+
requestServiceMock = sandbox.fake.resolves(openapiV3Schema);
105+
const service = new SchemaService.YAMLSchemaService(requestServiceMock);
106+
service.registerCustomSchemaProvider(() => {
107+
return new Promise<string | string[]>((resolve) => {
108+
resolve('http://fakeschema.faketld');
109+
});
110+
});
111+
112+
const schema = await service.getSchemaForResource('', yamlDock.documents[0]);
113+
expect(requestServiceMock).calledWithExactly('http://fakeschema.faketld');
114+
expect(schema).to.not.be.null;
115+
});
116+
70117
it('should handle url with fragments when root object is schema', async () => {
71118
const content = `# yaml-language-server: $schema=https://json-schema.org/draft-07/schema#/definitions/schemaArray`;
72119
const yamlDock = parse(content);

0 commit comments

Comments
 (0)