Skip to content

Commit

Permalink
Fix example string of type integer gets pasted as int
Browse files Browse the repository at this point in the history
Signed-off-by: Yevhen Vydolob <[email protected]>
  • Loading branch information
evidolob committed Oct 23, 2020
1 parent 72cdb5e commit 17e5a10
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 20 deletions.
57 changes: 37 additions & 20 deletions src/languageservice/services/yamlCompletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ export class YAMLCompletion extends JSONCompletion {
collector.add({
kind: this.getSuggestionKind(type),
label,
insertText: this.getInsertTextForValue(value, separatorAfter),
insertText: this.getInsertTextForValue(value, separatorAfter, type),
insertTextFormat: InsertTextFormat.Snippet,
detail: localize('json.suggest.default', 'Default value'),
});
Expand All @@ -496,7 +496,7 @@ export class YAMLCompletion extends JSONCompletion {
collector.add({
kind: this.getSuggestionKind(type),
label: value,
insertText: this.getInsertTextForValue(value, separatorAfter),
insertText: this.getInsertTextForValue(value, separatorAfter, type),
insertTextFormat: InsertTextFormat.Snippet,
});
hasProposals = true;
Expand Down Expand Up @@ -605,7 +605,7 @@ export class YAMLCompletion extends JSONCompletion {
collector.add({
kind: this.getSuggestionKind('boolean'),
label: value ? 'true' : 'false',
insertText: this.getInsertTextForValue(value, separatorAfter),
insertText: this.getInsertTextForValue(value, separatorAfter, 'boolean'),
insertTextFormat: InsertTextFormat.Snippet,
documentation: '',
});
Expand Down Expand Up @@ -644,13 +644,17 @@ export class YAMLCompletion extends JSONCompletion {
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
private getInsertTextForValue(value: any, separatorAfter: string): string {
private getInsertTextForValue(value: any, separatorAfter: string, type: string | string[]): string {
switch (typeof value) {
case 'object': {
const indent = this.indentation;
return this.getInsertTemplateForValue(value, indent, { index: 1 }, separatorAfter);
}
}
type = Array.isArray(type) ? type[0] : type;
if (type === 'string') {
value = convertToStringValue(value);
}
return this.getInsertTextForPlainText(value + separatorAfter);
}

Expand Down Expand Up @@ -744,11 +748,13 @@ export class YAMLCompletion extends JSONCompletion {
} else if (propertySchema.default !== undefined) {
switch (type) {
case 'boolean':
case 'string':
case 'number':
case 'integer':
insertText += `${indent}${key}: \${${insertIndex++}:${propertySchema.default}}\n`;
break;
case 'string':
insertText += `${indent}${key}: \${${insertIndex++}:${convertToStringValue(propertySchema.default)}}\n`;
break;
case 'array':
case 'object':
// TODO: support default value for array object
Expand Down Expand Up @@ -808,12 +814,20 @@ export class YAMLCompletion extends JSONCompletion {
separatorAfter: string,
ident = this.indentation
): string {
const propertyText = this.getInsertTextForValue(key, '');
const propertyText = this.getInsertTextForValue(key, '', 'string');
const resultText = propertyText + ':';

let value;
let nValueProposals = 0;
if (propertySchema) {
let type = Array.isArray(propertySchema.type) ? propertySchema.type[0] : propertySchema.type;
if (!type) {
if (propertySchema.properties) {
type = 'object';
} else if (propertySchema.items) {
type = 'array';
}
}
if (Array.isArray(propertySchema.defaultSnippets)) {
if (propertySchema.defaultSnippets.length === 1) {
const body = propertySchema.defaultSnippets[0].body;
Expand All @@ -834,19 +848,19 @@ export class YAMLCompletion extends JSONCompletion {
}
if (propertySchema.enum) {
if (!value && propertySchema.enum.length === 1) {
value = ' ' + this.getInsertTextForGuessedValue(propertySchema.enum[0], '');
value = ' ' + this.getInsertTextForGuessedValue(propertySchema.enum[0], '', type);
}
nValueProposals += propertySchema.enum.length;
}
if (isDefined(propertySchema.default)) {
if (!value) {
value = ' ' + this.getInsertTextForGuessedValue(propertySchema.default, '');
value = ' ' + this.getInsertTextForGuessedValue(propertySchema.default, '', type);
}
nValueProposals++;
}
if (Array.isArray(propertySchema.examples) && propertySchema.examples.length) {
if (!value) {
value = ' ' + this.getInsertTextForGuessedValue(propertySchema.examples[0], '');
value = ' ' + this.getInsertTextForGuessedValue(propertySchema.examples[0], '', type);
}
nValueProposals += propertySchema.examples.length;
}
Expand All @@ -858,14 +872,6 @@ export class YAMLCompletion extends JSONCompletion {
}`;
}
if (nValueProposals === 0) {
let type = Array.isArray(propertySchema.type) ? propertySchema.type[0] : propertySchema.type;
if (!type) {
if (propertySchema.properties) {
type = 'object';
} else if (propertySchema.items) {
type = 'array';
}
}
switch (type) {
case 'boolean':
value = ' $1';
Expand Down Expand Up @@ -898,24 +904,27 @@ export class YAMLCompletion extends JSONCompletion {
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
private getInsertTextForGuessedValue(value: any, separatorAfter: string): string {
private getInsertTextForGuessedValue(value: any, separatorAfter: string, type: string): string {
switch (typeof value) {
case 'object':
if (value === null) {
return '${1:null}' + separatorAfter;
}
return this.getInsertTextForValue(value, separatorAfter);
return this.getInsertTextForValue(value, separatorAfter, type);
case 'string': {
let snippetValue = JSON.stringify(value);
snippetValue = snippetValue.substr(1, snippetValue.length - 2); // remove quotes
snippetValue = this.getInsertTextForPlainText(snippetValue); // escape \ and }
if (type === 'string') {
snippetValue = convertToStringValue(snippetValue);
}
return '${1:' + snippetValue + '}' + separatorAfter;
}
case 'number':
case 'boolean':
return '${1:' + value + '}' + separatorAfter;
}
return this.getInsertTextForValue(value, separatorAfter);
return this.getInsertTextForValue(value, separatorAfter, type);
}

private getLabelForValue(value: string): string {
Expand Down Expand Up @@ -996,6 +1005,14 @@ export class YAMLCompletion extends JSONCompletion {
}
}

const isNumberExp = /^\d+$/;
function convertToStringValue(value: string): string {
if (value === 'true' || value === 'false' || value === 'null' || isNumberExp.test(value)) {
return `"${value}"`;
}

return value;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
function isDefined(val: any): val is object {
return val !== undefined;
Expand Down
54 changes: 54 additions & 0 deletions test/autoCompletion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1453,5 +1453,59 @@ suite('Auto Completion Tests', () => {
expect(completion.items[0].insertText).eq('fooBar:\n name: $1\n aaa:\n - $2');
});
});

it('should complete string which contains number in default value', async () => {
languageService.addSchema(SCHEMA_ID, {
type: 'object',
properties: {
env: {
type: 'integer',
default: '1',
},
enum: {
type: 'string',
default: '1',
},
},
});

const content = 'enum';
const completion = await parseSetup(content, 3);

const enumItem = completion.items.find((i) => i.label === 'enum');
expect(enumItem).to.not.undefined;
expect(enumItem.textEdit.newText).equal('enum: ${1:"1"}');

const envItem = completion.items.find((i) => i.label === 'env');
expect(envItem).to.not.undefined;
expect(envItem.textEdit.newText).equal('env: ${1:1}');
});

it('should complete string which contains number in examples values', async () => {
languageService.addSchema(SCHEMA_ID, {
type: 'object',
properties: {
fooBar: {
type: 'string',
examples: ['test', '1', 'true'],
},
},
});

const content = 'fooBar: \n';
const completion = await parseSetup(content, 8);

const testItem = completion.items.find((i) => i.label === 'test');
expect(testItem).to.not.undefined;
expect(testItem.textEdit.newText).equal('test');

const oneItem = completion.items.find((i) => i.label === '1');
expect(oneItem).to.not.undefined;
expect(oneItem.textEdit.newText).equal('"1"');

const trueItem = completion.items.find((i) => i.label === 'true');
expect(trueItem).to.not.undefined;
expect(trueItem.textEdit.newText).equal('"true"');
});
});
});

0 comments on commit 17e5a10

Please sign in to comment.