Skip to content

Commit

Permalink
Merge pull request #87 from 928PJY/object
Browse files Browse the repository at this point in the history
support generate snippets for object and array according to schema
  • Loading branch information
JPinkney authored Sep 9, 2018
2 parents e422bde + 0f62274 commit b6f7282
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 46 deletions.
168 changes: 133 additions & 35 deletions src/languageservice/services/yamlCompletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,16 @@ export class YAMLCompletion {
if (index < s.schema.items.length) {
this.addSchemaValueCompletions(s.schema.items[index], collector, separatorAfter, true);
}
} else {
} else if (s.schema.items.type === 'object') {
collector.add({
kind: this.getSuggestionKind(s.schema.items.type),
label: `- (array item)`,
documentation: `Create an item of an array${s.schema.description === undefined ? '' : '(' + s.schema.description + ')'}`,
insertText: `- ${this.getInsertTextForObject(s.schema.items, separatorAfter).insertText.trimLeft()}`,
insertTextFormat: InsertTextFormat.Snippet,
});
}
else {
this.addSchemaValueCompletions(s.schema.items, collector, separatorAfter, true);
}
}
Expand Down Expand Up @@ -527,6 +536,99 @@ export class YAMLCompletion {
return this.getInsertTextForPlainText(text + separatorAfter);
}

private getInsertTextForObject(schema: JSONSchema, separatorAfter: string, indent = '\t', insertIndex = 1) {
let insertText = "";
if (!schema.properties) {
insertText = `${indent}\$${insertIndex++}\n`;
return { insertText, insertIndex };
}

Object.keys(schema.properties).forEach((key: string) => {
let propertySchema = schema.properties[key];
let type = Array.isArray(propertySchema.type) ? propertySchema.type[0] : propertySchema.type;
if (!type) {
if (propertySchema.properties) {
type = 'object';
}
if (propertySchema.items) {
type = 'array';
}
}
if (schema.required && schema.required.indexOf(key) > -1) {
switch (type) {
case 'boolean':
case 'string':
case 'number':
case 'integer':
insertText += `${indent}${key}: \$${insertIndex++}\n`
break;
case 'array':
let arrayInsertResult = this.getInsertTextForArray(propertySchema.items, separatorAfter, `${indent}\t`, insertIndex++);
insertIndex = arrayInsertResult.insertIndex;
insertText += `${indent}${key}:\n${indent}\t- ${arrayInsertResult.insertText}\n`;
break;
case 'object':
let objectInsertResult = this.getInsertTextForObject(propertySchema, separatorAfter, `${indent}\t`, insertIndex++);
insertIndex = objectInsertResult.insertIndex;
insertText += `${indent}${key}:\n${objectInsertResult.insertText}\n`;
break;
}
} else if (propertySchema.default !== undefined) {
switch (type) {
case 'boolean':
case 'string':
case 'number':
case 'integer':
insertText += `${indent}${key}: \${${insertIndex++}:${propertySchema.default}}\n`
break;
case 'array':
case 'object':
// TODO: support default value for array object
break;
}
}
});
if (insertText.trim().length === 0) {
insertText = `${indent}\$${insertIndex++}\n`;
}
insertText = insertText.trimRight() + separatorAfter;
return { insertText, insertIndex };
}

private getInsertTextForArray(schema: JSONSchema, separatorAfter: string, indent = '\t', insertIndex = 1) {
let insertText = '';
if (!schema) {
insertText = `\$${insertIndex++}`;
}
let type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
if (!type) {
if (schema.properties) {
type = 'object';
}
if (schema.items) {
type = 'array';
}
}
switch (schema.type) {
case 'boolean':
insertText = `\${${insertIndex++}:false}`;
break;
case 'number':
case 'integer':
insertText = `\${${insertIndex++}:0}`;
break;
case 'string':
insertText = `\${${insertIndex++}:null}`;
break;
case 'object':
let objectInsertResult = this.getInsertTextForObject(schema, separatorAfter, `${indent}\t`, insertIndex++);
insertText = objectInsertResult.insertText.trimLeft();
insertIndex = objectInsertResult.insertIndex;
break;
}
return { insertText, insertIndex };
}

