diff --git a/.gitignore b/.gitignore index a9c741c727..6d2362abaf 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,7 @@ packages/ts/*/.coverage packages/ts/*/.vite packages/ts/*/types/** !packages/ts/*/.lintstagedrc.js -scripts/generator/results/ +scripts/prepare/results/ packages/java/hilla/*.json packages/java/hilla-react/*.json packages/java/hilla/src/main/java/com/vaadin/hilla/theme/ @@ -50,7 +50,7 @@ packages/java/hilla-react/src/main/java/com/vaadin/hilla/theme/ packages/ts/*/*.tgz # temporary scripts from platform for preparations -scripts/generator/src/ +scripts/prepare/src/ # backup files from some editors *~ diff --git a/packages/ts/generator-cli/src/GeneratorIO.ts b/packages/ts/generator-cli/src/GeneratorIO.ts index e86d5f3e0d..a866776cdb 100644 --- a/packages/ts/generator-cli/src/GeneratorIO.ts +++ b/packages/ts/generator-cli/src/GeneratorIO.ts @@ -68,7 +68,7 @@ export default class GeneratorIO { await Promise.all( [...filesToDelete].map(async (filename) => { const resolved = this.resolveGeneratedFile(filename); - if (await this.exists(resolved)) { + if (await GeneratorIO.exists(resolved)) { this.#logger.global.debug(`Deleting file ${filename}.`); await rm(resolved); } @@ -112,7 +112,7 @@ export default class GeneratorIO { * @param path - the file path to check */ // eslint-disable-next-line class-methods-use-this - async exists(path: string): Promise { + static async exists(path: string): Promise { try { await access(path, constants.F_OK); return true; diff --git a/packages/ts/generator-cli/test/GeneratorIO.spec.ts b/packages/ts/generator-cli/test/GeneratorIO.spec.ts index ee93fabed0..2febacc654 100644 --- a/packages/ts/generator-cli/test/GeneratorIO.spec.ts +++ b/packages/ts/generator-cli/test/GeneratorIO.spec.ts @@ -36,12 +36,12 @@ describe('Testing GeneratorIO', function (this: Mocha.Suite) { describe('Testing GeneratorIO.exists', () => { it('should detect that a file exists', async () => { const path = join(tmpDir, generatedFilenames[0]); - await expect(io.exists(path)).to.eventually.be.true; + await expect(GeneratorIO.exists(path)).to.eventually.be.true; }); it("should detect that a file doesn't exist", async () => { const path = join(tmpDir, 'nobody-created-me'); - await expect(io.exists(path)).to.eventually.be.false; + await expect(GeneratorIO.exists(path)).to.eventually.be.false; }); }); @@ -49,7 +49,7 @@ describe('Testing GeneratorIO', function (this: Mocha.Suite) { it('should create file index with right content', async () => { await io.createFileIndex(generatedFilenames); const indexPath = join(tmpDir, GeneratorIO.INDEX_FILENAME); - await expect(io.exists(indexPath)).to.eventually.be.true; + await expect(GeneratorIO.exists(indexPath)).to.eventually.be.true; const content = await io.read(indexPath); generatedFilenames.forEach((name) => expect(content).to.contain(name)); }); @@ -62,7 +62,7 @@ describe('Testing GeneratorIO', function (this: Mocha.Suite) { await Promise.all( generatedFilenames.map(async (name) => { const path = join(tmpDir, name); - await expect(io.exists(path)).to.eventually.be.true; + await expect(GeneratorIO.exists(path)).to.eventually.be.true; }), ); }); @@ -84,7 +84,9 @@ describe('Testing GeneratorIO', function (this: Mocha.Suite) { await expect( io.cleanOutputDir([generatedFilenames[0], generatedFilenames[1]], new Set(generatedFilenames)), ).to.eventually.have.property('size', generatedFilenames.length - 2); - const existenceResults = await Promise.all(generatedFilenames.map(async (name) => io.exists(join(tmpDir, name)))); + const existenceResults = await Promise.all( + generatedFilenames.map(async (name) => GeneratorIO.exists(join(tmpDir, name))), + ); expect(existenceResults).to.be.deep.equal([true, true, false]); }); @@ -94,7 +96,9 @@ describe('Testing GeneratorIO', function (this: Mocha.Suite) { 'size', generatedFilenames.length, ); - const existenceResults = await Promise.all(generatedFilenames.map(async (name) => io.exists(join(tmpDir, name)))); + const existenceResults = await Promise.all( + generatedFilenames.map(async (name) => GeneratorIO.exists(join(tmpDir, name))), + ); expect(existenceResults).to.be.deep.equal([false, false, false]); }); @@ -106,7 +110,7 @@ describe('Testing GeneratorIO', function (this: Mocha.Suite) { 'size', generatedFilenames.length, ); - await expect(io.exists(join(tmpDir, name))).to.eventually.be.true; + await expect(GeneratorIO.exists(join(tmpDir, name))).to.eventually.be.true; }); }); describe('Testing GeneratorIO.writeChangedFiles', () => { diff --git a/packages/ts/generator-plugin-model/src/EntityModelProcessor.ts b/packages/ts/generator-plugin-model/src/EntityModelProcessor.ts index 06171d2673..01a1439918 100644 --- a/packages/ts/generator-plugin-model/src/EntityModelProcessor.ts +++ b/packages/ts/generator-plugin-model/src/EntityModelProcessor.ts @@ -132,9 +132,7 @@ export class EntityClassModelProcessor extends EntityModelProcessor { if (decomposed.length > 2) { logger.debug( this.#component, - `The schema for a class component ${ - this.#fullyQualifiedName - } has more than two components. This plugin will ignore it.`, + `The schema for a class component ${this.#fullyQualifiedName} has more than two components. This plugin will ignore it.`, ); return undefined; } diff --git a/packages/ts/generator-plugin-model/src/MetadataProcessor.ts b/packages/ts/generator-plugin-model/src/MetadataProcessor.ts index 92c047abde..8328bc12f6 100644 --- a/packages/ts/generator-plugin-model/src/MetadataProcessor.ts +++ b/packages/ts/generator-plugin-model/src/MetadataProcessor.ts @@ -11,47 +11,44 @@ export type SchemaWithMetadata = Schema & { 'x-java-type'?: string; }; -export class MetadataProcessor { - process(schema: Schema): ObjectLiteralExpression | null { - const schemaWithMetadata = schema as SchemaWithMetadata; +function createAnnotationsProperty(schema: SchemaWithMetadata): PropertyAssignment | null { + const annotations = schema['x-annotations']; + const hasAnnotations = annotations && annotations.length > 0; + if (!hasAnnotations) { + return null; + } - const properties = [ - this.#createAnnotationsProperty(schemaWithMetadata), - this.#createJavaTypeProperty(schemaWithMetadata), - ].filter(Boolean) as PropertyAssignment[]; + const annotationLiterals = annotations.map((annotation) => + ts.factory.createObjectLiteralExpression([ + ts.factory.createPropertyAssignment('name', ts.factory.createStringLiteral(annotation.name)), + ]), + ); - if (properties.length === 0) { - return null; - } + return ts.factory.createPropertyAssignment( + 'annotations', + ts.factory.createArrayLiteralExpression(annotationLiterals), + ); +} - return ts.factory.createObjectLiteralExpression(properties); +function createJavaTypeProperty(schema: SchemaWithMetadata): PropertyAssignment | null { + const javaType = schema['x-java-type']; + if (!javaType) { + return null; } - #createAnnotationsProperty(schema: SchemaWithMetadata): PropertyAssignment | null { - const annotations = schema['x-annotations']; - const hasAnnotations = annotations && annotations.length > 0; - if (!hasAnnotations) { - return null; - } - - const annotationLiterals = annotations.map((annotation) => - ts.factory.createObjectLiteralExpression([ - ts.factory.createPropertyAssignment('name', ts.factory.createStringLiteral(annotation.name)), - ]), - ); - - return ts.factory.createPropertyAssignment( - 'annotations', - ts.factory.createArrayLiteralExpression(annotationLiterals), - ); - } + return ts.factory.createPropertyAssignment('javaType', ts.factory.createStringLiteral(javaType)); +} + +export function process(schema: Schema): ObjectLiteralExpression | null { + const schemaWithMetadata = schema as SchemaWithMetadata; - #createJavaTypeProperty(schema: SchemaWithMetadata): PropertyAssignment | null { - const javaType = schema['x-java-type']; - if (!javaType) { - return null; - } + const properties = [createAnnotationsProperty(schemaWithMetadata), createJavaTypeProperty(schemaWithMetadata)].filter( + Boolean, + ) as PropertyAssignment[]; - return ts.factory.createPropertyAssignment('javaType', ts.factory.createStringLiteral(javaType)); + if (properties.length === 0) { + return null; } + + return ts.factory.createObjectLiteralExpression(properties); } diff --git a/packages/ts/generator-plugin-model/src/ModelSchemaProcessor.ts b/packages/ts/generator-plugin-model/src/ModelSchemaProcessor.ts index 3c41e62232..0132bcd0d6 100644 --- a/packages/ts/generator-plugin-model/src/ModelSchemaProcessor.ts +++ b/packages/ts/generator-plugin-model/src/ModelSchemaProcessor.ts @@ -28,7 +28,7 @@ import ts, { type TypeNode, type TypeReferenceNode, } from 'typescript'; -import { MetadataProcessor } from './MetadataProcessor.js'; +import { process } from './MetadataProcessor.js'; import { createModelBuildingCallback, importBuiltInFormModel } from './utils.js'; import { hasValidationConstraints, ValidationConstraintProcessor } from './ValidationConstraintProcessor.js'; @@ -225,14 +225,12 @@ export class ModelSchemaTypeProcessor extends ModelSchemaPartProcessor { readonly #validationConstraintProcessor: ValidationConstraintProcessor; - readonly #metadataProcessor: MetadataProcessor; constructor(schema: Schema, dependencies: DependencyManager) { super(schema, dependencies); this.#validationConstraintProcessor = new ValidationConstraintProcessor((name) => importBuiltInFormModel(name, dependencies), ); - this.#metadataProcessor = new MetadataProcessor(); } override process(): readonly ts.Expression[] { @@ -242,7 +240,7 @@ export class ModelSchemaExpressionProcessor extends ModelSchemaPartProcessor 0) { @@ -300,8 +298,8 @@ export class ModelSchemaExpressionProcessor extends ModelSchemaPartProcessor): Expression { + static #processAttributes(attributes: Record): Expression { const names = Object.keys(attributes); const tpl = JSON.stringify(names.includes('value') && names.length === 1 ? attributes.value : attributes); diff --git a/packages/ts/generator-plugin-push/src/PushProcessor.ts b/packages/ts/generator-plugin-push/src/PushProcessor.ts index 81637a3d81..fb60718266 100644 --- a/packages/ts/generator-plugin-push/src/PushProcessor.ts +++ b/packages/ts/generator-plugin-push/src/PushProcessor.ts @@ -55,7 +55,7 @@ export class PushProcessor { ); if (importHillaCore) { - const updatedImportStatement = this.#removeInitImport(importHillaCore as ts.ImportDeclaration); + const updatedImportStatement = PushProcessor.#removeInitImport(importHillaCore as ts.ImportDeclaration); if (updatedImportStatement) { importStatements = importStatements.map((statement) => { @@ -74,7 +74,7 @@ export class PushProcessor { return createSourceFile(updatedStatements, this.#source.fileName); } - #doesInitParameterExist(parameters: ts.NodeArray): boolean { + static #doesInitParameterExist(parameters: ts.NodeArray): boolean { const last = parameters[parameters.length - 1]; const lastType = last.type as ts.TypeReferenceNode; const lastTypeName = lastType.typeName as ts.Identifier; @@ -82,7 +82,7 @@ export class PushProcessor { return lastTypeName.text === initParameterTypeName; } - #removeInitImport(importStatement: ts.ImportDeclaration): ts.Statement | undefined { + static #removeInitImport(importStatement: ts.ImportDeclaration): ts.Statement | undefined { const namedImports = importStatement.importClause?.namedBindings; if (namedImports && ts.isNamedImports(namedImports)) { const updatedElements = namedImports.elements.filter((element) => element.name.text !== 'EndpointRequestInit'); @@ -119,7 +119,7 @@ export class PushProcessor { #updateFunction(declaration: ts.FunctionDeclaration): ts.FunctionDeclaration { const { parameters } = declaration; - const doesInitParameterExist = this.#doesInitParameterExist(parameters); + const doesInitParameterExist = PushProcessor.#doesInitParameterExist(parameters); return ts.factory.createFunctionDeclaration( undefined, // no async @@ -129,11 +129,11 @@ export class PushProcessor { // Remove the `init` parameter doesInitParameterExist ? parameters.slice(0, -1) : parameters, this.#replacePromiseType(declaration), - this.#updateFunctionBody(declaration, doesInitParameterExist), + PushProcessor.#updateFunctionBody(declaration, doesInitParameterExist), ); } - #updateFunctionBody(declaration: ts.FunctionDeclaration, doesInitParameterExist: boolean): ts.Block { + static #updateFunctionBody(declaration: ts.FunctionDeclaration, doesInitParameterExist: boolean): ts.Block { const returnStatement = declaration.body!.statements[0] as ts.ReturnStatement; const { arguments: args, expression, typeArguments } = returnStatement.expression! as ts.CallExpression; const call = expression as ts.PropertyAccessExpression; diff --git a/packages/ts/lit-form/src/BinderRoot.ts b/packages/ts/lit-form/src/BinderRoot.ts index 3b91333b20..0e1ce91f34 100644 --- a/packages/ts/lit-form/src/BinderRoot.ts +++ b/packages/ts/lit-form/src/BinderRoot.ts @@ -282,6 +282,8 @@ export class BinderRoot extends BinderN * @param elm - the bound element * @param model - the bound model */ + // eslint ignored to allow overriding + // eslint-disable-next-line @typescript-eslint/class-methods-use-this getFieldStrategy(elm: HTMLElement, model?: AbstractModel): FieldStrategy { return getDefaultFieldStrategy(elm as FieldElement, model); } diff --git a/packages/ts/react-crud/src/data-provider.ts b/packages/ts/react-crud/src/data-provider.ts index b0da50be0e..32647919c1 100644 --- a/packages/ts/react-crud/src/data-provider.ts +++ b/packages/ts/react-crud/src/data-provider.ts @@ -138,6 +138,8 @@ export abstract class DataProvider { } export class InfiniteDataProvider extends DataProvider { + // cannot be static, otherwise it does not implement superclass + // eslint-disable-next-line @typescript-eslint/class-methods-use-this protected fetchTotalCount(): undefined { return undefined; } diff --git a/packages/ts/react-crud/test/GridController.ts b/packages/ts/react-crud/test/GridController.ts index e6e296ce63..069181e25d 100644 --- a/packages/ts/react-crud/test/GridController.ts +++ b/packages/ts/react-crud/test/GridController.ts @@ -83,7 +83,7 @@ export default class GridController { return cells.map((cell) => (getCellContent(cell) as HTMLElement).innerText); } - generateColumnHeaders(paths: readonly string[]): readonly string[] { + static generateColumnHeaders(paths: readonly string[]): readonly string[] { return paths.map((path) => path .substring(path.lastIndexOf('.') + 1) diff --git a/packages/ts/react-crud/test/autogrid.spec.tsx b/packages/ts/react-crud/test/autogrid.spec.tsx index 79d2879d3c..a4adaa0f71 100644 --- a/packages/ts/react-crud/test/autogrid.spec.tsx +++ b/packages/ts/react-crud/test/autogrid.spec.tsx @@ -53,7 +53,7 @@ export async function nextFrame(): Promise { async function assertColumnsOrder(grid: GridController, ...ids: string[]) { const columns = await grid.getColumns(); expect(columns).to.have.length(ids.length); - await expect(grid.getHeaderCellContents()).to.eventually.deep.equal(grid.generateColumnHeaders(ids)); + await expect(grid.getHeaderCellContents()).to.eventually.deep.equal(GridController.generateColumnHeaders(ids)); } async function assertColumns(grid: GridController, ...ids: string[]) {