@ovotech/avro-ts
Advanced tools
Comparing version 1.0.1 to 1.1.0
@@ -1,2 +0,29 @@ | ||
import { RecordType } from './types'; | ||
import { Schema, schema } from 'avsc'; | ||
import * as ts from 'typescript'; | ||
export interface Registry { | ||
[key: string]: ts.InterfaceDeclaration; | ||
} | ||
export interface Context { | ||
registry: Registry; | ||
root: boolean; | ||
namespace?: string; | ||
namespaces: { | ||
[key: string]: ts.TypeReferenceNode; | ||
}; | ||
logicalTypes: { | ||
[key: string]: ts.TypeReferenceNode; | ||
}; | ||
} | ||
export interface Result<TsType = ts.TypeNode> { | ||
type: TsType; | ||
context: Context; | ||
} | ||
export declare type Convert<TType = Schema> = (context: Context, type: TType) => Result<any>; | ||
export declare const result: <TsType = ts.TypeNode>(context: Context, type: TsType) => Result<TsType>; | ||
export declare const mapContext: <T = any, TsType = ts.TypeNode>(context: Context, items: T[], callbackfn: (context: Context, item: T) => Result<TsType>) => { | ||
items: TsType[]; | ||
context: Context; | ||
}; | ||
export declare const withEntry: (context: Context, entry: ts.InterfaceDeclaration) => Context; | ||
export declare const withNamespace: (context: Context, record: schema.RecordType) => Context; | ||
export interface State { | ||
@@ -11,2 +38,5 @@ output: string[]; | ||
} | ||
export declare function avroTs(recordType: RecordType, logicalTypes?: State['logicalTypes']): string; | ||
export declare const printAstNode: (node: Result<ts.TypeNode>) => string; | ||
export declare function avroTs(recordType: schema.RecordType, logicalTypes?: { | ||
[key: string]: string; | ||
}): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function avroTs(recordType, logicalTypes = {}) { | ||
const state = { output: [], repository: {}, logicalTypes }; | ||
convertRecord(recordType, state); | ||
return state.output.join('\n'); | ||
} | ||
exports.avroTs = avroTs; | ||
function convertRecord(recordType, state, namespace) { | ||
if (recordType.namespace) { | ||
state.repository[fullyQualifiedName(recordType)] = recordType.name; | ||
const ts = require("typescript"); | ||
exports.result = (context, type) => ({ | ||
context, | ||
type, | ||
}); | ||
exports.mapContext = (context, items, callbackfn) => items.reduce((all, item) => { | ||
const current = callbackfn(all.context, item); | ||
return { | ||
items: [...all.items, current.type], | ||
context: current.context, | ||
}; | ||
}, { items: [], context }); | ||
exports.withEntry = (context, entry) => ({ | ||
...context, | ||
registry: { ...context.registry, [entry.name.text]: entry }, | ||
}); | ||
exports.withNamespace = (context, record) => ({ | ||
...context, | ||
namespace: record.namespace, | ||
namespaces: { | ||
...context.namespaces, | ||
[fullyQualifiedName(context, record)]: ts.createTypeReferenceNode(record.name, undefined), | ||
}, | ||
}); | ||
const docToJSDoc = (doc) => `*\n${doc | ||
.split('\n') | ||
.map(line => ` * ${line}`) | ||
.join('\n')}\n `; | ||
const convertRecord = (context, type) => { | ||
const namespaceContext = type.namespace ? exports.withNamespace(context, type) : context; | ||
const fields = exports.mapContext({ ...namespaceContext, root: false }, type.fields, (fieldContext, fieldType) => { | ||
const field = convertType(fieldContext, fieldType.type); | ||
const prop = ts.createPropertySignature(undefined, fieldType.name, isOptional(fieldType.type) ? ts.createToken(ts.SyntaxKind.QuestionToken) : undefined, field.type, undefined); | ||
const propWithDoc = fieldType.doc | ||
? ts.addSyntheticLeadingComment(prop, ts.SyntaxKind.MultiLineCommentTrivia, docToJSDoc(fieldType.doc), true) | ||
: prop; | ||
return exports.result(field.context, propWithDoc); | ||
}); | ||
const interfaceType = ts.createInterfaceDeclaration(undefined, [ts.createToken(ts.SyntaxKind.ExportKeyword)], type.name, undefined, undefined, fields.items); | ||
if (context.root) { | ||
return exports.result(fields.context, interfaceType); | ||
} | ||
let buffer = `export interface ${recordType.name} {\n`; | ||
for (const field of recordType.fields) { | ||
buffer += convertFieldDec(field, state, recordType.namespace) + '\n'; | ||
else { | ||
return exports.result(exports.withEntry(fields.context, interfaceType), ts.createTypeReferenceNode(type.name, undefined)); | ||
} | ||
buffer += '}\n'; | ||
state.output.push(buffer); | ||
return recordType.name; | ||
} | ||
function convertFieldDec(field, state, namespace) { | ||
const optional = isOptional(field.type) ? '?' : ''; | ||
const doc = field.doc ? `/**\n * ${field.doc}\n */\n` : ''; | ||
return indent(`${doc}${field.name}${optional}: ${convertType(field.type, state, namespace)};`); | ||
} | ||
function convertType(type, state, namespace) { | ||
}; | ||
const convertType = (context, type) => { | ||
if (typeof type === 'string') { | ||
return convertPredefinedType(type, state) || convertPrimitive(type) || type; | ||
return convertPredefinedType(context, type); | ||
} | ||
else if (type instanceof Array) { | ||
return convertArrayType(type, state, namespace); | ||
else if (Array.isArray(type)) { | ||
return convertArrayType(context, type); | ||
} | ||
else if (isLogicalType(type)) { | ||
return convertLogicalType(type, state); | ||
return convertLogicalType(context, type); | ||
} | ||
else if (isRecordType(type)) { | ||
return convertRecord(type, state, namespace); | ||
return convertRecord(context, type); | ||
} | ||
else if (isArrayType(type)) { | ||
return convertType(type.items, state, namespace) + '[]'; | ||
const itemType = convertType(context, type.items); | ||
return exports.result(itemType.context, ts.createArrayTypeNode(itemType.type)); | ||
} | ||
else if (isMapType(type)) { | ||
return convertMapType(type, state, namespace); | ||
return convertMapType(context, type); | ||
} | ||
else if (isEnumType(type)) { | ||
return convertEnum(type); | ||
return convertEnum(context, type); | ||
} | ||
@@ -51,4 +75,4 @@ else { | ||
} | ||
} | ||
function convertPrimitive(avroType) { | ||
}; | ||
const convertPrimitive = (context, avroType) => { | ||
switch (avroType) { | ||
@@ -59,58 +83,49 @@ case 'long': | ||
case 'float': | ||
return 'number'; | ||
return exports.result(context, ts.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)); | ||
case 'bytes': | ||
return 'Buffer'; | ||
return exports.result(context, ts.createTypeReferenceNode('Buffer', undefined)); | ||
case 'null': | ||
return 'null'; | ||
return exports.result(context, ts.createNull()); | ||
case 'boolean': | ||
return 'boolean'; | ||
return exports.result(context, ts.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword)); | ||
case 'string': | ||
return 'string'; | ||
return exports.result(context, ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)); | ||
default: | ||
return 'any'; | ||
return exports.result(context, ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)); | ||
} | ||
} | ||
function convertEnum(enumType) { | ||
return enumType.symbols.map(symbol => JSON.stringify(symbol)).join(' | '); | ||
} | ||
function convertLogicalType(type, state) { | ||
return state.logicalTypes[type.logicalType] || convertPrimitive(type.type); | ||
} | ||
function convertPredefinedType(type, state) { | ||
return state.repository[type]; | ||
} | ||
function convertArrayType(type, state, namespace) { | ||
return type | ||
.map(t => { | ||
if (typeof t === 'object' && !(t instanceof Array) && isRecordType(t)) { | ||
return `{ '${fullyQualifiedName(t, namespace)}' : ${convertType(t, state, namespace)} }`; | ||
}; | ||
const convertEnum = (context, enumType) => exports.result(context, ts.createUnionTypeNode(enumType.symbols.map(symbol => ts.createLiteralTypeNode(ts.createLiteral(symbol))))); | ||
const convertLogicalType = (context, type) => context.logicalTypes[type.logicalType] | ||
? exports.result(context, context.logicalTypes[type.logicalType]) | ||
: convertPrimitive(context, type.type); | ||
const convertPredefinedType = (context, type) => context.namespaces[type] ? exports.result(context, context.namespaces[type]) : convertPrimitive(context, type); | ||
const convertArrayType = (context, type) => { | ||
const map = exports.mapContext(context, type, (itemContext, item) => { | ||
if (typeof item === 'object' && !Array.isArray(item) && isRecordType(item)) { | ||
const itemType = convertType(itemContext, item); | ||
return exports.result(itemType.context, ts.createTypeLiteralNode([ | ||
ts.createPropertySignature(undefined, ts.createStringLiteral(fullyQualifiedName(context, item)), undefined, itemType.type, undefined), | ||
])); | ||
} | ||
else { | ||
return convertType(t, state); | ||
return convertType(itemContext, item); | ||
} | ||
}) | ||
.join(' | '); | ||
} | ||
function convertMapType(type, state, namespace) { | ||
return `{ [index:string]:${convertType(type.values, state, namespace)} }`; | ||
} | ||
function isRecordType(type) { | ||
return type.type === 'record'; | ||
} | ||
function isArrayType(type) { | ||
return type.type === 'array'; | ||
} | ||
function isMapType(type) { | ||
return type.type === 'map'; | ||
} | ||
function isEnumType(type) { | ||
return type.type === 'enum'; | ||
} | ||
function isLogicalType(type) { | ||
return 'logicalType' in type; | ||
} | ||
function isUnion(type) { | ||
return type instanceof Array; | ||
} | ||
function isOptional(type) { | ||
}); | ||
return exports.result(map.context, ts.createUnionTypeNode(map.items)); | ||
}; | ||
const convertMapType = (context, type) => { | ||
const map = convertType(context, type.values); | ||
return exports.result(map.context, ts.createTypeLiteralNode([ | ||
ts.createIndexSignature(undefined, undefined, [ | ||
ts.createParameter(undefined, undefined, undefined, 'index', undefined, ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined), | ||
], map.type), | ||
])); | ||
}; | ||
const isRecordType = (type) => typeof type === 'object' && 'type' in type && type.type === 'record'; | ||
const isArrayType = (type) => typeof type === 'object' && 'type' in type && type.type === 'array'; | ||
const isMapType = (type) => typeof type === 'object' && 'type' in type && type.type === 'map'; | ||
const isEnumType = (type) => typeof type === 'object' && 'type' in type && type.type === 'enum'; | ||
const isLogicalType = (type) => typeof type === 'object' && 'logicalType' in type; | ||
const isUnion = (type) => typeof type === 'object' && Array.isArray(type); | ||
const isOptional = (type) => { | ||
if (isUnion(type)) { | ||
@@ -123,13 +138,27 @@ const t1 = type[0]; | ||
return false; | ||
} | ||
function fullyQualifiedName(type, namespace) { | ||
const currentNamespace = type.namespace || namespace; | ||
}; | ||
const fullyQualifiedName = (context, type) => { | ||
const currentNamespace = type.namespace || context.namespace; | ||
return currentNamespace ? `${currentNamespace}.${type.name}` : type.name; | ||
}; | ||
exports.printAstNode = (node) => { | ||
const resultFile = ts.createSourceFile('someFileName.ts', '', ts.ScriptTarget.Latest); | ||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); | ||
const entries = Object.values(node.context.registry); | ||
const fullSourceFile = ts.updateSourceFileNode(resultFile, entries); | ||
return [ | ||
printer.printNode(ts.EmitHint.Unspecified, node.type, fullSourceFile), | ||
...entries.map(entry => printer.printNode(ts.EmitHint.Unspecified, entry, fullSourceFile)), | ||
].join('\n\n'); | ||
}; | ||
function avroTs(recordType, logicalTypes = {}) { | ||
const context = { | ||
root: true, | ||
registry: {}, | ||
namespaces: {}, | ||
logicalTypes: Object.entries(logicalTypes).reduce((all, [name, type]) => ({ ...all, [name]: ts.createTypeReferenceNode(type, undefined) }), {}), | ||
}; | ||
return exports.printAstNode(convertRecord(context, recordType)); | ||
} | ||
function indent(text, prefix = ' ') { | ||
return text | ||
.split('\n') | ||
.map(row => prefix + row) | ||
.join('\n'); | ||
} | ||
exports.avroTs = avroTs; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@ovotech/avro-ts", | ||
"description": "Convert avro schemas into typescript interfaces", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"main": "dist/index.js", | ||
@@ -28,4 +28,3 @@ "source": "src/index.ts", | ||
"tslint": "^5.14.0", | ||
"tslint-config-prettier": "^1.18.0", | ||
"typescript": "^3.3.4000" | ||
"tslint-config-prettier": "^1.18.0" | ||
}, | ||
@@ -35,3 +34,6 @@ "jest": { | ||
}, | ||
"gitHead": "f68210eef2100a3c8e844c843e8745aa450cb62d" | ||
"dependencies": { | ||
"typescript": "^3.4.3" | ||
}, | ||
"gitHead": "33fbdb8057520cf1d3f229059a0231089febbaee" | ||
} |
@@ -5,3 +5,3 @@ # Avro TS | ||
It consists of a very quick sequential, functional parser. No dependencies. | ||
It consists of a very quick sequential, functional parser. Uses typescript's compiler api to convert avro to typescript AST, and pretty prints the results. No dependencies apart from typescript. | ||
@@ -17,5 +17,6 @@ ### Using | ||
```typescript | ||
import { schema } from 'avsc'; | ||
import { avroTs } from '@ovotech/avro-ts'; | ||
const avro: RecordType = JSON.parse(String(readFileSync(join(__dirname, 'avro', file)))); | ||
const avro: schema.RecordType = JSON.parse(String(readFileSync(join(__dirname, 'avro', file)))); | ||
const ts = avroTs(avro, { 'timestamp-millis': 'string', date: 'string' }); | ||
@@ -22,0 +23,0 @@ |
300
src/index.ts
@@ -1,3 +0,58 @@ | ||
import { ArrayType, BaseType, EnumType, Field, LogicalType, MapType, NamedType, RecordType, Type } from './types'; | ||
import { Schema, schema } from 'avsc'; | ||
import * as ts from 'typescript'; | ||
export interface Registry { | ||
[key: string]: ts.InterfaceDeclaration; | ||
} | ||
export interface Context { | ||
registry: Registry; | ||
root: boolean; | ||
namespace?: string; | ||
namespaces: { [key: string]: ts.TypeReferenceNode }; | ||
logicalTypes: { [key: string]: ts.TypeReferenceNode }; | ||
} | ||
export interface Result<TsType = ts.TypeNode> { | ||
type: TsType; | ||
context: Context; | ||
} | ||
export type Convert<TType = Schema> = (context: Context, type: TType) => Result<any>; | ||
export const result = <TsType = ts.TypeNode>(context: Context, type: TsType): Result<TsType> => ({ | ||
context, | ||
type, | ||
}); | ||
export const mapContext = <T = any, TsType = ts.TypeNode>( | ||
context: Context, | ||
items: T[], | ||
callbackfn: (context: Context, item: T) => Result<TsType>, | ||
) => | ||
items.reduce<{ items: TsType[]; context: Context }>( | ||
(all, item) => { | ||
const current = callbackfn(all.context, item); | ||
return { | ||
items: [...all.items, current.type], | ||
context: current.context, | ||
}; | ||
}, | ||
{ items: [], context }, | ||
); | ||
export const withEntry = (context: Context, entry: ts.InterfaceDeclaration): Context => ({ | ||
...context, | ||
registry: { ...context.registry, [entry.name.text]: entry }, | ||
}); | ||
export const withNamespace = (context: Context, record: schema.RecordType): Context => ({ | ||
...context, | ||
namespace: record.namespace, | ||
namespaces: { | ||
...context.namespaces, | ||
[fullyQualifiedName(context, record)]: ts.createTypeReferenceNode(record.name, undefined), | ||
}, | ||
}); | ||
export interface State { | ||
@@ -9,51 +64,66 @@ output: string[]; | ||
export function avroTs(recordType: RecordType, logicalTypes: State['logicalTypes'] = {}): string { | ||
const state: State = { output: [], repository: {}, logicalTypes }; | ||
const docToJSDoc = (doc: string) => | ||
`*\n${doc | ||
.split('\n') | ||
.map(line => ` * ${line}`) | ||
.join('\n')}\n `; | ||
convertRecord(recordType, state); | ||
return state.output.join('\n'); | ||
} | ||
const convertRecord: Convert<schema.RecordType> = (context, type) => { | ||
const namespaceContext = type.namespace ? withNamespace(context, type) : context; | ||
function convertRecord(recordType: RecordType, state: State, namespace?: string): string { | ||
if (recordType.namespace) { | ||
state.repository[fullyQualifiedName(recordType)] = recordType.name; | ||
} | ||
const fields = mapContext({ ...namespaceContext, root: false }, type.fields, (fieldContext, fieldType) => { | ||
const field = convertType(fieldContext, fieldType.type); | ||
const prop = ts.createPropertySignature( | ||
undefined, | ||
fieldType.name, | ||
isOptional(fieldType.type) ? ts.createToken(ts.SyntaxKind.QuestionToken) : undefined, | ||
field.type, | ||
undefined, | ||
); | ||
let buffer = `export interface ${recordType.name} {\n`; | ||
for (const field of recordType.fields) { | ||
buffer += convertFieldDec(field, state, recordType.namespace) + '\n'; | ||
} | ||
buffer += '}\n'; | ||
state.output.push(buffer); | ||
return recordType.name; | ||
} | ||
const propWithDoc = fieldType.doc | ||
? ts.addSyntheticLeadingComment(prop, ts.SyntaxKind.MultiLineCommentTrivia, docToJSDoc(fieldType.doc), true) | ||
: prop; | ||
function convertFieldDec(field: Field, state: State, namespace?: string): string { | ||
const optional = isOptional(field.type) ? '?' : ''; | ||
const doc = field.doc ? `/**\n * ${field.doc}\n */\n` : ''; | ||
return result(field.context, propWithDoc); | ||
}); | ||
return indent(`${doc}${field.name}${optional}: ${convertType(field.type, state, namespace)};`); | ||
} | ||
const interfaceType = ts.createInterfaceDeclaration( | ||
undefined, | ||
[ts.createToken(ts.SyntaxKind.ExportKeyword)], | ||
type.name, | ||
undefined, | ||
undefined, | ||
fields.items, | ||
); | ||
function convertType(type: Type, state: State, namespace?: string): string { | ||
if (context.root) { | ||
return result(fields.context, interfaceType); | ||
} else { | ||
return result(withEntry(fields.context, interfaceType), ts.createTypeReferenceNode(type.name, undefined)); | ||
} | ||
}; | ||
const convertType: Convert = (context, type) => { | ||
if (typeof type === 'string') { | ||
return convertPredefinedType(type, state) || convertPrimitive(type) || type; | ||
} else if (type instanceof Array) { | ||
return convertArrayType(type, state, namespace); | ||
return convertPredefinedType(context, type); | ||
} else if (Array.isArray(type)) { | ||
return convertArrayType(context, type); | ||
} else if (isLogicalType(type)) { | ||
return convertLogicalType(type, state); | ||
return convertLogicalType(context, type); | ||
} else if (isRecordType(type)) { | ||
return convertRecord(type, state, namespace); | ||
return convertRecord(context, type); | ||
} else if (isArrayType(type)) { | ||
return convertType(type.items, state, namespace) + '[]'; | ||
const itemType = convertType(context, type.items); | ||
return result(itemType.context, ts.createArrayTypeNode(itemType.type)); | ||
} else if (isMapType(type)) { | ||
return convertMapType(type, state, namespace); | ||
return convertMapType(context, type); | ||
} else if (isEnumType(type)) { | ||
return convertEnum(type); | ||
return convertEnum(context, type); | ||
} else { | ||
throw new Error(`Cannot work out type ${type}`); | ||
} | ||
} | ||
}; | ||
function convertPrimitive(avroType: string): string { | ||
const convertPrimitive: Convert = (context, avroType) => { | ||
switch (avroType) { | ||
@@ -64,69 +134,96 @@ case 'long': | ||
case 'float': | ||
return 'number'; | ||
return result(context, ts.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)); | ||
case 'bytes': | ||
return 'Buffer'; | ||
return result(context, ts.createTypeReferenceNode('Buffer', undefined)); | ||
case 'null': | ||
return 'null'; | ||
return result(context, ts.createNull()); | ||
case 'boolean': | ||
return 'boolean'; | ||
return result(context, ts.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword)); | ||
case 'string': | ||
return 'string'; | ||
return result(context, ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)); | ||
default: | ||
return 'any'; | ||
return result(context, ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)); | ||
} | ||
} | ||
}; | ||
function convertEnum(enumType: EnumType): string { | ||
return enumType.symbols.map(symbol => JSON.stringify(symbol)).join(' | '); | ||
} | ||
const convertEnum: Convert<schema.EnumType> = (context, enumType) => | ||
result( | ||
context, | ||
ts.createUnionTypeNode(enumType.symbols.map(symbol => ts.createLiteralTypeNode(ts.createLiteral(symbol)))), | ||
); | ||
function convertLogicalType(type: LogicalType, state: State): string { | ||
return state.logicalTypes[type.logicalType] || convertPrimitive(type.type); | ||
} | ||
const convertLogicalType: Convert<schema.LogicalType> = (context, type) => | ||
context.logicalTypes[type.logicalType] | ||
? result(context, context.logicalTypes[type.logicalType]) | ||
: convertPrimitive(context, type.type); | ||
function convertPredefinedType(type: string, state: State): string { | ||
return state.repository[type]; | ||
} | ||
const convertPredefinedType: Convert<string> = (context, type) => | ||
context.namespaces[type] ? result(context, context.namespaces[type]) : convertPrimitive(context, type); | ||
function convertArrayType(type: Type[], state: State, namespace?: string): string { | ||
return type | ||
.map(t => { | ||
if (typeof t === 'object' && !(t instanceof Array) && isRecordType(t)) { | ||
return `{ '${fullyQualifiedName(t, namespace)}' : ${convertType(t, state, namespace)} }`; | ||
} else { | ||
return convertType(t, state); | ||
} | ||
}) | ||
.join(' | '); | ||
} | ||
const convertArrayType: Convert<any[]> = (context, type) => { | ||
const map = mapContext(context, type, (itemContext, item) => { | ||
if (typeof item === 'object' && !Array.isArray(item) && isRecordType(item)) { | ||
const itemType = convertType(itemContext, item); | ||
return result( | ||
itemType.context, | ||
ts.createTypeLiteralNode([ | ||
ts.createPropertySignature( | ||
undefined, | ||
ts.createStringLiteral(fullyQualifiedName(context, item)), | ||
undefined, | ||
itemType.type, | ||
undefined, | ||
), | ||
]), | ||
); | ||
} else { | ||
return convertType(itemContext, item); | ||
} | ||
}); | ||
function convertMapType(type: MapType, state: State, namespace?: string): string { | ||
return `{ [index:string]:${convertType(type.values, state, namespace)} }`; | ||
} | ||
return result(map.context, ts.createUnionTypeNode(map.items)); | ||
}; | ||
function isRecordType(type: BaseType): type is RecordType { | ||
return type.type === 'record'; | ||
} | ||
const convertMapType: Convert<schema.MapType> = (context, type) => { | ||
const map = convertType(context, type.values); | ||
return result( | ||
map.context, | ||
ts.createTypeLiteralNode([ | ||
ts.createIndexSignature( | ||
undefined, | ||
undefined, | ||
[ | ||
ts.createParameter( | ||
undefined, | ||
undefined, | ||
undefined, | ||
'index', | ||
undefined, | ||
ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), | ||
undefined, | ||
), | ||
], | ||
map.type, | ||
), | ||
]), | ||
); | ||
}; | ||
function isArrayType(type: BaseType): type is ArrayType { | ||
return type.type === 'array'; | ||
} | ||
const isRecordType = (type: Schema): type is schema.RecordType => | ||
typeof type === 'object' && 'type' in type && type.type === 'record'; | ||
function isMapType(type: BaseType): type is MapType { | ||
return type.type === 'map'; | ||
} | ||
const isArrayType = (type: Schema): type is schema.ArrayType => | ||
typeof type === 'object' && 'type' in type && type.type === 'array'; | ||
function isEnumType(type: BaseType): type is EnumType { | ||
return type.type === 'enum'; | ||
} | ||
const isMapType = (type: Schema): type is schema.MapType => | ||
typeof type === 'object' && 'type' in type && type.type === 'map'; | ||
function isLogicalType(type: BaseType): type is LogicalType { | ||
return 'logicalType' in type; | ||
} | ||
const isEnumType = (type: Schema): type is schema.EnumType => | ||
typeof type === 'object' && 'type' in type && type.type === 'enum'; | ||
function isUnion(type: Type): type is NamedType[] { | ||
return type instanceof Array; | ||
} | ||
const isLogicalType = (type: Schema): type is schema.LogicalType => typeof type === 'object' && 'logicalType' in type; | ||
function isOptional(type: Type): boolean { | ||
const isUnion = (type: Schema): type is schema.NamedType[] => typeof type === 'object' && Array.isArray(type); | ||
const isOptional = (type: Schema): boolean => { | ||
if (isUnion(type)) { | ||
@@ -139,14 +236,33 @@ const t1 = type[0]; | ||
return false; | ||
} | ||
}; | ||
function fullyQualifiedName(type: RecordType, namespace?: string) { | ||
const currentNamespace = type.namespace || namespace; | ||
const fullyQualifiedName = (context: Context, type: schema.RecordType) => { | ||
const currentNamespace = type.namespace || context.namespace; | ||
return currentNamespace ? `${currentNamespace}.${type.name}` : type.name; | ||
} | ||
}; | ||
function indent(text: string, prefix = ' ') { | ||
return text | ||
.split('\n') | ||
.map(row => prefix + row) | ||
.join('\n'); | ||
export const printAstNode = (node: Result): string => { | ||
const resultFile = ts.createSourceFile('someFileName.ts', '', ts.ScriptTarget.Latest); | ||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); | ||
const entries = Object.values(node.context.registry); | ||
const fullSourceFile = ts.updateSourceFileNode(resultFile, entries); | ||
return [ | ||
printer.printNode(ts.EmitHint.Unspecified, node.type, fullSourceFile), | ||
...entries.map(entry => printer.printNode(ts.EmitHint.Unspecified, entry, fullSourceFile)), | ||
].join('\n\n'); | ||
}; | ||
export function avroTs(recordType: schema.RecordType, logicalTypes: { [key: string]: string } = {}): string { | ||
const context: Context = { | ||
root: true, | ||
registry: {}, | ||
namespaces: {}, | ||
logicalTypes: Object.entries(logicalTypes).reduce( | ||
(all, [name, type]) => ({ ...all, [name]: ts.createTypeReferenceNode(type, undefined) }), | ||
{}, | ||
), | ||
}; | ||
return printAstNode(convertRecord(context, recordType)); | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
28597
9
430
66
1
7
1
+ Addedtypescript@^3.4.3
+ Addedtypescript@3.9.10(transitive)