Skip to content

Commit

Permalink
fix: bunch of refactors and fixes (#168)
Browse files Browse the repository at this point in the history
- Fix JSON and YAML schema for configurations enabled custom generator when it's not possible.
- Disable eslint rule for nested switches as it makes sense long term
- Added test for parameter generator
- Refactored modules for better maintainability
- Fixed custom generator 
- Enabled internal and external configurations
- Fixed some other various checks.
  • Loading branch information
jonaslagoni authored Dec 1, 2024
1 parent 10f7876 commit c8f7e58
Show file tree
Hide file tree
Showing 25 changed files with 1,218 additions and 484 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"jest/globals": true
},
"rules": {
"sonarjs/no-nested-switch": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
Expand Down
23 changes: 0 additions & 23 deletions schemas/configuration-schema-0.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,29 +270,6 @@
}
},
"additionalProperties": false
},
{
"type": "object",
"properties": {
"id": {
"type": "string"
},
"dependencies": {
"type": "array",
"items": {
"type": "string"
}
},
"preset": {
"type": "string",
"const": "custom"
},
"options": {}
},
"required": [
"preset"
],
"additionalProperties": false
}
]
}
Expand Down
4 changes: 3 additions & 1 deletion scripts/generateSchemaFiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ const path = require('path');
const package = require('../package.json');
const majorVersion = package.version.split('.')[0];
const outputPath = path.resolve(__dirname, '../schemas', `configuration-schema-${majorVersion}.json`);

