intergen: Do not add I-prefix to interfaces
Renaming of existing types turned out to be too complicated because the code depends on checker.typeToString, and there is no way that I know of that would allow renaming of an existing type.
This commit is contained in:
parent
25593dd994
commit
b122ff093a
@ -1,4 +1,3 @@
|
|||||||
export * from './build'
|
export * from './build'
|
||||||
export * from './newlib'
|
export * from './newlib'
|
||||||
export * from './intergen'
|
export * from './intergen'
|
||||||
export * from './typecheck'
|
|
||||||
|
|||||||
160
packages/scripts/src/commands/intergen.test.ts
Normal file
160
packages/scripts/src/commands/intergen.test.ts
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
jest.mock('../log')
|
||||||
|
|
||||||
|
import {intergen} from './intergen'
|
||||||
|
import * as fs from 'fs'
|
||||||
|
import * as path from 'path'
|
||||||
|
import * as os from 'os'
|
||||||
|
|
||||||
|
describe('intergen', () => {
|
||||||
|
|
||||||
|
const tmpdir = os.tmpdir()
|
||||||
|
const templateName = 'intergen.tmp'
|
||||||
|
|
||||||
|
let sourceFiles: string[] = []
|
||||||
|
let i = 0
|
||||||
|
function createSourceFile(contents: string) {
|
||||||
|
i++
|
||||||
|
const sourceFile = path.join(tmpdir, templateName + i + '.ts')
|
||||||
|
fs.writeFileSync(sourceFile, contents)
|
||||||
|
sourceFiles.push(sourceFile)
|
||||||
|
return sourceFile
|
||||||
|
}
|
||||||
|
|
||||||
|
function execute(source: string): string {
|
||||||
|
const file = createSourceFile(source)
|
||||||
|
return intergen('intergen', '-i', file)
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
sourceFiles.forEach(f => fs.unlinkSync(f))
|
||||||
|
sourceFiles = []
|
||||||
|
})
|
||||||
|
|
||||||
|
it('converts exported class into interface', () => {
|
||||||
|
const result = execute(`export class Value {
|
||||||
|
amount: number
|
||||||
|
}`)
|
||||||
|
expect(result).toEqual(`export interface Value {
|
||||||
|
amount: number
|
||||||
|
}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does nothing when class is not exported', () => {
|
||||||
|
const result = execute(`class Value {
|
||||||
|
amount: number
|
||||||
|
}`)
|
||||||
|
expect(result).toEqual(``)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('converts inherited classes into interfaces', () => {
|
||||||
|
const result = execute(`class A {
|
||||||
|
a: number
|
||||||
|
}
|
||||||
|
export class B extends A {
|
||||||
|
b: string
|
||||||
|
}`)
|
||||||
|
expect(result).toEqual(`export interface B {
|
||||||
|
b: string
|
||||||
|
a: number
|
||||||
|
}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('converts referenced classes into interfaces', () => {
|
||||||
|
const result = execute(`class A {
|
||||||
|
a: number
|
||||||
|
}
|
||||||
|
export class B {
|
||||||
|
a: A
|
||||||
|
}`)
|
||||||
|
expect(result).toEqual(`export interface B {
|
||||||
|
a: A
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface A {
|
||||||
|
a: number
|
||||||
|
}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('correctly converts union properties', () => {
|
||||||
|
const result = execute(`export class A {
|
||||||
|
a: 'b' | 'c'
|
||||||
|
}`)
|
||||||
|
expect(result).toEqual(`export interface A {
|
||||||
|
a: "b" | "c"
|
||||||
|
}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('correctly converts array properties', () => {
|
||||||
|
const result = execute(`class Name {
|
||||||
|
firstName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Names {
|
||||||
|
names1: Name[]
|
||||||
|
names2: Array<Name>
|
||||||
|
names3: Name[][]
|
||||||
|
names4: Array<Array<Name>>
|
||||||
|
`)
|
||||||
|
expect(result).toEqual(`export interface Names {
|
||||||
|
names1: Name[]
|
||||||
|
names2: Name[]
|
||||||
|
names3: Name[][]
|
||||||
|
names4: Name[][]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Name {
|
||||||
|
firstName: string
|
||||||
|
}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('correctly converts intersections', () => {
|
||||||
|
const result = execute(`export class C {
|
||||||
|
c: A & B
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
a: string
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
b: number
|
||||||
|
}`)
|
||||||
|
expect(result).toEqual(`export interface C {
|
||||||
|
c: A & B
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface A {
|
||||||
|
a: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface B {
|
||||||
|
b: number
|
||||||
|
}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('correctly converts inline property definitions', () => {
|
||||||
|
const result = execute(`export class A {
|
||||||
|
b: {a: string, c: number}
|
||||||
|
}`)
|
||||||
|
expect(result).toEqual(`export interface A {
|
||||||
|
b: { a: string; c: number; }
|
||||||
|
}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('correctly converts inline defs w/ references', () => {
|
||||||
|
const result = execute(`class A {
|
||||||
|
a: number
|
||||||
|
}
|
||||||
|
export class B {
|
||||||
|
b: { a: A; c: number; }
|
||||||
|
}`)
|
||||||
|
expect(result).toEqual(`export interface B {
|
||||||
|
b: { a: A; c: number; }
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface A {
|
||||||
|
a: number
|
||||||
|
}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
@ -11,6 +11,11 @@ function isTypeReference(type: ts.ObjectType): type is ts.TypeReference {
|
|||||||
return !!(type.objectFlags & ts.ObjectFlags.Reference)
|
return !!(type.objectFlags & ts.ObjectFlags.Reference)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAnonymous(type: ts.Type): boolean {
|
||||||
|
return isObjectType(type) && !!(
|
||||||
|
type.objectFlags & ts.ObjectFlags.Anonymous)
|
||||||
|
}
|
||||||
|
|
||||||
function filterInvisibleProperties(type: ts.Symbol): boolean {
|
function filterInvisibleProperties(type: ts.Symbol): boolean {
|
||||||
const flags = ts.getCombinedModifierFlags(type.valueDeclaration)
|
const flags = ts.getCombinedModifierFlags(type.valueDeclaration)
|
||||||
return !(flags & ts.ModifierFlags.NonPublicAccessibilityModifier)
|
return !(flags & ts.ModifierFlags.NonPublicAccessibilityModifier)
|
||||||
@ -51,7 +56,7 @@ interface IClassDefinition {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function typecheck(...argv: string[]) {
|
export function intergen(...argv: string[]): string {
|
||||||
const args = argparse({
|
const args = argparse({
|
||||||
input: arg('string', {alias: 'i', required: true}),
|
input: arg('string', {alias: 'i', required: true}),
|
||||||
debug: arg('boolean'),
|
debug: arg('boolean'),
|
||||||
@ -191,8 +196,8 @@ export function typecheck(...argv: string[]) {
|
|||||||
function isNodeExported(node: ts.Node): boolean {
|
function isNodeExported(node: ts.Node): boolean {
|
||||||
return (
|
return (
|
||||||
(ts.getCombinedModifierFlags(node as any) &
|
(ts.getCombinedModifierFlags(node as any) &
|
||||||
ts.ModifierFlags.Export) !== 0 ||
|
ts.ModifierFlags.Export) !== 0
|
||||||
(!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile)
|
// (!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +301,10 @@ export function typecheck(...argv: string[]) {
|
|||||||
properties: classProperties,
|
properties: classProperties,
|
||||||
}
|
}
|
||||||
|
|
||||||
classDefs.push(classDef)
|
if (!isAnonymous(type)) {
|
||||||
|
// Prevent defining anonymous declarations as interfaces
|
||||||
|
classDefs.push(classDef)
|
||||||
|
}
|
||||||
typeDefinitions.set(type, classDef)
|
typeDefinitions.set(type, classDef)
|
||||||
|
|
||||||
classDef.allRelevantTypes.forEach(handleType)
|
classDef.allRelevantTypes.forEach(handleType)
|
||||||
@ -306,6 +314,11 @@ 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(),
|
||||||
|
isNodeExported(node),
|
||||||
|
ts.getCombinedModifierFlags(node as any),
|
||||||
|
!!node.parent,
|
||||||
|
node.parent.kind === ts.SyntaxKind.SourceFile)
|
||||||
// Only consider exported nodes
|
// Only consider exported nodes
|
||||||
if (!isNodeExported(node)) {
|
if (!isNodeExported(node)) {
|
||||||
return
|
return
|
||||||
@ -325,8 +338,12 @@ export function typecheck(...argv: string[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setTypeName(type: ts.Type, mappings: Map<ts.Type, string>) {
|
function setTypeName(type: ts.Type, mappings: Map<ts.Type, string>) {
|
||||||
|
if (isAnonymous(type)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const name = typeToString(type)
|
const name = typeToString(type)
|
||||||
mappings.set(type, `I${name}`)
|
// (type as any).symbol.name = 'I' + type.symbol.name
|
||||||
|
mappings.set(type, `${name}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const nameMappings = new Map<ts.Type, string>()
|
const nameMappings = new Map<ts.Type, string>()
|
||||||
@ -339,7 +356,7 @@ export function typecheck(...argv: string[]) {
|
|||||||
|
|
||||||
function createInterface(classDef: IClassDefinition): string {
|
function createInterface(classDef: IClassDefinition): string {
|
||||||
const name = nameMappings.get(classDef.type)!
|
const name = nameMappings.get(classDef.type)!
|
||||||
const start = `interface ${name} {`
|
const start = `export interface ${name} {`
|
||||||
const properties = classDef.properties.map(p => {
|
const properties = classDef.properties.map(p => {
|
||||||
return ` ${p.name}: ${nameMappings.get(p.type) || p.typeString}`
|
return ` ${p.name}: ${nameMappings.get(p.type) || p.typeString}`
|
||||||
})
|
})
|
||||||
@ -362,4 +379,5 @@ export function typecheck(...argv: string[]) {
|
|||||||
} else {
|
} else {
|
||||||
fs.writeFileSync(args.output, value)
|
fs.writeFileSync(args.output, value)
|
||||||
}
|
}
|
||||||
|
return value
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
import {format} from 'util'
|
import {format} from 'util'
|
||||||
|
|
||||||
const stdout: NodeJS.WriteStream = process.stdout
|
|
||||||
const stderr: NodeJS.WriteStream = process.stderr
|
|
||||||
|
|
||||||
export function error(message: string, ...values: any[]) {
|
export function error(message: string, ...values: any[]) {
|
||||||
stderr.write(format(message + '\n', ...values))
|
process.stderr.write(format(message + '\n', ...values))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function info(message: string, ...values: any[]) {
|
export function info(message: string, ...values: any[]) {
|
||||||
stdout.write(format(message + '\n', ...values))
|
process.stdout.write(format(message + '\n', ...values))
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user