VTable/docs/libs/template-parse/schemaHelper.js
2023-08-30 18:50:00 +08:00

227 lines
6.8 KiB
JavaScript

/* Adapted from echarts-doc by Apache ECharts
* https://github.com/apache/echarts-doc
* Licensed under the Apache-2.0 license
* url: https://github.com/apache/echarts-doc/blob/master/tool/schemaHelper.js
* License: https://github.com/apache/echarts-doc/blob/master/LICENSE
* @license
*/
function parseTypeValueOfArrayItem(schema, arrayItemKeys) {
const typeKey = arrayItemKeys.find(key => {
return !!(schema.properties && schema.properties[key] && schema.properties[key].default);
});
if (typeKey) {
return { key: typeKey, value: schema.properties[typeKey].default.replace(/'/g, '') };
}
return null;
}
function traverse(schema, rootName, arrayItemKeys, cb) {
function innerTraverse(schemaNode, path, noCallback) {
if (!noCallback) {
cb(path, schemaNode);
}
if (schemaNode.items) {
if (schemaNode.items.anyOf) {
schemaNode.items.anyOf.forEach(itemSchema => {
let res = parseTypeValueOfArrayItem(itemSchema, arrayItemKeys);
if (res) {
innerTraverse(itemSchema, path ? path + '-' + res.value.replace(/'/g, '') : res.value, false);
}
});
} else {
innerTraverse(schemaNode.items, path, true);
}
} else if (schemaNode.properties) {
for (let propName in schemaNode.properties) {
innerTraverse(schemaNode.properties[propName], path ? path + '.' + propName : propName, false);
}
}
// Or it's a leaf node.
}
innerTraverse(schema.option, rootName, false);
}
module.exports.traverse = traverse;
function convertToTree(rootSchema, rootNode, arrayItemKeys) {
function createNodeBase(schema) {
let schemaType = schema.type;
// Simplify type
if (schemaType instanceof Array && schemaType.length === 1) {
schemaType = schemaType[0];
}
let nodeBase = {};
// Get type from default if possible. Reduce size.
if (schema.default == null || typeof schema.default !== schemaType) {
nodeBase.type = schemaType;
}
if (schema.default != null) {
nodeBase.default = schema.default;
}
if (schema.items) {
// Array also may has properties.
nodeBase.isArray = true;
} else if (schema.properties && Object.keys(schema.properties).length) {
nodeBase.isObject = true;
}
return nodeBase;
}
function createArrayItemNode(schema, parentNode) {
let childNode = createNodeBase(schema, parentNode);
const res = parseTypeValueOfArrayItem(schema, arrayItemKeys);
if (res) {
childNode.arrayItemType = res.value;
childNode.arrayItemTypeKey = res.key;
childNode.arrayParentType = parentNode.type;
} else {
console.error('schema', schema);
throw new Error('Some thing wrong happens');
}
return childNode;
}
function createPropertyNode(propName, schema, parentNode) {
let childNode = createNodeBase(schema, parentNode);
childNode.prop = propName;
return childNode;
}
function processObjectType(currentSchema, currentNode) {
if (!currentSchema.properties) {
return;
}
let children = [];
for (let propName in currentSchema.properties) {
let childSchema = currentSchema.properties[propName];
let childNode = createPropertyNode(propName, childSchema, currentNode);
processRecursively(childSchema, childNode);
children.push(childNode);
}
if (children.length) {
currentNode.children = children;
}
}
function processArrayType(currentSchema, currentNode) {
if (!currentSchema.items) {
return;
}
// Each item of array may have different type of object.
// Like series, visualMap, legend
if (currentSchema.items.anyOf) {
let children = [];
currentSchema.items.anyOf.forEach(itemSchema => {
let childNode = createArrayItemNode(itemSchema, currentNode);
processRecursively(itemSchema, childNode);
children.push(childNode);
});
currentNode.children = children;
}
// Each item of array only have one type of object.
// Like data and most of the compoents.
else {
processObjectType(currentSchema.items, currentNode);
}
}
function processRecursively(currentSchema, currentNode) {
// Array also may has properties.
if (currentSchema.items) {
processArrayType(currentSchema, currentNode);
} else if (currentSchema.properties) {
processObjectType(currentSchema, currentNode);
}
return currentNode;
}
return processRecursively(rootSchema, rootNode, 0);
}
module.exports.extractOptionKeys = function (schema, arrayItemKeys) {
const keysRepeatCount = {};
const keysList = [];
traverse(schema, '', arrayItemKeys, (schemaPath, schemaNode) => {
if (!schemaPath) {
return;
}
const leafKey = schemaPath.split(/[\.-]/g).pop();
if (keysRepeatCount[leafKey] == null) {
keysRepeatCount[leafKey] = 0;
keysList.push(leafKey);
}
keysRepeatCount[leafKey]++;
});
return keysList
.map(key => {
return {
name: key,
count: keysRepeatCount[key]
};
})
.sort((a, b) => b.count - a.count);
};
// Partion the descriptions by the first part of path. For example
// { "title.label", "series-line.data", "series-bar.data" }
// Will be
// {
// "title": { "label" },
// "series-line": {"data"},
// "series-bar": {"data"}
// }
module.exports.extractDesc = function (schema, docName, arrayItemKeys) {
let descriptionsMap = {};
let propWithUIControlCount = 0;
let propTotalCount = 0;
traverse(schema, docName, arrayItemKeys, (schemaPath, schemaNode) => {
if (schemaNode.description) {
// Extract component level path
let parts = schemaPath.split('.');
let divider = parts.length > 2 ? 2 : 1;
let partionKey = parts.slice(0, divider).join('.');
let subKey = parts.slice(divider).join('.');
// 支持三级展开页面
if (parts.length > 3) {
if (parts[1].includes('-') && parts[2].includes('-')) {
partionKey = `${parts[0]}.${parts[1]}-${parts[2].split('-')[1]}`;
subKey = parts.slice(3).join('.');
} else if (parts[2].includes('-')) {
partionKey = `${parts[0]}.${parts[1]}-${parts[2]}`;
subKey = parts.slice(3).join('.');
}
}
descriptionsMap[partionKey] = descriptionsMap[partionKey] || {};
descriptionsMap[partionKey][subKey] = {
desc: schemaNode.description,
exampleBaseOptions: schemaNode.exampleBaseOptions,
uiControl: schemaNode.uiControl
};
propTotalCount++;
if (schemaNode.uiControl) {
propWithUIControlCount++;
}
}
});
console.log(
`Options with UIControl ${propWithUIControlCount} / ${propTotalCount} (${propWithUIControlCount / propTotalCount})`
);
return {
outline: convertToTree(schema.option, {}, arrayItemKeys),
descriptions: descriptionsMap
};
};