Last active
September 6, 2023 21:52
-
-
Save DerrikMilligan/5dbe22244ad666a2d527548424a74a1f to your computer and use it in GitHub Desktop.
Generate Wave Typescript Defintions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs') | |
const baseDocPath = './src/documentation/views/ui-components/' // 'tag/api.vue' | |
const basePath = './src/wave-ui/components/' | |
/** @type Record<string, {splitDocs: boolean, docs: string | false, file?: string}> */ | |
const components = { | |
'w-accordion': { splitDocs: false, docs: 'accordion' }, | |
'w-alert': { splitDocs: false, docs: 'alert' }, | |
'w-app': { splitDocs: false, docs: 'app' }, | |
'w-badge': { splitDocs: false, docs: 'badge' }, | |
'w-breadcrumbs': { splitDocs: false, docs: 'breadcrumbs' }, | |
'w-button': { splitDocs: false, docs: 'button', file: 'w-button/index' }, | |
'w-card': { splitDocs: false, docs: 'card' }, | |
'w-checkbox': { splitDocs: true, docs: 'checkbox' }, | |
'w-checkboxes': { splitDocs: true, docs: 'checkbox' }, | |
'w-confirm': { splitDocs: false, docs: 'confirm' }, | |
// 'w-date-picker': { splitDocs: false }, // Not a real component yet | |
'w-dialog': { splitDocs: false, docs: 'dialog' }, | |
'w-divider': { splitDocs: false, docs: 'divider' }, | |
'w-drawer': { splitDocs: false, docs: 'drawer' }, | |
'w-flex': { splitDocs: false, docs: false }, // No API docs | |
'w-form-element': { splitDocs: false, docs: false }, // No API docs | |
'w-form': { splitDocs: false, docs: 'form' }, | |
'w-grid': { splitDocs: false, docs: false }, // No API docs | |
'w-icon': { splitDocs: false, docs: 'icon' }, | |
'w-image': { splitDocs: false, docs: 'image' }, | |
'w-input': { splitDocs: false, docs: 'input' }, | |
'w-list': { splitDocs: false, docs: 'list' }, | |
'w-menu': { splitDocs: false, docs: 'menu' }, | |
'w-notification-manager': { splitDocs: true, docs: 'notification' }, | |
'w-notification': { splitDocs: true, docs: 'notification' }, | |
'w-overlay': { splitDocs: false, docs: 'overlay' }, | |
// 'w-paralax': { splitDocs: false, docs: false }, // Not a real component yet | |
'w-progress': { splitDocs: false, docs: 'progress' }, | |
'w-radio': { splitDocs: true, docs: 'radio' }, | |
'w-radios': { splitDocs: true, docs: 'radio' }, | |
'w-rating': { splitDocs: false, docs: 'rating' }, | |
// 'w-scrollable': { splitDocs: false, docs: 'scrollable' }, | |
'w-select': { splitDocs: false, docs: 'select' }, | |
'w-slider': { splitDocs: false, docs: 'slider' }, | |
// 'w-slideshow': { splitDocs: false, docs: 'slideshow' }, // Not a real component yet | |
'w-spinner': { splitDocs: false, docs: 'spinner' }, | |
'w-steps': { splitDocs: false, docs: 'steps' }, | |
'w-switch': { splitDocs: false, docs: 'switch' }, | |
'w-table': { splitDocs: false, docs: 'table' }, | |
'w-tabs': { splitDocs: false, docs: 'tabs', file: 'w-tabs/index' }, | |
'w-tag': { splitDocs: false, docs: 'tag' }, | |
'w-textarea': { splitDocs: false, docs: 'textarea' }, | |
'w-timeline': { splitDocs: false, docs: 'timeline' }, | |
'w-toolbar': { splitDocs: false, docs: 'toolbar' }, | |
'w-tooltip': { splitDocs: false, docs: 'tooltip' }, | |
'w-tree': { splitDocs: false, docs: 'tree' }, | |
} | |
function cleanComponentName(componentTag) { | |
const [_, ...pieces] = componentTag.split('-') | |
return pieces.map(piece => piece.charAt(0).toUpperCase() + piece.slice(1)).join('') | |
} | |
/** | |
* Cleans out html tags from an html description and makes them markdown styled with backticks | |
* | |
* @param {string} description | |
* @returns {string} | |
*/ | |
function cleanHtmlDescription(description) { | |
return description | |
.replace(/<code>(.*?)<\/code>/gmi, `\`$1\``) | |
.replace(/<strong.*?>(.*?)<\/strong>/gmi, `\`$1\``) | |
.replace(/<em.*?>(.*?)<\/em>/gmi, `\`$1\``) | |
.replace(/<a.*?>(.*?)<\/a>/gmi, `\`$1\``) | |
.replace(/<span.*?>(.*?)<\/span>/gmi, `\`$1\``) | |
.replace('&', '&') | |
.replace('<', '<') | |
.replace('>', '>') | |
.replace('\\', '') | |
.split('<br>') | |
.map(s => s.trim()) | |
.join('\n * ') | |
} | |
/** | |
* Attempt to build a typescript union type from an array of javascript types | |
* | |
* @param {Array<string>} types - An array of javascript types as strings | |
* @returns {string} the typescript type | |
*/ | |
function buildTypeScriptType(types) { | |
if (Array.isArray(types) === false || types.length === 0) { | |
return 'any' | |
} | |
return types.reduce((acc, type, index) => { | |
if (type === 'String') { | |
acc += 'string' | |
} else if (type === 'Number') { | |
acc += 'number' | |
} else if (type === 'Boolean') { | |
acc += 'boolean' | |
} else if (type === 'Array') { | |
acc += 'Array<any>' | |
} else if (type === 'Object') { | |
acc += '{}' | |
} else if (type instanceof String) { | |
acc += `'${type}'` | |
} | |
if ((index + 1) < types.length) { | |
acc += '|' | |
} | |
return acc | |
}, '') | |
} | |
const propsRegex = new RegExp('\\s+(\\S+):\\s+{\\n?\\s*(type:\\s\\[?(.*?)\\]?)?,?\\n?\\s*?(default:\\s+(.*?)\\s+)?\\s*(required:\\s+(true|false)\\s+)?\\s*?},?\\s*(\\/\\/.*)?$', 'gm') | |
const propsDescriptionRegex = new RegExp("\\s+(\\S+):\\s+'(.*?)',?$", 'gm') | |
/** | |
* Extract props from a component file and an apiFile | |
* | |
* @param {string} componentFile - The body of the component file | |
* @param {string} apiFile - The body of the API documentation file | |
* @returns {Array<{name: string, types: Array<string>, default: any, required: boolean, description: string}>} | |
*/ | |
function extractProps(componentFile, apiFile) { | |
const propsDescriptions = [ | |
...apiFile | |
.split(/propsDescs\s?[=:] {/i)[1] | |
?.split('}')[0] | |
?.matchAll(propsDescriptionRegex) || [], | |
].map(matches => ({ | |
name : matches[1], | |
description: matches[2], | |
})) | |
const props = [ ...componentFile.matchAll(propsRegex) ] | |
return props | |
.map(match => { | |
// Remove the entry containing the enitre everything | |
match.splice(0, 1) | |
// Base props object, pieces 0 will always be the prop name | |
const prop = { | |
name : match[0], | |
types : [], | |
default : undefined, | |
required : false, | |
description: '', | |
} | |
let index = match.findIndex(piece => piece && piece.includes('type')) | |
if (index !== -1 && match[index + 1]) { | |
prop.types = match[index + 1].split(',').map(s => s.trim()) | |
} | |
index = match.findIndex(piece => piece && piece.includes('default')) | |
if (index !== -1 && match[index + 1]) { | |
prop.default = match[index + 1] | |
} | |
index = match.findIndex(piece => piece && piece.includes('required')) | |
if (index !== -1 && match[index + 1]) { | |
prop.required = !!match[index + 1] | |
} | |
index = match.findIndex(piece => piece && piece.includes('//')) | |
if (index !== -1 && match[index + 1]) { | |
prop.description = match[index + 1] | |
} | |
const apiDescription = propsDescriptions.find(p => p.name === prop.name)?.description ?? '' | |
if (apiDescription !== undefined) { | |
prop.description = apiDescription | |
} | |
return prop | |
}) | |
} | |
/** | |
* Build a typescript interface for a given components props | |
* | |
* @param {string} component - The component name: eg: w-tag | |
* @param {Array<{name: string, types: Array<string>, default: any, required: boolean, description: string}>} props - All the prop information | |
* @returns {string} The typescript interface | |
*/ | |
function buildPropsTypescriptDefinitions(component, props) { | |
const properComponentName = cleanComponentName(component) | |
let output = `export interface Wave${properComponentName}Props {\n` | |
for (const prop of props) { | |
const types = buildTypeScriptType(prop.types) | |
let links = [ ...prop.description?.match(/href=".*?"/gmi) ?? [] ] | |
.map(href => href.split('"')[1]) | |
.map(link => `\n * @see https://antoniandre.github.io/wave-ui/${link}`) | |
.join('') | |
const description = cleanHtmlDescription(prop.description) | |
const defaults = prop.default !== undefined | |
? ` - Default: ${prop.default}` | |
: '' | |
const propBody = ` /** | |
* ${description.length > 0 ? description : 'TODO: Add Description'} | |
* @property {${types}} ${prop.required ? '[' : ''}${prop.name}${prop.required ? ']' : ''}${defaults} | |
* @see https://antoniandre.github.io/wave-ui/${component}${links} | |
*/ | |
${prop.name}${prop.required ? '' : '?'}: ${types}\n\n` | |
output += propBody | |
} | |
output += `}\n` | |
return output | |
} | |
/** | |
* Extract emits from a component file and an apiFile | |
* | |
* @param {string} componentFile - The body of the component file | |
* @param {string} apiFile - The body of the API documentation file | |
* @returns {Array<{name: string, description: string, params: Record<string, string>}>} | |
*/ | |
function extractEmits(componentFile, apiFile) { | |
if (componentFile.includes('emits') === false) { | |
return [] | |
} | |
/** @type Array<string> */ | |
const emitDeclarations = JSON.parse('[' + componentFile.split('emits: [')[1].split(']')[0].replace(/'/g, '"') + ']') | |
// Super ghetto and potentially dangerous... But it works | |
/** @type Record<string, { description?: string, params?: Array<Record<string, string>>}> */ | |
let emitDescriptions = apiFile.replace('eventsDescs = {', 'events = {').split('events = {') || [] | |
if (Array.isArray(emitDescriptions) && emitDescriptions.length > 1 && emitDescriptions[1].length > 0 && emitDescriptions[1][0] !== '}') { | |
emitDescriptions = emitDescriptions[1].split('\n}') | |
if (Array.isArray(emitDescriptions) && emitDescriptions.length > 0) { | |
emitDescriptions = eval(`({${emitDescriptions[0]}})`) | |
} | |
} | |
const emits = emitDeclarations.map(emitName => { | |
const description = Object.prototype.hasOwnProperty.call(emitDescriptions, emitName) ? emitDescriptions[emitName] : null | |
const emit = { | |
name: emitName, | |
...description, | |
} | |
emit.description = emit.description ?? '' | |
emit.params = emit.params ?? {} | |
emit.params = Object.keys(emit.params).reduce((acc, param) => { | |
// eslint-disable-next-line no-useless-escape | |
acc[param.replace(/[\[\]]/ig, '')] = emit.params[param] | |
return acc | |
}, {}) | |
return emit | |
}) | |
return emits | |
} | |
/** | |
* Build a typescript interface for a given components emits | |
* | |
* @param {string} component - The component name: eg: w-tag | |
* @param {Array<{name: string, description: string, params: Record<string, string>}>} emits - All the emit information | |
* @returns {string} The typescript interface | |
*/ | |
function buildEmitsTypescriptDefinitions(component, emits) { | |
const properComponentName = cleanComponentName(component) | |
let output = `export interface Wave${properComponentName}Emits {\n` | |
for (const emit of emits) { | |
let methodName = emit.name.replace(/-(.)/ig, (_, char) => char.toUpperCase()) | |
methodName = `on${methodName.charAt(0).toUpperCase()}${methodName.slice(1)}` | |
const methodDefParams = Object.keys(emit.params) | |
.map((param, index) => `renameMe${index + 1}: ${buildTypeScriptType(param)}`) | |
.join(', ') | |
const methodDef = `'${methodName}'?: (${methodDefParams}) => void` | |
const jsdocParams = Object.keys(emit.params) | |
.map((param, index) => `\n * @param {${buildTypeScriptType(param)}} renameMe${index + 1}${emit.params[param] ? ' - ' + emit.params[param] : '' }`) | |
.join('') | |
const emitBody = ` /** | |
* ${emit.description.length > 0 ? emit.description : 'TODO: Add Description'}${jsdocParams} | |
* @see https://antoniandre.github.io/wave-ui/${component} | |
*/ | |
${methodDef}\n\n` | |
output += emitBody | |
} | |
output += `}\n` | |
return output | |
} | |
const computedDefRegex = new RegExp('((?:^\\s+(\\w+)\\s?\\(.*?\\)\\s*?{)+)', 'gm') | |
/** | |
* Extract computed properties from a component file and an apiFile | |
* | |
* @param {string} componentFile - The body of the component file | |
* @param {string} apiFile - The body of the API documentation file | |
* @returns {Array<{name: string>} | |
*/ | |
function extractComputed(componentFile, apiFile) { | |
if (componentFile.includes('computed') === false) { | |
return [] | |
} | |
const computedSection = componentFile.split('computed: {')[1].split('\n }')[0] | |
const computedDeclarations = [ ...computedSection.matchAll(computedDefRegex) ] | |
.filter(matches => matches[2] !== 'if' && matches[2] !== 'switch' && matches[2] !== 'for') | |
.map(matches => ({ name: matches[2] })) | |
return computedDeclarations | |
} | |
/** | |
* Build a typescript interface for a given components computed items | |
* | |
* @param {string} component - The component name: eg: w-tag | |
* @param {Array<{name: string>} computeds - All the computed information | |
* @returns {string} The typescript interface | |
*/ | |
function buildComputedTypescriptDefinitions(component, computeds) { | |
const properComponentName = cleanComponentName(component) | |
let output = `export interface Wave${properComponentName}Computeds extends ComputedOptions {\n` | |
for (const computed of computeds) { | |
const computedBody = ` /** | |
* TODO: Add Description | |
* @see https://antoniandre.github.io/wave-ui/${component} | |
*/ | |
${computed.name}: ComputedGetter<any>\n\n` | |
output += computedBody | |
} | |
output += `}\n` | |
return output | |
} | |
const methodsDefRegex = new RegExp('((?:^\\s+(\\w+)\\s?\\((.*?)\\)\\s*?{)+)', 'gm') | |
/** | |
* Extract methods from a component file and an apiFile | |
* | |
* @param {string} componentFile - The body of the component file | |
* @param {string} apiFile - The body of the API documentation file | |
* @returns {Array<{name: string, params: Array<{name: string, default: string | undefined}>>} | |
*/ | |
function extractMethods(componentFile, apiFile) { | |
if (componentFile.includes('methods') === false) { | |
return [] | |
} | |
const methodsSection = componentFile.split('methods: {')[1].split('\n }')[0] | |
const methodDeclarations = [ ...methodsSection.matchAll(methodsDefRegex) ] | |
.filter(matches => matches[2] !== 'if' && matches[2] !== 'for') | |
.map(matches => ({ | |
name: matches[2], | |
params: (matches[3] || '') | |
.split(',') | |
?.map(param => param.trim()) | |
?.filter(param => param.length > 0) | |
?.map(param => { | |
const pieces = param.split('=').map(p => p.trim()) | |
return pieces.length > 1 ? { name: pieces[0], default: pieces[1] } : { name: pieces[0], default: undefined } | |
}) || [] | |
})) | |
return methodDeclarations | |
} | |
/** | |
* Build a typescript interface for a given components methods | |
* | |
* @param {string} component - The component name: eg: w-tag | |
* @param {Array<{name: string, params: Array<{name: string, default: string | undefined}>>} methods - All the method information | |
* @returns {string} The typescript interface | |
*/ | |
function buildMethodsTypescriptDefinitions(component, methods) { | |
const properComponentName = cleanComponentName(component) | |
let output = `export interface Wave${properComponentName}Methods extends MethodOptions {\n` | |
for (const method of methods) { | |
const methodDefParams = method.params | |
.map(param => `${param.name}${param.default !== undefined ? '?' : ''}: any`) | |
.join(', ') | |
const methodDef = `${method.name}(${methodDefParams}): void` | |
const jsdocParams = method.params | |
.map(param => `\n * @param {any} ${param.default !== undefined ? '[' : ''}${param.name}${param.default !== undefined ? `] - ${param.default}` : ''}`) | |
.join('') | |
const methodBody = ` /** | |
* TODO: Add Description${jsdocParams} | |
* @see https://antoniandre.github.io/wave-ui/${component} | |
*/ | |
${methodDef}\n\n` | |
output += methodBody | |
} | |
output += `}\n` | |
return output | |
} | |
const slotDefRegex = new RegExp('((?:^\\s+slot(\\(((.|\\n)*?)\\)(\\n|\\s))?)+)', 'igm') | |
const extractAttributesRegex = new RegExp(':?(\\S+)="(.*?)"', 'igm') | |
/** | |
* Extract slots from a component file and an apiFile | |
* | |
* @param {string} componentFile - The body of the component file | |
* @param {string} apiFile - The body of the API documentation file | |
* @returns {Array<{name: string, description: string, params: Record<string, string>>} | |
*/ | |
function extractSlots(componentFile, apiFile) { | |
if (componentFile.includes('slot') === false) { | |
return [] | |
} | |
const templateSection = componentFile.split(/<template.*?>/i)[1].split('</template>')[0] | |
// Super ghetto and potentially dangerous... But it works | |
/** @type Record<string, { description?: string, params?: Array<Record<string, string>>}> */ | |
let slotDescriptions = apiFile.split(/slots\s?[:=] {/) || [] | |
if (Array.isArray(slotDescriptions) && slotDescriptions.length > 1 && slotDescriptions[1][0] !== '}') { | |
let pieces = slotDescriptions[1].split('\n}') | |
if (Array.isArray(pieces) && pieces.length > 1) { | |
slotDescriptions = eval(`({${pieces[0]}})`) | |
} | |
} | |
const slots = [ ...templateSection.matchAll(slotDefRegex) ] | |
.map(matches => { | |
const attributes = matches[3] !== undefined ? [ ...matches[3].matchAll(extractAttributesRegex) ] : [] | |
const name = (attributes.find(m => m[1].includes('name')) || [ 0, 0, 'default' ])[2].replace(/\${i.*?}/i, 'x').replace(/`/g, '') | |
const params = attributes | |
.filter(m => m[1].includes('v-') === false) | |
.filter(m => m[1].includes('name') === false) | |
.map(m => m[1]) | |
const description = Object.prototype.hasOwnProperty.call(slotDescriptions, name) ? slotDescriptions[name] : null | |
const slot = { name, ...description } | |
slot.description = slot.description ?? '' | |
slot.params = slot.params ?? {} | |
// Add any potentially missing slot params | |
for (const param of params) { | |
if (Object.prototype.hasOwnProperty.call(slot.params, param) === false) { | |
slot.params[param] = 'TODO: Describe me!' | |
} | |
} | |
return slot | |
}) | |
// Remove the duplicate items... | |
return [ ...new Set(slots.map(s => s.name)) ].map(name => { | |
const matchingSlot = slots.find(s => s.name === name) | |
return { | |
name, | |
params: matchingSlot.params, | |
description: matchingSlot.description, | |
} | |
}) | |
} | |
/** | |
* Build a typescript interface for a given components slots | |
* | |
* @param {string} component - The component name: eg: w-tag | |
* @param {Array<{name: string, description: string, params: Record<string, string>>} slots - All the slot information | |
* @returns {string} The typescript interface | |
*/ | |
function buildSlotsTypescriptDefinitions(component, slots) { | |
const properComponentName = cleanComponentName(component) | |
let output = `export type Wave${properComponentName}Slots = SlotsType<{\n` | |
let dynamicSlotDefs = '' | |
for (const slot of slots) { | |
const paramNames = Object.keys(slot.params) | |
const slotParams = paramNames | |
.map(param => `${param}: any`) | |
.join(', ') | |
const methodDef = `(${paramNames.length > 0 ? `_: { ${slotParams} }` : ''}) => any` | |
const jsdocParams = paramNames | |
.map(paramName => `\n * @param {any} ${paramName}${slot.params[paramName].length > 0 ? ` ${cleanHtmlDescription(slot.params[paramName])}` : ''}`) | |
.join('') | |
const slotDescription = ` /** | |
* ${slot.description?.length > 0 ? cleanHtmlDescription(slot.description) : 'TODO: Add Description'}${jsdocParams} | |
* @see https://antoniandre.github.io/wave-ui/${component} | |
*/` | |
output += `${slotDescription}\n '${slot.name}': ${methodDef}\n\n` | |
if (slot.name.includes('.x')) { | |
const cleanName = slot.name.replace('.x', '') | |
dynamicSlotDefs += `} & {\n${slotDescription}\n [k in \`${cleanName}\${number}\`]: ${methodDef}\n` | |
} | |
} | |
output += `${dynamicSlotDefs}}>\n` | |
return output | |
} | |
/** | |
* Build a full typescript declaration file for a given component | |
* | |
* @async | |
* @param {string} component - Component name | |
* @param {boolean} splitDocs - Whether the documentation is shared between multiple components | |
*/ | |
function buildFullComponentDefinition(component, splitDocs) { | |
const componentPath = components[component].file !== undefined | |
? `${basePath}${components[component].file}.vue` | |
: `${basePath}${component}.vue` | |
const componentFile = fs.readFileSync(componentPath, 'utf8') | |
let componentApiFile = components[component].docs | |
? fs.readFileSync(`${baseDocPath}${components[component].docs}/api.vue`, 'utf8') | |
: '' | |
const properComponentName = cleanComponentName(component) | |
if (splitDocs) { | |
let pieces = componentApiFile.split(`${component.split('-')[1]} = {`) | |
if (pieces && pieces.length > 1) { | |
pieces = pieces[1].split('\n}') | |
if (pieces && pieces.length > 0) { | |
componentApiFile = pieces[0].replace(/^\s\s/igm, '') | |
} | |
} | |
} | |
const props = extractProps(componentFile, componentApiFile) | |
const propsTypescriptDef = buildPropsTypescriptDefinitions(component, props) | |
const emits = extractEmits(componentFile, componentApiFile) | |
const emitsTypescriptDef = buildEmitsTypescriptDefinitions(component, emits) | |
const computeds = extractComputed(componentFile, componentApiFile) | |
const computedTypescriptDef = buildComputedTypescriptDefinitions(component, computeds) | |
const methods = extractMethods(componentFile, componentApiFile) | |
const methodsTypescriptDef = buildMethodsTypescriptDefinitions(component, methods) | |
const slots = extractSlots(componentFile, componentApiFile) | |
const slotsTypescriptDef = buildSlotsTypescriptDefinitions(component, slots) | |
return `/* eslint-disable no-unused-vars */ | |
/* eslint-disable @typescript-eslint/no-explicit-any */ | |
/* eslint-disable @typescript-eslint/ban-types */ | |
import { | |
ComputedGetter, | |
ComputedOptions, | |
DefineComponent, | |
EmitsOptions, | |
ExtractDefaultPropTypes, | |
MethodOptions, | |
SlotsType | |
} from 'vue' | |
import { | |
PublicProps, | |
ResolveProps | |
} from '../extra-vue-types' | |
// ---------------------------------------------------------------------------- | |
// Props | |
// ---------------------------------------------------------------------------- | |
${propsTypescriptDef} | |
// ---------------------------------------------------------------------------- | |
// Emits | |
// ---------------------------------------------------------------------------- | |
${emitsTypescriptDef} | |
// ---------------------------------------------------------------------------- | |
// Computeds | |
// ---------------------------------------------------------------------------- | |
${computedTypescriptDef} | |
// ---------------------------------------------------------------------------- | |
// Methods | |
// ---------------------------------------------------------------------------- | |
${methodsTypescriptDef} | |
// ---------------------------------------------------------------------------- | |
// Slots | |
// ---------------------------------------------------------------------------- | |
${slotsTypescriptDef} | |
// ---------------------------------------------------------------------------- | |
// Component | |
// ---------------------------------------------------------------------------- | |
export type W${properComponentName} = DefineComponent< | |
Wave${properComponentName}Props, | |
{}, | |
{}, | |
Wave${properComponentName}Computeds, | |
Wave${properComponentName}Methods, | |
{}, | |
{}, | |
Wave${properComponentName}Emits & EmitsOptions, | |
string, | |
PublicProps, | |
ResolveProps<Wave${properComponentName}Props & Wave${properComponentName}Emits, EmitsOptions>, | |
ExtractDefaultPropTypes<Wave${properComponentName}Props>, | |
Wave${properComponentName}Slots | |
> | |
` | |
} | |
function main() { | |
for (const component of Object.keys(components)) { | |
const properComponentName = cleanComponentName(component) | |
const typedefs = buildFullComponentDefinition(component, components[component].splitDocs) | |
const path = `./src/@types/components/W${properComponentName}.ts` | |
fs.stat(path, (err, stat) => { | |
if (err === null) { | |
fs.rmSync(path) | |
} | |
fs.writeFileSync(path, typedefs) | |
}) | |
} | |
const path = `./src/@types/components/index.ts` | |
fs.stat(path, (err, stat) => { | |
if (err === null) { | |
fs.rmSync(path) | |
} | |
fs.writeFileSync(path, Object.keys(components) | |
.map(component => { | |
const properComponentName = cleanComponentName(component) | |
return `export { W${properComponentName} } from './W${properComponentName}'` | |
}) | |
.join('\n') + '\n' | |
) | |
}) | |
} | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment