Complete residential site build with Docker Compose & Gitea Actions deployment
This commit is contained in:
Generated
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
import { Alias, Document, LineCounter } from 'yaml';
|
||||
import { ASTNode, YamlNode } from '../jsonASTTypes';
|
||||
type NodeRange = [number, number, number];
|
||||
export declare const aliasDepth: {
|
||||
maxRefCount: number;
|
||||
currentRefDepth: number;
|
||||
aliasResolutionCache: Map<Alias, ASTNode>;
|
||||
};
|
||||
export declare function convertAST(parent: ASTNode, node: YamlNode, doc: Document, lineCounter: LineCounter): ASTNode | undefined;
|
||||
export declare function toOffsetLength(range: NodeRange): [number, number];
|
||||
export {};
|
||||
Generated
Vendored
+176
@@ -0,0 +1,176 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Red Hat, Inc. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { isScalar, isMap, isPair, isSeq, isNode, isAlias, } from 'yaml';
|
||||
import { NullASTNodeImpl, PropertyASTNodeImpl, StringASTNodeImpl, ObjectASTNodeImpl, NumberASTNodeImpl, ArrayASTNodeImpl, BooleanASTNodeImpl, } from './jsonDocument';
|
||||
// Exported for tests
|
||||
export const aliasDepth = {
|
||||
maxRefCount: 1000,
|
||||
currentRefDepth: 0,
|
||||
aliasResolutionCache: new Map(),
|
||||
};
|
||||
export function convertAST(parent, node, doc, lineCounter) {
|
||||
if (!parent) {
|
||||
// first invocation
|
||||
aliasDepth.currentRefDepth = 0;
|
||||
aliasDepth.aliasResolutionCache = new Map();
|
||||
}
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
if (isMap(node)) {
|
||||
return convertMap(node, parent, doc, lineCounter);
|
||||
}
|
||||
if (isPair(node)) {
|
||||
return convertPair(node, parent, doc, lineCounter);
|
||||
}
|
||||
if (isSeq(node)) {
|
||||
return convertSeq(node, parent, doc, lineCounter);
|
||||
}
|
||||
if (isScalar(node)) {
|
||||
return convertScalar(node, parent);
|
||||
}
|
||||
if (isAlias(node) && aliasDepth.currentRefDepth < aliasDepth.maxRefCount) {
|
||||
return convertAlias(node, parent, doc, lineCounter);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
function convertMap(node, parent, doc, lineCounter) {
|
||||
let range;
|
||||
if (node.flow && !node.range) {
|
||||
range = collectFlowMapRange(node);
|
||||
}
|
||||
else {
|
||||
range = node.range;
|
||||
}
|
||||
const result = new ObjectASTNodeImpl(parent, node, ...toFixedOffsetLength(range, lineCounter));
|
||||
for (const it of node.items) {
|
||||
if (isPair(it)) {
|
||||
result.properties.push(convertAST(result, it, doc, lineCounter));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function convertPair(node, parent, doc, lineCounter) {
|
||||
const keyNode = node.key;
|
||||
const valueNode = node.value;
|
||||
const rangeStart = keyNode.range[0];
|
||||
let rangeEnd = keyNode.range[1];
|
||||
let nodeEnd = keyNode.range[2];
|
||||
if (valueNode) {
|
||||
rangeEnd = valueNode.range[1];
|
||||
nodeEnd = valueNode.range[2];
|
||||
}
|
||||
// Pair does not return a range using the key/value ranges to fake one.
|
||||
const result = new PropertyASTNodeImpl(parent, node, ...toFixedOffsetLength([rangeStart, rangeEnd, nodeEnd], lineCounter));
|
||||
if (isAlias(keyNode)) {
|
||||
const keyAlias = new StringASTNodeImpl(parent, keyNode, ...toOffsetLength(keyNode.range));
|
||||
keyAlias.value = keyNode.source;
|
||||
result.keyNode = keyAlias;
|
||||
}
|
||||
else {
|
||||
result.keyNode = convertAST(result, keyNode, doc, lineCounter);
|
||||
}
|
||||
result.valueNode = convertAST(result, valueNode, doc, lineCounter);
|
||||
return result;
|
||||
}
|
||||
function convertSeq(node, parent, doc, lineCounter) {
|
||||
const result = new ArrayASTNodeImpl(parent, node, ...toOffsetLength(node.range));
|
||||
for (const it of node.items) {
|
||||
if (isNode(it)) {
|
||||
const convertedNode = convertAST(result, it, doc, lineCounter);
|
||||
// due to recursion protection, convertAST may return undefined
|
||||
if (convertedNode) {
|
||||
result.children.push(convertedNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function convertScalar(node, parent) {
|
||||
if (node.value === null) {
|
||||
return new NullASTNodeImpl(parent, node, ...toOffsetLength(node.range));
|
||||
}
|
||||
switch (typeof node.value) {
|
||||
case 'string': {
|
||||
const result = new StringASTNodeImpl(parent, node, ...toOffsetLength(node.range));
|
||||
result.value = node.value;
|
||||
return result;
|
||||
}
|
||||
case 'boolean':
|
||||
return new BooleanASTNodeImpl(parent, node, node.value, node.source, ...toOffsetLength(node.range));
|
||||
case 'number': {
|
||||
const result = new NumberASTNodeImpl(parent, node, ...toOffsetLength(node.range));
|
||||
result.value = node.value;
|
||||
result.isInteger = Number.isInteger(result.value);
|
||||
return result;
|
||||
}
|
||||
default: {
|
||||
// fail safe converting, we need to return some node anyway
|
||||
const result = new StringASTNodeImpl(parent, node, ...toOffsetLength(node.range));
|
||||
result.value = node.source;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
function convertAlias(node, parent, doc, lineCounter) {
|
||||
if (aliasDepth.aliasResolutionCache.has(node)) {
|
||||
return aliasDepth.aliasResolutionCache.get(node);
|
||||
}
|
||||
aliasDepth.currentRefDepth++;
|
||||
const resolvedNode = node.resolve(doc);
|
||||
let ans;
|
||||
if (resolvedNode) {
|
||||
ans = convertAST(parent, resolvedNode, doc, lineCounter);
|
||||
}
|
||||
else {
|
||||
const resultNode = new StringASTNodeImpl(parent, node, ...toOffsetLength(node.range));
|
||||
resultNode.value = node.source;
|
||||
ans = resultNode;
|
||||
}
|
||||
aliasDepth.currentRefDepth--;
|
||||
aliasDepth.aliasResolutionCache.set(node, ans);
|
||||
return ans;
|
||||
}
|
||||
export function toOffsetLength(range) {
|
||||
return [range[0], range[1] - range[0]];
|
||||
}
|
||||
/**
|
||||
* Convert offsets to offset+length with fix length to not include '\n' character in some cases
|
||||
* @param range the yaml ast range
|
||||
* @param lineCounter the line counter
|
||||
* @returns the offset and length
|
||||
*/
|
||||
function toFixedOffsetLength(range, lineCounter) {
|
||||
const start = lineCounter.linePos(range[0]);
|
||||
const end = lineCounter.linePos(range[1]);
|
||||
const result = [range[0], range[1] - range[0]];
|
||||
// -1 as range may include '\n'
|
||||
if (start.line !== end.line && (lineCounter.lineStarts.length !== end.line || end.col === 1)) {
|
||||
result[1]--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function collectFlowMapRange(node) {
|
||||
let start = Number.MAX_SAFE_INTEGER;
|
||||
let end = 0;
|
||||
for (const it of node.items) {
|
||||
if (isPair(it)) {
|
||||
if (isNode(it.key)) {
|
||||
if (it.key.range && it.key.range[0] <= start) {
|
||||
start = it.key.range[0];
|
||||
}
|
||||
}
|
||||
if (isNode(it.value)) {
|
||||
if (it.value.range && it.value.range[2] >= end) {
|
||||
end = it.value.range[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return [start, end, end];
|
||||
}
|
||||
//# sourceMappingURL=ast-converter.js.map
|
||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { ASTNode } from '../jsonASTTypes';
|
||||
export declare function getNodeValue(node: ASTNode): any;
|
||||
export declare function contains(node: ASTNode, offset: number, includeRightBound?: boolean): boolean;
|
||||
export declare function findNodeAtOffset(node: ASTNode, offset: number, includeRightBound: boolean): ASTNode;
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function getNodeValue(node) {
|
||||
switch (node.type) {
|
||||
case 'array':
|
||||
return node.children.map(getNodeValue);
|
||||
case 'object': {
|
||||
const obj = Object.create(null);
|
||||
for (let _i = 0, _a = node.children; _i < _a.length; _i++) {
|
||||
const prop = _a[_i];
|
||||
const valueNode = prop.children[1];
|
||||
if (valueNode) {
|
||||
obj[prop.children[0].value] = getNodeValue(valueNode);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
case 'null':
|
||||
case 'string':
|
||||
case 'number':
|
||||
return node.value;
|
||||
case 'boolean':
|
||||
return node.source;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
export function contains(node, offset, includeRightBound = false) {
|
||||
return ((offset >= node.offset && offset <= node.offset + node.length) || (includeRightBound && offset === node.offset + node.length));
|
||||
}
|
||||
export function findNodeAtOffset(node, offset, includeRightBound) {
|
||||
if (includeRightBound === void 0) {
|
||||
includeRightBound = false;
|
||||
}
|
||||
if (contains(node, offset, includeRightBound)) {
|
||||
const children = node.children;
|
||||
if (Array.isArray(children)) {
|
||||
for (let i = 0; i < children.length && children[i].offset <= offset; i++) {
|
||||
const item = findNodeAtOffset(children[i], offset, includeRightBound);
|
||||
if (item) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
//# sourceMappingURL=astNodeUtils.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"astNodeUtils.js","sourceRoot":"","sources":["../../../../src/languageservice/parser/astNodeUtils.ts"],"names":[],"mappings":"AAEA,8DAA8D;AAC9D,MAAM,UAAU,YAAY,CAAC,IAAa;IACxC,QAAQ,IAAI,CAAC,IAAI,EAAE;QACjB,KAAK,OAAO;YACV,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACzC,KAAK,QAAQ,CAAC,CAAC;YACb,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChC,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE;gBACzD,MAAM,IAAI,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBACpB,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACnC,IAAI,SAAS,EAAE;oBACb,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAe,CAAC,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;iBACjE;aACF;YACD,OAAO,GAAG,CAAC;SACZ;QACD,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,QAAQ;YACX,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,IAAI,CAAC,MAAM,CAAC;QACrB;YACE,OAAO,SAAS,CAAC;KACpB;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAa,EAAE,MAAc,EAAE,iBAAiB,GAAG,KAAK;IAC/E,OAAO,CACL,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAC9H,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAa,EAAE,MAAc,EAAE,iBAA0B;IACxF,IAAI,iBAAiB,KAAK,KAAK,CAAC,EAAE;QAChC,iBAAiB,GAAG,KAAK,CAAC;KAC3B;IACD,IAAI,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,CAAC,EAAE;QAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC,EAAE,EAAE;gBACxE,MAAM,IAAI,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC;gBACtE,IAAI,IAAI,EAAE;oBACR,OAAO,IAAI,CAAC;iBACb;aACF;SACF;QACD,OAAO,IAAI,CAAC;KACb;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
||||
Generated
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
import { Tags } from 'yaml';
|
||||
/**
|
||||
* Converts the tags from settings and adds known tags such as !include
|
||||
* and returns Tags that can be used by the parser.
|
||||
* @param customTags Tags for parser
|
||||
*/
|
||||
export declare function getCustomTags(customTags: string[]): Tags;
|
||||
Generated
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
import { isSeq, isMap } from 'yaml';
|
||||
import { filterInvalidCustomTags } from '../utils/arrUtils';
|
||||
class CommonTagImpl {
|
||||
constructor(tag, type) {
|
||||
this.tag = tag;
|
||||
this.type = type;
|
||||
}
|
||||
get collection() {
|
||||
if (this.type === 'mapping') {
|
||||
return 'map';
|
||||
}
|
||||
if (this.type === 'sequence') {
|
||||
return 'seq';
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
resolve(value) {
|
||||
if (isMap(value) && this.type === 'mapping') {
|
||||
return value;
|
||||
}
|
||||
if (isSeq(value) && this.type === 'sequence') {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === 'string' && this.type === 'scalar') {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
class IncludeTag {
|
||||
constructor() {
|
||||
this.tag = '!include';
|
||||
this.type = 'scalar';
|
||||
}
|
||||
resolve(value, onError) {
|
||||
if (value && value.length > 0 && value.trim()) {
|
||||
return value;
|
||||
}
|
||||
onError('!include without value');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Converts the tags from settings and adds known tags such as !include
|
||||
* and returns Tags that can be used by the parser.
|
||||
* @param customTags Tags for parser
|
||||
*/
|
||||
export function getCustomTags(customTags) {
|
||||
const tags = [];
|
||||
const filteredTags = filterInvalidCustomTags(customTags);
|
||||
for (const tag of filteredTags) {
|
||||
const typeInfo = tag.split(' ');
|
||||
const tagName = typeInfo[0];
|
||||
const tagType = (typeInfo[1] && typeInfo[1].toLowerCase()) || 'scalar';
|
||||
tags.push(new CommonTagImpl(tagName, tagType));
|
||||
}
|
||||
tags.push(new IncludeTag());
|
||||
return tags;
|
||||
}
|
||||
//# sourceMappingURL=custom-tag-provider.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"custom-tag-provider.js","sourceRoot":"","sources":["../../../../src/languageservice/parser/custom-tag-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,EAAE,KAAK,EAAoB,MAAM,MAAM,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,MAAM,aAAa;IAIjB,YAAY,GAAW,EAAE,IAAY;QACnC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IACD,IAAI,UAAU;QACZ,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE;YAC3B,OAAO,KAAK,CAAC;SACd;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE;YAC5B,OAAO,KAAK,CAAC;SACd;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,CAAC,KAAiC;QACvC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE;YAC3C,OAAO,KAAK,CAAC;SACd;QACD,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE;YAC5C,OAAO,KAAK,CAAC;SACd;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE;YACvD,OAAO,KAAK,CAAC;SACd;IACH,CAAC;CACF;AAED,MAAM,UAAU;IAAhB;QACkB,QAAG,GAAG,UAAU,CAAC;QACjB,SAAI,GAAG,QAAQ,CAAC;IAUlC,CAAC;IANC,OAAO,CAAC,KAAa,EAAE,OAAkC;QACvD,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE;YAC7C,OAAO,KAAK,CAAC;SACd;QACD,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACpC,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,UAAoB;IAChD,MAAM,IAAI,GAAG,EAAE,CAAC;IAChB,MAAM,YAAY,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC;IACzD,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE;QAC9B,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,QAAQ,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;KAChD;IACD,IAAI,CAAC,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC;IAC5B,OAAO,IAAI,CAAC;AACd,CAAC"}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
import * as Parser from './jsonDocument';
|
||||
export declare function setKubernetesParserOption(jsonDocuments: Parser.JSONDocument[], option: boolean): void;
|
||||
export declare function isKubernetesAssociatedDocument(textDocument: TextDocument, paths: string[]): boolean;
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { FilePatternAssociation } from '../utils/filePatternAssociation';
|
||||
export function setKubernetesParserOption(jsonDocuments, option) {
|
||||
for (const jsonDoc of jsonDocuments) {
|
||||
jsonDoc.isKubernetes = option;
|
||||
}
|
||||
}
|
||||
export function isKubernetesAssociatedDocument(textDocument, paths) {
|
||||
for (const path in paths) {
|
||||
const globPath = paths[path];
|
||||
const fpa = new FilePatternAssociation(globPath);
|
||||
if (fpa.matchesPattern(textDocument.uri)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//# sourceMappingURL=isKubernetes.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"isKubernetes.js","sourceRoot":"","sources":["../../../../src/languageservice/parser/isKubernetes.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAGzE,MAAM,UAAU,yBAAyB,CAAC,aAAoC,EAAE,MAAe;IAC7F,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE;QACnC,OAAO,CAAC,YAAY,GAAG,MAAM,CAAC;KAC/B;AACH,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,YAA0B,EAAE,KAAe;IACxF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACxB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,GAAG,GAAG,IAAI,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAEjD,IAAI,GAAG,CAAC,cAAc,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE;YACxC,OAAO,IAAI,CAAC;SACb;KACF;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
||||
Generated
Vendored
+83
@@ -0,0 +1,83 @@
|
||||
import { JSONSchema } from '../jsonSchema';
|
||||
import { ASTNode, ObjectASTNode, ArrayASTNode, BooleanASTNode, NumberASTNode, StringASTNode, NullASTNode, PropertyASTNode, YamlNode } from '../jsonASTTypes';
|
||||
import { Diagnostic, Range } from 'vscode-languageserver-types';
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
import { Node, Pair } from 'yaml';
|
||||
import { type IApplicableSchema } from './schemaValidation/baseValidator';
|
||||
declare abstract class ASTNodeImpl {
|
||||
abstract readonly type: 'object' | 'property' | 'array' | 'number' | 'boolean' | 'null' | 'string';
|
||||
offset: number;
|
||||
length: number;
|
||||
readonly parent: ASTNode;
|
||||
location: string;
|
||||
readonly internalNode: YamlNode;
|
||||
constructor(parent: ASTNode, internalNode: YamlNode, offset: number, length?: number);
|
||||
getNodeFromOffsetEndInclusive(offset: number): ASTNode;
|
||||
get children(): ASTNode[];
|
||||
toString(): string;
|
||||
}
|
||||
export declare class NullASTNodeImpl extends ASTNodeImpl implements NullASTNode {
|
||||
type: 'null';
|
||||
value: any;
|
||||
constructor(parent: ASTNode, internalNode: Node, offset: number, length?: number);
|
||||
}
|
||||
export declare class BooleanASTNodeImpl extends ASTNodeImpl implements BooleanASTNode {
|
||||
type: 'boolean';
|
||||
value: boolean;
|
||||
source: string;
|
||||
constructor(parent: ASTNode, internalNode: Node, boolValue: boolean, boolSource: string, offset: number, length?: number);
|
||||
}
|
||||
export declare class ArrayASTNodeImpl extends ASTNodeImpl implements ArrayASTNode {
|
||||
type: 'array';
|
||||
items: ASTNode[];
|
||||
constructor(parent: ASTNode, internalNode: Node, offset: number, length?: number);
|
||||
get children(): ASTNode[];
|
||||
}
|
||||
export declare class NumberASTNodeImpl extends ASTNodeImpl implements NumberASTNode {
|
||||
type: 'number';
|
||||
isInteger: boolean;
|
||||
value: number;
|
||||
constructor(parent: ASTNode, internalNode: Node, offset: number, length?: number);
|
||||
}
|
||||
export declare class StringASTNodeImpl extends ASTNodeImpl implements StringASTNode {
|
||||
type: 'string';
|
||||
value: string;
|
||||
constructor(parent: ASTNode, internalNode: Node, offset: number, length?: number);
|
||||
}
|
||||
export declare class PropertyASTNodeImpl extends ASTNodeImpl implements PropertyASTNode {
|
||||
type: 'property';
|
||||
keyNode: StringASTNode;
|
||||
valueNode: ASTNode;
|
||||
colonOffset: number;
|
||||
constructor(parent: ObjectASTNode, internalNode: Pair, offset: number, length?: number);
|
||||
get children(): ASTNode[];
|
||||
}
|
||||
export declare class ObjectASTNodeImpl extends ASTNodeImpl implements ObjectASTNode {
|
||||
type: 'object';
|
||||
properties: PropertyASTNode[];
|
||||
constructor(parent: ASTNode, internalNode: Node, offset: number, length?: number);
|
||||
get children(): ASTNode[];
|
||||
}
|
||||
export interface JSONDocumentConfig {
|
||||
collectComments?: boolean;
|
||||
}
|
||||
export declare enum EnumMatch {
|
||||
Key = 0,
|
||||
Enum = 1
|
||||
}
|
||||
export declare function newJSONDocument(root: ASTNode, diagnostics?: Diagnostic[]): JSONDocument;
|
||||
export declare class JSONDocument {
|
||||
readonly root: ASTNode;
|
||||
readonly syntaxErrors: Diagnostic[];
|
||||
readonly comments: Range[];
|
||||
isKubernetes: boolean;
|
||||
disableAdditionalProperties: boolean;
|
||||
uri: string;
|
||||
constructor(root: ASTNode, syntaxErrors?: Diagnostic[], comments?: Range[]);
|
||||
getNodeFromOffset(offset: number, includeRightBound?: boolean): ASTNode | undefined;
|
||||
getNodeFromOffsetEndInclusive(offset: number): ASTNode;
|
||||
visit(visitor: (node: ASTNode) => boolean): void;
|
||||
validate(textDocument: TextDocument, schema: JSONSchema): Diagnostic[];
|
||||
getMatchingSchemas(schema: JSONSchema, focusOffset?: number, exclude?: ASTNode, didCallFromAutoComplete?: boolean): IApplicableSchema[];
|
||||
}
|
||||
export {};
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
import { findNodeAtOffset } from './astNodeUtils';
|
||||
import { getValidator } from './schemaValidation/validatorFactory';
|
||||
class ASTNodeImpl {
|
||||
constructor(parent, internalNode, offset, length) {
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
this.parent = parent;
|
||||
this.internalNode = internalNode;
|
||||
}
|
||||
getNodeFromOffsetEndInclusive(offset) {
|
||||
const collector = [];
|
||||
const findNode = (node) => {
|
||||
if (offset >= node.offset && offset <= node.offset + node.length) {
|
||||
const children = node.children;
|
||||
for (let i = 0; i < children.length && children[i].offset <= offset; i++) {
|
||||
const item = findNode(children[i]);
|
||||
if (item) {
|
||||
collector.push(item);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const foundNode = findNode(this);
|
||||
let currMinDist = Number.MAX_VALUE;
|
||||
let currMinNode = null;
|
||||
for (const currNode of collector) {
|
||||
const minDist = currNode.length + currNode.offset - offset + (offset - currNode.offset);
|
||||
if (minDist < currMinDist) {
|
||||
currMinNode = currNode;
|
||||
currMinDist = minDist;
|
||||
}
|
||||
}
|
||||
return currMinNode || foundNode;
|
||||
}
|
||||
get children() {
|
||||
return [];
|
||||
}
|
||||
toString() {
|
||||
return ('type: ' +
|
||||
this.type +
|
||||
' (' +
|
||||
this.offset +
|
||||
'/' +
|
||||
this.length +
|
||||
')' +
|
||||
(this.parent ? ' parent: {' + this.parent.toString() + '}' : ''));
|
||||
}
|
||||
}
|
||||
export class NullASTNodeImpl extends ASTNodeImpl {
|
||||
constructor(parent, internalNode, offset, length) {
|
||||
super(parent, internalNode, offset, length);
|
||||
this.type = 'null';
|
||||
this.value = null;
|
||||
}
|
||||
}
|
||||
export class BooleanASTNodeImpl extends ASTNodeImpl {
|
||||
constructor(parent, internalNode, boolValue, boolSource, offset, length) {
|
||||
super(parent, internalNode, offset, length);
|
||||
this.type = 'boolean';
|
||||
this.value = boolValue;
|
||||
this.source = boolSource;
|
||||
}
|
||||
}
|
||||
export class ArrayASTNodeImpl extends ASTNodeImpl {
|
||||
constructor(parent, internalNode, offset, length) {
|
||||
super(parent, internalNode, offset, length);
|
||||
this.type = 'array';
|
||||
this.items = [];
|
||||
}
|
||||
get children() {
|
||||
return this.items;
|
||||
}
|
||||
}
|
||||
export class NumberASTNodeImpl extends ASTNodeImpl {
|
||||
constructor(parent, internalNode, offset, length) {
|
||||
super(parent, internalNode, offset, length);
|
||||
this.type = 'number';
|
||||
this.isInteger = true;
|
||||
this.value = Number.NaN;
|
||||
}
|
||||
}
|
||||
export class StringASTNodeImpl extends ASTNodeImpl {
|
||||
constructor(parent, internalNode, offset, length) {
|
||||
super(parent, internalNode, offset, length);
|
||||
this.type = 'string';
|
||||
this.value = '';
|
||||
}
|
||||
}
|
||||
export class PropertyASTNodeImpl extends ASTNodeImpl {
|
||||
constructor(parent, internalNode, offset, length) {
|
||||
super(parent, internalNode, offset, length);
|
||||
this.type = 'property';
|
||||
this.colonOffset = -1;
|
||||
}
|
||||
get children() {
|
||||
return this.valueNode ? [this.keyNode, this.valueNode] : [this.keyNode];
|
||||
}
|
||||
}
|
||||
export class ObjectASTNodeImpl extends ASTNodeImpl {
|
||||
constructor(parent, internalNode, offset, length) {
|
||||
super(parent, internalNode, offset, length);
|
||||
this.type = 'object';
|
||||
this.properties = [];
|
||||
}
|
||||
get children() {
|
||||
return this.properties;
|
||||
}
|
||||
}
|
||||
export var EnumMatch;
|
||||
(function (EnumMatch) {
|
||||
EnumMatch[EnumMatch["Key"] = 0] = "Key";
|
||||
EnumMatch[EnumMatch["Enum"] = 1] = "Enum";
|
||||
})(EnumMatch || (EnumMatch = {}));
|
||||
export function newJSONDocument(root, diagnostics = []) {
|
||||
return new JSONDocument(root, diagnostics, []);
|
||||
}
|
||||
export class JSONDocument {
|
||||
constructor(root, syntaxErrors = [], comments = []) {
|
||||
this.root = root;
|
||||
this.syntaxErrors = syntaxErrors;
|
||||
this.comments = comments;
|
||||
}
|
||||
getNodeFromOffset(offset, includeRightBound = false) {
|
||||
if (this.root) {
|
||||
return findNodeAtOffset(this.root, offset, includeRightBound);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
getNodeFromOffsetEndInclusive(offset) {
|
||||
return this.root && this.root.getNodeFromOffsetEndInclusive(offset);
|
||||
}
|
||||
visit(visitor) {
|
||||
if (this.root) {
|
||||
const doVisit = (node) => {
|
||||
let ctn = visitor(node);
|
||||
const children = node.children;
|
||||
if (Array.isArray(children)) {
|
||||
for (let i = 0; i < children.length && ctn; i++) {
|
||||
ctn = doVisit(children[i]);
|
||||
}
|
||||
}
|
||||
return ctn;
|
||||
};
|
||||
doVisit(this.root);
|
||||
}
|
||||
}
|
||||
validate(textDocument, schema) {
|
||||
if (!this.root || !schema)
|
||||
return null;
|
||||
const validator = getValidator(schema._dialect);
|
||||
return validator.validateDocument(this.root, textDocument, schema, {
|
||||
isKubernetes: this.isKubernetes,
|
||||
disableAdditionalProperties: this.disableAdditionalProperties,
|
||||
uri: this.uri,
|
||||
});
|
||||
}
|
||||
getMatchingSchemas(schema, focusOffset = -1, exclude = null, didCallFromAutoComplete) {
|
||||
if (!this.root || !schema)
|
||||
return [];
|
||||
const validator = getValidator(schema._dialect);
|
||||
return validator.getMatchingSchemas(this.root, schema, {
|
||||
isKubernetes: this.isKubernetes,
|
||||
disableAdditionalProperties: this.disableAdditionalProperties,
|
||||
uri: this.uri,
|
||||
callFromAutoComplete: didCallFromAutoComplete,
|
||||
}, focusOffset, exclude);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=jsonDocument.js.map
|
||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Parse a boolean according to the specification
|
||||
*
|
||||
* Return:
|
||||
* true if its a true value
|
||||
* false if its a false value
|
||||
*/
|
||||
export declare function parseYamlBoolean(input: string): boolean;
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Parse a boolean according to the specification
|
||||
*
|
||||
* Return:
|
||||
* true if its a true value
|
||||
* false if its a false value
|
||||
*/
|
||||
export function parseYamlBoolean(input) {
|
||||
if (['true', 'True', 'TRUE', 'y', 'Y', 'yes', 'Yes', 'YES', 'on', 'On', 'ON'].lastIndexOf(input) >= 0) {
|
||||
return true;
|
||||
}
|
||||
else if (['false', 'False', 'FALSE', 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF'].lastIndexOf(input) >= 0) {
|
||||
return false;
|
||||
}
|
||||
throw `Invalid boolean "${input}"`;
|
||||
}
|
||||
//# sourceMappingURL=scalar-type.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scalar-type.js","sourceRoot":"","sources":["../../../../src/languageservice/parser/scalar-type.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;QACrG,OAAO,IAAI,CAAC;KACb;SAAM,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;QAC/G,OAAO,KAAK,CAAC;KACd;IACD,MAAM,oBAAoB,KAAK,GAAG,CAAC;AACrC,CAAC"}
|
||||
node_modules/yaml-language-server/lib/esm/languageservice/parser/schemaValidation/baseValidator.d.ts
Generated
Vendored
+124
@@ -0,0 +1,124 @@
|
||||
import type { JSONSchema, JSONSchemaRef, SchemaDialect } from '../../jsonSchema';
|
||||
import type { ASTNode, ArrayASTNode, NumberASTNode, ObjectASTNode, StringASTNode } from '../../jsonASTTypes';
|
||||
import { ErrorCode } from 'vscode-json-languageservice';
|
||||
import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver-types';
|
||||
import type { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
export declare const YAML_SOURCE = "YAML";
|
||||
export interface IRange {
|
||||
offset: number;
|
||||
length: number;
|
||||
}
|
||||
export declare enum ProblemType {
|
||||
missingRequiredPropWarning = "missingRequiredPropWarning",
|
||||
typeMismatchWarning = "typeMismatchWarning",
|
||||
constWarning = "constWarning"
|
||||
}
|
||||
export declare const ProblemTypeMessages: Record<ProblemType, string>;
|
||||
export interface IProblem {
|
||||
location: IRange;
|
||||
severity: DiagnosticSeverity;
|
||||
code?: ErrorCode;
|
||||
message: string;
|
||||
source?: string;
|
||||
problemType?: ProblemType;
|
||||
problemArgs?: string[];
|
||||
schemaUri?: string[];
|
||||
data?: Record<string, unknown>;
|
||||
}
|
||||
export interface IApplicableSchema {
|
||||
node: ASTNode;
|
||||
inverted?: boolean;
|
||||
schema: JSONSchema;
|
||||
}
|
||||
export interface ISchemaCollector {
|
||||
schemas: IApplicableSchema[];
|
||||
add(schema: IApplicableSchema): void;
|
||||
merge(other: ISchemaCollector): void;
|
||||
include(node: ASTNode): boolean;
|
||||
newSub(): ISchemaCollector;
|
||||
}
|
||||
export declare const formats: Record<string, {
|
||||
errorMessage: string;
|
||||
pattern: RegExp;
|
||||
}>;
|
||||
export declare class ValidationResult {
|
||||
problems: IProblem[];
|
||||
propertiesMatches: number;
|
||||
propertiesValueMatches: number;
|
||||
primaryValueMatches: number;
|
||||
enumValueMatch: boolean;
|
||||
enumValues: any[];
|
||||
/**
|
||||
* Optional bookkeeping for newer drafts (2019/2020).
|
||||
* BaseValidator only populates evaluatedProperties conservatively for object keywords it processes directly.
|
||||
*/
|
||||
evaluatedProperties?: Set<string>;
|
||||
evaluatedItemsByNode?: Map<ASTNode, Set<number>>;
|
||||
constructor(isKubernetes: boolean);
|
||||
getEvaluatedItems(node: ASTNode): Set<number>;
|
||||
hasProblems(): boolean;
|
||||
merge(other: ValidationResult): void;
|
||||
mergeEnumValues(other: ValidationResult): void;
|
||||
mergeWarningGeneric(sub: ValidationResult, problemTypesToMerge: ProblemType[]): void;
|
||||
mergePropertyMatch(propertyValidationResult: ValidationResult, mergeEvaluated?: boolean): void;
|
||||
private mergeSources;
|
||||
compareGeneric(other: ValidationResult): number;
|
||||
compareKubernetes(other: ValidationResult): number;
|
||||
}
|
||||
export interface Options {
|
||||
isKubernetes: boolean;
|
||||
disableAdditionalProperties: boolean;
|
||||
uri: string;
|
||||
callFromAutoComplete?: boolean;
|
||||
}
|
||||
interface IValidationMatch {
|
||||
schema: JSONSchema;
|
||||
validationResult: ValidationResult;
|
||||
matchingSchemas: ISchemaCollector;
|
||||
}
|
||||
export declare abstract class BaseValidator {
|
||||
protected collectSeenKeys(node: ObjectASTNode): Record<string, ASTNode>;
|
||||
validateDocument(root: ASTNode, textDocument: TextDocument, schema: JSONSchema, options: Options): Diagnostic[];
|
||||
getMatchingSchemas(root: ASTNode, schema: JSONSchema, options: Options, focusOffset: number, exclude: ASTNode | null): IApplicableSchema[];
|
||||
protected getNoOpCollector(): ISchemaCollector;
|
||||
protected getSchemaSource(schema: JSONSchema, originalSchema: JSONSchema): string;
|
||||
protected getSchemaUri(schema: JSONSchema, originalSchema: JSONSchema): string[];
|
||||
/**
|
||||
* Draft-specific hook: interpret numeric bounds in the draft’s way.
|
||||
* - Draft07+: numeric exclusiveMinimum/exclusiveMaximum
|
||||
* - Draft04: boolean exclusiveMinimum/exclusiveMaximum that modify minimum/maximum
|
||||
*/
|
||||
protected abstract getNumberLimits(schema: JSONSchema): {
|
||||
minimum?: number;
|
||||
maximum?: number;
|
||||
exclusiveMinimum?: number;
|
||||
exclusiveMaximum?: number;
|
||||
};
|
||||
/**
|
||||
* Get the current validator's dialect.
|
||||
*/
|
||||
protected abstract getCurrentDialect(): SchemaDialect;
|
||||
protected validateNode(node: ASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options): void;
|
||||
protected validateGenericNode(node: ASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options): void;
|
||||
protected validateStringNode(node: StringASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult): void;
|
||||
protected validateNumberNode(node: NumberASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult): void;
|
||||
protected validateArrayNode(node: ArrayASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options): void;
|
||||
protected applyContains(node: ArrayASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, _matchingSchemas: ISchemaCollector, options: Options): void;
|
||||
protected applyArrayLength(node: ArrayASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, _options: Options): void;
|
||||
protected applyUniqueItems(node: ArrayASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult): void;
|
||||
protected validateObjectNode(node: ObjectASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options): void;
|
||||
protected applyRequired(node: ObjectASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, _options: Options, seenKeys: Record<string, ASTNode>): void;
|
||||
protected applyProperties(_node: ObjectASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options, seenKeys: Record<string, ASTNode>, _unprocessedProperties: string[], propertyProcessed: (prop: string) => void): void;
|
||||
protected applyPatternProperties(_node: ObjectASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options, seenKeys: Record<string, ASTNode>, unprocessedProperties: string[], propertyProcessed: (prop: string) => void): void;
|
||||
protected applyAdditionalProperties(_node: ObjectASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options, seenKeys: Record<string, ASTNode>, unprocessedProperties: string[]): void;
|
||||
protected applyPropertyCount(node: ObjectASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult): void;
|
||||
protected applyDependencies(node: ObjectASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options, seenKeys: Record<string, ASTNode>): void;
|
||||
protected applyPropertyNames(node: ObjectASTNode, schema: JSONSchema, validationResult: ValidationResult, options: Options): void;
|
||||
protected applyUnevaluatedProperties(_node: ObjectASTNode, _schema: JSONSchema, _originalSchema: JSONSchema, _validationResult: ValidationResult, _matchingSchemas: ISchemaCollector, _options: Options, _seenKeys?: Record<string, ASTNode>, _unprocessedProperties?: string[]): void;
|
||||
protected applyUnevaluatedItems(_node: ArrayASTNode | ASTNode, _schema: JSONSchema, _originalSchema: JSONSchema, _validationResult: ValidationResult, _matchingSchemas: ISchemaCollector, _options: Options): void;
|
||||
protected alternativeComparison(subValidationResult: ValidationResult, bestMatch: IValidationMatch, subSchema: JSONSchema, subMatchingSchemas: ISchemaCollector): IValidationMatch;
|
||||
protected genericComparison(node: ASTNode, maxOneMatch: boolean, subValidationResult: ValidationResult, bestMatch: IValidationMatch, subSchema: JSONSchema, subMatchingSchemas: ISchemaCollector): IValidationMatch;
|
||||
protected mergeValidationMatches(bestMatch: IValidationMatch, subMatchingSchemas: ISchemaCollector, subValidationResult: ValidationResult): void;
|
||||
}
|
||||
export declare function asSchema(schema: JSONSchemaRef): JSONSchema | undefined;
|
||||
export {};
|
||||
Generated
Vendored
+1254
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
import type { JSONSchema } from '../../jsonSchema';
|
||||
import { SchemaDialect } from '../../jsonSchema';
|
||||
import { BaseValidator } from './baseValidator';
|
||||
export declare class Draft04Validator extends BaseValidator {
|
||||
protected getCurrentDialect(): SchemaDialect;
|
||||
/**
|
||||
* Keyword: exclusiveMinimum/exclusiveMaximum
|
||||
*
|
||||
* Booleans that make minimum/maximum exclusive.
|
||||
*/
|
||||
protected getNumberLimits(schema: JSONSchema): {
|
||||
minimum?: number;
|
||||
maximum?: number;
|
||||
exclusiveMinimum?: number;
|
||||
exclusiveMaximum?: number;
|
||||
};
|
||||
}
|
||||
Generated
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) IBM Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { SchemaDialect } from '../../jsonSchema';
|
||||
import { isBoolean, isNumber } from '../../utils/objects';
|
||||
import { BaseValidator } from './baseValidator';
|
||||
export class Draft04Validator extends BaseValidator {
|
||||
getCurrentDialect() {
|
||||
return SchemaDialect.draft04;
|
||||
}
|
||||
/**
|
||||
* Keyword: exclusiveMinimum/exclusiveMaximum
|
||||
*
|
||||
* Booleans that make minimum/maximum exclusive.
|
||||
*/
|
||||
getNumberLimits(schema) {
|
||||
const minimum = isNumber(schema.minimum) ? schema.minimum : undefined;
|
||||
const maximum = isNumber(schema.maximum) ? schema.maximum : undefined;
|
||||
const exclusiveMinimum = isBoolean(schema.exclusiveMinimum) && schema.exclusiveMinimum ? minimum : undefined;
|
||||
const exclusiveMaximum = isBoolean(schema.exclusiveMaximum) && schema.exclusiveMaximum ? maximum : undefined;
|
||||
return {
|
||||
minimum: exclusiveMinimum === undefined ? minimum : undefined,
|
||||
maximum: exclusiveMaximum === undefined ? maximum : undefined,
|
||||
exclusiveMinimum,
|
||||
exclusiveMaximum,
|
||||
};
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=draft04Validator.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"draft04Validator.js","sourceRoot":"","sources":["../../../../../src/languageservice/parser/schemaValidation/draft04Validator.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAGhG,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,OAAO,gBAAiB,SAAQ,aAAa;IAC9B,iBAAiB;QAClC,OAAO,aAAa,CAAC,OAAO,CAAC;IAC/B,CAAC;IAED;;;;OAIG;IACgB,eAAe,CAAC,MAAkB;QAMnD,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QACtE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAEtE,MAAM,gBAAgB,GAAG,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAC7G,MAAM,gBAAgB,GAAG,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAE7G,OAAO;YACL,OAAO,EAAE,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;YAC7D,OAAO,EAAE,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;YAC7D,gBAAgB;YAChB,gBAAgB;SACjB,CAAC;IACJ,CAAC;CACF"}
|
||||
Generated
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
import type { JSONSchema } from '../../jsonSchema';
|
||||
import { SchemaDialect } from '../../jsonSchema';
|
||||
import { BaseValidator } from './baseValidator';
|
||||
export declare class Draft07Validator extends BaseValidator {
|
||||
protected getCurrentDialect(): SchemaDialect;
|
||||
/**
|
||||
* Keyword: exclusiveMinimum/exclusiveMaximum are treated as numeric bounds
|
||||
*/
|
||||
protected getNumberLimits(schema: JSONSchema): {
|
||||
minimum?: number;
|
||||
maximum?: number;
|
||||
exclusiveMinimum?: number;
|
||||
exclusiveMaximum?: number;
|
||||
};
|
||||
}
|
||||
Generated
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) IBM Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { SchemaDialect } from '../../jsonSchema';
|
||||
import { isNumber } from '../../utils/objects';
|
||||
import { BaseValidator } from './baseValidator';
|
||||
export class Draft07Validator extends BaseValidator {
|
||||
getCurrentDialect() {
|
||||
return SchemaDialect.draft07;
|
||||
}
|
||||
/**
|
||||
* Keyword: exclusiveMinimum/exclusiveMaximum are treated as numeric bounds
|
||||
*/
|
||||
getNumberLimits(schema) {
|
||||
const minimum = isNumber(schema.minimum) ? schema.minimum : undefined;
|
||||
const maximum = isNumber(schema.maximum) ? schema.maximum : undefined;
|
||||
const exclusiveMinimum = isNumber(schema.exclusiveMinimum) ? schema.exclusiveMinimum : undefined;
|
||||
const exclusiveMaximum = isNumber(schema.exclusiveMaximum) ? schema.exclusiveMaximum : undefined;
|
||||
return {
|
||||
minimum: exclusiveMinimum === undefined ? minimum : undefined,
|
||||
maximum: exclusiveMaximum === undefined ? maximum : undefined,
|
||||
exclusiveMinimum,
|
||||
exclusiveMaximum,
|
||||
};
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=draft07Validator.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"draft07Validator.js","sourceRoot":"","sources":["../../../../../src/languageservice/parser/schemaValidation/draft07Validator.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAGhG,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,OAAO,gBAAiB,SAAQ,aAAa;IAC9B,iBAAiB;QAClC,OAAO,aAAa,CAAC,OAAO,CAAC;IAC/B,CAAC;IAED;;OAEG;IACO,eAAe,CAAC,MAAkB;QAM1C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QACtE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAEtE,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC;QACjG,MAAM,gBAAgB,GAAG,QAAQ,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC;QAEjG,OAAO;YACL,OAAO,EAAE,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;YAC7D,OAAO,EAAE,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;YAC7D,gBAAgB;YAChB,gBAAgB;SACjB,CAAC;IACJ,CAAC;CACF"}
|
||||
Generated
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
import type { JSONSchema } from '../../jsonSchema';
|
||||
import { SchemaDialect } from '../../jsonSchema';
|
||||
import type { ASTNode, ArrayASTNode, ObjectASTNode } from '../../jsonASTTypes';
|
||||
import { Draft07Validator } from './draft07Validator';
|
||||
import { ValidationResult } from './baseValidator';
|
||||
import type { ISchemaCollector, Options } from './baseValidator';
|
||||
export declare class Draft2019Validator extends Draft07Validator {
|
||||
protected getCurrentDialect(): SchemaDialect;
|
||||
/**
|
||||
* Keyword: contains + minContains/maxContains
|
||||
*
|
||||
* Draft-07 behavior: contains must match at least 1 item.
|
||||
* Draft-2019-09 behavior: minContains/maxContains constrain how many matches are required/allowed.
|
||||
*/
|
||||
protected applyContains(node: ArrayASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, _matchingSchemas: ISchemaCollector, options: Options): void;
|
||||
/**
|
||||
* Keyword: dependentRequired + dependentSchemas.
|
||||
*/
|
||||
protected applyDependencies(node: ObjectASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options, seenKeys: Record<string, ASTNode>): void;
|
||||
/**
|
||||
* Keyword: unevaluatedProperties
|
||||
*/
|
||||
protected applyUnevaluatedProperties(node: ObjectASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options, seenKeys?: Record<string, ASTNode>): void;
|
||||
/**
|
||||
* Keyword: unevaluatedItems
|
||||
*/
|
||||
protected applyUnevaluatedItems(node: ArrayASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options): void;
|
||||
}
|
||||
Generated
Vendored
+224
@@ -0,0 +1,224 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) IBM Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { SchemaDialect } from '../../jsonSchema';
|
||||
import { isNumber } from '../../utils/objects';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { DiagnosticSeverity } from 'vscode-languageserver-types';
|
||||
import { ErrorCode } from 'vscode-json-languageservice';
|
||||
import { Draft07Validator } from './draft07Validator';
|
||||
import { ValidationResult, asSchema } from './baseValidator';
|
||||
export class Draft2019Validator extends Draft07Validator {
|
||||
getCurrentDialect() {
|
||||
return SchemaDialect.draft2019;
|
||||
}
|
||||
/**
|
||||
* Keyword: contains + minContains/maxContains
|
||||
*
|
||||
* Draft-07 behavior: contains must match at least 1 item.
|
||||
* Draft-2019-09 behavior: minContains/maxContains constrain how many matches are required/allowed.
|
||||
*/
|
||||
applyContains(node, schema, originalSchema, validationResult, _matchingSchemas, options) {
|
||||
const containsSchema = asSchema(schema.contains);
|
||||
if (!containsSchema)
|
||||
return;
|
||||
const minContainsRaw = schema.minContains;
|
||||
const maxContainsRaw = schema.maxContains;
|
||||
const minContains = isNumber(minContainsRaw) ? minContainsRaw : 1;
|
||||
const maxContains = isNumber(maxContainsRaw) ? maxContainsRaw : undefined;
|
||||
let matchCount = 0;
|
||||
const items = (node.items ?? []);
|
||||
for (const item of items) {
|
||||
const itemValidationResult = new ValidationResult(options.isKubernetes);
|
||||
this.validateNode(item, containsSchema, schema, itemValidationResult, this.getNoOpCollector(), options);
|
||||
if (!itemValidationResult.hasProblems()) {
|
||||
matchCount++;
|
||||
if (maxContains !== undefined && matchCount > maxContains) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matchCount < minContains) {
|
||||
validationResult.problems.push({
|
||||
location: { offset: node.offset, length: node.length },
|
||||
severity: DiagnosticSeverity.Warning,
|
||||
message: schema.errorMessage || l10n.t('Array has too few items matching "contains". Expected {0} or more.', minContains),
|
||||
source: this.getSchemaSource(schema, originalSchema),
|
||||
schemaUri: this.getSchemaUri(schema, originalSchema),
|
||||
});
|
||||
}
|
||||
if (maxContains !== undefined && matchCount > maxContains) {
|
||||
validationResult.problems.push({
|
||||
location: { offset: node.offset, length: node.length },
|
||||
severity: DiagnosticSeverity.Warning,
|
||||
message: schema.errorMessage || l10n.t('Array has too many items matching "contains". Expected {0} or fewer.', maxContains),
|
||||
source: this.getSchemaSource(schema, originalSchema),
|
||||
schemaUri: this.getSchemaUri(schema, originalSchema),
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Keyword: dependentRequired + dependentSchemas.
|
||||
*/
|
||||
applyDependencies(node, schema, originalSchema, validationResult, matchingSchemas, options, seenKeys) {
|
||||
// keep draft-07 dependencies support
|
||||
super.applyDependencies(node, schema, originalSchema, validationResult, matchingSchemas, options, seenKeys);
|
||||
const dependentRequired = schema.dependentRequired;
|
||||
if (dependentRequired && typeof dependentRequired === 'object') {
|
||||
for (const prop of Object.keys(dependentRequired)) {
|
||||
if (!seenKeys[prop])
|
||||
continue;
|
||||
const requiredProps = dependentRequired[prop];
|
||||
if (!Array.isArray(requiredProps))
|
||||
continue;
|
||||
for (const requiredProp of requiredProps) {
|
||||
if (!seenKeys[requiredProp]) {
|
||||
validationResult.problems.push({
|
||||
location: { offset: node.offset, length: node.length },
|
||||
severity: DiagnosticSeverity.Warning,
|
||||
message: l10n.t('Object is missing property {0} required by property {1}.', requiredProp, prop),
|
||||
source: this.getSchemaSource(schema, originalSchema),
|
||||
schemaUri: this.getSchemaUri(schema, originalSchema),
|
||||
});
|
||||
}
|
||||
else {
|
||||
validationResult.propertiesValueMatches++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const dependentSchemas = schema.dependentSchemas;
|
||||
if (dependentSchemas && typeof dependentSchemas === 'object') {
|
||||
for (const prop of Object.keys(dependentSchemas)) {
|
||||
if (!seenKeys[prop])
|
||||
continue;
|
||||
const depSchema = asSchema(dependentSchemas[prop]);
|
||||
if (!depSchema)
|
||||
continue;
|
||||
const depValidationResult = new ValidationResult(options.isKubernetes);
|
||||
this.validateNode(node, depSchema, schema, depValidationResult, matchingSchemas, options);
|
||||
validationResult.mergePropertyMatch(depValidationResult);
|
||||
validationResult.mergeEnumValues(depValidationResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Keyword: unevaluatedProperties
|
||||
*/
|
||||
applyUnevaluatedProperties(node, schema, originalSchema, validationResult, matchingSchemas, options, seenKeys) {
|
||||
const unevaluated = schema.unevaluatedProperties;
|
||||
if (unevaluated === undefined)
|
||||
return;
|
||||
if (!seenKeys)
|
||||
return;
|
||||
// ensure evaluatedProperties exists
|
||||
validationResult.evaluatedProperties ?? (validationResult.evaluatedProperties = new Set());
|
||||
// remaining = properties not evaluated by properties/patternProperties/additionalProperties
|
||||
const remaining = Object.keys(seenKeys).filter((name) => !validationResult.evaluatedProperties?.has(name));
|
||||
if (remaining.length === 0)
|
||||
return;
|
||||
// unevaluatedProperties: false => forbid remaining properties
|
||||
if (unevaluated === false) {
|
||||
for (const propName of remaining) {
|
||||
const child = seenKeys[propName];
|
||||
if (!child)
|
||||
continue;
|
||||
const propertyNode = child.type === 'property' ? child : child.parent;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const keyNode = propertyNode.keyNode;
|
||||
if (!keyNode)
|
||||
continue;
|
||||
validationResult.problems.push({
|
||||
location: { offset: keyNode.offset, length: keyNode.length },
|
||||
severity: DiagnosticSeverity.Warning,
|
||||
code: ErrorCode.PropertyExpected,
|
||||
message: schema.errorMessage || l10n.t('Property {0} is not allowed.', propName),
|
||||
source: this.getSchemaSource(schema, originalSchema),
|
||||
schemaUri: this.getSchemaUri(schema, originalSchema),
|
||||
});
|
||||
validationResult.evaluatedProperties?.add(propName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// unevaluatedProperties: true => allow anything remaining, but mark evaluated
|
||||
if (unevaluated === true) {
|
||||
for (const propName of remaining) {
|
||||
validationResult.evaluatedProperties?.add(propName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// unevaluatedProperties: <schema> => validate value of each remaining property
|
||||
const unevaluatedSchema = asSchema(unevaluated);
|
||||
if (!unevaluatedSchema)
|
||||
return;
|
||||
for (const propName of remaining) {
|
||||
const child = seenKeys[propName];
|
||||
if (!child)
|
||||
continue;
|
||||
const valueNode = child.type === 'property' ? child.valueNode : child;
|
||||
if (!valueNode)
|
||||
continue;
|
||||
const subResult = new ValidationResult(options.isKubernetes);
|
||||
this.validateNode(valueNode, unevaluatedSchema, schema, subResult, matchingSchemas, options);
|
||||
validationResult.mergePropertyMatch(subResult);
|
||||
validationResult.mergeEnumValues(subResult);
|
||||
validationResult.evaluatedProperties?.add(propName);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Keyword: unevaluatedItems
|
||||
*/
|
||||
applyUnevaluatedItems(node, schema, originalSchema, validationResult, matchingSchemas, options) {
|
||||
const unevaluated = schema.unevaluatedItems;
|
||||
if (unevaluated === undefined)
|
||||
return;
|
||||
const items = (node.items ?? []);
|
||||
if (items.length === 0)
|
||||
return;
|
||||
const evaluated = validationResult.getEvaluatedItems(node);
|
||||
const remaining = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (!evaluated.has(i))
|
||||
remaining.push(i);
|
||||
}
|
||||
if (remaining.length === 0)
|
||||
return;
|
||||
// unevaluatedItems: false => forbid remaining indices
|
||||
if (unevaluated === false) {
|
||||
for (const idx of remaining) {
|
||||
const item = items[idx];
|
||||
validationResult.problems.push({
|
||||
location: { offset: item.offset, length: item.length || 1 },
|
||||
severity: DiagnosticSeverity.Warning,
|
||||
code: ErrorCode.PropertyExpected,
|
||||
message: schema.errorMessage || l10n.t('Array has too many items according to schema. Expected {0} or fewer.', idx),
|
||||
source: this.getSchemaSource(schema, originalSchema),
|
||||
schemaUri: this.getSchemaUri(schema, originalSchema),
|
||||
});
|
||||
evaluated.add(idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// unevaluatedItems: true => allow everything remaining, but mark evaluated
|
||||
if (unevaluated === true) {
|
||||
for (const idx of remaining)
|
||||
evaluated.add(idx);
|
||||
return;
|
||||
}
|
||||
// unevaluatedItems: <schema> => validate remaining items against that schema
|
||||
const unevaluatedSchema = asSchema(unevaluated);
|
||||
if (!unevaluatedSchema)
|
||||
return;
|
||||
for (const idx of remaining) {
|
||||
const item = items[idx];
|
||||
const subResult = new ValidationResult(options.isKubernetes);
|
||||
// validate the item node with the unevaluatedItems subschema
|
||||
this.validateNode(item, unevaluatedSchema, schema, subResult, matchingSchemas, options);
|
||||
validationResult.merge(subResult);
|
||||
validationResult.mergeEnumValues(subResult);
|
||||
evaluated.add(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=draft2019Validator.js.map
|
||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
import type { JSONSchema } from '../../jsonSchema';
|
||||
import { SchemaDialect } from '../../jsonSchema';
|
||||
import type { ArrayASTNode } from '../../jsonASTTypes';
|
||||
import { Draft2019Validator } from './draft2019Validator';
|
||||
import type { ISchemaCollector, Options } from './baseValidator';
|
||||
import { ValidationResult } from './baseValidator';
|
||||
export declare class Draft2020Validator extends Draft2019Validator {
|
||||
protected getCurrentDialect(): SchemaDialect;
|
||||
/**
|
||||
* Keyword: prefixItems + items
|
||||
*/
|
||||
protected validateArrayNode(node: ArrayASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, matchingSchemas: ISchemaCollector, options: Options): void;
|
||||
/**
|
||||
* Draft 2020-12: contains keyword affects the unevaluatedItems keyword
|
||||
*/
|
||||
protected applyContains(node: ArrayASTNode, schema: JSONSchema, originalSchema: JSONSchema, validationResult: ValidationResult, _matchingSchemas: ISchemaCollector, options: Options): void;
|
||||
}
|
||||
Generated
Vendored
+126
@@ -0,0 +1,126 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) IBM Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { SchemaDialect } from '../../jsonSchema';
|
||||
import { isNumber } from '../../utils/objects';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
import { DiagnosticSeverity } from 'vscode-languageserver-types';
|
||||
import { Draft2019Validator } from './draft2019Validator';
|
||||
import { ValidationResult, asSchema } from './baseValidator';
|
||||
export class Draft2020Validator extends Draft2019Validator {
|
||||
getCurrentDialect() {
|
||||
return SchemaDialect.draft2020;
|
||||
}
|
||||
/**
|
||||
* Keyword: prefixItems + items
|
||||
*/
|
||||
validateArrayNode(node, schema, originalSchema, validationResult, matchingSchemas, options) {
|
||||
const items = (node.items ?? []);
|
||||
// prefixItems/items/contains contribute to evaluatedItems
|
||||
const evaluatedItems = validationResult.getEvaluatedItems(node);
|
||||
const prefixItems = schema.prefixItems;
|
||||
// validate prefixItems
|
||||
if (Array.isArray(prefixItems)) {
|
||||
const limit = Math.min(prefixItems.length, items.length);
|
||||
for (let i = 0; i < limit; i++) {
|
||||
const subSchema = asSchema(prefixItems[i]);
|
||||
if (!subSchema) {
|
||||
evaluatedItems.add(i);
|
||||
continue;
|
||||
}
|
||||
const itemValidationResult = new ValidationResult(options.isKubernetes);
|
||||
this.validateNode(items[i], subSchema, schema, itemValidationResult, matchingSchemas, options);
|
||||
validationResult.mergePropertyMatch(itemValidationResult, false);
|
||||
validationResult.mergeEnumValues(itemValidationResult);
|
||||
// mark as evaluated even if invalid (avoids duplicate unevaluatedItems noise)
|
||||
evaluatedItems.add(i);
|
||||
}
|
||||
}
|
||||
// validate remaining items against items
|
||||
const itemsKeyword = schema.items;
|
||||
const prefixLen = Array.isArray(prefixItems) ? prefixItems.length : 0;
|
||||
if (items.length > prefixLen) {
|
||||
if (itemsKeyword === false) {
|
||||
// "items": false => no items allowed beyond prefixItems
|
||||
validationResult.problems.push({
|
||||
location: { offset: node.offset, length: node.length },
|
||||
severity: DiagnosticSeverity.Warning,
|
||||
message: l10n.t('Array has too many items according to schema. Expected {0} or fewer.', prefixLen),
|
||||
source: this.getSchemaSource(schema, originalSchema),
|
||||
schemaUri: this.getSchemaUri(schema, originalSchema),
|
||||
});
|
||||
// mark these as evaluated by "items": false (so unevaluatedItems doesn't also complain)
|
||||
for (let i = prefixLen; i < items.length; i++) {
|
||||
evaluatedItems.add(i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const tailSchema = asSchema(itemsKeyword);
|
||||
// if items is undefined, there's no constraint for remaining items and they remain unevaluated
|
||||
if (tailSchema) {
|
||||
for (let i = prefixLen; i < items.length; i++) {
|
||||
const itemValidationResult = new ValidationResult(options.isKubernetes);
|
||||
this.validateNode(items[i], tailSchema, schema, itemValidationResult, matchingSchemas, options);
|
||||
validationResult.mergePropertyMatch(itemValidationResult, false);
|
||||
validationResult.mergeEnumValues(itemValidationResult);
|
||||
// mark as evaluated even if invalid (avoids duplicate unevaluatedItems noise)
|
||||
evaluatedItems.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// contains enforces min/max and marks matching indices as evaluated
|
||||
this.applyContains(node, schema, originalSchema, validationResult, matchingSchemas, options);
|
||||
// generic array keywords
|
||||
this.applyArrayLength(node, schema, originalSchema, validationResult, options);
|
||||
this.applyUniqueItems(node, schema, originalSchema, validationResult);
|
||||
}
|
||||
/**
|
||||
* Draft 2020-12: contains keyword affects the unevaluatedItems keyword
|
||||
*/
|
||||
applyContains(node, schema, originalSchema, validationResult, _matchingSchemas, options) {
|
||||
const containsSchema = asSchema(schema.contains);
|
||||
if (!containsSchema)
|
||||
return;
|
||||
const items = (node.items ?? []);
|
||||
const minContainsRaw = schema.minContains;
|
||||
const maxContainsRaw = schema.maxContains;
|
||||
const minContains = isNumber(minContainsRaw) ? minContainsRaw : 1;
|
||||
const maxContains = isNumber(maxContainsRaw) ? maxContainsRaw : undefined;
|
||||
let matchCount = 0;
|
||||
// ensure evaluatedItems exists
|
||||
const evaluatedItems = validationResult.getEvaluatedItems(node);
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const itemValidationResult = new ValidationResult(options.isKubernetes);
|
||||
this.validateNode(items[i], containsSchema, schema, itemValidationResult, this.getNoOpCollector(), options);
|
||||
if (!itemValidationResult.hasProblems()) {
|
||||
// items that match contains are considered evaluated
|
||||
evaluatedItems.add(i);
|
||||
matchCount++;
|
||||
if (maxContains !== undefined && matchCount > maxContains) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matchCount < minContains) {
|
||||
validationResult.problems.push({
|
||||
location: { offset: node.offset, length: node.length },
|
||||
severity: DiagnosticSeverity.Warning,
|
||||
message: schema.errorMessage || l10n.t('Array has too few items matching "contains". Expected {0} or more.', minContains),
|
||||
source: this.getSchemaSource(schema, originalSchema),
|
||||
schemaUri: this.getSchemaUri(schema, originalSchema),
|
||||
});
|
||||
}
|
||||
if (maxContains !== undefined && matchCount > maxContains) {
|
||||
validationResult.problems.push({
|
||||
location: { offset: node.offset, length: node.length },
|
||||
severity: DiagnosticSeverity.Warning,
|
||||
message: schema.errorMessage || l10n.t('Array has too many items matching "contains". Expected {0} or fewer.', maxContains),
|
||||
source: this.getSchemaSource(schema, originalSchema),
|
||||
schemaUri: this.getSchemaUri(schema, originalSchema),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=draft2020Validator.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"draft2020Validator.js","sourceRoot":"","sources":["../../../../../src/languageservice/parser/schemaValidation/draft2020Validator.ts"],"names":[],"mappings":"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"}
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
import { SchemaDialect } from '../../jsonSchema';
|
||||
import { BaseValidator } from './baseValidator';
|
||||
export declare function getValidator(dialect: SchemaDialect): BaseValidator;
|
||||
Generated
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) IBM Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { SchemaDialect } from '../../jsonSchema';
|
||||
import { Draft04Validator } from './draft04Validator';
|
||||
import { Draft07Validator } from './draft07Validator';
|
||||
import { Draft2019Validator } from './draft2019Validator';
|
||||
import { Draft2020Validator } from './draft2020Validator';
|
||||
export function getValidator(dialect) {
|
||||
switch (dialect) {
|
||||
case SchemaDialect.draft04:
|
||||
return new Draft04Validator();
|
||||
case SchemaDialect.draft07:
|
||||
return new Draft07Validator();
|
||||
case SchemaDialect.draft2019:
|
||||
return new Draft2019Validator();
|
||||
case SchemaDialect.draft2020:
|
||||
return new Draft2020Validator();
|
||||
default:
|
||||
return new Draft07Validator(); // fallback
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=validatorFactory.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"validatorFactory.js","sourceRoot":"","sources":["../../../../../src/languageservice/parser/schemaValidation/validatorFactory.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,UAAU,YAAY,CAAC,OAAsB;IACjD,QAAQ,OAAO,EAAE;QACf,KAAK,aAAa,CAAC,OAAO;YACxB,OAAO,IAAI,gBAAgB,EAAE,CAAC;QAChC,KAAK,aAAa,CAAC,OAAO;YACxB,OAAO,IAAI,gBAAgB,EAAE,CAAC;QAChC,KAAK,aAAa,CAAC,SAAS;YAC1B,OAAO,IAAI,kBAAkB,EAAE,CAAC;QAClC,KAAK,aAAa,CAAC,SAAS;YAC1B,OAAO,IAAI,kBAAkB,EAAE,CAAC;QAClC;YACE,OAAO,IAAI,gBAAgB,EAAE,CAAC,CAAC,WAAW;KAC7C;AACH,CAAC"}
|
||||
Generated
Vendored
+71
@@ -0,0 +1,71 @@
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
import { JSONDocument } from './jsonDocument';
|
||||
import { Document, LineCounter } from 'yaml';
|
||||
import { ASTNode, YamlNode } from '../jsonASTTypes';
|
||||
import { ParserOptions } from './yamlParser07';
|
||||
import { YAMLDocDiagnostic } from '../utils/parseUtils';
|
||||
import { TextBuffer } from '../utils/textBuffer';
|
||||
import { Token } from 'yaml/dist/parse/cst';
|
||||
/**
|
||||
* These documents are collected into a final YAMLDocument
|
||||
* and passed to the `parseYAML` caller.
|
||||
*/
|
||||
export declare class SingleYAMLDocument extends JSONDocument {
|
||||
private lineCounter;
|
||||
private _internalDocument;
|
||||
root: ASTNode;
|
||||
currentDocIndex: number;
|
||||
private _lineComments;
|
||||
constructor(lineCounter?: LineCounter);
|
||||
/**
|
||||
* Create a deep copy of this document
|
||||
*/
|
||||
clone(): SingleYAMLDocument;
|
||||
private collectLineComments;
|
||||
/**
|
||||
* Updates the internal AST tree of the object
|
||||
* from the internal node. This is call whenever the
|
||||
* internalDocument is set but also can be called to
|
||||
* reflect any changes on the underlying document
|
||||
* without setting the internalDocument explicitly.
|
||||
*/
|
||||
updateFromInternalDocument(): void;
|
||||
set internalDocument(document: Document);
|
||||
get internalDocument(): Document;
|
||||
get lineComments(): string[];
|
||||
set lineComments(val: string[]);
|
||||
get errors(): YAMLDocDiagnostic[];
|
||||
get warnings(): YAMLDocDiagnostic[];
|
||||
getNodeFromPosition(positionOffset: number, textBuffer: TextBuffer, configuredIndentation?: number): [YamlNode | undefined, boolean];
|
||||
findClosestNode(offset: number, textBuffer: TextBuffer, configuredIndentation?: number): YamlNode;
|
||||
private getProperParentByIndentation;
|
||||
getParent(node: YamlNode): YamlNode | undefined;
|
||||
}
|
||||
/**
|
||||
* Contains the SingleYAMLDocuments, to be passed
|
||||
* to the `parseYAML` caller.
|
||||
*/
|
||||
export declare class YAMLDocument {
|
||||
documents: SingleYAMLDocument[];
|
||||
tokens: Token[];
|
||||
private errors;
|
||||
private warnings;
|
||||
constructor(documents: SingleYAMLDocument[], tokens: Token[]);
|
||||
}
|
||||
export declare class YamlDocuments {
|
||||
private cache;
|
||||
/**
|
||||
* Get cached YAMLDocument
|
||||
* @param document TextDocument to parse
|
||||
* @param parserOptions YAML parserOptions
|
||||
* @param addRootObject if true and document is empty add empty object {} to force schema usage
|
||||
* @returns the YAMLDocument
|
||||
*/
|
||||
getYamlDocument(document: TextDocument, parserOptions?: ParserOptions, addRootObject?: boolean): YAMLDocument;
|
||||
/**
|
||||
* For test purpose only!
|
||||
*/
|
||||
clear(): void;
|
||||
private ensureCache;
|
||||
}
|
||||
export declare const yamlDocumentsCache: YamlDocuments;
|
||||
Generated
Vendored
+258
@@ -0,0 +1,258 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Red Hat, Inc. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { JSONDocument } from './jsonDocument';
|
||||
import { isNode, isPair, isScalar, visit } from 'yaml';
|
||||
import { defaultOptions, parse as parseYAML } from './yamlParser07';
|
||||
import { ErrorCode } from 'vscode-json-languageservice';
|
||||
import { convertAST } from './ast-converter';
|
||||
import { isArrayEqual } from '../utils/arrUtils';
|
||||
import { getParent } from '../utils/yamlAstUtils';
|
||||
import { getIndentation } from '../utils/strings';
|
||||
/**
|
||||
* These documents are collected into a final YAMLDocument
|
||||
* and passed to the `parseYAML` caller.
|
||||
*/
|
||||
export class SingleYAMLDocument extends JSONDocument {
|
||||
constructor(lineCounter) {
|
||||
super(null, []);
|
||||
this.lineCounter = lineCounter;
|
||||
}
|
||||
/**
|
||||
* Create a deep copy of this document
|
||||
*/
|
||||
clone() {
|
||||
const copy = new SingleYAMLDocument(this.lineCounter);
|
||||
copy.isKubernetes = this.isKubernetes;
|
||||
copy.disableAdditionalProperties = this.disableAdditionalProperties;
|
||||
copy.uri = this.uri;
|
||||
copy.currentDocIndex = this.currentDocIndex;
|
||||
copy._lineComments = this.lineComments.slice();
|
||||
// this will re-create root node
|
||||
copy.internalDocument = this._internalDocument.clone();
|
||||
return copy;
|
||||
}
|
||||
collectLineComments() {
|
||||
this._lineComments = [];
|
||||
if (this._internalDocument.commentBefore) {
|
||||
const comments = this._internalDocument.commentBefore.split('\n');
|
||||
comments.forEach((comment) => this._lineComments.push(`#${comment}`));
|
||||
}
|
||||
visit(this.internalDocument, (_key, node) => {
|
||||
if (node?.commentBefore) {
|
||||
const comments = node?.commentBefore.split('\n');
|
||||
comments.forEach((comment) => this._lineComments.push(`#${comment}`));
|
||||
}
|
||||
if (node?.comment) {
|
||||
this._lineComments.push(`#${node.comment}`);
|
||||
}
|
||||
});
|
||||
if (this._internalDocument.comment) {
|
||||
this._lineComments.push(`#${this._internalDocument.comment}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Updates the internal AST tree of the object
|
||||
* from the internal node. This is call whenever the
|
||||
* internalDocument is set but also can be called to
|
||||
* reflect any changes on the underlying document
|
||||
* without setting the internalDocument explicitly.
|
||||
*/
|
||||
updateFromInternalDocument() {
|
||||
this.root = convertAST(null, this._internalDocument.contents, this._internalDocument, this.lineCounter);
|
||||
}
|
||||
set internalDocument(document) {
|
||||
this._internalDocument = document;
|
||||
this.updateFromInternalDocument();
|
||||
}
|
||||
get internalDocument() {
|
||||
return this._internalDocument;
|
||||
}
|
||||
get lineComments() {
|
||||
if (!this._lineComments) {
|
||||
this.collectLineComments();
|
||||
}
|
||||
return this._lineComments;
|
||||
}
|
||||
set lineComments(val) {
|
||||
this._lineComments = val;
|
||||
}
|
||||
get errors() {
|
||||
return this.internalDocument.errors.map(YAMLErrorToYamlDocDiagnostics);
|
||||
}
|
||||
get warnings() {
|
||||
return this.internalDocument.warnings.map(YAMLErrorToYamlDocDiagnostics);
|
||||
}
|
||||
getNodeFromPosition(positionOffset, textBuffer, configuredIndentation) {
|
||||
const position = textBuffer.getPosition(positionOffset);
|
||||
const lineContent = textBuffer.getLineContent(position.line);
|
||||
if (lineContent.trim().length === 0) {
|
||||
return [this.findClosestNode(positionOffset, textBuffer, configuredIndentation), true];
|
||||
}
|
||||
const textAfterPosition = lineContent.substring(position.character);
|
||||
const spacesAfterPositionMatch = textAfterPosition.match(/^([ ]+)\n?$/);
|
||||
const areOnlySpacesAfterPosition = !!spacesAfterPositionMatch;
|
||||
const countOfSpacesAfterPosition = spacesAfterPositionMatch?.[1].length;
|
||||
let closestNode;
|
||||
visit(this.internalDocument, (key, node) => {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
const range = node.range;
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
const isNullNodeOnTheLine = () => areOnlySpacesAfterPosition &&
|
||||
positionOffset + countOfSpacesAfterPosition === range[2] &&
|
||||
isScalar(node) &&
|
||||
node.value === null;
|
||||
if ((range[0] <= positionOffset && range[1] >= positionOffset) || isNullNodeOnTheLine()) {
|
||||
closestNode = node;
|
||||
}
|
||||
else {
|
||||
return visit.SKIP;
|
||||
}
|
||||
});
|
||||
return [closestNode, false];
|
||||
}
|
||||
findClosestNode(offset, textBuffer, configuredIndentation) {
|
||||
let offsetDiff = this.internalDocument.range[2];
|
||||
let maxOffset = this.internalDocument.range[0];
|
||||
let closestNode;
|
||||
visit(this.internalDocument, (key, node) => {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
const range = node.range;
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
const diff = range[1] - offset;
|
||||
if (maxOffset <= range[0] && diff <= 0 && Math.abs(diff) <= offsetDiff) {
|
||||
offsetDiff = Math.abs(diff);
|
||||
maxOffset = range[0];
|
||||
closestNode = node;
|
||||
}
|
||||
});
|
||||
const position = textBuffer.getPosition(offset);
|
||||
const lineContent = textBuffer.getLineContent(position.line);
|
||||
const indentation = getIndentation(lineContent, position.character);
|
||||
if (isScalar(closestNode) && closestNode.value === null) {
|
||||
return closestNode;
|
||||
}
|
||||
if (indentation === position.character) {
|
||||
closestNode = this.getProperParentByIndentation(indentation, closestNode, textBuffer, '', configuredIndentation);
|
||||
}
|
||||
return closestNode;
|
||||
}
|
||||
getProperParentByIndentation(indentation, node, textBuffer, currentLine, configuredIndentation, rootParent) {
|
||||
if (!node) {
|
||||
return this.internalDocument.contents;
|
||||
}
|
||||
configuredIndentation = !configuredIndentation ? 2 : configuredIndentation;
|
||||
if (isNode(node) && node.range) {
|
||||
const position = textBuffer.getPosition(node.range[0]);
|
||||
const lineContent = textBuffer.getLineContent(position.line);
|
||||
currentLine = currentLine === '' ? lineContent.trim() : currentLine;
|
||||
if (currentLine.startsWith('-') && indentation === configuredIndentation && currentLine === lineContent.trim()) {
|
||||
position.character += indentation;
|
||||
}
|
||||
if (position.character > indentation && position.character > 0) {
|
||||
const parent = this.getParent(node);
|
||||
if (parent) {
|
||||
return this.getProperParentByIndentation(indentation, parent, textBuffer, currentLine, configuredIndentation, rootParent);
|
||||
}
|
||||
}
|
||||
else if (position.character < indentation) {
|
||||
const parent = this.getParent(node);
|
||||
if (isPair(parent) && isNode(parent.value)) {
|
||||
return parent.value;
|
||||
}
|
||||
else if (isPair(rootParent) && isNode(rootParent.value)) {
|
||||
return rootParent.value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
else if (isPair(node)) {
|
||||
rootParent = node;
|
||||
const parent = this.getParent(node);
|
||||
return this.getProperParentByIndentation(indentation, parent, textBuffer, currentLine, configuredIndentation, rootParent);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
getParent(node) {
|
||||
return getParent(this.internalDocument, node);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Contains the SingleYAMLDocuments, to be passed
|
||||
* to the `parseYAML` caller.
|
||||
*/
|
||||
export class YAMLDocument {
|
||||
constructor(documents, tokens) {
|
||||
this.documents = documents;
|
||||
this.tokens = tokens;
|
||||
this.errors = [];
|
||||
this.warnings = [];
|
||||
}
|
||||
}
|
||||
export class YamlDocuments {
|
||||
constructor() {
|
||||
// a mapping of URIs to cached documents
|
||||
this.cache = new Map();
|
||||
}
|
||||
/**
|
||||
* Get cached YAMLDocument
|
||||
* @param document TextDocument to parse
|
||||
* @param parserOptions YAML parserOptions
|
||||
* @param addRootObject if true and document is empty add empty object {} to force schema usage
|
||||
* @returns the YAMLDocument
|
||||
*/
|
||||
getYamlDocument(document, parserOptions, addRootObject = false) {
|
||||
this.ensureCache(document, parserOptions ?? defaultOptions, addRootObject);
|
||||
return this.cache.get(document.uri).document;
|
||||
}
|
||||
/**
|
||||
* For test purpose only!
|
||||
*/
|
||||
clear() {
|
||||
this.cache.clear();
|
||||
}
|
||||
ensureCache(document, parserOptions, addRootObject) {
|
||||
const key = document.uri;
|
||||
if (!this.cache.has(key)) {
|
||||
this.cache.set(key, { version: -1, document: new YAMLDocument([], []), parserOptions: defaultOptions });
|
||||
}
|
||||
const cacheEntry = this.cache.get(key);
|
||||
if (cacheEntry.version !== document.version ||
|
||||
(parserOptions.customTags && !isArrayEqual(cacheEntry.parserOptions.customTags, parserOptions.customTags))) {
|
||||
let text = document.getText();
|
||||
// if text is contains only whitespace wrap all text in object to force schema selection
|
||||
if (addRootObject && !/\S/.test(text)) {
|
||||
text = `{${text}}`;
|
||||
}
|
||||
const doc = parseYAML(text, parserOptions, document);
|
||||
cacheEntry.document = doc;
|
||||
cacheEntry.version = document.version;
|
||||
cacheEntry.parserOptions = parserOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
export const yamlDocumentsCache = new YamlDocuments();
|
||||
function YAMLErrorToYamlDocDiagnostics(error) {
|
||||
return {
|
||||
message: error.message,
|
||||
location: {
|
||||
start: error.pos[0],
|
||||
end: error.pos[1],
|
||||
toLineEnd: true,
|
||||
},
|
||||
severity: 1,
|
||||
code: ErrorCode.Undefined,
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=yaml-documents.js.map
|
||||
Generated
Vendored
+1
File diff suppressed because one or more lines are too long
Generated
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
import { YAMLDocument, SingleYAMLDocument } from './yaml-documents';
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
export { YAMLDocument, SingleYAMLDocument };
|
||||
export type YamlVersion = '1.1' | '1.2';
|
||||
export interface ParserOptions {
|
||||
customTags: string[];
|
||||
yamlVersion: YamlVersion;
|
||||
}
|
||||
export declare const defaultOptions: ParserOptions;
|
||||
/**
|
||||
* `yaml-ast-parser-custom-tags` parses the AST and
|
||||
* returns YAML AST nodes, which are then formatted
|
||||
* for consumption via the language server.
|
||||
*/
|
||||
export declare function parse(text: string, parserOptions?: ParserOptions, document?: TextDocument): YAMLDocument;
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Red Hat, Inc. All rights reserved.
|
||||
* Copyright (c) Adam Voss. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { Parser, Composer, LineCounter } from 'yaml';
|
||||
import { YAMLDocument, SingleYAMLDocument } from './yaml-documents';
|
||||
import { getCustomTags } from './custom-tag-provider';
|
||||
import { TextBuffer } from '../utils/textBuffer';
|
||||
export { YAMLDocument, SingleYAMLDocument };
|
||||
export const defaultOptions = {
|
||||
customTags: [],
|
||||
yamlVersion: '1.2',
|
||||
};
|
||||
/**
|
||||
* `yaml-ast-parser-custom-tags` parses the AST and
|
||||
* returns YAML AST nodes, which are then formatted
|
||||
* for consumption via the language server.
|
||||
*/
|
||||
export function parse(text, parserOptions = defaultOptions, document) {
|
||||
const options = {
|
||||
strict: false,
|
||||
customTags: getCustomTags(parserOptions.customTags),
|
||||
version: parserOptions.yamlVersion ?? defaultOptions.yamlVersion,
|
||||
keepSourceTokens: true,
|
||||
};
|
||||
const composer = new Composer(options);
|
||||
const lineCounter = new LineCounter();
|
||||
let isLastLineEmpty = false;
|
||||
if (document) {
|
||||
const textBuffer = new TextBuffer(document);
|
||||
const position = textBuffer.getPosition(text.length);
|
||||
const lineContent = textBuffer.getLineContent(position.line);
|
||||
isLastLineEmpty = lineContent.trim().length === 0;
|
||||
}
|
||||
const parser = isLastLineEmpty ? new Parser() : new Parser(lineCounter.addNewLine);
|
||||
const tokens = parser.parse(text);
|
||||
const tokensArr = Array.from(tokens);
|
||||
const docs = composer.compose(tokensArr, true, text.length);
|
||||
// Generate the SingleYAMLDocs from the AST nodes
|
||||
const yamlDocs = Array.from(docs, (doc) => parsedDocToSingleYAMLDocument(doc, lineCounter));
|
||||
// Consolidate the SingleYAMLDocs
|
||||
return new YAMLDocument(yamlDocs, tokensArr);
|
||||
}
|
||||
function parsedDocToSingleYAMLDocument(parsedDoc, lineCounter) {
|
||||
const syd = new SingleYAMLDocument(lineCounter);
|
||||
syd.internalDocument = parsedDoc;
|
||||
return syd;
|
||||
}
|
||||
//# sourceMappingURL=yamlParser07.js.map
|
||||
Generated
Vendored
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"yamlParser07.js","sourceRoot":"","sources":["../../../../src/languageservice/parser/yamlParser07.ts"],"names":[],"mappings":"AAAA;;;;gGAIgG;AAEhG,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAY,WAAW,EAAgD,MAAM,MAAM,CAAC;AAC7G,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,CAAC;AAO5C,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,KAAK;CACnB,CAAC;AACF;;;;GAIG;AACH,MAAM,UAAU,KAAK,CAAC,IAAY,EAAE,gBAA+B,cAAc,EAAE,QAAuB;IACxG,MAAM,OAAO,GAAmD;QAC9D,MAAM,EAAE,KAAK;QACb,UAAU,EAAE,aAAa,CAAC,aAAa,CAAC,UAAU,CAAC;QACnD,OAAO,EAAE,aAAa,CAAC,WAAW,IAAI,cAAc,CAAC,WAAW;QAChE,gBAAgB,EAAE,IAAI;KACvB,CAAC;IACF,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;IACtC,IAAI,eAAe,GAAG,KAAK,CAAC;IAC5B,IAAI,QAAQ,EAAE;QACZ,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrD,MAAM,WAAW,GAAG,UAAU,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7D,eAAe,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC;KACnD;IACD,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5D,iDAAiD;IACjD,MAAM,QAAQ,GAAyB,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,6BAA6B,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;IAElH,iCAAiC;IACjC,OAAO,IAAI,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,6BAA6B,CAAC,SAAmB,EAAE,WAAwB;IAClF,MAAM,GAAG,GAAG,IAAI,kBAAkB,CAAC,WAAW,CAAC,CAAC;IAChD,GAAG,CAAC,gBAAgB,GAAG,SAAS,CAAC;IACjC,OAAO,GAAG,CAAC;AACb,CAAC"}
|
||||
Reference in New Issue
Block a user