const TypeDoc = require('typedoc'); const path = require('path'); const fs = require('fs'); const rootDir = path.resolve(__dirname, '../'); const outputPath = path.resolve(rootDir, 'doc/common/apidoc'); const staticMessages = { methods: "Defines methods that can be accessed by the component's reference.", emits: 'Defines emit that determine the behavior of the component based on a given condition or report the actions that the component takes.', slots: 'Defines the slots used by the component.', functions: 'Defines the custom functions used by the module.', events: "Defines the custom events used by the component's emit.", interfaces: 'Defines the custom interfaces used by the module.', types: 'Defines the custom types used by the module.', tokens: 'Define design tokens used by the component.' }; const app = new TypeDoc.Application(); // If you want TypeDoc to load tsconfig.json / typedoc.json files app.options.addReader(new TypeDoc.TSConfigReader()); app.options.addReader(new TypeDoc.TypeDocReader()); app.bootstrap({ // typedoc options here name: 'PrimeVue', entryPoints: [`components/lib/`], entryPointStrategy: 'expand', hideGenerator: true, excludeExternals: true, includeVersion: true, searchInComments: true, disableSources: true, logLevel: 'Error', sort: ['source-order'], exclude: ['node_modules', 'components/lib/**/*.js'] }); const project = app.convert(); if (project) { const doc = {}; const parseText = (text) => { return text.replace(/{/g, '{').replace(/}/g, '}'); }; project.children.forEach((module) => { const { name, comment } = module; const description = comment && comment.summary.map((s) => s.text || '').join(' '); doc[name] = { description }; const module_component_group = module.groups?.find((g) => g.title === 'Component'); let methods = { description: staticMessages['methods'], values: [] }; module_component_group && module_component_group.children.forEach((component) => { const description = component.comment && component.comment.summary .map((s) => { const text = s.text || ''; const splittedText = text.split('_'); return splittedText[1] ? splittedText[1] : text; }) .join(' '); !doc[name]['components'] && (doc[name]['components'] = {}); const component_method_group = component.groups && component.groups.find((g) => g.title === 'Methods'); component_method_group && component_method_group.children.forEach((method) => { const signature = method.getAllSignatures()[0]; methods.values.push({ name: signature.name, parameters: signature.parameters.map((param) => { return { name: param.name, type: param.type.toString(), description: param.comment && param.comment.summary.map((s) => s.text || '').join(' ') }; }), returnType: signature.type.toString(), description: signature.comment && signature.comment.summary.map((s) => s.text || '').join(' ') }); }); const component_props_id = component.extendedTypes && component.extendedTypes[0].typeArguments && component.extendedTypes[0].typeArguments[0] && component.extendedTypes[0].typeArguments[0]._target; const module_properties_group = module.groups.find((g) => g.title === 'Properties'); const component_props = module_properties_group && module_properties_group.children.find((c) => (component_props_id ? c.id === component_props_id : true)); const props = { description: '', values: [] }; const emit = { description: staticMessages['emit'], values: [] }; if (component_props) { props.description = component_props.comment ? component_props.comment.summary.map((s) => parseText(s.text || '')).join(' ') : ''; const component_props_group = component_props.groups && component_props.groups.find((g) => g.title === 'Properties'); component_props_group && component_props_group.children.forEach((prop) => { if (!prop.inheritedFrom || (prop.inheritedFrom && !prop.inheritedFrom.toString().startsWith('Omit.data-pr-'))) { props.values.push({ name: prop.name, optional: prop.flags.isOptional, readonly: prop.flags.isReadonly, type: prop.type.toString(), default: prop.comment && prop.comment.getTag('@defaultValue') ? parseText(prop.comment.getTag('@defaultValue').content[0]?.text || '') : '', // TODO: Check description: prop.comment && prop.comment.summary.map((s) => parseText(s.text || '')).join(' '), deprecated: prop.comment && prop.comment.getTag('@deprecated') ? parseText(prop.comment.getTag('@deprecated').content[0]?.text) : undefined }); } }); const component_props_methods_group = component_props.groups && component_props.groups.find((g) => g.title === 'Methods'); component_props_methods_group && component_props_methods_group.children.forEach((method) => { const signature = method.getAllSignatures()[0]; methods.values.push({ name: signature.name, parameters: signature.parameters.map((param) => { return { name: param.name, optional: param.flags.isOptional, type: param.type.toString(), description: param.comment && param.comment.summary.map((s) => parseText(s.text || '')).join(' ') }; }), returnType: signature.type.toString(), description: signature.comment.summary.map((s) => parseText(s.text || '')).join(' ') }); }); } doc[name]['components'][component.name] = { description, methods }; }); const module_model_group = module.groups?.find((g) => g.title === 'Model'); module_model_group && module_model_group.children.forEach((model) => { const event_props_description = model.comment && model.comment.summary.map((s) => s.text || '').join(' '); !doc[name]['model'] && (doc[name]['model'] = {}); const props = { description: '', values: [] }; const methods = { description: '', values: [] }; const model_props_group = model.groups.find((g) => g.title === 'Properties'); model_props_group && model_props_group.children.forEach((prop) => { props.values.push({ name: prop.name, optional: prop.flags.isOptional, readonly: prop.flags.isReadonly, type: prop.type.toString(), default: prop.comment && prop.comment.getTag('@defaultValue') ? prop.comment.getTag('@defaultValue').content[0]?.text || '' : '', // TODO: Check description: prop.comment && prop.comment.summary.map((s) => s.text || '').join(' ') }); }); const model_methods_group = model.groups.find((g) => g.title === 'Methods'); model_methods_group && model_methods_group.children.forEach((method) => { const signature = method.getAllSignatures()[0]; const isSlot = model.name.includes('Slots'); methods.values.push({ name: signature.name, parameters: signature.parameters.map((param) => { let type = param.type.toString(); if (param.type.declaration && isSlot) { type = ''; if (param.type.declaration.children) { param.type.declaration.children.forEach((child) => { if (child.signatures) { const childSinature = child.signatures[0]; const parameters = childSinature.parameters.reduce((acc, { name, type }, index) => (index === 0 ? `${name}: ${type.name}` : `${acc}, ${name}: ${type.name}`), ''); type += ` \t ${childSinature.name}(${parameters}): ${childSinature.type?.name}, // ${childSinature.comment?.summary[0]?.text}\n `; } else { const childType = child.type.elementType ? child.type.elementType.name : child.type.name; type += ` \t ${child.name}: ${childType}, // ${child.comment?.summary[0]?.text}\n `; } }); } type = `{\n ${type} }`; } return { name: param.name, optional: param.flags.isOptional, type: type, description: param.comment && param.comment.summary.map((s) => parseText(s.text || '')).join(' ') }; }), returnType: signature.type.toString(), description: signature.comment && signature.comment.summary.map((s) => parseText(s.text || '')).join(' '), deprecated: signature.comment && signature.comment.getTag('@deprecated') ? parseText(signature.comment.getTag('@deprecated').content[0]?.text) : undefined }); }); doc[name]['model'][model.name] = { description: event_props_description, props, methods }; }); const module_functions_group = module.groups?.find((g) => g.title === 'Functions'); module_functions_group && module_functions_group.children.forEach((method) => { !doc[name]['functions'] && (doc[name]['functions'] = { description: staticMessages['functions'], values: {} }); const signatures = method.getAllSignatures(); if (signatures && signatures.length > 0) { const signature = signatures[0]; doc[name]['functions'].values[method.name] = { name: signature.name, parameters: signature.parameters.map((param) => { return { name: param.name, type: param.type.toString(), description: param.comment && param.comment.summary.map((s) => s.text || '').join(' ') }; }), returnType: signature.type.toString(), description: signature.comment && signature.comment.summary.map((s) => s.text || '').join(' ') }; } }); const module_events_group = module.groups?.find((g) => g.title === 'Events'); module_events_group && module_events_group.children.forEach((event) => { const event_props_description = event.comment && event.comment.summary.map((s) => s.text || '').join(' '); const component_prop = event.comment && event.comment.getTag('@see') ? event.comment.getTag('@see').content[0]?.text || '' : ''; // TODO: Check const event_extendedBy = event.extendedBy && event.extendedBy.toString(); !doc[name]['events'] && (doc[name]['events'] = { description: staticMessages['events'], values: {} }); const props = []; const event_props_group = event.groups.find((g) => g.title === 'Properties'); event_props_group && event_props_group.children.forEach((prop) => { props.push({ name: prop.name, optional: prop.flags.isOptional, readonly: prop.flags.isReadonly, type: prop.type.toString(), //default: prop.comment && prop.comment.getTag('@defaultValue') ? prop.comment.getTag('@defaultValue').content[0].text : '', // TODO: Check description: prop.comment && prop.comment.summary.map((s) => s.text || '').join(' ') }); }); doc[name]['events'].values[event.name] = { description: event_props_description, relatedProp: component_prop, props, extendedBy: event_extendedBy }; }); const module_interfaces_group = module.groups?.find((g) => g.title === 'Interfaces'); module_interfaces_group && module_interfaces_group.children.forEach((event) => { const event_props_description = event.comment && event.comment.summary.map((s) => s.text || '').join(' '); let component_prop = ''; if (event.comment && event.comment.getTag('@see')) { const tag = event.comment.getTag('@see'); const content = tag.content[0]; if (content.text.includes("['")) { component_prop = `${content.target.name}${content.text}`; } else { component_prop = `${content.text === content.target?.name ? content.target.parent.name : content.target?.name}.${content.text}`; } } const event_extendedBy = event.extendedBy && event.extendedBy.toString(); const event_extendedTypes = event.extendedTypes && event.extendedTypes.toString(); !doc[name]['interfaces'] && (doc[name]['interfaces'] = { description: staticMessages['interfaces'], eventDescription: staticMessages['events'], methodDescription: staticMessages['methods'], typeDescription: staticMessages['types'], values: {} }); const props = []; const methods = []; if (event.groups) { const event_props_group = event.groups.find((g) => g.title === 'Properties'); event_props_group && event_props_group.children.forEach((prop) => { props.push({ name: prop.name, optional: prop.flags.isOptional, readonly: prop.flags.isReadonly, type: prop.type.toString(), default: prop.comment && prop.comment.getTag('@defaultValue') ? prop.comment.getTag('@defaultValue').content[0]?.text || '' : '', // TODO: Check description: prop.comment && prop.comment.summary .map((s) => { if (s.text.indexOf('[here]') > -1) { return `${s.text.slice(0, s.text.indexOf('[here]'))} here ${s.text.slice(s.text.indexOf(')') + 1)}`; } return s.text || ''; }) .join(' '), deprecated: prop.comment && prop.comment.getTag('@deprecated') ? parseText(prop.comment.getTag('@deprecated').content[0]?.text) : undefined }); }); const event_methods_group = event.groups.find((g) => g.title === 'Methods'); event_methods_group && event_methods_group.children.forEach((method) => { const signature = method.getAllSignatures()[0]; const isSlot = event.name.includes('Slots'); methods.push({ name: signature.name, parameters: signature.parameters.map((param) => { let type = param.type.toString(); if (param.type.declaration && isSlot) { type = ''; if (param.type.declaration.children) { param.type.declaration.children.forEach((child) => { if (child.signatures) { const childSinature = child.signatures[0]; const parameters = childSinature.parameters.reduce((acc, { name, type }, index) => (index === 0 ? `${name}: ${type.name}` : `${acc}, ${name}: ${type.name}`), ''); type += ` \t ${childSinature.name}(${parameters}): ${childSinature.type?.name}, // ${childSinature.comment?.summary[0]?.text}\n `; } else { if (child.type?.declaration?.signatures) { let functionParameters = ''; child.type?.declaration?.signatures[0]?.parameters.map((param, index) => { if (index !== 0) functionParameters += `, `; functionParameters += `${param.name}: ${param.type?.name}`; }); if (child.type?.declaration?.signatures[0]?.comment?.getTag('@deprecated')?.content[0]?.text) { type += `\t ${child.name}: (${functionParameters}) ⇒ ${child.type?.declaration?.signatures[0]?.type?.name}, // ${child.type?.declaration?.signatures[0]?.comment.summary[0]?.text}\n`; } else { type += `\t ${child.name}: (${functionParameters}) ⇒ ${child.type?.declaration?.signatures[0]?.type?.name}, // ${child.type?.declaration?.signatures[0]?.comment.summary[0]?.text}\n`; } } else { const childType = child.type.elementType ? child.type.elementType.name : child.type.name; type += ` \t ${child.name}: ${childType}, // ${child.comment?.summary[0]?.text}\n `; } } }); } type = `{\n ${type}}`; } return { name: param.name, optional: param.flags.isOptional, type: type, description: param.comment && param.comment.summary.map((s) => parseText(s.text || '')).join(' ') }; }), returnType: signature.type.toString(), description: signature.comment && signature.comment.summary.map((s) => parseText(s.text || '')).join(' '), deprecated: signature.comment && signature.comment.getTag('@deprecated') ? parseText(signature.comment.getTag('@deprecated').content[0]?.text) : undefined }); }); } const signature = event.getAllSignatures(); if (signature && signature.length > 0) { const parameter = signature[0].parameters[0]; props.push({ name: `[${parameter.name}: ${parameter.type.toString()}]`, optional: parameter.flags.isOptional, readonly: parameter.flags.isReadonly, type: signature[0].type.toString(), //default: prop.comment && prop.comment.getTag('@defaultValue') ? prop.comment.getTag('@defaultValue').content[0].text : '', // TODO: Check description: signature[0].comment && signature[0].comment.summary.map((s) => s.text || '').join(' ') }); } doc[name]['interfaces'].values[event.name] = { description: event_props_description, relatedProp: component_prop, props, methods, extendedBy: event_extendedBy, extendedTypes: event_extendedTypes }; }); const module_enumerations_group = module.groups?.find((g) => g.title === 'Enumerations'); module_enumerations_group && module_enumerations_group.children.forEach((event) => { const event_props_description = event.comment && event.comment.summary.map((s) => s.text || '').join(' '); !doc[name]['enumerations'] && (doc[name]['enumerations'] = { description: staticMessages['enumerations'], values: {} }); const members = []; if (event.groups) { const event_members_group = event.groups.find((g) => g.title === 'Enumeration Members'); event_members_group && event_members_group.children.forEach((prop) => { members.push({ name: prop.name, optional: prop.flags.isOptional, readonly: prop.flags.isReadonly, value: prop.type.toString(), description: prop.comment && prop.comment.summary .map((s) => { if (s.text.indexOf('[here]') > -1) { return `${s.text.slice(0, s.text.indexOf('[here]'))} here ${s.text.slice(s.text.indexOf(')') + 1)}`; } return s.text || ''; }) .join(' '), deprecated: prop.comment && prop.comment.getTag('@deprecated') ? parseText(prop.comment.getTag('@deprecated').content[0]?.text) : undefined }); }); } doc[name]['enumerations'].values[event.name] = { description: event_props_description, members }; }); const module_types_group = module.groups?.find((g) => g.title === 'Type Aliases'); module_types_group && module_types_group.children.forEach((event) => { const event_props_description = event.comment && event.comment.summary.map((s) => s.text || '').join(' '); !doc[name]['types'] && (doc[name]['types'] = { description: staticMessages['types'], values: {} }); let values = event.type.toString(); if (values.includes('Function') && event.type.types) { values = ''; for (const [i, type] of event.type.types.entries()) { if (type.declaration && type.declaration.signatures) { const signature = type.declaration.signatures[0]; const parameters = signature.parameters.reduce((acc, { name, type }, index) => (index === 0 ? `${name}: ${type.name}` : `${acc}, ${name}: ${type.name}`), ''); values += i === 0 ? `(${parameters}) => ${signature.type?.name}` : ` | (${parameters}) => ${signature.type?.name}`; } else { const typeName = type.name || type.value; values += i === 0 ? `${typeName}` : ` | ${typeName}`; } } } const declaration = event.type.declaration; if (declaration) { const groups = declaration.groups && declaration.groups.find((g) => g.title === 'Properties'); const map = {}; groups && groups.children.forEach((prop) => { const description = prop.comment && prop.comment.summary.map((s) => s.text || '').join(' '); map[`${prop.name}${prop.flags.isOptional ? '?' : ''}`] = `${prop.type.toString()}, ${description ? '// ' + description : ''}`; }); values = JSON.stringify(map, null, 4); } doc[name]['types'].values[event.name] = { values, description: event_props_description }; }); const module_namespaces_group = module.groups?.find((g) => g.title === 'Namespaces'); module_namespaces_group && module_namespaces_group.children.forEach((pevent) => { const module_interfaces_group = pevent?.groups?.find((g) => g.title === 'Interfaces'); module_interfaces_group && module_interfaces_group.children.forEach((event) => { const event_props_description = event.comment && event.comment.summary.map((s) => s.text || '').join(' '); let component_prop = ''; if (event.comment && event.comment.getTag('@see')) { const tag = event.comment.getTag('@see'); const content = tag.content[0]; if (content.text.includes("['")) { component_prop = `${content.target.name}${content.text}`; } else { component_prop = `${content.text === content.target?.name ? content.target.parent.name : content.target?.name}.${content.text}`; } } !doc[name]['tokens'] && (doc[name]['tokens'] = { description: staticMessages['tokens'], values: {} }); const props = []; const setProps = (_declaration, _name) => { if (_declaration?.groups) { const event_props_group = _declaration.groups.find((g) => g.title === 'Properties'); event_props_group && event_props_group.children.forEach((prop) => { if (prop.type?.declaration) { setProps(prop.type?.declaration, prop.name); } else if (prop.comment?.getTag('@designToken')) { props.push({ name: _name ? `${_name}.${prop.name}` : prop.name, token: prop.comment.getTag('@designToken').content[0]?.text || '', optional: prop.flags.isOptional, readonly: prop.flags.isReadonly, type: prop.type.toString(), default: prop.comment && prop.comment.getTag('@defaultValue') ? prop.comment.getTag('@defaultValue').content[0]?.text || '' : '', // TODO: Check description: prop.comment && prop.comment.summary .map((s) => { if (s.text.indexOf('[here]') > -1) { return `${s.text.slice(0, s.text.indexOf('[here]'))} here ${s.text.slice( s.text.indexOf(')') + 1 )}`; } return s.text || ''; }) .join(' '), deprecated: prop.comment && prop.comment.getTag('@deprecated') ? parseText(prop.comment.getTag('@deprecated').content[0]?.text) : undefined }); } }); } }; setProps(event); doc[name]['tokens'].values[event.name] = { description: event_props_description, props }; }); }); // app.generateJson(module, `./api-generator/module-typedoc.json`); }); const typedocJSON = JSON.stringify(doc, null, 4); !fs.existsSync(outputPath) && fs.mkdirSync(outputPath); fs.writeFileSync(path.resolve(outputPath, 'index.json'), typedocJSON); // app.generateJson(project, `./api-generator/typedoc.json`); }