ui-modules/utils/yaml-editor/addon/hint/super-hint-yaml-schema.js (94 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import CodeMirror from 'codemirror';
import jsyaml from 'js-yaml';
import {SchemaMatcher} from './schema-matcher';
import blueprintSchema from '../schemas/blueprint.json';
import blueprintEntitySchema from '../schemas/blueprint-entity.json';
import blueprintLocationSchema from '../schemas/blueprint-location.json';
import catalogSchema from '../schemas/catalog.json';
import catalogItemReferenceSchema from '../schemas/catalog-item-reference.json';
import catalogItemInlineSchema from '../schemas/catalog-item-inline.json';
import catalogVersionSchema from '../schemas/catalog-version.json';
import rootSchema from '../schemas/root.json';
CodeMirror.registerGlobalHelper('superHint', 'yamlBlueprint', (mode, cm) => (mode.name === 'yaml' && mode.type === 'blueprint'), (cm, options) => {
let schemaMatcher = new SchemaMatcher();
schemaMatcher.registerSchema(JSON.parse(blueprintSchema));
schemaMatcher.registerSchema(JSON.parse(blueprintEntitySchema));
schemaMatcher.registerSchema(JSON.parse(blueprintLocationSchema));
return superHint(schemaMatcher, blueprintSchema, cm, options);
});
CodeMirror.registerGlobalHelper('superHint', 'yamlCatalog', (mode, cm) => (mode.name === 'yaml' && mode.type === 'catalog'), (cm, options) => {
let schemaMatcher = new SchemaMatcher();
schemaMatcher.registerSchema(JSON.parse(catalogSchema));
schemaMatcher.registerSchema(JSON.parse(catalogItemReferenceSchema));
schemaMatcher.registerSchema(JSON.parse(catalogItemInlineSchema));
schemaMatcher.registerSchema(JSON.parse(catalogVersionSchema));
return superHint(schemaMatcher, catalogSchema, cm, options);
});
CodeMirror.registerGlobalHelper('superHint', 'yamlBrooklyn', (mode, cm) => (mode.name === 'yaml' && mode.type === 'brooklyn'), (cm, options) => {
let schemaMatcher = new SchemaMatcher();
schemaMatcher.registerSchema(JSON.parse(blueprintSchema));
schemaMatcher.registerSchema(JSON.parse(blueprintEntitySchema));
schemaMatcher.registerSchema(JSON.parse(blueprintLocationSchema));
schemaMatcher.registerSchema(JSON.parse(catalogSchema));
schemaMatcher.registerSchema(JSON.parse(catalogItemReferenceSchema));
schemaMatcher.registerSchema(JSON.parse(catalogItemInlineSchema));
schemaMatcher.registerSchema(JSON.parse(catalogVersionSchema));
return superHint(schemaMatcher, rootSchema, cm, options);
});
function superHint(schemaMatcher, baseSchema, cm, options) {
return new Promise((resolve, reject) => {
let cursor = cm.getCursor();
let currentText = cm.getLine(cursor.line);
let separatorMatch = currentText.match(/:\s+/);
let isKey = separatorMatch === null || cursor.ch < separatorMatch['index'] + separatorMatch[0].length;
let start = cursor.ch;
while (start && !/\s/.test(currentText.charAt(start - 1))) {
--start;
}
let keyword = currentText.slice(start, cursor.ch);
let hints = {
list: [],
from: CodeMirror.Pos(cursor.line, start),
to: cursor
};
if (!isKey) {
resolve(hints);
} else {
try {
let levels = new Set();
let cursor = cm.getCursor();
let line = cursor.line;
let prevLine = cursor.line > 0 ? cursor.line - 1 : 0;
while (!levels.has(0) && line > 0) {
levels.add(cm.getLine(line).match(/^([\s\-]*)/)[1].length);
line--;
}
levels = Array.from(levels).sort((a, b) => (a - b));
let level = cm.getRange(CodeMirror.Pos(cursor.line, 0), cursor).match(/^([\s\-]*)/)[1].length;
if (levels.indexOf(level) > -1) {
level = levels.indexOf(level);
}
let json = jsyaml.safeLoad(cm.getRange(CodeMirror.Pos(0, 0), CodeMirror.Pos(prevLine, cm.getLine(prevLine).length)));
schemaMatcher.findProperties(json, JSON.parse(baseSchema), level).then(properties => {
resolve(Object.assign(hints, {
list: properties
.filter(property => keyword.length < 1 || property.$key.indexOf(keyword) > -1)
.map(property => {
let helper = ['pattern', 'minItems', 'maxItems', 'enum'].reduce((helper, prop) => {
if (property.hasOwnProperty(prop)) {
helper.push(`${prop}: ${property[prop]}`);
}
return helper;
}, []).join(';');
return cm.superHint(`${property.$key}: `, property.$key, `(${property.type}) ${helper}`, property.description);
})
}));
}).catch(ex => {
reject(new Error(`Cannot retrieve suggestions: ${ex.message}`));
});
} catch (ex) {
resolve(hints);
}
}
});
}