Add typecheck.ts
This uses TypeScript's TypeChecker to determine the types and the code is a little cleaner, but still needs a lot of work: - Determine how to figure out class type parameters
This commit is contained in:
parent
7a26d5c0f1
commit
d7b2ad7a38
@ -1,3 +1,4 @@
|
|||||||
export * from './build'
|
export * from './build'
|
||||||
export * from './newlib'
|
export * from './newlib'
|
||||||
export * from './intergen'
|
export * from './intergen'
|
||||||
|
export * from './typecheck'
|
||||||
|
|||||||
113
packages/scripts/src/commands/typecheck.ts
Normal file
113
packages/scripts/src/commands/typecheck.ts
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import * as ts from 'typescript'
|
||||||
|
import * as fs from 'fs'
|
||||||
|
|
||||||
|
export function typecheck() {
|
||||||
|
interface DocEntry {
|
||||||
|
name?: string
|
||||||
|
fileName?: string
|
||||||
|
documentation?: string
|
||||||
|
type?: string
|
||||||
|
constructors?: DocEntry[]
|
||||||
|
parameters?: DocEntry[]
|
||||||
|
returnType?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Generate documentation for all classes in a set of .ts files */
|
||||||
|
function generateDocumentation(
|
||||||
|
fileNames: string[],
|
||||||
|
options: ts.CompilerOptions,
|
||||||
|
): void {
|
||||||
|
// Build a program using the set of root file names in fileNames
|
||||||
|
const program = ts.createProgram(fileNames, options)
|
||||||
|
|
||||||
|
// Get the checker, we will use it to find more about classes
|
||||||
|
const checker = program.getTypeChecker()
|
||||||
|
|
||||||
|
// Visit every sourceFile in the program
|
||||||
|
for (const sourceFile of program.getSourceFiles()) {
|
||||||
|
if (!sourceFile.isDeclarationFile) {
|
||||||
|
// Walk the tree to search for classes
|
||||||
|
ts.forEachChild(sourceFile, visit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
/** visit nodes finding exported classes */
|
||||||
|
function visit(node: ts.Node) {
|
||||||
|
// Only consider exported nodes
|
||||||
|
if (!isNodeExported(node)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ts.isClassDeclaration(node) && node.name) {
|
||||||
|
// This is a top level class, get its symbol
|
||||||
|
const symbol = checker.getSymbolAtLocation(node.name)
|
||||||
|
if (symbol) {
|
||||||
|
console.log('class', symbol.getName())
|
||||||
|
|
||||||
|
// console.log('symbolToString', checker.symbolToString(symbol))
|
||||||
|
|
||||||
|
// const tpd = checker.symbolToTypeParameterDeclarations(symbol)
|
||||||
|
// if (tpd) {
|
||||||
|
// console.log(' type params: %o', tpd.map(t => {
|
||||||
|
// ts.getCombinedModifierFlags(t.symbol.valueDeclaration)
|
||||||
|
// return {
|
||||||
|
// name: t.name.text,
|
||||||
|
// constraint: !!t.constraint,
|
||||||
|
// default: !!t.default,
|
||||||
|
// // constraint: !!t.constraint
|
||||||
|
// // ? checker.getTypeFromTypeNode(t.constraint)
|
||||||
|
// // : undefined,
|
||||||
|
// }
|
||||||
|
// }))
|
||||||
|
// }
|
||||||
|
|
||||||
|
const type = checker.getDeclaredTypeOfSymbol(symbol)
|
||||||
|
// const properties = checker.getPropertiesOfType(type)
|
||||||
|
const properties = type.getApparentProperties()
|
||||||
|
|
||||||
|
console.log(' %o', properties
|
||||||
|
.filter(p => {
|
||||||
|
const flags = ts.getCombinedModifierFlags(p.valueDeclaration)
|
||||||
|
// return s.parent && s.parent.flags & 32 /* Class */
|
||||||
|
// ? flags
|
||||||
|
// : flags & ~28 /* AccessibilityModifier */;
|
||||||
|
return !(flags & ts.ModifierFlags.NonPublicAccessibilityModifier)
|
||||||
|
})
|
||||||
|
.map(p => {
|
||||||
|
const propType = checker
|
||||||
|
.getTypeOfSymbolAtLocation(p, p.valueDeclaration!)
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: p.getName(),
|
||||||
|
type: checker.typeToString(propType),
|
||||||
|
classOrIface: propType.isClassOrInterface(),
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
// output.push(serializeClass(symbol))
|
||||||
|
}
|
||||||
|
// No need to walk any further, class expressions/inner declarations
|
||||||
|
// cannot be exported
|
||||||
|
} else if (ts.isModuleDeclaration(node)) {
|
||||||
|
// This is a namespace, visit its children
|
||||||
|
ts.forEachChild(node, visit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** True if this is visible outside this file, false otherwise */
|
||||||
|
function isNodeExported(node: ts.Node): boolean {
|
||||||
|
return (
|
||||||
|
(ts.getCombinedModifierFlags(node as any) &
|
||||||
|
ts.ModifierFlags.Export) !== 0 ||
|
||||||
|
(!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = __dirname + '/' + 'intergen.sample.ts'
|
||||||
|
generateDocumentation([path], {
|
||||||
|
target: ts.ScriptTarget.ES5,
|
||||||
|
module: ts.ModuleKind.CommonJS,
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user