import { Node } from 'unist';
import u from 'unist-builder';
import { DemoComponent, DemoComponentName } from './types';
/**
* Creates all the Nodes necessary to render a Demo Component.
*
* It will render something like the follwing:
* ```hbs
*
*
*
*
*
* Demo markdown content
*
*
*
* Code Snippet (with any highlight applied from remark)
*
*
*
* ```
*/
export function createDemoNodes(component: DemoComponent): Node[] {
const nodes: Node[] = [
u('html', ``)
];
if (component.description) {
nodes.push(
u(
'html',
``
),
component.description.ast,
u('html', '')
);
}
nodes.push(
u('html', ''),
u('html', `<${component.name.pascalCase} />`),
u('html', '')
);
if (component.chunks.length > 1) {
nodes.push(u('html', ''));
component.chunks.forEach((chunk) => {
nodes.push(
u('html', ``),
chunk.snippet,
u('html', '')
);
});
nodes.push(u('html', ''));
} else {
component.chunks.forEach((chunk) => {
nodes.push(
u('html', ``),
chunk.snippet,
u('html', '')
);
});
}
nodes.push(u('html', ''));
return nodes;
}
const MAP_LANG_TO_EXT = {
javascript: 'js',
typescript: 'ts',
handlebars: 'hbs',
'html.hbs': 'hbs',
'html.handlebars': 'hbs'
};
/*
* It returns the file extension from a lang string.
*/
export function getExt(lang: string): string {
lang = lang.toLowerCase();
return MAP_LANG_TO_EXT[lang] || lang;
}
/*
* Delete a node from a list of nodes
*/
export function deleteNode(
nodes: unknown,
nodeToDelete: Node | undefined
): void {
if (!nodeToDelete) {
return;
}
if (Array.isArray(nodes)) {
const index = nodes.findIndex((item) => item === nodeToDelete);
if (index !== -1) {
nodes.splice(index, 1);
}
}
}
/*
* Replace a node from a list of nodes
*/
export function replaceNode(
nodes: unknown,
nodeToDelete: Node,
...newNodes: Node[]
): void {
if (Array.isArray(nodes)) {
const index = nodes.findIndex((item) => item === nodeToDelete);
if (index !== -1) {
nodes.splice(index, 1, ...newNodes);
}
}
}
/*
* Generate the component name from the source path of the demo
*
* It returns both dash case and pastal case.
* The dash-case can be used for the file name and the PascalCase for the
* rendering of the component.
*/
export function generateDemoComponentName(
identifier: string,
seenNames: Set,
tentativeCount = 1
): DemoComponentName {
const dashCase = identifier
.split('.')[0]
.toLowerCase()
.replace(/\/|\\/g, '-')
.replace(/[^a-zA-Z0-9|-]/g, '');
const pascalCase = dashCase
.replace(/(\w)(\w*)/g, function (_, g1, g2) {
return `${g1.toUpperCase()}${g2.toLowerCase()}`;
})
.replace(/-/g, '');
if (seenNames.has(dashCase)) {
return generateDemoComponentName(
`${dashCase}${tentativeCount}`,
seenNames,
tentativeCount + 1
);
}
seenNames.add(dashCase);
return {
dashCase,
pascalCase
};
}
/**
* Checks if a property is of type DemoComponent[]
*/
export function isDemoComponents(
components: unknown
): components is DemoComponent[] {
if (
Array.isArray(components) &&
typeof components[0] == 'object' &&
{}.hasOwnProperty.call(components[0], 'name') &&
{}.hasOwnProperty.call(components[0], 'chunks')
) {
return true;
}
return false;
}