const disabledPresets = ['custom']
const jsonSchema = zodToJsonSchema(types.zodTheCodegenConfiguration, {
definitions: {
AsyncAPICodegenConfiguration: types.zodAsyncAPICodegenConfiguration
}
});
// Remove any NON-JSON and Yaml available generators
jsonSchema.definitions['AsyncAPICodegenConfiguration'].properties['generators'].items.anyOf = jsonSchema.definitions['AsyncAPICodegenConfiguration']?.properties['generators']?.items?.anyOf?.filter((obj) => !obj.properties.preset.const.includes(disabledPresets))
const stringifiedSchema = JSON.stringify(jsonSchema, null, 4);
console.log(`Writing the following schema to ${outputPath}:
${stringifiedSchema}`);
Expand Down
109 changes: 101 additions & 8 deletions src/codegen/configuration-manager.ts → src/codegen/configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,32 @@ import {
TheCodegenConfiguration,
zodTheCodegenConfiguration,
Generators,
TheCodegenConfigurationInternal
TheCodegenConfigurationInternal,
RunGeneratorContext,
PresetTypes,
SupportedLanguages,
GeneratorsInternal
} from './types';
import {getDefaultConfiguration} from './generators/index';
import {
defaultCustomGenerator,
defaultTypeScriptParametersOptions,
defaultTypeScriptPayloadGenerator
} from './generators';
import {Logger} from '../LoggingInterface';
import {fromError} from 'zod-validation-error';
import {includeTypeScriptChannelDependencies} from './generators/typescript/channels';
import {
defaultTypeScriptChannelsGenerator,
includeTypeScriptChannelDependencies
} from './generators/typescript/channels';
import {mergePartialAndDefault} from './utils';
import {cosmiconfig} from 'cosmiconfig';
import {includeTypeScriptClientDependencies} from './generators/typescript/client';
import {
defaultTypeScriptClientGenerator,
includeTypeScriptClientDependencies
} from './generators/typescript/client';
import path from 'path';
import {loadAsyncapi} from './inputs/asyncapi';
import {defaultTypeScriptHeadersOptions} from './generators/typescript';
const moduleName = 'codegen';
const explorer = cosmiconfig(moduleName, {
searchPlaces: [
Expand All @@ -26,7 +43,7 @@ const explorer = cosmiconfig(moduleName, {
});

/**
* Load the configuration from file.
* Load configuration from file.
*/
export async function loadConfigFile(filePath?: string): Promise<{
config: TheCodegenConfiguration;
Expand Down Expand Up @@ -80,15 +97,21 @@ export function realizeConfiguration(

const generatorIds: string[] = [];
for (const [index, generator] of config.generators.entries()) {
const language = (generator as any).language ?? config.language;
const language = (generator as any).language !== undefined ? (generator as any).language : config.language ?? 'typescript';
if (!generator?.preset) {
continue;
}
const defaultGenerator = getDefaultConfiguration(
generator.preset,
language
);
const generatorToUse = mergePartialAndDefault(defaultGenerator, generator);
if (!defaultGenerator) {
throw new Error('Unable to determine default generator');
}
const generatorToUse = mergePartialAndDefault(
defaultGenerator,
generator as any
) as GeneratorsInternal;
const oldId = generatorToUse.id;
// Make sure that each generator has unique ids if they dont explicit define one
if (generatorToUse.id === defaultGenerator.id) {
Expand Down Expand Up @@ -116,7 +139,7 @@ export function realizeConfiguration(
.split(';')
.join('\n')
);
throw new Error(`Not a valid configuration file; ${validationError}`);
throw new Error(`Invalid configuration file; ${validationError}`);
}
const newGenerators = ensureProperGenerators(
config as TheCodegenConfiguration
Expand Down Expand Up @@ -156,3 +179,73 @@ function ensureProperGenerators(config: TheCodegenConfiguration) {

return iterateGenerators(Array.from(config.generators.values()));
}

/**
* Returns the default generator for the preset of the language
*/
export function getDefaultConfiguration(
preset: PresetTypes,
language: SupportedLanguages
): GeneratorsInternal | undefined {
switch (preset) {
case 'payloads':
switch (language) {
case 'typescript':
return defaultTypeScriptPayloadGenerator;
}
break;
case 'headers':
switch (language) {
case 'typescript':
return defaultTypeScriptHeadersOptions;
}
break;
case 'channels':
switch (language) {
case 'typescript':
return defaultTypeScriptChannelsGenerator;
}
break;
case 'client':
switch (language) {
case 'typescript':
return defaultTypeScriptClientGenerator;
}
break;
case 'custom':
return defaultCustomGenerator;
case 'parameters':
switch (language) {
case 'typescript':
return defaultTypeScriptParametersOptions;
}
break;
}
return undefined;
}

/**
* Load configuration and input document to create generator context
*
* @param configFile
*/
export async function realizeGeneratorContext(
configFile: string | undefined
): Promise<RunGeneratorContext> {
const {config, filePath} = await loadAndRealizeConfigFile(configFile);
Logger.info(`Found configuration was ${JSON.stringify(config)}`);
const documentPath = path.resolve(path.dirname(filePath), config.inputPath);
Logger.info(`Found document at '${documentPath}'`);
Logger.info(`Found input '${config.inputType}'`);
const context: RunGeneratorContext = {
configuration: config,
documentPath,
configFilePath: filePath
};
if (config.inputType === 'asyncapi') {
const document = await loadAsyncapi(context);
context.asyncapiDocument = document;
}

return context;
}
46 changes: 26 additions & 20 deletions src/codegen/generators/generic/custom.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {AsyncAPIDocumentInterface} from '@asyncapi/parser';
import {GenericCodegenContext, GenericGeneratorOptions} from '../../types';
import {GenericCodegenContext} from '../../types';
import {z} from 'zod';

export interface CustomContext extends GenericCodegenContext {
Expand All @@ -8,34 +8,40 @@ export interface CustomContext extends GenericCodegenContext {
generator: CustomGenerator;
}

export interface CustomGenerator extends GenericGeneratorOptions {
preset: 'custom';
renderFunction: (context: CustomContext, options: any) => any;
options?: any;
}

export const zodCustomGenerator = z.object({
id: z.string().optional(),
dependencies: z.array(z.string()).optional(),
preset: z.literal('custom'),
options: z.any().optional(),
id: z.string().optional().default('custom'),
dependencies: z.array(z.string()).optional().default([]),
preset: z.literal('custom').default('custom'),
options: z.any().optional().default({}),
renderFunction: z
.function()
.args(
z
.object({
inputType: z.enum(['asyncapi']),
inputType: z.enum(['asyncapi']).default('asyncapi'),
asyncapiDocument: z
.any()
.describe(
`Type is AsyncAPIDocumentInterface form @asyncapi/parser`
),
generator: z.any(),
options: z.any()
dependencyOutputs: z.record(z.any()).default({})
})
.optional(),
z.any().optional()
.default({}),
z
.any()
.optional()
.describe('The provided options by the user')
.default({})
)
.returns(z.any())
.optional()
.default(() => {})
});

export const defaultCustomGenerator: CustomGenerator = {
preset: 'custom',
id: 'custom',
renderFunction: () => {}
};
export type CustomGenerator = z.input<typeof zodCustomGenerator>;

export type CustomGeneratorInternal = z.infer<typeof zodCustomGenerator>;

export const defaultCustomGenerator: CustomGeneratorInternal =
zodCustomGenerator.parse({});
Loading

0 comments on commit c8f7e58

Please sign in to comment.