@markuplint/ml-spec
Version:
Types and schema that specs of the Markup languages for markuplint
81 lines (80 loc) • 2.42 kB
JavaScript
import { resolveNamespace } from '../utils/resolve-namespace.js';
const cacheMap = new Map();
const schemaCache = new WeakSet();
export function getAttrSpecs(localName, namespace, schema) {
if (!schemaCache.has(schema)) {
cacheMap.clear();
}
const { localNameWithNS } = resolveNamespace(localName, namespace ?? undefined);
const cache = cacheMap.get(localNameWithNS);
if (cache !== undefined) {
return cache;
}
schemaCache.add(schema);
const elSpec = schema.specs.find(spec => spec.name === localNameWithNS);
if (!elSpec) {
cacheMap.set(localNameWithNS, null);
return null;
}
const globalAttrs = schema.def['#globalAttrs'];
let attrs = {};
for (const catName in elSpec.globalAttrs) {
// @ts-ignore
const catAttrs = elSpec.globalAttrs[catName];
if (catAttrs === false) {
continue;
}
if (typeof catAttrs === 'boolean') {
const global = globalAttrs[catName];
attrs = {
...attrs,
...global,
};
continue;
}
if (Array.isArray(catAttrs)) {
const global = globalAttrs[catName];
if (!global) {
continue;
}
for (const selectedName of catAttrs) {
const selected = global[selectedName];
attrs[selectedName] = {
...attrs[selectedName],
...selected,
};
}
continue;
}
}
for (const attrName in elSpec.attributes) {
const attr = elSpec.attributes[attrName];
if (!attr) {
continue;
}
const current = attrs[attrName];
attrs[attrName] = {
description: '',
...current,
...attr,
};
}
const attrList = Object.keys(attrs).map(name => {
const attr = attrs[name];
return { name, type: 'Any', ...attr };
});
attrList.sort(nameCompare);
cacheMap.set(localNameWithNS, attrList);
return attrList;
}
export function nameCompare(a, b) {
const nameA = typeof a === 'string' ? a : a.name.toUpperCase();
const nameB = typeof b === 'string' ? b : b.name.toUpperCase();
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
}