Add -i, -o flags to typecheck.ts
This commit is contained in:
parent
f8536b7446
commit
cca888641a
@ -1,6 +1,7 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as ts from 'typescript'
|
import * as ts from 'typescript'
|
||||||
import {argparse, arg} from '@rondo/argparse'
|
import {argparse, arg} from '@rondo/argparse'
|
||||||
|
import {error, info} from '../log'
|
||||||
|
|
||||||
function isObjectType(type: ts.Type): type is ts.ObjectType {
|
function isObjectType(type: ts.Type): type is ts.ObjectType {
|
||||||
return !!(type.flags & ts.TypeFlags.Object)
|
return !!(type.flags & ts.TypeFlags.Object)
|
||||||
@ -52,19 +53,23 @@ interface IClassDefinition {
|
|||||||
|
|
||||||
export function typecheck(...argv: string[]) {
|
export function typecheck(...argv: string[]) {
|
||||||
const args = argparse({
|
const args = argparse({
|
||||||
file: arg('string', {
|
input: arg('string', {alias: 'i', required: true}),
|
||||||
default: __dirname + '/' + 'intergen.sample.ts',
|
|
||||||
alias: 'f',
|
|
||||||
}),
|
|
||||||
debug: arg('boolean'),
|
debug: arg('boolean'),
|
||||||
help: arg('boolean', {alias: 'h'}),
|
help: arg('boolean', {alias: 'h'}),
|
||||||
|
output: arg('string', {default: '-'}),
|
||||||
}).parse(argv)
|
}).parse(argv)
|
||||||
|
|
||||||
|
function debug(m: string, ...meta: any[]) {
|
||||||
|
if (args.debug) {
|
||||||
|
error(m, ...meta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Generate interfaces for all exported classes in a set of .ts files */
|
/** Generate interfaces for all exported classes in a set of .ts files */
|
||||||
function generateInterfaces(
|
function classesToInterfaces(
|
||||||
fileNames: string[],
|
fileNames: string[],
|
||||||
options: ts.CompilerOptions,
|
options: ts.CompilerOptions,
|
||||||
): void {
|
): string[] {
|
||||||
// Build a program using the set of root file names in fileNames
|
// Build a program using the set of root file names in fileNames
|
||||||
const program = ts.createProgram(fileNames, options)
|
const program = ts.createProgram(fileNames, options)
|
||||||
|
|
||||||
@ -82,45 +87,45 @@ export function typecheck(...argv: string[]) {
|
|||||||
* of types. For example: types.filter(filterGlobalTypes)
|
* of types. For example: types.filter(filterGlobalTypes)
|
||||||
*/
|
*/
|
||||||
function filterGlobalTypes(type: ts.Type): boolean {
|
function filterGlobalTypes(type: ts.Type): boolean {
|
||||||
// console.log('fgt', typeToString(type))
|
debug('filterGlobalTypes: %s', typeToString(type))
|
||||||
if (type.aliasSymbol) {
|
if (type.aliasSymbol) {
|
||||||
// keep type aliases
|
// keep type aliases
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
const symbol = type.getSymbol()
|
const symbol = type.getSymbol()
|
||||||
if (!symbol) {
|
if (!symbol) {
|
||||||
// console.log(' no symbol')
|
debug(' no symbol')
|
||||||
// e.g. string or number types have no symbol
|
// e.g. string or number types have no symbol
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (symbol && symbol.flags & ts.SymbolFlags.Transient) {
|
if (symbol && symbol.flags & ts.SymbolFlags.Transient) {
|
||||||
console.log(' is transient')
|
debug(' is transient')
|
||||||
// Array is transient. not sure if this is the best way to figure this
|
// Array is transient. not sure if this is the best way to figure this
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// if (symbol && !((symbol as any).parent)) {
|
// if (symbol && !((symbol as any).parent)) {
|
||||||
// // console.log(' no parent', symbol)
|
// // debug(' no parent', symbol)
|
||||||
// // e.g. Array symbol has no parent
|
// // e.g. Array symbol has no parent
|
||||||
// return false
|
// return false
|
||||||
// }
|
// }
|
||||||
if (type.isLiteral()) {
|
if (type.isLiteral()) {
|
||||||
// console.log(' is literal')
|
debug(' is literal')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (type.isUnionOrIntersection()) {
|
if (type.isUnionOrIntersection()) {
|
||||||
// console.log(' is u or i')
|
debug(' is u or i')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (isObjectType(type) && isTypeReference(type)) {
|
if (isObjectType(type) && isTypeReference(type)) {
|
||||||
// console.log(' is object type')
|
debug(' is object type')
|
||||||
if (isObjectType(type.target) &&
|
if (isObjectType(type.target) &&
|
||||||
type.target.objectFlags & ts.ObjectFlags.Tuple) {
|
type.target.objectFlags & ts.ObjectFlags.Tuple) {
|
||||||
// console.log(' is tuple')
|
debug(' is tuple')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log(' keep!')
|
debug(' keep!')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +272,7 @@ export function typecheck(...argv: string[]) {
|
|||||||
name: p.getName(),
|
name: p.getName(),
|
||||||
type: propType,
|
type: propType,
|
||||||
relevantTypes,
|
relevantTypes,
|
||||||
typeString: typeToString(type),
|
typeString: typeToString(propType),
|
||||||
optional,
|
optional,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -291,18 +296,6 @@ export function typecheck(...argv: string[]) {
|
|||||||
properties: classProperties,
|
properties: classProperties,
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`interface ${classDef.name} {`)
|
|
||||||
console.log(' ',
|
|
||||||
classDef.properties
|
|
||||||
.map(p => p.name + ': ' + typeToString(p.type) + ' {' +
|
|
||||||
p.relevantTypes.map(typeToString) + '}')
|
|
||||||
.join('\n '),
|
|
||||||
)
|
|
||||||
console.log('}')
|
|
||||||
console.log('\n allRelevantTypes:\n ',
|
|
||||||
classDef.allRelevantTypes.map(typeToString).join('\n '))
|
|
||||||
console.log('\n')
|
|
||||||
|
|
||||||
classDefs.push(classDef)
|
classDefs.push(classDef)
|
||||||
typeDefinitions.set(type, classDef)
|
typeDefinitions.set(type, classDef)
|
||||||
|
|
||||||
@ -313,18 +306,6 @@ export function typecheck(...argv: string[]) {
|
|||||||
* Visit nodes finding exported classes
|
* Visit nodes finding exported classes
|
||||||
*/
|
*/
|
||||||
function visit(node: ts.Node) {
|
function visit(node: ts.Node) {
|
||||||
// console.log('node.getText()', node.getText())
|
|
||||||
// console.log('node.kind', node.kind)
|
|
||||||
|
|
||||||
if (ts.isExportDeclaration(node)) {
|
|
||||||
if (node.exportClause) {
|
|
||||||
// console.log('export {...} from', node.exportClause.elements.length)
|
|
||||||
} else {
|
|
||||||
// console.log('export * from...')
|
|
||||||
// it is exporting *
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only consider exported nodes
|
// Only consider exported nodes
|
||||||
if (!isNodeExported(node)) {
|
if (!isNodeExported(node)) {
|
||||||
return
|
return
|
||||||
@ -343,32 +324,42 @@ export function typecheck(...argv: string[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// const defs: Map<ts.Type, IClassDefinition> = new Map()
|
function setTypeName(type: ts.Type, mappings: Map<ts.Type, string>) {
|
||||||
// classDefs.forEach(classDef => {
|
const name = typeToString(type)
|
||||||
// defs.set(classDef.type, classDef)
|
mappings.set(type, `I${name}`)
|
||||||
// })
|
}
|
||||||
|
|
||||||
// classDefs.forEach(classDef => {
|
const nameMappings = new Map<ts.Type, string>()
|
||||||
// classDef.allRelevantTypes.forEach(type => {
|
for (const classDef of classDefs) {
|
||||||
// if (!defs.has(type)) {
|
setTypeName(classDef.type, nameMappings)
|
||||||
// handleType(type)
|
for (const t of classDef.allRelevantTypes) {
|
||||||
// }
|
setTypeName(classDef.type, nameMappings)
|
||||||
// })
|
}
|
||||||
// })
|
}
|
||||||
|
|
||||||
// const Vote = classDefs.find(c => c.name === 'Vote')
|
function createInterface(classDef: IClassDefinition): string {
|
||||||
// if (Vote) {
|
const name = nameMappings.get(classDef.type)!
|
||||||
// console.log('found vote')
|
const start = `interface ${name} {`
|
||||||
// const U = Vote.allRelevantTypes.find(t => typeToString(t) === 'User')
|
const properties = classDef.properties.map(p => {
|
||||||
// if (U) {
|
return ` ${p.name}: ${nameMappings.get(p.type) || p.typeString}`
|
||||||
// console.log('found user')
|
})
|
||||||
// handleType(U)
|
.join('\n')
|
||||||
// }
|
const end = '}'
|
||||||
// }
|
return `${start}\n${properties}\n${end}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return classDefs.map(createInterface)
|
||||||
}
|
}
|
||||||
|
|
||||||
generateInterfaces([args.file], {
|
const interfaces = classesToInterfaces([args.input], {
|
||||||
target: ts.ScriptTarget.ES5,
|
target: ts.ScriptTarget.ES5,
|
||||||
module: ts.ModuleKind.CommonJS,
|
module: ts.ModuleKind.CommonJS,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const value = interfaces.join('\n\n')
|
||||||
|
if (args.output === '-') {
|
||||||
|
info(value)
|
||||||
|
} else {
|
||||||
|
fs.writeFileSync(args.output, value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user