From 323dea4d75217be84fbc4bc93d4ac517ab00f697 Mon Sep 17 00:00:00 2001 From: Ruslan Lopatin Date: Tue, 29 Aug 2023 09:55:15 +0700 Subject: [PATCH] Update to `churi` v0.15 API --- package.json | 4 +- src/impl/ts/ts-options-literal.ts | 35 +++++++++-- src/impl/uc-transformer.ts | 4 +- src/impl/uct-bundle.ts | 100 ++++-------------------------- src/impl/uct-lib.spec.ts | 42 +------------ src/impl/uct-tasks.ts | 4 +- 6 files changed, 49 insertions(+), 140 deletions(-) diff --git a/package.json b/package.json index adcd7af..6561f75 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ }, "sideEffects": false, "peerDependencies": { - "churi": "^0.11.0", + "churi": "^0.15.0-pre.0", "typescript": "5.0.4 - 5.3.0" }, "dependencies": { @@ -44,7 +44,7 @@ "@types/node": "^18.17.11", "@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/parser": "^6.4.1", - "churi": "^0.14.0", + "churi": "^0.15.0-pre.0", "eslint": "^8.48.0", "eslint-plugin-jest": "^27.2.3", "gh-pages": "^6.0.0", diff --git a/src/impl/ts/ts-options-literal.ts b/src/impl/ts/ts-options-literal.ts index 9ebeef3..349b8b4 100644 --- a/src/impl/ts/ts-options-literal.ts +++ b/src/impl/ts/ts-options-literal.ts @@ -130,15 +130,40 @@ export class TsOptionValue { ); } - getValue(): string | number | undefined { + getBoolean(): boolean | undefined { + const value = this.getValue(); + + if (value === undefined || typeof value === 'boolean') { + return value; + } + + throw new TsError( + `Value of option ${this.#name} in ${this.#options.target} expected to be a boolean constant`, + { node: this.#valueNode }, + ); + } + + getValue(): string | number | boolean | null | undefined { const initializer = this.#initializer; if (initializer) { - if (ts.isStringLiteralLike(initializer)) { - return initializer.text; + if (ts.isLiteralExpression(initializer)) { + if (ts.isStringLiteralLike(initializer)) { + return initializer.text; + } + if (ts.isNumericLiteral(initializer)) { + return Number(initializer.text); + } } - if (ts.isNumericLiteral(initializer)) { - return Number(initializer.text); + + switch (initializer.kind) { + case ts.SyntaxKind.TrueKeyword: + return true; + case ts.SyntaxKind.FalseKeyword: + return false; + case ts.SyntaxKind.NullKeyword: + return null; + default: } const { diff --git a/src/impl/uc-transformer.ts b/src/impl/uc-transformer.ts index 6eafb5a..b81992a 100644 --- a/src/impl/uc-transformer.ts +++ b/src/impl/uc-transformer.ts @@ -1,4 +1,4 @@ -import { UcDeserializer, UcFormatName } from 'churi'; +import { UcDeserializer } from 'churi'; import { EsNameRegistry } from 'esgen'; import { capitalize } from 'httongue'; import path from 'node:path'; @@ -184,7 +184,7 @@ export class UcTransformer { modelId, from: stTfm.sourceFile.fileName, mode: (options.mode?.getString() as UcDeserializer.Mode | undefined) ?? 'universal', - format: (options.from?.getString() as UcFormatName | undefined) ?? 'charge', + byTokens: options.byTokens?.getBoolean() ?? false, }); return replacement; diff --git a/src/impl/uct-bundle.ts b/src/impl/uct-bundle.ts index 5ffc98b..45e63a0 100644 --- a/src/impl/uct-bundle.ts +++ b/src/impl/uct-bundle.ts @@ -1,4 +1,3 @@ -import { UcFormatName, UcPresentationName } from 'churi'; import { EsCode, EsFunction, @@ -18,7 +17,6 @@ export class UctBundle { readonly #setup: UctSetup; #distFile: string; - #presentations?: EsCode; #ucdModels?: EsCode; #ucsModels?: EsCode; @@ -44,44 +42,22 @@ export class UctBundle { (this.#ucdModels ??= new EsCode()).write(this.#addDeserializer(task)); } - #addDeserializer({ fnId, modelId, from, mode, format }: UctCompileDeserializerFn): EsSnippet { + #addDeserializer({ fnId, modelId, from, mode, byTokens }: UctCompileDeserializerFn): EsSnippet { const moduleSpec = this.#setup.relativeImport(this.#setup.tsRoot.rootDir!, from); const model = esImport(moduleSpec, modelId.text); - let lexerOptions: UctLexerOptions | undefined; - - if (format !== 'tokens') { - lexerOptions = UCT_FORMAT_LEXERS[format]; - - this.#addPresentation(format); - this.#addPresentations(lexerOptions?.presentations); - } return code => { code .write(esline`${fnId}: {`) - .indent(code => { - code.write(esline`model: ${model},`).write(`mode: ${esStringLiteral(mode)},`); - if (lexerOptions) { - const { lexer, inset } = lexerOptions; - - code.write(esline`lexer: ${lexer},`); - if (inset) { - code.write(esline`inset: ${inset},`); - } - } - }) + .indent( + esline`model: ${model},`, + `mode: ${esStringLiteral(mode)},`, + `byTokens: ${byTokens},`, + ) .write('}'); }; } - #addPresentation(presentation: UcPresentationName): void { - (this.#presentations ??= new EsCode()).write(esStringLiteral(presentation) + ','); - } - - #addPresentations(presentations: readonly UcPresentationName[] | undefined): void { - presentations?.forEach(presentation => this.#addPresentation(presentation)); - } - compileUcSerializer(task: UctCompileSerializerFn): void { (this.#ucsModels ??= new EsCode()).write(this.#addSerializer(task)); } @@ -90,7 +66,12 @@ export class UctBundle { const moduleSpec = this.#setup.relativeImport(this.#setup.tsRoot.rootDir!, from); const model = esImport(moduleSpec, modelId.text); - return esline`${fnId}: ${model},`; + return code => { + code + .write(esline`${fnId}: {`) + .indent(esline`model: ${model},`) + .write('},'); + }; } emitBundlerFn(): EsFunction | undefined { @@ -125,7 +106,6 @@ export class UctBundle { .write(esline`new ${UcdCompiler}({`) .indent(code => { code.write(`models: {`).indent(ucdModels).write(`},`); - code.write(this.#presentationsOption()); }) .write('})'); }); @@ -184,60 +164,4 @@ export class UctBundle { ); } - #presentationsOption(): EsSnippet { - const presentations = this.#presentations; - - if (!presentations) { - return EsCode.none; - } - - return code => { - code.write(`presentations: [`).indent(presentations).write(`],`); - }; - } - -} - -const UCT_FORMAT_LEXERS: { - readonly [format in UcFormatName]: UctLexerOptions; -} = { - charge: { - lexer: createLexerOption('UcChargeLexer'), - }, - plainText: { - lexer: createLexerOption('UcPlainTextLexer'), - }, - uriEncoded: { - lexer: createLexerOption('UcURIEncodedLexer'), - }, - uriParams: { - presentations: ['uriParam'], - lexer: createLexerOption('UcURIParamsLexer'), - inset: createLexerOption('UcChargeLexer'), - }, -}; - -interface UctLexerOptions { - presentations?: readonly UcPresentationName[] | undefined; - readonly lexer: EsSnippet; - readonly inset?: EsSnippet | undefined; -} - -function createLexerOption(lexer: string, from = 'churi'): EsSnippet { - return code => { - code - .write(esline`({ emit }) => code => {`) - .indent(code => { - const $esImport = esImport('esgen', 'esImport'); - - code - .write( - esline`const Lexer = ${$esImport}(${esStringLiteral(from)}, ${esStringLiteral( - lexer, - )});`, - ) - .write(`code.line('return new ', Lexer, '(', emit, ');');`); - }) - .write('}'); - }; } diff --git a/src/impl/uct-lib.spec.ts b/src/impl/uct-lib.spec.ts index dc5c245..3744ef2 100644 --- a/src/impl/uct-lib.spec.ts +++ b/src/impl/uct-lib.spec.ts @@ -125,53 +125,13 @@ export const readValue = createUcDeserializer(String); expect(file).toContain('export function readValue('); expect(file).toContain('new UcChargeLexer('); }); - it('emits deserializer lib with custom lexer', async () => { - transform( - { - 'deserializer.ts': ` -import { createUcDeserializer } from 'churi'; - -export const readValue = createUcDeserializer(String, { from: 'uriEncoded' }); - `, - }, - createUcTransformer, - ); - - await lib.compile(); - - const file = await fs.readFile(`${testDir}/test.uc-lib.js`, 'utf-8'); - - expect(file).toContain('export function readValue('); - expect(file).toContain('new UcURIEncodedLexer('); - expect(file).not.toContain('new UcChargeLexer('); - }); - it('emits deserializer lib with custom inset', async () => { - transform( - { - 'deserializer.ts': ` -import { createUcDeserializer } from 'churi'; - -export const readValue = createUcDeserializer(String, { from: 'uriParams' }); - `, - }, - createUcTransformer, - ); - - await lib.compile(); - - const file = await fs.readFile(`${testDir}/test.uc-lib.js`, 'utf-8'); - - expect(file).toContain('export function readValue('); - expect(file).toContain('new UcURIParamsLexer('); - expect(file).toContain('new UcChargeLexer('); - }); it('emits by-tokens deserializer', async () => { transform( { 'deserializer.ts': ` import { createUcDeserializer } from 'churi'; -export const readValue = createUcDeserializer(String, { from: 'tokens' }); +export const readValue = createUcDeserializer(String, { byTokens: true }); `, }, createUcTransformer, diff --git a/src/impl/uct-tasks.ts b/src/impl/uct-tasks.ts index b15f342..f3e4920 100644 --- a/src/impl/uct-tasks.ts +++ b/src/impl/uct-tasks.ts @@ -1,4 +1,4 @@ -import { UcDeserializer, UcFormatName } from 'churi'; +import { UcDeserializer } from 'churi'; import ts from 'typescript'; import { UctBundle } from './uct-bundle.js'; @@ -14,7 +14,7 @@ export interface UctCompileDeserializerFn { readonly modelId: ts.Identifier; readonly from: string; readonly mode: UcDeserializer.Mode; - readonly format: UcFormatName | 'tokens'; + readonly byTokens: boolean; } export interface UctCompileSerializerFn {