lion/packages/ui/scripts/cem.js
2025-02-13 14:10:02 +01:00

106 lines
3.4 KiB
JavaScript

import fs from 'fs';
// eslint-disable-next-line import/no-extraneous-dependencies
import { globby } from 'globby';
// eslint-disable-next-line import/no-extraneous-dependencies
import { createModuleGraph } from '@thepassle/module-graph';
// eslint-disable-next-line import/no-extraneous-dependencies
import { create, ts } from '@custom-elements-manifest/analyzer';
// eslint-disable-next-line import/no-extraneous-dependencies
import { litPlugin } from '@custom-elements-manifest/analyzer/src/features/framework-plugins/lit/lit.js';
// eslint-disable-next-line import/no-extraneous-dependencies
import { generateCustomData } from 'cem-plugin-vs-code-custom-data-generator';
/**
* Find all entrypoints for lion to create the CEM from
*/
const globs = await globby('./exports/**/*.js');
/**
* Based on the entrypoints, create a module graph including @lion/ui dependency
* We'll feed these modules to the CEM analyzer
*/
const moduleGraph = await createModuleGraph(globs, {
exclude: [
/** Don't include translations in the CEM */
i => i.includes('/translations/'),
/** Don't include SVGs in the CEM */
i => i.endsWith('.svg.js'),
],
});
/**
* @param {{name: string}} a
* @param {{name: string}} b
* @returns
*/
function sortName(a, b) {
const nameA = a.name?.toUpperCase(); // ignore upper and lowercase
const nameB = b.name?.toUpperCase(); // ignore upper and lowercase
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
// names must be equal
return 0;
}
/**
* Create ts.sourceFiles from the modules in the module graph
* to pass to the CEM analyzer
*/
const modules = [];
for (const [, module] of moduleGraph.modules) {
modules.push(ts.createSourceFile(module.path, module.source, ts.ScriptTarget.ES2015, true));
}
/** Exclude information inherited from these mixins, they're generally not useful for public api */
const inheritanceDenyList = [
'ScopedElementsMixin',
'SyncUpdatableMixin',
'LocalizeMixin',
'SlotMixin',
];
const cem = create({
modules,
plugins: [
...litPlugin(),
generateCustomData(),
{
packageLinkPhase({ customElementsManifest }) {
for (const definition of customElementsManifest.modules) {
for (const declaration of definition.declarations) {
if (declaration.kind === 'class' && declaration?.members?.length) {
/**
* Filter out unwanted information from the docs
*/
declaration.members = declaration.members
.filter(
/** @param {{inheritedFrom: {name: string}}} member */ member =>
!inheritanceDenyList.includes(member.inheritedFrom?.name),
)
.sort(sortName);
/**
* Set privacy for members based on naming conventions
*/
for (const m of declaration.members) {
if (!m.privacy && !m.name?.startsWith('_') && !m.name?.startsWith('#')) {
m.privacy = 'public';
} else if (m.name?.startsWith('#') || m.name?.startsWith('__')) {
m.privacy = 'private';
} else if (!m.privacy && m.name?.startsWith('_')) {
m.privacy = 'protected';
}
}
}
}
}
},
},
],
});
fs.writeFileSync('./custom-elements.json', JSON.stringify(cem, null, 2));