diff --git a/.prettierrc b/.prettierrc index cd319c57..012a8b10 100644 --- a/.prettierrc +++ b/.prettierrc @@ -4,4 +4,4 @@ "semi": false, "singleQuote": true, "arrowParens": "always" - } +} diff --git a/package-lock.json b/package-lock.json index c2e7ed79..94673f50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1699,9 +1699,9 @@ "dev": true }, "prettier": { - "version": "1.16.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", - "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.17.0.tgz", + "integrity": "sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw==", "dev": true }, "q": { @@ -1741,9 +1741,9 @@ "dev": true }, "source-map-support": { - "version": "0.5.11", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.11.tgz", - "integrity": "sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ==", + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", "dev": true, "requires": { "buffer-from": "^1.0.0", diff --git a/package.json b/package.json index 97303421..e5d8c0a6 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "scripts": { "clean": "rimraf ./coverage ./dist ./**/codegen", "clean:all": "npm run clean && rimraf ./node_modules package-lock.json", - "codegen": "node ./dist/main/bin/index.js --sourceDir ./src/tests/integration/thrift --outDir ./src/tests/integration/apache/codegen", + "codegen": "node ./dist/main/bin/index.js --target apache --sourceDir ./src/tests/integration/thrift --outDir ./src/tests/integration/apache/codegen", "prebuild": "npm run clean && npm run lint && npm run format", "build": "npm run build:only", "build:only": "tsc", @@ -57,7 +57,7 @@ "chai": "^4.2.0", "mocha": "^5.2.0", "nyc": "^13.3.0", - "prettier": "^1.15.3", + "prettier": "^1.17.0", "rimraf": "^2.6.2", "source-map-support": "^0.5.9", "thrift": "^0.11.0", diff --git a/src/main/generator/index.ts b/src/main/generator/index.ts index f82aaf75..1e4f4bcd 100644 --- a/src/main/generator/index.ts +++ b/src/main/generator/index.ts @@ -11,7 +11,7 @@ import { import { rendererForTarget } from '../render' import { processStatements, renderStatement } from './iterator' -import { exportsForFile } from '../resolver/utils' +import { exportsForFile } from '../resolver' import { IGeneratedFile, INamespace, diff --git a/src/main/index.ts b/src/main/index.ts index df62a34b..b98c3baf 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -3,7 +3,6 @@ import * as path from 'path' import { parseFromSource, parseThriftFile } from './parser' import { - CompileTarget, IFileExports, IGeneratedFile, IMakeOptions, @@ -32,9 +31,19 @@ import { print } from './printer' import { readThriftFile } from './reader' import { rendererForTarget } from './render' import { resolveFile } from './resolver' -import { exportsForFile } from './resolver/utils' +import { exportsForFile } from './resolver' import { validateFile } from './validator' +import * as Parser from './parser' +import * as Resolver from './resolver' +import * as Validator from './validator' +import * as Utils from './utils' + +export { Resolver } +export { Parser } +export { Validator } +export { Utils } + /** * This function is mostly for testing purposes. It does not support includes. * Given a string of Thrift IDL it will return a string of TypeScript. If the @@ -45,29 +54,19 @@ import { validateFile } from './validator' */ export function make( source: string, - target: CompileTarget = 'thrift-server', - strictUnions: boolean = false, + options: Partial = {}, ): string { - const options: IMakeOptions = mergeWithDefaults({ - target, - strictUnions, - }) - const parsedFile: IParsedFile = parseFromSource(source, options) - const resolvedFile: IResolvedFile = resolveFile(parsedFile, {}, '', options) - const validatedFile: IResolvedFile = validateFile(resolvedFile, {}, '') - - if (validatedFile.errors.length > 0) { - throw new Error(`Shit broke`) - } + const mergedOptions: IMakeOptions = mergeWithDefaults(options) + const validatedFile: IResolvedFile = parseThriftSource(source, options) - const fileExports: IFileExports = exportsForFile(resolvedFile.body) + const fileExports: IFileExports = exportsForFile(validatedFile.body) const state: IRenderState = { - options, + options: mergedOptions, currentNamespace: { type: 'Namespace', namespace: emptyNamespace(), files: { - [resolvedFile.sourceFile.fullPath]: resolvedFile, + [validatedFile.sourceFile.fullPath]: validatedFile, }, exports: fileExports, includedNamespaces: {}, @@ -85,41 +84,53 @@ export function make( sourceDir: '', outDir: '', namespaces: {}, - options, + options: mergedOptions, }, } return print( - processStatements(resolvedFile.body, state, rendererForTarget(target)), + processStatements( + validatedFile.body, + state, + rendererForTarget(mergedOptions.target), + ), ) } -export async function generate(options: Partial): Promise { +export function parseThriftSource( + source: string, + options: Partial = {}, +): IResolvedFile { const mergedOptions: IMakeOptions = mergeWithDefaults(options) - - // Root at which we operate relative to - const rootDir: string = path.resolve(process.cwd(), mergedOptions.rootDir) - - // Where do we save generated files - const outDir: string = path.resolve(rootDir, mergedOptions.outDir) - - // Where do we read source files - const sourceDir: string = path.resolve(rootDir, mergedOptions.sourceDir) - - const fileNames: Array = collectSourceFiles( - sourceDir, - mergedOptions, + const parsedFile: IParsedFile = parseFromSource( + source, + mergedOptions.fallbackNamespace, ) - - const thriftFiles: Array = await Promise.all( - fileNames.map((next: string) => { - return readThriftFile(next, [sourceDir]) - }), + const resolvedFile: IResolvedFile = resolveFile( + parsedFile, + {}, + '', + mergedOptions.fallbackNamespace, ) + const validatedFile: IResolvedFile = validateFile(resolvedFile, {}, '') + if (validatedFile.errors.length > 0) { + throw new Error(`Unable to validate thrift source`) + } + + return validatedFile +} + +export async function parseThriftFiles( + thriftFiles: Array, + options: { + sourceDir: string + fallbackNamespace: string + }, +): Promise> { const parsedFiles: Array = thriftFiles.map( (next: ISourceFile) => { - const parsed = parseThriftFile(next, mergedOptions) + const parsed = parseThriftFile(next, options.fallbackNamespace) return parsed }, ) @@ -134,7 +145,12 @@ export async function generate(options: Partial): Promise { const resolvedFiles: Array = parsedFiles.map( (next: IParsedFile) => { - return resolveFile(next, parsedFileMap, sourceDir, mergedOptions) + return resolveFile( + next, + parsedFileMap, + options.sourceDir, + options.fallbackNamespace, + ) }, ) @@ -144,7 +160,7 @@ export async function generate(options: Partial): Promise { if (resolvedInvalidFiles.length > 0) { printErrors(resolvedInvalidFiles) - process.exitCode = 1 + throw new Error(`Unable to parse Thrift files`) } else { const resolvedFileMap: ResolvedFileMap = resolvedFiles.reduce( (acc: ResolvedFileMap, next: IResolvedFile) => { @@ -155,7 +171,7 @@ export async function generate(options: Partial): Promise { ) const validatedFiles: Array = resolvedFiles.map( (next: IResolvedFile) => { - return validateFile(next, resolvedFileMap, sourceDir) + return validateFile(next, resolvedFileMap, options.sourceDir) }, ) @@ -165,24 +181,76 @@ export async function generate(options: Partial): Promise { if (validatedInvalidFiles.length > 0) { printErrors(validatedInvalidFiles) - process.exitCode = 1 + throw new Error(`Unable to parse Thrift files`) } else { - const namespaces: INamespaceMap = organizeByNamespace(resolvedFiles) - - const thriftProject: IThriftProject = { - type: 'ThriftProject', - rootDir, - outDir, - sourceDir, - namespaces, - options: mergedOptions, - } - - const generatedFiles: Array = generateProject( - thriftProject, - ) - - saveFiles(generatedFiles, outDir) + return validatedFiles } } } + +export async function readThriftFiles(options: { + rootDir: string + sourceDir: string + files?: Array +}): Promise> { + // Root at which we operate relative to + const rootDir: string = path.resolve(process.cwd(), options.rootDir) + + // Where do we read source files + const sourceDir: string = path.resolve(rootDir, options.sourceDir) + + const fileNames: Array = collectSourceFiles( + sourceDir, + options.files, + ) + + const thriftFiles: Array = await Promise.all( + fileNames.map((next: string) => { + return readThriftFile(next, [sourceDir]) + }), + ) + + return thriftFiles +} + +export async function generate(options: Partial): Promise { + const mergedOptions: IMakeOptions = mergeWithDefaults(options) + + // Root at which we operate relative to + const rootDir: string = path.resolve(process.cwd(), mergedOptions.rootDir) + + // Where do we save generated files + const outDir: string = path.resolve(rootDir, mergedOptions.outDir) + + // Where do we read source files + const sourceDir: string = path.resolve(rootDir, mergedOptions.sourceDir) + + const thriftFiles: Array = await readThriftFiles({ + rootDir, + sourceDir, + files: mergedOptions.files, + }) + + const validatedFiles: Array = await parseThriftFiles( + thriftFiles, + { + sourceDir, + fallbackNamespace: mergedOptions.fallbackNamespace, + }, + ) + + const namespaces: INamespaceMap = organizeByNamespace(validatedFiles) + + const thriftProject: IThriftProject = { + type: 'ThriftProject', + rootDir, + outDir, + sourceDir, + namespaces, + options: mergedOptions, + } + + const generatedFiles: Array = generateProject(thriftProject) + + saveFiles(generatedFiles, outDir) +} diff --git a/src/main/parser/index.ts b/src/main/parser/index.ts index 50180a0f..f044db93 100644 --- a/src/main/parser/index.ts +++ b/src/main/parser/index.ts @@ -4,11 +4,10 @@ import { ThriftDocument, ThriftErrors, } from '@creditkarma/thrift-parser' -import { exportsForFile } from '../resolver/utils' +import { exportsForFile } from '../resolver' import { IFileExports, IFileIncludes, - IMakeOptions, INamespacePath, IParsedFile, ISourceFile, @@ -28,7 +27,7 @@ export function parseThriftString(source: string): ThriftDocument { export function parseFromSource( source: string, - options: IMakeOptions, + fallbackNamespace: string, ): IParsedFile { const sourceFile: ISourceFile = { type: 'SourceFile', @@ -38,16 +37,19 @@ export function parseFromSource( source, } - return parseThriftFile(sourceFile, options) + return parseThriftFile(sourceFile, fallbackNamespace) } export function parseThriftFile( file: ISourceFile, - options: IMakeOptions, + fallbackNamespace: string, ): IParsedFile { const thriftDoc: ThriftDocument = parseThriftString(file.source) const exports: IFileExports = exportsForFile(thriftDoc.body) - const namespace: INamespacePath = namespaceForFile(thriftDoc.body, options) + const namespace: INamespacePath = namespaceForFile( + thriftDoc.body, + fallbackNamespace, + ) const includes: IFileIncludes = includesForFile(thriftDoc.body, file) return { diff --git a/src/main/render/apache/service/client.ts b/src/main/render/apache/service/client.ts index 4d01d924..a40d6c17 100644 --- a/src/main/render/apache/service/client.ts +++ b/src/main/render/apache/service/client.ts @@ -40,7 +40,7 @@ import { typeNodeForFieldType, } from '../types' -import { resolveIdentifierName } from '../../../resolver/utils' +import { resolveIdentifierName } from '../../../resolver' import { IRenderState } from '../../../types' export function renderClient( diff --git a/src/main/render/apache/service/processor.ts b/src/main/render/apache/service/processor.ts index 559b159c..009fa94d 100644 --- a/src/main/render/apache/service/processor.ts +++ b/src/main/render/apache/service/processor.ts @@ -28,7 +28,7 @@ import { import { resolveIdentifierDefinition, resolveIdentifierName, -} from '../../../resolver/utils' +} from '../../../resolver' import { IRenderState } from '../../../types' import { diff --git a/src/main/render/apache/struct/read.ts b/src/main/render/apache/struct/read.ts index 854b958e..41b24d36 100644 --- a/src/main/render/apache/struct/read.ts +++ b/src/main/render/apache/struct/read.ts @@ -36,7 +36,7 @@ import { THRIFT_IDENTIFIERS, THRIFT_TYPES } from '../identifiers' import { resolveIdentifierDefinition, resolveIdentifierName, -} from '../../../resolver/utils' +} from '../../../resolver' import { READ_METHODS } from './methods' /** diff --git a/src/main/render/apache/struct/write.ts b/src/main/render/apache/struct/write.ts index 2d414836..e2e6984b 100644 --- a/src/main/render/apache/struct/write.ts +++ b/src/main/render/apache/struct/write.ts @@ -30,7 +30,7 @@ import { import { COMMON_IDENTIFIERS, THRIFT_IDENTIFIERS } from '../identifiers' -import { resolveIdentifierDefinition } from '../../../resolver/utils' +import { resolveIdentifierDefinition } from '../../../resolver' import { WRITE_METHODS, WriteMethodName } from './methods' function isNotVoid(field: FieldDefinition): boolean { diff --git a/src/main/render/apache/typedef.ts b/src/main/render/apache/typedef.ts index 5b1a7799..50cd6f27 100644 --- a/src/main/render/apache/typedef.ts +++ b/src/main/render/apache/typedef.ts @@ -4,7 +4,7 @@ import { SyntaxType, TypedefDefinition } from '@creditkarma/thrift-parser' import { TypeMapping } from './types' -import { resolveIdentifierName } from '../../resolver/utils' +import { resolveIdentifierName } from '../../resolver' import { IRenderState, IResolvedIdentifier } from '../../types' function renderTypeDefForIdentifier( diff --git a/src/main/render/apache/types.ts b/src/main/render/apache/types.ts index 637c32ac..dd6b0ef6 100644 --- a/src/main/render/apache/types.ts +++ b/src/main/render/apache/types.ts @@ -14,7 +14,7 @@ import { import { resolveIdentifierDefinition, resolveIdentifierName, -} from '../../resolver/utils' +} from '../../resolver' import { createBooleanType, createNumberType, diff --git a/src/main/render/apache/values.ts b/src/main/render/apache/values.ts index f7e353e9..07661816 100644 --- a/src/main/render/apache/values.ts +++ b/src/main/render/apache/values.ts @@ -16,7 +16,7 @@ import { import { COMMON_IDENTIFIERS } from './identifiers' -import { resolveIdentifierName } from '../../resolver/utils' +import { resolveIdentifierName } from '../../resolver' import { IRenderState } from '../../types' import { propertyAccessForIdentifier } from './utils' diff --git a/src/main/render/shared/service/index.ts b/src/main/render/shared/service/index.ts index f1ad27f9..b73b30b3 100644 --- a/src/main/render/shared/service/index.ts +++ b/src/main/render/shared/service/index.ts @@ -10,7 +10,7 @@ import { COMMON_IDENTIFIERS } from '../identifiers' import { createAnyType, TypeMapping } from '../types' -import { resolveIdentifierName } from '../../../resolver/utils' +import { resolveIdentifierName } from '../../../resolver' import { IRenderState } from '../../../types' import { createFunctionParameter } from '../utils' diff --git a/src/main/render/thrift-server/initializers.ts b/src/main/render/thrift-server/initializers.ts index 3ed38bfc..26c9c2fe 100644 --- a/src/main/render/thrift-server/initializers.ts +++ b/src/main/render/thrift-server/initializers.ts @@ -16,7 +16,7 @@ import { import { COMMON_IDENTIFIERS } from './identifiers' -import { resolveIdentifierName } from '../../resolver/utils' +import { resolveIdentifierName } from '../../resolver' import { IRenderState } from '../../types' import { propertyAccessForIdentifier } from './utils' diff --git a/src/main/render/thrift-server/service/client.ts b/src/main/render/thrift-server/service/client.ts index e28bb384..fbc65646 100644 --- a/src/main/render/thrift-server/service/client.ts +++ b/src/main/render/thrift-server/service/client.ts @@ -47,7 +47,7 @@ import { renderServiceAnnotationsStaticProperty, } from '../annotations' -import { resolveIdentifierName } from '../../../resolver/utils' +import { resolveIdentifierName } from '../../../resolver' import { createClassConstructor } from '../../shared/utils' import { looseName, strictName, toolkitName } from '../struct/utils' diff --git a/src/main/render/thrift-server/service/processor.ts b/src/main/render/thrift-server/service/processor.ts index 2f832e19..e2160d6e 100644 --- a/src/main/render/thrift-server/service/processor.ts +++ b/src/main/render/thrift-server/service/processor.ts @@ -63,7 +63,7 @@ import { import { resolveIdentifierDefinition, resolveIdentifierName, -} from '../../../resolver/utils' +} from '../../../resolver' import { className, looseName, strictName, toolkitName } from '../struct/utils' function objectLiteralForServiceFunctions( diff --git a/src/main/render/thrift-server/service/utils.ts b/src/main/render/thrift-server/service/utils.ts index 691ba291..ce827984 100644 --- a/src/main/render/thrift-server/service/utils.ts +++ b/src/main/render/thrift-server/service/utils.ts @@ -13,7 +13,7 @@ import { DefinitionType, IRenderState } from '../../../types' import { COMMON_IDENTIFIERS } from '../identifiers' -import { resolveIdentifierDefinition } from '../../../resolver/utils' +import { resolveIdentifierDefinition } from '../../../resolver' import { createStringType } from '../../shared/types' export function capitalize(str: string): string { diff --git a/src/main/render/thrift-server/struct/decode.ts b/src/main/render/thrift-server/struct/decode.ts index 0c7d91a7..d12bf442 100644 --- a/src/main/render/thrift-server/struct/decode.ts +++ b/src/main/render/thrift-server/struct/decode.ts @@ -40,7 +40,7 @@ import { DefinitionType, IRenderState } from '../../../types' import { READ_METHODS } from './methods' -import { resolveIdentifierDefinition } from '../../../resolver/utils' +import { resolveIdentifierDefinition } from '../../../resolver' import { strictNameForStruct, toolkitName } from './utils' diff --git a/src/main/render/thrift-server/struct/encode.ts b/src/main/render/thrift-server/struct/encode.ts index 24296cd9..5185a442 100644 --- a/src/main/render/thrift-server/struct/encode.ts +++ b/src/main/render/thrift-server/struct/encode.ts @@ -15,7 +15,7 @@ import { COMMON_IDENTIFIERS, THRIFT_IDENTIFIERS } from '../identifiers' import { WRITE_METHODS, WriteMethodName } from './methods' -import { resolveIdentifierDefinition } from '../../../resolver/utils' +import { resolveIdentifierDefinition } from '../../../resolver' import { coerceType, diff --git a/src/main/render/thrift-server/struct/reader.ts b/src/main/render/thrift-server/struct/reader.ts index dab4fc73..f957fa28 100644 --- a/src/main/render/thrift-server/struct/reader.ts +++ b/src/main/render/thrift-server/struct/reader.ts @@ -16,7 +16,7 @@ import { import { className, toolkitName } from './utils' -import { resolveIdentifierDefinition } from '../../../resolver/utils' +import { resolveIdentifierDefinition } from '../../../resolver' import { DefinitionType, IRenderState } from '../../../types' import { createMethodCall } from '../../shared/utils' import { COMMON_IDENTIFIERS } from '../identifiers' diff --git a/src/main/render/thrift-server/struct/utils.ts b/src/main/render/thrift-server/struct/utils.ts index a72edf10..7f266389 100644 --- a/src/main/render/thrift-server/struct/utils.ts +++ b/src/main/render/thrift-server/struct/utils.ts @@ -8,7 +8,7 @@ import { import { COMMON_IDENTIFIERS, THRIFT_IDENTIFIERS } from '../identifiers' -import { resolveIdentifierName } from '../../../resolver/utils' +import { resolveIdentifierName } from '../../../resolver' import { IRenderState, IResolvedIdentifier } from '../../../types' import { throwProtocolException } from '../utils' diff --git a/src/main/render/thrift-server/typedef.ts b/src/main/render/thrift-server/typedef.ts index 0ae7a09a..01868369 100644 --- a/src/main/render/thrift-server/typedef.ts +++ b/src/main/render/thrift-server/typedef.ts @@ -24,7 +24,7 @@ import { import { resolveIdentifierDefinition, resolveIdentifierName, -} from '../../resolver/utils' +} from '../../resolver' function renderStrictInterfaceReexport( id: IResolvedIdentifier, diff --git a/src/main/render/thrift-server/types.ts b/src/main/render/thrift-server/types.ts index ce77456a..f67d8091 100644 --- a/src/main/render/thrift-server/types.ts +++ b/src/main/render/thrift-server/types.ts @@ -21,7 +21,7 @@ import { import { resolveIdentifierDefinition, resolveIdentifierName, -} from '../../resolver/utils' +} from '../../resolver' import { looseName, strictName } from './struct/utils' export * from '../shared/types' diff --git a/src/main/resolver/index.ts b/src/main/resolver/index.ts index 775d66aa..9d95c9c6 100644 --- a/src/main/resolver/index.ts +++ b/src/main/resolver/index.ts @@ -1,466 +1,7 @@ -import { - ConstValue, - EnumMember, - FieldDefinition, - FieldID, - FieldType, - FunctionDefinition, - FunctionType, - Identifier, - IntConstant, - SyntaxType, - ThriftStatement, -} from '@creditkarma/thrift-parser' - -import { - IFileExports, - IMakeOptions, - INamespacePath, - INamespacePathMap, - INamespaceToIncludeMap, - IParsedFile, - IResolvedFile, - ParsedFileMap, -} from '../types' - -import { createValidationError, IThriftError, ValidationError } from '../errors' - -import { emptyLocation, namespaceForInclude } from '../utils' - -import { +export { resolveFile } from './resolveFile' +export { exportsForFile, - resolveConstValue, resolveIdentifierDefinition, + resolveConstValue, + resolveIdentifierName, } from './utils' - -/** - * What do you mean, resolve file? - * - * There are a few things we need to do to resolve a file. - * - * 1. We need to resolve the value of all the identifiers in a given file. - * - * 2. We need to keep track of all the namespaces being used in this file. - * - * 3. We need to rewrite the paths for imported identifiers. - * - * For example, if a identifier is being imported from another file such as "operation.Operation", we - * need to rewrite this so that the file path is replaced with the namespace path such as - * "com_test_operation.Operation" - * - * 4. We need to rewrite indetifiers that point to primitive constants with the primitive value. - * - * 5. We need to make sure every field has an ID - * - * 6. We need to rewrite all enum members with an initiaizer - * - * - * @param parsedFile - * @param files - * @param sourceDir - * @param options - */ -export function resolveFile( - parsedFile: IParsedFile, - files: ParsedFileMap, - sourceDir: string, - options: IMakeOptions, -): IResolvedFile { - const body: Array = parsedFile.body - const bodySize: number = body.length - let currentIndex: number = 0 - - const errors: Array = [] - const includedNamespaces: INamespacePathMap = {} - const namespaceToInclude: INamespaceToIncludeMap = {} - - function resolveStatements(): Array { - const newBody: Array = [] - while (!isAtEnd()) { - try { - const statement = resolveStatement(body[currentIndex]) - - if (statement !== null) { - newBody.push(statement) - } - } catch (e) { - errors.push(createValidationError(e.message, e.loc)) - } - - currentIndex += 1 - } - - return newBody - } - - function isAtEnd(): boolean { - return currentIndex >= bodySize - } - - function resolveStatement( - statement: ThriftStatement, - ): ThriftStatement | null { - switch (statement.type) { - case SyntaxType.NamespaceDefinition: - case SyntaxType.IncludeDefinition: - case SyntaxType.CppIncludeDefinition: - return null - - case SyntaxType.TypedefDefinition: - return { - type: SyntaxType.TypedefDefinition, - name: statement.name, - definitionType: resolveFieldType(statement.definitionType), - annotations: statement.annotations, - comments: statement.comments, - loc: statement.loc, - } - - case SyntaxType.ConstDefinition: - return { - type: SyntaxType.ConstDefinition, - name: statement.name, - fieldType: resolveFieldType(statement.fieldType), - initializer: resolveValue( - statement.initializer, - statement.fieldType, - ), - comments: statement.comments, - annotations: statement.annotations, - loc: statement.loc, - } - - case SyntaxType.EnumDefinition: - return { - type: SyntaxType.EnumDefinition, - name: statement.name, - members: resolveEnumMembers(statement.members), - comments: statement.comments, - annotations: statement.annotations, - loc: statement.loc, - } - - case SyntaxType.StructDefinition: - return { - type: SyntaxType.StructDefinition, - name: statement.name, - fields: resolveFields(statement.fields), - comments: statement.comments, - annotations: statement.annotations, - loc: statement.loc, - } - - case SyntaxType.UnionDefinition: - return { - type: SyntaxType.UnionDefinition, - name: statement.name, - fields: resolveFields(statement.fields), - comments: statement.comments, - annotations: statement.annotations, - loc: statement.loc, - } - - case SyntaxType.ExceptionDefinition: - return { - type: SyntaxType.ExceptionDefinition, - name: statement.name, - fields: resolveFields(statement.fields), - comments: statement.comments, - annotations: statement.annotations, - loc: statement.loc, - } - - case SyntaxType.ServiceDefinition: - return { - type: SyntaxType.ServiceDefinition, - name: statement.name, - functions: resolveFunctions(statement.functions), - extends: - statement.extends === null - ? null - : resolveIdentifier(statement.extends), - comments: statement.comments, - annotations: statement.annotations, - loc: statement.loc, - } - - default: - const msg: never = statement - throw new Error(`Non-exhaustive match for ${msg}`) - } - } - - function resolveIdentifier(id: Identifier): Identifier { - return { - type: SyntaxType.Identifier, - value: resolveName(id.value), - annotations: id.annotations, - loc: id.loc, - } - } - - function resolveName(name: string): string { - const [head, ...tail] = name.split('.') - if (parsedFile.exports[head] !== undefined) { - return name - } else if (parsedFile.includes[head] !== undefined) { - const namespace: INamespacePath = namespaceForInclude( - parsedFile.includes[head], - files, - sourceDir, - options, - ) - const includeAccessor: string = namespace.name - .split('') - .map((next: string) => { - if (next === '.') { - return '_' - } else { - return next - } - }) - .join('') - includedNamespaces[includeAccessor] = namespace - namespaceToInclude[includeAccessor] = head - return [includeAccessor, ...tail].join('.') - } else { - return name - } - } - - function resolveFunctionType(fieldType: FunctionType): FunctionType { - switch (fieldType.type) { - case SyntaxType.VoidKeyword: - return fieldType - - default: - return resolveFieldType(fieldType) - } - } - - function isBaseType(fieldType: FieldType): boolean { - switch (fieldType.type) { - case SyntaxType.I8Keyword: - case SyntaxType.I16Keyword: - case SyntaxType.I32Keyword: - case SyntaxType.I64Keyword: - case SyntaxType.StringKeyword: - case SyntaxType.BinaryKeyword: - return true - default: - return false - } - } - - function resolveFieldType(fieldType: FieldType): FieldType { - switch (fieldType.type) { - /** - * An Identifier can refer to either a container type or an alias to another - * type. Here we check for the typedef case and resolve to the base type in that - * case. - */ - case SyntaxType.Identifier: - const definition = resolveIdentifierDefinition( - fieldType, - parsedFile, - files, - sourceDir, - ) - if (definition.type === SyntaxType.TypedefDefinition) { - if (isBaseType(definition.definitionType)) { - return definition.definitionType - } else { - return resolveIdentifier(fieldType) - } - } else { - return resolveIdentifier(fieldType) - } - - case SyntaxType.ListType: - return { - type: SyntaxType.ListType, - valueType: resolveFieldType(fieldType.valueType), - annotations: fieldType.annotations, - loc: fieldType.loc, - } - - case SyntaxType.SetType: - return { - type: SyntaxType.SetType, - valueType: resolveFieldType(fieldType.valueType), - annotations: fieldType.annotations, - loc: fieldType.loc, - } - - case SyntaxType.MapType: - return { - type: SyntaxType.MapType, - valueType: resolveFieldType(fieldType.valueType), - keyType: resolveFieldType(fieldType.keyType), - annotations: fieldType.annotations, - loc: fieldType.loc, - } - - default: - return fieldType - } - } - - function resolveEnumMembers( - enumMembers: Array, - ): Array { - let previousValue: number = -1 - - return enumMembers.map( - (next: EnumMember): EnumMember => { - let initializer: IntConstant - - if (next.initializer !== null) { - previousValue = parseInt(next.initializer.value.value, 10) - initializer = next.initializer - } else { - initializer = { - type: SyntaxType.IntConstant, - value: { - type: SyntaxType.IntegerLiteral, - value: `${++previousValue}`, - loc: emptyLocation(), - }, - loc: emptyLocation(), - } - } - - return { - type: SyntaxType.EnumMember, - name: next.name, - initializer, - comments: next.comments, - annotations: next.annotations, - loc: next.loc, - } - }, - ) - } - - function resolveValue( - value: ConstValue, - fieldType: FunctionType, - ): ConstValue { - const resolvedValue: ConstValue = resolveConstValue( - value, - fieldType, - parsedFile, - files, - sourceDir, - ) - - if (resolvedValue.type === SyntaxType.Identifier) { - return resolveIdentifier(resolvedValue) - } else { - return resolvedValue - } - } - - function resolveFields( - fields: Array, - ): Array { - let generatedFieldID: number = 0 - const usedFieldIDs: Array = [] - - function resolveFieldID(fieldID: FieldID | null): FieldID { - if (fieldID === null) { - return { - type: SyntaxType.FieldID, - value: --generatedFieldID, - loc: emptyLocation(), - } - } else if (fieldID.value < 0) { - throw new ValidationError( - `Field IDs should be positive integers, found ${ - fieldID.value - }`, - fieldID.loc, - ) - } else if (usedFieldIDs.indexOf(fieldID.value) > -1) { - throw new ValidationError( - `Found duplicate usage of fieldID: ${fieldID.value}`, - fieldID.loc, - ) - } else { - usedFieldIDs.push(fieldID.value) - return fieldID - } - } - - return fields.map( - (field: FieldDefinition): FieldDefinition => { - return { - type: SyntaxType.FieldDefinition, - name: field.name, - fieldID: resolveFieldID(field.fieldID), - fieldType: resolveFunctionType(field.fieldType), - requiredness: field.requiredness, - defaultValue: - field.defaultValue === null - ? null - : resolveValue(field.defaultValue, field.fieldType), - comments: field.comments, - annotations: field.annotations, - loc: field.loc, - } - }, - ) - } - - function resolveFunctions( - funcs: Array, - ): Array { - return funcs.map( - (func: FunctionDefinition): FunctionDefinition => { - return { - type: SyntaxType.FunctionDefinition, - name: func.name, - oneway: func.oneway, - returnType: resolveFunctionType(func.returnType), - fields: resolveFields( - func.fields.map((next: FieldDefinition) => { - next.requiredness = - next.requiredness === 'optional' - ? 'optional' - : 'required' - return next - }), - ), - throws: resolveFields( - func.throws.map((next: FieldDefinition) => { - next.requiredness = - next.requiredness === 'optional' - ? 'optional' - : 'required' - return next - }), - ), - modifiers: func.modifiers, - comments: func.comments, - annotations: func.annotations, - loc: func.loc, - } - }, - ) - } - - const resolvedBody: Array = resolveStatements() - const resolvedExports: IFileExports = exportsForFile(resolvedBody) - - return { - type: 'ResolvedFile', - sourceFile: parsedFile.sourceFile, - namespace: parsedFile.namespace, - includedNamespaces, - namespaceToInclude, - includes: parsedFile.includes, - exports: resolvedExports, - body: resolvedBody, - errors, - } -} diff --git a/src/main/resolver/resolveFile.ts b/src/main/resolver/resolveFile.ts new file mode 100644 index 00000000..ef8f737c --- /dev/null +++ b/src/main/resolver/resolveFile.ts @@ -0,0 +1,465 @@ +import { + ConstValue, + EnumMember, + FieldDefinition, + FieldID, + FieldType, + FunctionDefinition, + FunctionType, + Identifier, + IntConstant, + SyntaxType, + ThriftStatement, +} from '@creditkarma/thrift-parser' + +import { + IFileExports, + INamespacePath, + INamespacePathMap, + INamespaceToIncludeMap, + IParsedFile, + IResolvedFile, + ParsedFileMap, +} from '../types' + +import { createValidationError, IThriftError, ValidationError } from '../errors' + +import { emptyLocation, namespaceForInclude } from '../utils' + +import { + exportsForFile, + resolveConstValue, + resolveIdentifierDefinition, +} from './utils' + +/** + * What do you mean, resolve file? + * + * There are a few things we need to do to resolve a file. + * + * 1. We need to resolve the value of all the identifiers in a given file. + * + * 2. We need to keep track of all the namespaces being used in this file. + * + * 3. We need to rewrite the paths for imported identifiers. + * + * For example, if a identifier is being imported from another file such as "operation.Operation", we + * need to rewrite this so that the file path is replaced with the namespace path such as + * "com_test_operation.Operation" + * + * 4. We need to rewrite indetifiers that point to primitive constants with the primitive value. + * + * 5. We need to make sure every field has an ID + * + * 6. We need to rewrite all enum members with an initiaizer + * + * + * @param parsedFile + * @param files + * @param sourceDir + * @param options + */ +export function resolveFile( + parsedFile: IParsedFile, + files: ParsedFileMap, + sourceDir: string, + fallbackNamespace: string, +): IResolvedFile { + const body: Array = parsedFile.body + const bodySize: number = body.length + let currentIndex: number = 0 + + const errors: Array = [] + const includedNamespaces: INamespacePathMap = {} + const namespaceToInclude: INamespaceToIncludeMap = {} + + function resolveStatements(): Array { + const newBody: Array = [] + while (!isAtEnd()) { + try { + const statement = resolveStatement(body[currentIndex]) + + if (statement !== null) { + newBody.push(statement) + } + } catch (e) { + errors.push(createValidationError(e.message, e.loc)) + } + + currentIndex += 1 + } + + return newBody + } + + function isAtEnd(): boolean { + return currentIndex >= bodySize + } + + function resolveStatement( + statement: ThriftStatement, + ): ThriftStatement | null { + switch (statement.type) { + case SyntaxType.NamespaceDefinition: + case SyntaxType.IncludeDefinition: + case SyntaxType.CppIncludeDefinition: + return null + + case SyntaxType.TypedefDefinition: + return { + type: SyntaxType.TypedefDefinition, + name: statement.name, + definitionType: resolveFieldType(statement.definitionType), + annotations: statement.annotations, + comments: statement.comments, + loc: statement.loc, + } + + case SyntaxType.ConstDefinition: + return { + type: SyntaxType.ConstDefinition, + name: statement.name, + fieldType: resolveFieldType(statement.fieldType), + initializer: resolveValue( + statement.initializer, + statement.fieldType, + ), + comments: statement.comments, + annotations: statement.annotations, + loc: statement.loc, + } + + case SyntaxType.EnumDefinition: + return { + type: SyntaxType.EnumDefinition, + name: statement.name, + members: resolveEnumMembers(statement.members), + comments: statement.comments, + annotations: statement.annotations, + loc: statement.loc, + } + + case SyntaxType.StructDefinition: + return { + type: SyntaxType.StructDefinition, + name: statement.name, + fields: resolveFields(statement.fields), + comments: statement.comments, + annotations: statement.annotations, + loc: statement.loc, + } + + case SyntaxType.UnionDefinition: + return { + type: SyntaxType.UnionDefinition, + name: statement.name, + fields: resolveFields(statement.fields), + comments: statement.comments, + annotations: statement.annotations, + loc: statement.loc, + } + + case SyntaxType.ExceptionDefinition: + return { + type: SyntaxType.ExceptionDefinition, + name: statement.name, + fields: resolveFields(statement.fields), + comments: statement.comments, + annotations: statement.annotations, + loc: statement.loc, + } + + case SyntaxType.ServiceDefinition: + return { + type: SyntaxType.ServiceDefinition, + name: statement.name, + functions: resolveFunctions(statement.functions), + extends: + statement.extends === null + ? null + : resolveIdentifier(statement.extends), + comments: statement.comments, + annotations: statement.annotations, + loc: statement.loc, + } + + default: + const msg: never = statement + throw new Error(`Non-exhaustive match for ${msg}`) + } + } + + function resolveIdentifier(id: Identifier): Identifier { + return { + type: SyntaxType.Identifier, + value: resolveName(id.value), + annotations: id.annotations, + loc: id.loc, + } + } + + function resolveName(name: string): string { + const [head, ...tail] = name.split('.') + if (parsedFile.exports[head] !== undefined) { + return name + } else if (parsedFile.includes[head] !== undefined) { + const namespace: INamespacePath = namespaceForInclude( + parsedFile.includes[head], + files, + sourceDir, + fallbackNamespace, + ) + const includeAccessor: string = namespace.name + .split('') + .map((next: string) => { + if (next === '.') { + return '_' + } else { + return next + } + }) + .join('') + includedNamespaces[includeAccessor] = namespace + namespaceToInclude[includeAccessor] = head + return [includeAccessor, ...tail].join('.') + } else { + return name + } + } + + function resolveFunctionType(fieldType: FunctionType): FunctionType { + switch (fieldType.type) { + case SyntaxType.VoidKeyword: + return fieldType + + default: + return resolveFieldType(fieldType) + } + } + + function isBaseType(fieldType: FieldType): boolean { + switch (fieldType.type) { + case SyntaxType.I8Keyword: + case SyntaxType.I16Keyword: + case SyntaxType.I32Keyword: + case SyntaxType.I64Keyword: + case SyntaxType.StringKeyword: + case SyntaxType.BinaryKeyword: + return true + default: + return false + } + } + + function resolveFieldType(fieldType: FieldType): FieldType { + switch (fieldType.type) { + /** + * An Identifier can refer to either a container type or an alias to another + * type. Here we check for the typedef case and resolve to the base type in that + * case. + */ + case SyntaxType.Identifier: + const definition = resolveIdentifierDefinition( + fieldType, + parsedFile, + files, + sourceDir, + ) + if (definition.type === SyntaxType.TypedefDefinition) { + if (isBaseType(definition.definitionType)) { + return definition.definitionType + } else { + return resolveIdentifier(fieldType) + } + } else { + return resolveIdentifier(fieldType) + } + + case SyntaxType.ListType: + return { + type: SyntaxType.ListType, + valueType: resolveFieldType(fieldType.valueType), + annotations: fieldType.annotations, + loc: fieldType.loc, + } + + case SyntaxType.SetType: + return { + type: SyntaxType.SetType, + valueType: resolveFieldType(fieldType.valueType), + annotations: fieldType.annotations, + loc: fieldType.loc, + } + + case SyntaxType.MapType: + return { + type: SyntaxType.MapType, + valueType: resolveFieldType(fieldType.valueType), + keyType: resolveFieldType(fieldType.keyType), + annotations: fieldType.annotations, + loc: fieldType.loc, + } + + default: + return fieldType + } + } + + function resolveEnumMembers( + enumMembers: Array, + ): Array { + let previousValue: number = -1 + + return enumMembers.map( + (next: EnumMember): EnumMember => { + let initializer: IntConstant + + if (next.initializer !== null) { + previousValue = parseInt(next.initializer.value.value, 10) + initializer = next.initializer + } else { + initializer = { + type: SyntaxType.IntConstant, + value: { + type: SyntaxType.IntegerLiteral, + value: `${++previousValue}`, + loc: emptyLocation(), + }, + loc: emptyLocation(), + } + } + + return { + type: SyntaxType.EnumMember, + name: next.name, + initializer, + comments: next.comments, + annotations: next.annotations, + loc: next.loc, + } + }, + ) + } + + function resolveValue( + value: ConstValue, + fieldType: FunctionType, + ): ConstValue { + const resolvedValue: ConstValue = resolveConstValue( + value, + fieldType, + parsedFile, + files, + sourceDir, + ) + + if (resolvedValue.type === SyntaxType.Identifier) { + return resolveIdentifier(resolvedValue) + } else { + return resolvedValue + } + } + + function resolveFields( + fields: Array, + ): Array { + let generatedFieldID: number = 0 + const usedFieldIDs: Array = [] + + function resolveFieldID(fieldID: FieldID | null): FieldID { + if (fieldID === null) { + return { + type: SyntaxType.FieldID, + value: --generatedFieldID, + loc: emptyLocation(), + } + } else if (fieldID.value < 0) { + throw new ValidationError( + `Field IDs should be positive integers, found ${ + fieldID.value + }`, + fieldID.loc, + ) + } else if (usedFieldIDs.indexOf(fieldID.value) > -1) { + throw new ValidationError( + `Found duplicate usage of fieldID: ${fieldID.value}`, + fieldID.loc, + ) + } else { + usedFieldIDs.push(fieldID.value) + return fieldID + } + } + + return fields.map( + (field: FieldDefinition): FieldDefinition => { + return { + type: SyntaxType.FieldDefinition, + name: field.name, + fieldID: resolveFieldID(field.fieldID), + fieldType: resolveFunctionType(field.fieldType), + requiredness: field.requiredness, + defaultValue: + field.defaultValue === null + ? null + : resolveValue(field.defaultValue, field.fieldType), + comments: field.comments, + annotations: field.annotations, + loc: field.loc, + } + }, + ) + } + + function resolveFunctions( + funcs: Array, + ): Array { + return funcs.map( + (func: FunctionDefinition): FunctionDefinition => { + return { + type: SyntaxType.FunctionDefinition, + name: func.name, + oneway: func.oneway, + returnType: resolveFunctionType(func.returnType), + fields: resolveFields( + func.fields.map((next: FieldDefinition) => { + next.requiredness = + next.requiredness === 'optional' + ? 'optional' + : 'required' + return next + }), + ), + throws: resolveFields( + func.throws.map((next: FieldDefinition) => { + next.requiredness = + next.requiredness === 'optional' + ? 'optional' + : 'required' + return next + }), + ), + modifiers: func.modifiers, + comments: func.comments, + annotations: func.annotations, + loc: func.loc, + } + }, + ) + } + + const resolvedBody: Array = resolveStatements() + const resolvedExports: IFileExports = exportsForFile(resolvedBody) + + return { + type: 'ResolvedFile', + sourceFile: parsedFile.sourceFile, + namespace: parsedFile.namespace, + includedNamespaces, + namespaceToInclude, + includes: parsedFile.includes, + exports: resolvedExports, + body: resolvedBody, + errors, + } +} diff --git a/src/main/utils.ts b/src/main/utils.ts index f974b1c3..fa04fed7 100644 --- a/src/main/utils.ts +++ b/src/main/utils.ts @@ -18,7 +18,6 @@ import { IFileIncludes, IGeneratedFile, IIncludePath, - IMakeOptions, INamespaceMap, INamespacePath, INamespacePathMap, @@ -89,10 +88,10 @@ export function deepMerge( export function collectSourceFiles( sourceDir: string, - options: IMakeOptions, + files?: Array, ): Array { - if (options.files && options.files.length > 0) { - return options.files + if (files && files.length > 0) { + return files } else { return glob.sync(`${sourceDir}/**/*.thrift`) } @@ -127,10 +126,13 @@ export function namespaceForInclude( include: IIncludePath, files: IProcessedFileMap, sourceDir: string, - options: IMakeOptions, + fallbackNamespace: string, ): INamespacePath { const file: T = fileForInclude(include, files, sourceDir) - const namespace: INamespacePath = namespaceForFile(file.body, options) + const namespace: INamespacePath = namespaceForFile( + file.body, + fallbackNamespace, + ) return namespace } @@ -194,16 +196,16 @@ function collectNamespaces(body: Array): INamespacePathMap { export function namespaceForFile( body: Array, - options: IMakeOptions, + fallbackNamespace: string, ): INamespacePath { const namespaceMap = collectNamespaces(body) if (namespaceMap.js) { return namespaceMap.js } else if ( - options.fallbackNamespace !== 'none' && - namespaceMap[options.fallbackNamespace] + fallbackNamespace !== 'none' && + namespaceMap[fallbackNamespace] ) { - return namespaceMap[options.fallbackNamespace] + return namespaceMap[fallbackNamespace] } else { return emptyNamespace() } diff --git a/src/main/validator/index.ts b/src/main/validator/index.ts index e04fd535..4039dc74 100644 --- a/src/main/validator/index.ts +++ b/src/main/validator/index.ts @@ -11,10 +11,7 @@ import { } from '@creditkarma/thrift-parser' import { createValidationError, IThriftError, ValidationError } from '../errors' -import { - resolveConstValue, - resolveIdentifierDefinition, -} from '../resolver/utils' +import { resolveConstValue, resolveIdentifierDefinition } from '../resolver' import { DefinitionType, IResolvedFile, ResolvedFileMap } from '../types' import { constToTypeString, fieldTypeToString } from './utils' diff --git a/src/tests/unit/index.spec.ts b/src/tests/unit/index.spec.ts index 53118727..26961d39 100644 --- a/src/tests/unit/index.spec.ts +++ b/src/tests/unit/index.spec.ts @@ -186,7 +186,10 @@ describe('Thrift TypeScript Generator', () => { 'basic_union.strict_union', 'thrift-server', ) - const actual: string = make(content, 'thrift-server', true) + const actual: string = make(content, { + target: 'thrift-server', + strictUnions: true, + }) assert.deepEqual(actual, expected) }) @@ -207,7 +210,10 @@ describe('Thrift TypeScript Generator', () => { 'nested_union.strict_union', 'thrift-server', ) - const actual: string = make(content, 'thrift-server', true) + const actual: string = make(content, { + target: 'thrift-server', + strictUnions: true, + }) assert.deepEqual(actual, expected) }) @@ -228,7 +234,10 @@ describe('Thrift TypeScript Generator', () => { 'basic_service.strict_union', 'thrift-server', ) - const actual: string = make(content, 'thrift-server', true) + const actual: string = make(content, { + target: 'thrift-server', + strictUnions: true, + }) assert.deepEqual(actual, expected) }) @@ -248,7 +257,7 @@ describe('Thrift TypeScript Generator', () => { const list LIST_CONST = ['hello', 'world', 'foo', 'bar'] ` const expected: string = readSolution('complex_const') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -264,7 +273,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('multi_field_struct') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -274,7 +283,7 @@ describe('Thrift TypeScript Generator', () => { struct MyStruct {} ` const expected: string = readSolution('empty_struct') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -287,7 +296,7 @@ describe('Thrift TypeScript Generator', () => { } ( foo = "bar", two = "three", alone, dot.foo = "bar", dot.lonely ) ` const expected: string = readSolution('annotations_struct') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -305,7 +314,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('nested_struct') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -329,7 +338,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('complex_nested_struct') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -342,7 +351,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('basic_union') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -355,7 +364,7 @@ describe('Thrift TypeScript Generator', () => { } ( foo = "bar", two = "three", alone, dot.foo = "bar", dot.lonely ) ` const expected: string = readSolution('annotations_union') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -365,7 +374,7 @@ describe('Thrift TypeScript Generator', () => { union MyUnion {} ` const expected: string = readSolution('empty_union') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -383,7 +392,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('nested_union') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -396,7 +405,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('basic_exception') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -409,7 +418,7 @@ describe('Thrift TypeScript Generator', () => { } ( foo = "bar", two = "three", alone, dot.foo = "bar", dot.lonely ) ` const expected: string = readSolution('annotations_exception') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -422,7 +431,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('required_field_exception') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -440,7 +449,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('nested_exception') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -459,7 +468,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('basic_service') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -478,7 +487,7 @@ describe('Thrift TypeScript Generator', () => { } ( foo = "bar", two = "three", alone, dot.foo = "bar", dot.lonely ) ` const expected: string = readSolution('annotations_service') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -495,7 +504,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('i64_service') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -512,7 +521,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('throws_service') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -537,7 +546,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('throws_multi_service') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -552,7 +561,7 @@ describe('Thrift TypeScript Generator', () => { ` const expected: string = readSolution('resolved_field_service') - const actual: string = make(content) + const actual: string = make(content, { target: 'thrift-server' }) assert.deepEqual(actual, expected) }) @@ -568,7 +577,7 @@ describe('Thrift TypeScript Generator', () => { const list LIST_CONST = ['hello', 'world', 'foo', 'bar'] ` const expected: string = readSolution('basic_const', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -578,7 +587,7 @@ describe('Thrift TypeScript Generator', () => { typedef string name ` const expected: string = readSolution('basic_typedef', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -593,7 +602,7 @@ describe('Thrift TypeScript Generator', () => { typedef MyEnum AnotherName ` const expected: string = readSolution('enum_typedef', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -614,7 +623,7 @@ describe('Thrift TypeScript Generator', () => { const AnotherName WHAT = AnotherName.ONE ` const expected: string = readSolution('complex_typedef', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -628,7 +637,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('basic_enum', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -645,7 +654,7 @@ describe('Thrift TypeScript Generator', () => { 'field_initialized_enum', 'apache', ) - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -664,7 +673,7 @@ describe('Thrift TypeScript Generator', () => { 'multi_field_struct', 'apache', ) - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -680,7 +689,7 @@ describe('Thrift TypeScript Generator', () => { 'implicit_optional_struct', 'apache', ) - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -692,7 +701,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('map_struct', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -704,7 +713,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('nested_map_struct', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -716,7 +725,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('list_struct', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -731,7 +740,7 @@ describe('Thrift TypeScript Generator', () => { 'nested_list_struct', 'apache', ) - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -743,7 +752,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('set_struct', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -755,7 +764,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('nested_set_struct', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -771,7 +780,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('return_id_struct', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -790,7 +799,7 @@ describe('Thrift TypeScript Generator', () => { 'container_id_struct', 'apache', ) - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -802,7 +811,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('basic_exception', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -815,7 +824,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('basic_union', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -828,7 +837,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('nested_list_union', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -840,7 +849,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('basic_service', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -852,7 +861,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('i64_service', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -868,7 +877,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('throws_service', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -896,7 +905,7 @@ describe('Thrift TypeScript Generator', () => { 'throws_multi_service', 'apache', ) - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) @@ -912,7 +921,7 @@ describe('Thrift TypeScript Generator', () => { } ` const expected: string = readSolution('return_service', 'apache') - const actual: string = make(content, 'apache') + const actual: string = make(content, { target: 'apache' }) assert.deepEqual(actual, expected) }) diff --git a/tsconfig.json b/tsconfig.json index 6d3c8689..f5f8e141 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,21 +1,21 @@ { - "compilerOptions": { - "target": "es6", - "module": "commonjs", - "moduleResolution": "node", - "sourceMap": true, - "declaration": true, - "rootDir": "./src", - "outDir": "./dist", - "noEmitOnError": true, - "strict": true, - "noUnusedLocals": true, - "pretty": true, - "removeComments": true - }, - "exclude": [ - "node_modules", - "src/tests/", - "dist" - ] + "compilerOptions": { + "target": "es2017", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "declaration": true, + "rootDir": "./src", + "outDir": "./dist", + "noEmitOnError": true, + "strict": true, + "noUnusedLocals": true, + "pretty": true, + "removeComments": true + }, + "exclude": [ + "node_modules", + "src/tests/", + "dist" + ] }