mirror of
https://github.com/mathuo/dockview
synced 2025-02-01 22:15:44 +00:00
645 lines
19 KiB
JavaScript
645 lines
19 KiB
JavaScript
import { execSync } from 'child_process';
|
|
import { readFileSync, existsSync, writeFileSync } from 'fs';
|
|
import { ReflectionKind } from 'typedoc';
|
|
|
|
/**
|
|
* #region inputs
|
|
*/
|
|
|
|
// typedoc output
|
|
const TYPEDOC_OUTPUT_FILE = './generated/typedoc.output.json';
|
|
// doc output
|
|
const API_OUTPUT_FILE = './packages/docs/src/generated/api.output.json';
|
|
// declarations to document (e.g. class names, interface names)
|
|
const DOCUMENT_LIST = [
|
|
// dockview
|
|
'DockviewApi',
|
|
'IDockviewReactProps',
|
|
'DockviewPanelApi',
|
|
// splitview
|
|
'SplitviewApi',
|
|
'ISplitviewReactProps',
|
|
'SplitviewPanelApi',
|
|
// gridview
|
|
'GridviewApi',
|
|
'IGridviewReactProps',
|
|
'GridviewPanelApi',
|
|
// paneview
|
|
'PaneviewApi',
|
|
'IPaneviewReactProps',
|
|
'PaneviewPanelApi',
|
|
];
|
|
|
|
const EXPORT_REMAPPING = {
|
|
Event: 'DockviewEvent',
|
|
Emitter: 'DockviewEmitter',
|
|
IDisposable: 'IDockviewDisposable',
|
|
MutableDisposable: 'DockviewMutableDisposable',
|
|
CompositeDisposable: 'DockviewCompositeDisposable',
|
|
};
|
|
|
|
const SKIP_DOC = ['Event'];
|
|
|
|
/**
|
|
* #region generating Typedoc output
|
|
*/
|
|
|
|
console.log('running docs');
|
|
|
|
if (!existsSync(TYPEDOC_OUTPUT_FILE)) {
|
|
execSync(
|
|
`typedoc --json ${TYPEDOC_OUTPUT_FILE}`,
|
|
(error, stdout, stderr) => {
|
|
console.log('stdout: ' + stdout);
|
|
console.log('stderr: ' + stderr);
|
|
if (error !== null) {
|
|
console.log('exec error: ' + error);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
const content = JSON.parse(readFileSync(TYPEDOC_OUTPUT_FILE));
|
|
|
|
const dockviewCore = content.children.find(
|
|
(child) => child.name === 'dockview-core'
|
|
);
|
|
const dockview = content.children.find((child) => child.name === 'dockview');
|
|
const dockviewVue = content.children.find((child) => child.name === 'dockview-vue');
|
|
|
|
|
|
const declarations = [dockviewCore, dockview, dockviewVue]
|
|
.flatMap(
|
|
(item) => item.children
|
|
// .filter((child) => DOCUMENT_LIST.includes(child.name))
|
|
)
|
|
.filter(Boolean);
|
|
|
|
function parseTypeArguments(args) {
|
|
if (Array.isArray(args.typeArguments)) {
|
|
return `<${args.typeArguments.map(parseType).join(', ')}>`;
|
|
}
|
|
return '';
|
|
}
|
|
|
|
function parseType(obj) {
|
|
switch (obj.type) {
|
|
case 'union':
|
|
return obj.types.map(parseType).reverse().join(' | ');
|
|
case 'intrinsic':
|
|
return obj.name;
|
|
case 'literal':
|
|
return `'${obj.value}'`;
|
|
case 'reflection':
|
|
return parse(obj.declaration).code;
|
|
case 'reference':
|
|
return `${obj.qualifiedName ?? obj.name}${parseTypeArguments(obj)}`;
|
|
case 'array':
|
|
return `${parseType(obj.elementType)}[]`;
|
|
case 'intersection':
|
|
return obj.types.map(parseType).reverse().join(' & ');
|
|
case 'predicate':
|
|
return `${obj.name} is ${parseType(obj.targetType)}`;
|
|
case 'tuple':
|
|
return `[${obj.elements.map(parseType)}]`;
|
|
case 'namedTupleMember':
|
|
return `[${obj.name}: ${parseType(obj.element)}]`;
|
|
default:
|
|
throw new Error(`unhandled type ${obj.type}`);
|
|
}
|
|
}
|
|
|
|
function parseComplexType(obj) {
|
|
switch (obj.type) {
|
|
case 'union':
|
|
return {
|
|
type: 'or',
|
|
values: obj.types.map(parseComplexType).reverse(),
|
|
};
|
|
case 'intrinsic':
|
|
return { type: obj.type, value: obj.name };
|
|
case 'literal':
|
|
return { type: obj.type, value: obj.value };
|
|
case 'reflection':
|
|
return { type: obj.type, value: parse(obj.declaration) };
|
|
case 'reference': {
|
|
if (obj.refersToTypeParameter) {
|
|
return {
|
|
type: obj.type,
|
|
value: obj.name,
|
|
source: obj.package,
|
|
refersToTypeParameter: true,
|
|
};
|
|
}
|
|
|
|
if (obj.qualifiedName) {
|
|
return {
|
|
type: obj.type,
|
|
value: obj.qualifiedName,
|
|
source: obj.sourceFileName
|
|
? obj.sourceFileName.startsWith('packages/dockview')
|
|
? 'dockview'
|
|
: 'external'
|
|
: obj.package,
|
|
typeArguments: obj.typeArguments?.map(parseComplexType),
|
|
};
|
|
}
|
|
|
|
return {
|
|
type: obj.type,
|
|
value: obj.name,
|
|
source: obj.package,
|
|
typeArguments: obj.typeArguments?.map(parseComplexType),
|
|
};
|
|
}
|
|
case 'array':
|
|
return {
|
|
type: obj.type,
|
|
value: parseComplexType(obj.elementType),
|
|
};
|
|
case 'intersection':
|
|
return {
|
|
type: obj.type,
|
|
values: obj.types.map(parseComplexType).reverse(),
|
|
};
|
|
case 'predicate':
|
|
return {
|
|
type: obj.type,
|
|
lhs: obj.name,
|
|
rhs: parseComplexType(obj.targetType),
|
|
};
|
|
case 'tuple':
|
|
return {
|
|
type: obj.type,
|
|
values: obj.elements.map(parseComplexType),
|
|
};
|
|
case 'namedTupleMember':
|
|
return {
|
|
type: obj.type,
|
|
values: parseComplexType(obj.element),
|
|
};
|
|
default:
|
|
throw new Error(`unhandled type ${obj.type}`);
|
|
}
|
|
}
|
|
|
|
function extractPiecesFromType(obj) {
|
|
if (obj.type === 'reference' && obj.package?.startsWith('dockview-')) {
|
|
let result = { name: obj.name };
|
|
|
|
if (Array.isArray(obj.typeArguments)) {
|
|
const typeArgs = obj.typeArguments
|
|
.map(extractPiecesFromType)
|
|
.filter(Boolean);
|
|
if (typeArgs.length > 0) {
|
|
result.typeArgs = typeArgs;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function parse(data) {
|
|
const { name, comment, flags } = data;
|
|
|
|
let code = '';
|
|
const pieces = [];
|
|
|
|
switch (data.kind) {
|
|
case ReflectionKind.Accessor: // 262144
|
|
if (!data.getSignature) {
|
|
return null;
|
|
}
|
|
|
|
const getSignature = parse(data.getSignature);
|
|
code += getSignature.code;
|
|
// pieces.push(...getSignature.pieces);
|
|
|
|
return {
|
|
name,
|
|
code,
|
|
kind: 'accessor',
|
|
value: getSignature,
|
|
comment: getSignature.comment,
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.Method: // 2048
|
|
const methodSignature = data.signatures.map((signature) =>
|
|
parse(signature)
|
|
);
|
|
pieces.push(...methodSignature.flatMap((_) => _.pieces));
|
|
|
|
code += methodSignature
|
|
.map((signature) => signature.code)
|
|
.join('\n');
|
|
|
|
return {
|
|
name,
|
|
code,
|
|
kind: 'method',
|
|
signature: methodSignature,
|
|
comment: data.signatures[0].comment,
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.Property: // 1024
|
|
code += parseType(data.type);
|
|
pieces.push({
|
|
kind: 'property',
|
|
value: extractPiecesFromType(data.type),
|
|
});
|
|
|
|
return {
|
|
name,
|
|
code,
|
|
kind: 'property',
|
|
type: parseComplexType(data.type),
|
|
flags,
|
|
comment,
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
|
|
case ReflectionKind.Parameter: // 32768
|
|
code += `${name}`;
|
|
|
|
if (flags.isOptional) {
|
|
code += '?';
|
|
}
|
|
code += ': ';
|
|
|
|
code += parseType(data.type);
|
|
pieces.push({
|
|
kind: 'parameter',
|
|
value: extractPiecesFromType(data.type),
|
|
});
|
|
|
|
return {
|
|
name,
|
|
code,
|
|
type: parseComplexType(data.type),
|
|
kind: 'parameter',
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.TypeLiteral: // 65536
|
|
let result = {};
|
|
|
|
if (Array.isArray(data.children)) {
|
|
code += `{ `;
|
|
code += data.children
|
|
.map((child) => {
|
|
let code = `${child.name}`;
|
|
|
|
if (child.flags.isOptional) {
|
|
code += '?';
|
|
}
|
|
const childData = parse(child);
|
|
// pieces.push(...childData.pieces);
|
|
|
|
code += `: ${childData.code}`;
|
|
return code;
|
|
})
|
|
.join(', ');
|
|
code += ` }`;
|
|
|
|
result.properties = data.children.map((_) => {
|
|
const result = parse(_);
|
|
|
|
if (result.kind !== 'property') {
|
|
throw new Error(`invalid ${result.kind}`);
|
|
}
|
|
|
|
return result;
|
|
});
|
|
}
|
|
|
|
if (Array.isArray(data.signatures)) {
|
|
const signatures = data.signatures.map((signature) => {
|
|
const result = parse(signature);
|
|
|
|
if (
|
|
result.kind !== 'callSignature' &&
|
|
result.kind !== 'constructorSignature'
|
|
) {
|
|
throw new Error(`invalid ${result.kind}`);
|
|
}
|
|
|
|
return result;
|
|
});
|
|
code += signatures
|
|
.map((signature) => signature.code)
|
|
.join(', ');
|
|
// pieces.push(...signatures.flatMap((_) => _.pieces));
|
|
|
|
if (result.type) {
|
|
throw new Error('anc');
|
|
}
|
|
|
|
result.signatures = signatures;
|
|
}
|
|
|
|
return {
|
|
name,
|
|
code,
|
|
// pieces,
|
|
kind: 'typeLiteral',
|
|
properties: result.properties,
|
|
signatures: result.signatures,
|
|
};
|
|
case ReflectionKind.CallSignature: // 4096
|
|
const typeParameters = [];
|
|
let _parameters = [];
|
|
|
|
if (Array.isArray(data.typeParameter)) {
|
|
code += `<${data.typeParameter.map((typeParameter) => {
|
|
let type = `${typeParameter.name}`;
|
|
|
|
const result = { name: type };
|
|
|
|
if (typeParameter.type) {
|
|
type += ` extends ${parseType(typeParameter.type)}`;
|
|
|
|
result.extends = parseComplexType(typeParameter.type);
|
|
|
|
pieces.push({
|
|
kind: 'typearg',
|
|
value: extractPiecesFromType(typeParameter.type),
|
|
});
|
|
}
|
|
|
|
if (typeParameter.default) {
|
|
type += ` = ${typeParameter.default.name}`;
|
|
pieces.push({
|
|
kind: 'typearg_default',
|
|
value: extractPiecesFromType(typeParameter.default),
|
|
});
|
|
|
|
result.default = typeParameter.default.name;
|
|
}
|
|
|
|
typeParameters.push(result);
|
|
|
|
return type;
|
|
})}>`;
|
|
}
|
|
|
|
code += '(';
|
|
|
|
if (Array.isArray(data.parameters)) {
|
|
const parameters = data.parameters.map((parameter) =>
|
|
parse(parameter)
|
|
);
|
|
|
|
_parameters = parameters;
|
|
|
|
code += `${parameters
|
|
.map((parameter) => parameter.code)
|
|
.join(', ')}`;
|
|
// pieces.push(...parameters.flatMap((_) => _.pieces));
|
|
}
|
|
|
|
code += '): ';
|
|
|
|
code += parseType(data.type);
|
|
pieces.push({
|
|
kind: 'return',
|
|
value: extractPiecesFromType(data.type),
|
|
});
|
|
|
|
return {
|
|
name,
|
|
comment,
|
|
typeParameters,
|
|
parameters: _parameters,
|
|
returnType: parseComplexType(data.type),
|
|
code,
|
|
kind: 'callSignature',
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.GetSignature: // 524288
|
|
code += parseType(data.type);
|
|
pieces.push({
|
|
kind: 'signature',
|
|
value: extractPiecesFromType(data.type),
|
|
});
|
|
|
|
return {
|
|
name,
|
|
comment,
|
|
code,
|
|
kind: 'getSignature',
|
|
returnType: parseComplexType(data.type),
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.Function: // 64
|
|
if (data.signatures.length > 1) {
|
|
throw new Error('unhandled');
|
|
}
|
|
const functionSignature = parse(data.signatures[0]);
|
|
// pieces.push(...functionSignature.pieces);
|
|
|
|
code += functionSignature.code;
|
|
return {
|
|
name,
|
|
comment,
|
|
code,
|
|
signature: parse(data.signatures[0]),
|
|
kind: 'function',
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.Variable: // 32
|
|
return {
|
|
name,
|
|
comment,
|
|
code,
|
|
kind: 'variable',
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.EnumMember: // 16
|
|
return {
|
|
name,
|
|
comment,
|
|
code,
|
|
kind: 'enumMember',
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.Interface: // 16
|
|
return {
|
|
name,
|
|
comment,
|
|
code,
|
|
kind: 'interface',
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.ConstructorSignature: // 16384
|
|
return {
|
|
name,
|
|
comment,
|
|
code,
|
|
kind: 'constructorSignature',
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.Constructor: // 512
|
|
// don't care for constrcutors
|
|
return {
|
|
name,
|
|
comment,
|
|
kind: 'constructor',
|
|
code,
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
case ReflectionKind.TypeAlias: // 2097152
|
|
const typeParameters1 = [];
|
|
|
|
if (Array.isArray(data.typeParameter)) {
|
|
code += `<${data.typeParameter.map((typeParameter) => {
|
|
let type = `${typeParameter.name}`;
|
|
|
|
const result = { name: typeParameter.name };
|
|
|
|
if (typeParameter.type) {
|
|
type += ` extends ${parseType(typeParameter.type)}`;
|
|
|
|
result.extends = parseComplexType(typeParameter.type);
|
|
|
|
pieces.push({
|
|
kind: 'typearg',
|
|
value: extractPiecesFromType(typeParameter.type),
|
|
});
|
|
}
|
|
|
|
if (typeParameter.default) {
|
|
type += ` = ${typeParameter.default.name}`;
|
|
pieces.push({
|
|
kind: 'typearg_default',
|
|
value: extractPiecesFromType(typeParameter.default),
|
|
});
|
|
|
|
result.default = typeParameter.default.name;
|
|
}
|
|
|
|
typeParameters1.push(result);
|
|
|
|
return type;
|
|
})}>`;
|
|
}
|
|
|
|
code += parseType(data.type);
|
|
pieces.push({
|
|
kind: 'typearg',
|
|
value: extractPiecesFromType(data.type),
|
|
});
|
|
|
|
return {
|
|
name,
|
|
comment,
|
|
code,
|
|
typeParameters: typeParameters1,
|
|
type: parseComplexType(data.type),
|
|
kind: 'typeAlias',
|
|
// pieces: pieces.filter((_) => _.value !== null),
|
|
};
|
|
default:
|
|
throw new Error(`unhandled kind ${data.kind}`);
|
|
}
|
|
}
|
|
|
|
function parseDeclarationMetadata(declaration) {
|
|
switch (declaration.kind) {
|
|
case ReflectionKind.Namespace:
|
|
return { kind: 'namespace' };
|
|
case ReflectionKind.Variable:
|
|
return { kind: 'variable' };
|
|
case ReflectionKind.Enum:
|
|
return { kind: 'enum' };
|
|
case ReflectionKind.Function:
|
|
return { kind: 'function' };
|
|
case ReflectionKind.Class:
|
|
return { kind: 'class' };
|
|
case ReflectionKind.Interface:
|
|
return { kind: 'interface' };
|
|
case ReflectionKind.TypeAlias:
|
|
return { kind: 'typeAlias' };
|
|
default:
|
|
throw new Error(`unhandled declaration kind ${declaration.kind}`);
|
|
}
|
|
}
|
|
|
|
function createDocument(declarations) {
|
|
const documentation = {};
|
|
|
|
function parseDeclaration(declaration) {
|
|
const { children, name, extendedTypes } = declaration;
|
|
|
|
/**
|
|
* 4: Namespace
|
|
* 8: Enum
|
|
* 64: Function
|
|
* 128: Class
|
|
* 256: Interface
|
|
* 2097152: TypeAlias
|
|
*/
|
|
|
|
const metadata = parseDeclarationMetadata(declaration);
|
|
|
|
documentation[name] = {
|
|
...metadata,
|
|
name,
|
|
children: [],
|
|
extends: []
|
|
};
|
|
|
|
if (!children) {
|
|
documentation[name] = {
|
|
...parse(declaration),
|
|
};
|
|
// documentation[name].metadata = parse(declaration);
|
|
}
|
|
|
|
if (children) {
|
|
for (const child of children) {
|
|
try {
|
|
const { flags } = child;
|
|
|
|
if (flags.isPrivate) {
|
|
continue;
|
|
}
|
|
|
|
const output = parse(child);
|
|
|
|
if (output) {
|
|
output.pieces = Array.from(new Set(output.pieces))
|
|
.filter(Boolean)
|
|
.sort();
|
|
delete output.pieces;
|
|
// delete output.comment;
|
|
|
|
documentation[name].children.push(output);
|
|
}
|
|
} catch (err) {
|
|
console.error('error', err, JSON.stringify(child, null, 4));
|
|
process.exit(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(extendedTypes) {
|
|
for(const extendedType of extendedTypes) {
|
|
if(extendedType.package && extendedType.package.startsWith("dockview")) {
|
|
documentation[name].extends.push(extendedType.name);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
for (const declaration of declarations) {
|
|
parseDeclaration(declaration);
|
|
}
|
|
|
|
return documentation;
|
|
}
|
|
|
|
const documentation = createDocument(declarations);
|
|
writeFileSync(API_OUTPUT_FILE, JSON.stringify(documentation, null, 4));
|