From f420939e5f1afe6fe4bb947901c6c60e6ae4d990 Mon Sep 17 00:00:00 2001 From: Julian Labeit Date: Fri, 27 Dec 2024 15:30:50 +0100 Subject: [PATCH 1/3] feat(dart): add support fort dart generator --- README.md | 1 + src/generators/dart.ts | 66 ++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 8 +++-- 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 src/generators/dart.ts diff --git a/README.md b/README.md index d2ec833..c873543 100644 --- a/README.md +++ b/README.md @@ -29,5 +29,6 @@ npx lexigen -u -s -p The generator assumes that the mixpanel tracking package is already installed and setup. It only imports the package at the top of the generated file. diff --git a/src/generators/dart.ts b/src/generators/dart.ts new file mode 100644 index 0000000..d0a5a1a --- /dev/null +++ b/src/generators/dart.ts @@ -0,0 +1,66 @@ +import { pascalCase } from 'change-case' +import { JSONSchema } from 'json-schema-to-typescript' + +import { EventSchema } from '../mixpanel' + +const dartTypeMapping: { [key: string]: string } = { + string: 'String', + number: 'double', + integer: 'int', + boolean: 'bool', + array: 'List', + object: 'Map', +} + +const generateDartMethod = (eventName: string, schema: JSONSchema): string => { + const requiredFields = schema.required || [] + const properties = schema.properties || {} + + const methodParams = Object.entries(properties) + .map(([key, value]: [string, any]) => { + const type = dartTypeMapping[value.type] || 'dynamic' + const isRequired = requiredFields === true || requiredFields.includes(key) + const paramName = pascalCase(key) + return `${isRequired ? 'required ' : ''}${type}${isRequired ? '' : '?'} ${paramName}` + }) + .join(', ') + + const propertiesMap = Object.entries(properties) + .map(([key, _]) => `'${key}': ${pascalCase(key)}`) + .join(',\n ') + + if (!methodParams) { + return ` static void track${pascalCase(eventName)}Event() => + _track('${eventName}');` + } + + return ` static void track${pascalCase(eventName)}Event({ + ${methodParams} + }) => + _track('${eventName}', properties: { + ${propertiesMap}, + });` +} + +const formatDescription = (event: EventSchema): string => { + return event.schemaJson.description ? `/// ${event.schemaJson.description}\n` : '' +} + +export const generate = async (events: EventSchema[]): Promise => { + const eventMethods = events.map((event) => { + return `${formatDescription(event)}${generateDartMethod(event.name, event.schemaJson)}` + }) + + return ` +import 'package:mixpanel_flutter/mixpanel_flutter.dart'; + +/// Abstract class to track analytics events +abstract class AnalyticsEvents { + static void _track(String eventName, {Map? properties}) { + Mixpanel.instance.track(eventName, properties); + } + +${eventMethods.join('\n\n')} +} +` +} diff --git a/src/index.ts b/src/index.ts index f0c6e48..8f94779 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,15 +3,19 @@ import yargs from 'yargs' import { hideBin } from 'yargs/helpers' +import { generate as generateDart } from './generators/dart' import { generate as generateTypescript } from './generators/typescripts' import { fetchEventsSchema } from './mixpanel' +type GeneratorFunctionType = typeof generateTypescript enum GenerationOptions { typescript = 'typescript', + dart = 'dart', } -const generators: Record = { +const generators: Record = { typescript: generateTypescript, + dart: generateDart, } const { username, secret, project, target, filter } = yargs(hideBin(process.argv)) @@ -36,7 +40,7 @@ const { username, secret, project, target, filter } = yargs(hideBin(process.argv .option('target', { alias: 't', type: 'string', - choices: [GenerationOptions.typescript], + choices: [GenerationOptions.typescript, GenerationOptions.dart], description: 'A target API to generate.', default: 'typescript', }) From f0a84aa6cb82f7d9a660aefbd77a0f2e4321dce9 Mon Sep 17 00:00:00 2001 From: Julian Labeit Date: Sat, 28 Dec 2024 17:54:12 +0100 Subject: [PATCH 2/3] fix(dart): use lower pascal case and boilerplate code --- README.md | 2 +- src/generators/dart.ts | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c873543..97d0f90 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ npx lexigen -u -s -p ', } +const lowerPascalCase = (str: string): string => { + const result = pascalCase(str) + return result.charAt(0).toLowerCase() + result.slice(1) +} + const generateDartMethod = (eventName: string, schema: JSONSchema): string => { const requiredFields = schema.required || [] const properties = schema.properties || {} @@ -20,13 +25,13 @@ const generateDartMethod = (eventName: string, schema: JSONSchema): string => { .map(([key, value]: [string, any]) => { const type = dartTypeMapping[value.type] || 'dynamic' const isRequired = requiredFields === true || requiredFields.includes(key) - const paramName = pascalCase(key) + const paramName = lowerPascalCase(key) return `${isRequired ? 'required ' : ''}${type}${isRequired ? '' : '?'} ${paramName}` }) .join(', ') const propertiesMap = Object.entries(properties) - .map(([key, _]) => `'${key}': ${pascalCase(key)}`) + .map(([key, _]) => `'${key}': ${lowerPascalCase(key)}`) .join(',\n ') if (!methodParams) { @@ -54,10 +59,11 @@ export const generate = async (events: EventSchema[]): Promise => { return ` import 'package:mixpanel_flutter/mixpanel_flutter.dart'; -/// Abstract class to track analytics events -abstract class AnalyticsEvents { +class Lexicon { + static Mixpanel? mixpanel; + static void _track(String eventName, {Map? properties}) { - Mixpanel.instance.track(eventName, properties); + mixpanel?.track(eventName, properties: properties); } ${eventMethods.join('\n\n')} From 58ebecd6a207c74978467e16182ae0012f7d4668 Mon Sep 17 00:00:00 2001 From: Julian Labeit Date: Mon, 30 Dec 2024 17:47:01 +0100 Subject: [PATCH 3/3] fix(dart): review comments --- src/generators/dart.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/generators/dart.ts b/src/generators/dart.ts index 05967d2..b0692b7 100644 --- a/src/generators/dart.ts +++ b/src/generators/dart.ts @@ -1,4 +1,4 @@ -import { pascalCase } from 'change-case' +import { camelCase, pascalCase } from 'change-case' import { JSONSchema } from 'json-schema-to-typescript' import { EventSchema } from '../mixpanel' @@ -12,11 +12,6 @@ const dartTypeMapping: { [key: string]: string } = { object: 'Map', } -const lowerPascalCase = (str: string): string => { - const result = pascalCase(str) - return result.charAt(0).toLowerCase() + result.slice(1) -} - const generateDartMethod = (eventName: string, schema: JSONSchema): string => { const requiredFields = schema.required || [] const properties = schema.properties || {} @@ -25,13 +20,13 @@ const generateDartMethod = (eventName: string, schema: JSONSchema): string => { .map(([key, value]: [string, any]) => { const type = dartTypeMapping[value.type] || 'dynamic' const isRequired = requiredFields === true || requiredFields.includes(key) - const paramName = lowerPascalCase(key) + const paramName = camelCase(key) return `${isRequired ? 'required ' : ''}${type}${isRequired ? '' : '?'} ${paramName}` }) .join(', ') const propertiesMap = Object.entries(properties) - .map(([key, _]) => `'${key}': ${lowerPascalCase(key)}`) + .map(([key, _]) => `'${key}': ${camelCase(key)}`) .join(',\n ') if (!methodParams) {