Include : and new lines where appropriate when auto-completing
This commit is contained in:
@@ -373,4 +373,51 @@ jobs:
|
|||||||
end: {line: 6, character: 17}
|
end: {line: 6, character: 17}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("completes with indentation", () => {
|
||||||
|
it("default indentation", async () => {
|
||||||
|
const input = `on: push
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
step|`;
|
||||||
|
const result = await complete(...getPositionFromCursor(input));
|
||||||
|
|
||||||
|
// Sequence
|
||||||
|
expect(result.filter(x => x.label === "steps").map(x => x.textEdit?.newText)).toEqual(["steps:\n - "]);
|
||||||
|
|
||||||
|
// Mapping
|
||||||
|
expect(result.filter(x => x.label === "env").map(x => x.textEdit?.newText)).toEqual(["env:\n "]);
|
||||||
|
|
||||||
|
// Value
|
||||||
|
expect(result.filter(x => x.label === "timeout-minutes").map(x => x.textEdit?.newText)).toEqual([
|
||||||
|
"timeout-minutes: "
|
||||||
|
]);
|
||||||
|
|
||||||
|
// One-of
|
||||||
|
expect(result.filter(x => x.label === "concurrency").map(x => x.textEdit?.newText)).toEqual(["concurrency"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("custom indentation", async () => {
|
||||||
|
// Use 3 spaces to indent
|
||||||
|
const input = `on: push
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
step|`;
|
||||||
|
const result = await complete(...getPositionFromCursor(input));
|
||||||
|
|
||||||
|
// Sequence
|
||||||
|
expect(result.filter(x => x.label === "steps").map(x => x.textEdit?.newText)).toEqual(["steps:\n - "]);
|
||||||
|
|
||||||
|
// Mapping
|
||||||
|
expect(result.filter(x => x.label === "env").map(x => x.textEdit?.newText)).toEqual(["env:\n "]);
|
||||||
|
|
||||||
|
// Value
|
||||||
|
expect(result.filter(x => x.label === "timeout-minutes").map(x => x.textEdit?.newText)).toEqual([
|
||||||
|
"timeout-minutes: "
|
||||||
|
]);
|
||||||
|
|
||||||
|
// One-of
|
||||||
|
expect(result.filter(x => x.label === "concurrency").map(x => x.textEdit?.newText)).toEqual(["concurrency"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {getContext, Mode} from "./context-providers/default";
|
|||||||
import {getWorkflowContext, WorkflowContext} from "./context/workflow-context";
|
import {getWorkflowContext, WorkflowContext} from "./context/workflow-context";
|
||||||
import {nullTrace} from "./nulltrace";
|
import {nullTrace} from "./nulltrace";
|
||||||
import {findToken} from "./utils/find-token";
|
import {findToken} from "./utils/find-token";
|
||||||
|
import {guessIndentation} from "./utils/indentation-guesser";
|
||||||
import {mapRange} from "./utils/range";
|
import {mapRange} from "./utils/range";
|
||||||
import {transform} from "./utils/transform";
|
import {transform} from "./utils/transform";
|
||||||
import {Value, ValueProviderConfig} from "./value-providers/config";
|
import {Value, ValueProviderConfig} from "./value-providers/config";
|
||||||
@@ -94,18 +95,23 @@ export async function complete(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const values = await getValues(token, keyToken, parent, valueProviderConfig, workflowContext);
|
const indentation = guessIndentation(newDoc, 2, true); // Use 2 spaces as default and most common for YAML
|
||||||
|
const indentString = " ".repeat(indentation.tabSize);
|
||||||
|
|
||||||
|
const values = await getValues(token, keyToken, parent, valueProviderConfig, workflowContext, indentString);
|
||||||
let replaceRange: Range | undefined;
|
let replaceRange: Range | undefined;
|
||||||
if (token?.range) {
|
if (token?.range) {
|
||||||
replaceRange = mapRange(token.range);
|
replaceRange = mapRange(token.range);
|
||||||
}
|
}
|
||||||
|
|
||||||
return values.map(value => {
|
return values.map(value => {
|
||||||
|
const newText = value.insertText || value.label;
|
||||||
|
|
||||||
const item: CompletionItem = {
|
const item: CompletionItem = {
|
||||||
label: value.label,
|
label: value.label,
|
||||||
detail: value.description,
|
detail: value.description,
|
||||||
tags: value.deprecated ? [CompletionItemTag.Deprecated] : undefined,
|
tags: value.deprecated ? [CompletionItemTag.Deprecated] : undefined,
|
||||||
textEdit: replaceRange ? TextEdit.replace(replaceRange, value.label) : undefined
|
textEdit: replaceRange ? TextEdit.replace(replaceRange, newText) : TextEdit.insert(position, newText)
|
||||||
};
|
};
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
@@ -117,7 +123,8 @@ async function getValues(
|
|||||||
keyToken: TemplateToken | null,
|
keyToken: TemplateToken | null,
|
||||||
parent: TemplateToken | null,
|
parent: TemplateToken | null,
|
||||||
valueProviderConfig: ValueProviderConfig | undefined,
|
valueProviderConfig: ValueProviderConfig | undefined,
|
||||||
workflowContext: WorkflowContext
|
workflowContext: WorkflowContext,
|
||||||
|
indentation: string
|
||||||
): Promise<Value[]> {
|
): Promise<Value[]> {
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
return [];
|
return [];
|
||||||
@@ -150,7 +157,7 @@ async function getValues(
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const values = definitionValues(def);
|
const values = definitionValues(def, indentation);
|
||||||
return filterAndSortCompletionOptions(values, existingValues);
|
return filterAndSortCompletionOptions(values, existingValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,269 @@
|
|||||||
|
// Copied from https://github.com/microsoft/vscode/blob/c3b617f9b058e01cbc5cf00ec3813a7047326503/src/vs/editor/common/model/indentationGuesser.ts
|
||||||
|
// And adapted to work with languageserver-textdocument types
|
||||||
|
|
||||||
|
import {TextDocument} from "vscode-languageserver-textdocument";
|
||||||
|
|
||||||
|
enum CharCode {
|
||||||
|
Space = 32,
|
||||||
|
Tab = 9,
|
||||||
|
Comma = 44
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLineContent(doc: TextDocument, lineNumber: number): string {
|
||||||
|
return doc.getText({
|
||||||
|
start: {
|
||||||
|
line: lineNumber - 1,
|
||||||
|
character: 0
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: lineNumber - 1,
|
||||||
|
character: Number.MAX_SAFE_INTEGER
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLineCharCode(doc: TextDocument, lineNumber: number, index: number): number {
|
||||||
|
return doc
|
||||||
|
.getText({
|
||||||
|
start: {
|
||||||
|
line: lineNumber - 1,
|
||||||
|
character: index
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: lineNumber - 1,
|
||||||
|
character: index + 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.charCodeAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class SpacesDiffResult {
|
||||||
|
public spacesDiff: number = 0;
|
||||||
|
public looksLikeAlignment: boolean = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the diff in spaces between two line's indentation.
|
||||||
|
*/
|
||||||
|
function spacesDiff(a: string, aLength: number, b: string, bLength: number, result: SpacesDiffResult): void {
|
||||||
|
result.spacesDiff = 0;
|
||||||
|
result.looksLikeAlignment = false;
|
||||||
|
|
||||||
|
// This can go both ways (e.g.):
|
||||||
|
// - a: "\t"
|
||||||
|
// - b: "\t "
|
||||||
|
// => This should count 1 tab and 4 spaces
|
||||||
|
|
||||||
|
let i: number;
|
||||||
|
|
||||||
|
for (i = 0; i < aLength && i < bLength; i++) {
|
||||||
|
const aCharCode = a.charCodeAt(i);
|
||||||
|
const bCharCode = b.charCodeAt(i);
|
||||||
|
|
||||||
|
if (aCharCode !== bCharCode) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let aSpacesCnt = 0,
|
||||||
|
aTabsCount = 0;
|
||||||
|
for (let j = i; j < aLength; j++) {
|
||||||
|
const aCharCode = a.charCodeAt(j);
|
||||||
|
if (aCharCode === CharCode.Space) {
|
||||||
|
aSpacesCnt++;
|
||||||
|
} else {
|
||||||
|
aTabsCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let bSpacesCnt = 0,
|
||||||
|
bTabsCount = 0;
|
||||||
|
for (let j = i; j < bLength; j++) {
|
||||||
|
const bCharCode = b.charCodeAt(j);
|
||||||
|
if (bCharCode === CharCode.Space) {
|
||||||
|
bSpacesCnt++;
|
||||||
|
} else {
|
||||||
|
bTabsCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aSpacesCnt > 0 && aTabsCount > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bSpacesCnt > 0 && bTabsCount > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabsDiff = Math.abs(aTabsCount - bTabsCount);
|
||||||
|
const spacesDiff = Math.abs(aSpacesCnt - bSpacesCnt);
|
||||||
|
|
||||||
|
if (tabsDiff === 0) {
|
||||||
|
// check if the indentation difference might be caused by alignment reasons
|
||||||
|
// sometime folks like to align their code, but this should not be used as a hint
|
||||||
|
result.spacesDiff = spacesDiff;
|
||||||
|
|
||||||
|
if (spacesDiff > 0 && 0 <= bSpacesCnt - 1 && bSpacesCnt - 1 < a.length && bSpacesCnt < b.length) {
|
||||||
|
if (b.charCodeAt(bSpacesCnt) !== CharCode.Space && a.charCodeAt(bSpacesCnt - 1) === CharCode.Space) {
|
||||||
|
if (a.charCodeAt(a.length - 1) === CharCode.Comma) {
|
||||||
|
// This looks like an alignment desire: e.g.
|
||||||
|
// const a = b + c,
|
||||||
|
// d = b - c;
|
||||||
|
result.looksLikeAlignment = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (spacesDiff % tabsDiff === 0) {
|
||||||
|
result.spacesDiff = spacesDiff / tabsDiff;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result for a guessIndentation
|
||||||
|
*/
|
||||||
|
export interface IGuessedIndentation {
|
||||||
|
/**
|
||||||
|
* If indentation is based on spaces (`insertSpaces` = true), then what is the number of spaces that make an indent?
|
||||||
|
*/
|
||||||
|
tabSize: number;
|
||||||
|
/**
|
||||||
|
* Is indentation based on spaces?
|
||||||
|
*/
|
||||||
|
insertSpaces: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function guessIndentation(
|
||||||
|
source: TextDocument,
|
||||||
|
defaultTabSize: number,
|
||||||
|
defaultInsertSpaces: boolean
|
||||||
|
): IGuessedIndentation {
|
||||||
|
// Look at most at the first 10k lines
|
||||||
|
const linesCount = Math.min(source.lineCount, 10000);
|
||||||
|
|
||||||
|
let linesIndentedWithTabsCount = 0; // number of lines that contain at least one tab in indentation
|
||||||
|
let linesIndentedWithSpacesCount = 0; // number of lines that contain only spaces in indentation
|
||||||
|
|
||||||
|
let previousLineText = ""; // content of latest line that contained non-whitespace chars
|
||||||
|
let previousLineIndentation = 0; // index at which latest line contained the first non-whitespace char
|
||||||
|
|
||||||
|
const ALLOWED_TAB_SIZE_GUESSES = [2, 4, 6, 8, 3, 5, 7]; // prefer even guesses for `tabSize`, limit to [2, 8].
|
||||||
|
const MAX_ALLOWED_TAB_SIZE_GUESS = 8; // max(ALLOWED_TAB_SIZE_GUESSES) = 8
|
||||||
|
|
||||||
|
const spacesDiffCount = [0, 0, 0, 0, 0, 0, 0, 0, 0]; // `tabSize` scores
|
||||||
|
const tmp = new SpacesDiffResult();
|
||||||
|
|
||||||
|
for (let lineNumber = 1; lineNumber <= linesCount; lineNumber++) {
|
||||||
|
const currentLineText = getLineContent(source, lineNumber);
|
||||||
|
const currentLineLength = currentLineText.length;
|
||||||
|
|
||||||
|
// if the text buffer is chunk based, so long lines are cons-string, v8 will flattern the string when we check charCode.
|
||||||
|
// checking charCode on chunks directly is cheaper.
|
||||||
|
const useCurrentLineText = currentLineLength <= 65536;
|
||||||
|
|
||||||
|
let currentLineHasContent = false; // does `currentLineText` contain non-whitespace chars
|
||||||
|
let currentLineIndentation = 0; // index at which `currentLineText` contains the first non-whitespace char
|
||||||
|
let currentLineSpacesCount = 0; // count of spaces found in `currentLineText` indentation
|
||||||
|
let currentLineTabsCount = 0; // count of tabs found in `currentLineText` indentation
|
||||||
|
for (let j = 0, lenJ = currentLineLength; j < lenJ; j++) {
|
||||||
|
const charCode = useCurrentLineText ? currentLineText.charCodeAt(j) : getLineCharCode(source, lineNumber, j);
|
||||||
|
|
||||||
|
if (charCode === CharCode.Tab) {
|
||||||
|
currentLineTabsCount++;
|
||||||
|
} else if (charCode === CharCode.Space) {
|
||||||
|
currentLineSpacesCount++;
|
||||||
|
} else {
|
||||||
|
// Hit non whitespace character on this line
|
||||||
|
currentLineHasContent = true;
|
||||||
|
currentLineIndentation = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore empty or only whitespace lines
|
||||||
|
if (!currentLineHasContent) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentLineTabsCount > 0) {
|
||||||
|
linesIndentedWithTabsCount++;
|
||||||
|
} else if (currentLineSpacesCount > 1) {
|
||||||
|
linesIndentedWithSpacesCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
spacesDiff(previousLineText, previousLineIndentation, currentLineText, currentLineIndentation, tmp);
|
||||||
|
|
||||||
|
if (tmp.looksLikeAlignment) {
|
||||||
|
// if defaultInsertSpaces === true && the spaces count == tabSize, we may want to count it as valid indentation
|
||||||
|
//
|
||||||
|
// - item1
|
||||||
|
// - item2
|
||||||
|
//
|
||||||
|
// otherwise skip this line entirely
|
||||||
|
//
|
||||||
|
// const a = 1,
|
||||||
|
// b = 2;
|
||||||
|
|
||||||
|
if (!(defaultInsertSpaces && defaultTabSize === tmp.spacesDiff)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentSpacesDiff = tmp.spacesDiff;
|
||||||
|
if (currentSpacesDiff <= MAX_ALLOWED_TAB_SIZE_GUESS) {
|
||||||
|
spacesDiffCount[currentSpacesDiff]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
previousLineText = currentLineText;
|
||||||
|
previousLineIndentation = currentLineIndentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
let insertSpaces = defaultInsertSpaces;
|
||||||
|
if (linesIndentedWithTabsCount !== linesIndentedWithSpacesCount) {
|
||||||
|
insertSpaces = linesIndentedWithTabsCount < linesIndentedWithSpacesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tabSize = defaultTabSize;
|
||||||
|
|
||||||
|
// Guess tabSize only if inserting spaces...
|
||||||
|
if (insertSpaces) {
|
||||||
|
let tabSizeScore = insertSpaces ? 0 : 0.1 * linesCount;
|
||||||
|
|
||||||
|
// console.log("score threshold: " + tabSizeScore);
|
||||||
|
|
||||||
|
ALLOWED_TAB_SIZE_GUESSES.forEach(possibleTabSize => {
|
||||||
|
const possibleTabSizeScore = spacesDiffCount[possibleTabSize];
|
||||||
|
if (possibleTabSizeScore > tabSizeScore) {
|
||||||
|
tabSizeScore = possibleTabSizeScore;
|
||||||
|
tabSize = possibleTabSize;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Let a tabSize of 2 win even if it is not the maximum
|
||||||
|
// (only in case 4 was guessed)
|
||||||
|
if (
|
||||||
|
tabSize === 4 &&
|
||||||
|
spacesDiffCount[4] > 0 &&
|
||||||
|
spacesDiffCount[2] > 0 &&
|
||||||
|
spacesDiffCount[2] >= spacesDiffCount[4] / 2
|
||||||
|
) {
|
||||||
|
tabSize = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log('--------------------------');
|
||||||
|
// console.log('linesIndentedWithTabsCount: ' + linesIndentedWithTabsCount + ', linesIndentedWithSpacesCount: ' + linesIndentedWithSpacesCount);
|
||||||
|
// console.log('spacesDiffCount: ' + spacesDiffCount);
|
||||||
|
// console.log('tabSize: ' + tabSize + ', tabSizeScore: ' + tabSizeScore);
|
||||||
|
|
||||||
|
return {
|
||||||
|
insertSpaces: insertSpaces,
|
||||||
|
tabSize: tabSize
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ export interface Value {
|
|||||||
label: string;
|
label: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
deprecated?: boolean;
|
deprecated?: boolean;
|
||||||
|
insertText?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ValueProviderKind {
|
export enum ValueProviderKind {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {BooleanDefinition} from "@github/actions-workflow-parser/templates/schema/boolean-definition";
|
import {BooleanDefinition} from "@github/actions-workflow-parser/templates/schema/boolean-definition";
|
||||||
import {Definition} from "@github/actions-workflow-parser/templates/schema/definition";
|
import {Definition} from "@github/actions-workflow-parser/templates/schema/definition";
|
||||||
|
import {DefinitionType} from "@github/actions-workflow-parser/templates/schema/definition-type";
|
||||||
import {MappingDefinition} from "@github/actions-workflow-parser/templates/schema/mapping-definition";
|
import {MappingDefinition} from "@github/actions-workflow-parser/templates/schema/mapping-definition";
|
||||||
import {OneOfDefinition} from "@github/actions-workflow-parser/templates/schema/one-of-definition";
|
import {OneOfDefinition} from "@github/actions-workflow-parser/templates/schema/one-of-definition";
|
||||||
import {SequenceDefinition} from "@github/actions-workflow-parser/templates/schema/sequence-definition";
|
import {SequenceDefinition} from "@github/actions-workflow-parser/templates/schema/sequence-definition";
|
||||||
@@ -8,15 +9,15 @@ import {getWorkflowSchema} from "@github/actions-workflow-parser/workflows/workf
|
|||||||
import {Value} from "./config";
|
import {Value} from "./config";
|
||||||
import {stringsToValues} from "./strings-to-values";
|
import {stringsToValues} from "./strings-to-values";
|
||||||
|
|
||||||
export function definitionValues(def: Definition): Value[] {
|
export function definitionValues(def: Definition, indentation: string): Value[] {
|
||||||
const schema = getWorkflowSchema();
|
const schema = getWorkflowSchema();
|
||||||
|
|
||||||
if (def instanceof MappingDefinition) {
|
if (def instanceof MappingDefinition) {
|
||||||
return mappingValues(def, schema.definitions);
|
return mappingValues(def, schema.definitions, indentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def instanceof OneOfDefinition) {
|
if (def instanceof OneOfDefinition) {
|
||||||
return oneOfValues(def, schema.definitions);
|
return oneOfValues(def, schema.definitions, indentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def instanceof BooleanDefinition) {
|
if (def instanceof BooleanDefinition) {
|
||||||
@@ -35,30 +36,64 @@ export function definitionValues(def: Definition): Value[] {
|
|||||||
if (def instanceof SequenceDefinition) {
|
if (def instanceof SequenceDefinition) {
|
||||||
const itemDef = schema.getDefinition(def.itemType);
|
const itemDef = schema.getDefinition(def.itemType);
|
||||||
if (itemDef) {
|
if (itemDef) {
|
||||||
return definitionValues(itemDef);
|
return definitionValues(itemDef, indentation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function mappingValues(mappingDefinition: MappingDefinition, definitions: {[key: string]: Definition}): Value[] {
|
function mappingValues(
|
||||||
|
mappingDefinition: MappingDefinition,
|
||||||
|
definitions: {[key: string]: Definition},
|
||||||
|
indentation: string
|
||||||
|
): Value[] {
|
||||||
const properties: Value[] = [];
|
const properties: Value[] = [];
|
||||||
for (const [key, value] of Object.entries(mappingDefinition.properties)) {
|
for (const [key, value] of Object.entries(mappingDefinition.properties)) {
|
||||||
|
let insertText: string | undefined;
|
||||||
|
|
||||||
let description: string | undefined;
|
let description: string | undefined;
|
||||||
if (value.type) {
|
if (value.type) {
|
||||||
const typeDef = definitions[value.type];
|
const typeDef = definitions[value.type];
|
||||||
description = typeDef?.description;
|
description = typeDef?.description;
|
||||||
|
|
||||||
|
if (typeDef) {
|
||||||
|
switch (typeDef.definitionType) {
|
||||||
|
case DefinitionType.Sequence:
|
||||||
|
insertText = `${key}:\n${indentation}- `;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DefinitionType.Mapping:
|
||||||
|
insertText = `${key}:\n${indentation}`;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DefinitionType.OneOf:
|
||||||
|
// No special insertText in this case
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
insertText = `${key}: `;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
properties.push({label: key, description: description});
|
|
||||||
|
properties.push({
|
||||||
|
label: key,
|
||||||
|
description,
|
||||||
|
insertText
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
function oneOfValues(oneOfDefinition: OneOfDefinition, definitions: {[key: string]: Definition}): Value[] {
|
function oneOfValues(
|
||||||
|
oneOfDefinition: OneOfDefinition,
|
||||||
|
definitions: {[key: string]: Definition},
|
||||||
|
indentation: string
|
||||||
|
): Value[] {
|
||||||
const values: Value[] = [];
|
const values: Value[] = [];
|
||||||
for (const key of oneOfDefinition.oneOf) {
|
for (const key of oneOfDefinition.oneOf) {
|
||||||
values.push(...definitionValues(definitions[key]));
|
values.push(...definitionValues(definitions[key], indentation));
|
||||||
}
|
}
|
||||||
return distinctValues(values);
|
return distinctValues(values);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user