private getInsertTextForProperty(key: string, propertySchema: JSONSchema, addValue: boolean, separatorAfter: string): string {

let propertyText = this.getInsertTextForValue(key, '');
Expand All @@ -536,48 +638,44 @@ export class YAMLCompletion {
let resultText = propertyText + ':';

let value;
let nValueProposals = 0;
if (propertySchema) {
if (propertySchema.default !== undefined) {
value = ` \${1:${propertySchema.default}}`
}
else if (propertySchema.properties) {
return `${resultText}\n${this.getInsertTextForObject(propertySchema, separatorAfter).insertText}`;
}
else if (propertySchema.items) {
return `${resultText}\n\t- ${this.getInsertTextForArray(propertySchema.items, separatorAfter).insertText}`;
}
else {
if (nValueProposals === 0) {
var 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';
break;
case 'string':
value = ' $1';
break;
case 'object':
value = '\n\t';
break;
case 'array':
value = '\n\t- ';
break;
case 'number':
case 'integer':
value = ' ${1:0}';
break;
case 'null':
value = ' ${1:null}';
break;
default:
return propertyText;
}
var type = Array.isArray(propertySchema.type) ? propertySchema.type[0] : propertySchema.type;
switch (type) {
case 'boolean':
value = ' $1';
break;
case 'string':
value = ' $1';
break;
case 'object':
value = '\n\t';
break;
case 'array':
value = '\n\t- ';
break;
case 'number':
case 'integer':
value = ' ${1:0}';
break;
case 'null':
value = ' ${1:null}';
break;
default:
return propertyText;
}
}
}
if (!value || nValueProposals > 1) {
if (!value) {
value = '$1';
}
return resultText + value + separatorAfter;
Expand Down
26 changes: 16 additions & 10 deletions test/autoCompletion2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ suite("Auto Completion Tests", () => {

describe('doComplete', function(){



it('Array autocomplete without word', (done) => {
let content = "authors:\n - ";
let completion = parseSetup(content, 14);
Expand All @@ -59,6 +57,22 @@ suite("Auto Completion Tests", () => {
}).then(done, done);
});

it('Array autocomplete without word on array symbol', (done) => {
let content = "authors:\n -";
let completion = parseSetup(content, 13);
completion.then(function(result){
assert.notEqual(result.items.length, 0);
}).then(done, done);
});

it('Array autocomplete without word on space before array symbol', (done) => {
let content = "authors:\n - name: test\n "
let completion = parseSetup(content, 24);
completion.then(function(result){
assert.notEqual(result.items.length, 0);
}).then(done, done);
});

it('Array autocomplete with letter', (done) => {
let content = "authors:\n - n";
let completion = parseSetup(content, 14);
Expand Down Expand Up @@ -127,14 +141,6 @@ suite("Auto Completion Tests", () => {
}).then(done, done);
});

it('Autocompletion does not complete on wrong spot in array node', (done) => {
let content = "authors:\n - name: test\n "
let completion = parseSetup(content, 24);
completion.then(function(result){
assert.equal(result.items.length, 0);
}).then(done, done);
});

});

});
Expand Down
2 changes: 1 addition & 1 deletion test/autoCompletion3.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ suite("Auto Completion Tests", () => {
return completionHelper(testTextDocument, testTextDocument.positionAt(position));
}

it('Array of enum autocomplete without word', (done) => {
it('Array of enum autocomplete without word on array symbol', (done) => {
let content = "optionalUnityReferences:\n -";
let completion = parseSetup(content, 29);
completion.then(function(result){
Expand Down

0 comments on commit b6f7282

Please sign in to comment.