Skip to content

Commit

Permalink
generated Patch APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
tomsontom committed Feb 11, 2025
1 parent 803aa32 commit c41ecb2
Show file tree
Hide file tree
Showing 10 changed files with 611 additions and 17 deletions.
7 changes: 4 additions & 3 deletions dsl/src/cli/java-client-api/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ export function generateBase(
artifactConfig: JavaClientAPIGeneratorConfig
): Artifact {
const packageName = `${artifactConfig.rootPackageName}.model`;

const importCollector = new JavaImportsCollector(packageName);
const fqn = importCollector.importType.bind(importCollector);
return {
name: '_Base.java',
content: toString(
generateCompilationUnit(
packageName,
new JavaImportsCollector(packageName),
generateBaseContent()
importCollector,
generateBaseContent(fqn)
),
'\t'
),
Expand Down
18 changes: 18 additions & 0 deletions dsl/src/cli/java-gen-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,24 @@ export class JavaImportsCollector {
}
}

export function primitiveToObject(type: string) {
switch (type) {
case 'boolean':
return 'Boolean';
case 'double':
return 'Double';
case 'float':
return 'Float';
case 'int':
return 'Integer';
case 'long':
return 'Long';
case 'short':
return 'Short';
}
return type;
}

export type ImportGroup = {
readonly imports: readonly string[];
};
19 changes: 18 additions & 1 deletion dsl/src/cli/java-model-api/base.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
import { CompositeGeneratorNode, NL } from 'langium/generate';

export function generateBaseContent() {
export function generateBaseContent(fqn: (type: string) => string) {
const Function = fqn('java.util.function.Function');
const Consumer = fqn('java.util.function.Consumer');

const result = new CompositeGeneratorNode();
result.append('public interface _Base {', NL);
result.indent((classBody) => {
classBody.append('public interface Nillable<T> {', NL);
classBody.indent((innerBody) => {
innerBody.append(
`public <R> R apply(${Function}<T, R> function, R defaultValue);`,
NL,
NL
);
innerBody.append(`public void accept(${Consumer}<T> block);`, NL, NL);
innerBody.append(
`public <R> Nillable<R> map(${Function}<T, R> mapper);`,
NL
);
});
classBody.append('}', NL, NL);
classBody.append('public interface BaseData {', NL);
classBody.append('}', NL, NL);
classBody.append('public interface BaseDataBuilder<T> {', NL);
Expand Down
68 changes: 63 additions & 5 deletions dsl/src/cli/java-model-api/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ import {
allResolvedRecordProperties,
isMInlineEnumType,
isMProperty,
isMResolvedProperty,
MResolvedBaseProperty,
MResolvedRecordType,
} from '../model.js';
import { generateInlineEnum } from './enum.js';
import { toFirstUpper } from '../util.js';
import {
generateBuilderPropertyAccessor,
generatePatchBuilderPropertyAccessor,
generatePatchPropertyAccessor,
generatePropertyAccessor,
} from './shared.js';

Expand Down Expand Up @@ -41,9 +44,19 @@ export function generateRecordContent(
);
if (t.patchable) {
classBody.appendNewLine();
classBody.append(generatePatch(t));
classBody.append(
generatePatch(t, allProps, nativeTypeSubstitues, basePackageName, fqn)
);
classBody.appendNewLine();
classBody.append(generatePatchBuilder(t));
classBody.append(
generatePatchBuilder(
t,
allProps,
nativeTypeSubstitues,
basePackageName,
fqn
)
);
}
});
node.append('}');
Expand Down Expand Up @@ -125,16 +138,61 @@ function generateDataBuilder(
return node;
}

function generatePatch(t: MResolvedRecordType) {
function generatePatch(
t: MResolvedRecordType,
props: MResolvedBaseProperty[],
nativeTypeSubstitues: Record<string, string> | undefined,
basePackageName: string,
fqn: (type: string) => string
) {
const node = new CompositeGeneratorNode();
node.append(`public interface Patch extends ${t.name} {`, NL);
node.indent((classBody) => {
classBody.append(
...props
.filter(isMResolvedProperty)
.flatMap((p) => [
generatePatchPropertyAccessor(
p,
nativeTypeSubstitues,
basePackageName,
fqn
),
NL,
])
);
});
node.append('}', NL);
return node;
}

function generatePatchBuilder(t: MResolvedRecordType) {
function generatePatchBuilder(
t: MResolvedRecordType,
props: MResolvedBaseProperty[],
nativeTypeSubstitues: Record<string, string> | undefined,
basePackageName: string,
fqn: (type: string) => string
) {
const node = new CompositeGeneratorNode();
node.append(`public interface PatchBuilder {`, NL);
node.append(
`public interface PatchBuilder extends _Base.BaseDataBuilder<${t.name}.Patch> {`,
NL
);
node.indent((classBody) => {
classBody.append(
...props
.filter(isMResolvedProperty)
.flatMap((p) => [
generatePatchBuilderPropertyAccessor(
p,
nativeTypeSubstitues,
basePackageName,
fqn
),
NL,
])
);
});
node.append('}', NL);
return node;
}
Expand Down
100 changes: 98 additions & 2 deletions dsl/src/cli/java-model-api/shared.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { CompositeGeneratorNode, NL } from 'langium/generate';
import { isMProperty, MResolvedBaseProperty } from '../model.js';
import { computeAPIType } from '../java-gen-utils.js';
import {
isMProperty,
MResolvedBaseProperty,
MResolvedPropery,
} from '../model.js';
import { computeAPIType, primitiveToObject } from '../java-gen-utils.js';
import { toFirstUpper } from '../util.js';

export function generatePropertyAccessor(
Expand Down Expand Up @@ -56,3 +60,95 @@ export function generateBuilderPropertyAccessor(
}
return node;
}

export function generatePatchPropertyAccessor(
property: MResolvedPropery,
nativeTypeSubstitues: Record<string, string> | undefined,
basePackageName: string,
fqn: (type: string) => string
) {
const node = new CompositeGeneratorNode();
if (
property.variant === 'builtin' ||
property.variant === 'enum' ||
property.variant === 'inline-enum' ||
property.variant === 'scalar'
) {
const type = primitiveToObject(
computeAPIType(property, nativeTypeSubstitues, basePackageName, fqn)
);
if (property.optional || property.nullable) {
node.append(`public _Base.Nillable<${type}> ${property.name}();`, NL);
} else {
const Optional = fqn('java.util.Optional');
node.append(`public ${Optional}<${type}> ${property.name}();`, NL);
}
} else {
const type = computeAPIType(
property,
nativeTypeSubstitues,
basePackageName,
fqn
);
if (property.optional || property.nullable) {
node.append(`public _Base.Nillable<${type}> ${property.name}();`, NL);
} else {
const Optional = fqn('java.util.Optional');
node.append(`public ${Optional}<${type}> ${property.name}();`, NL);
}
}

return node;
}

export function generatePatchBuilderPropertyAccessor(
property: MResolvedPropery,
nativeTypeSubstitues: Record<string, string> | undefined,
basePackageName: string,
fqn: (type: string) => string
) {
const node = new CompositeGeneratorNode();
if (
property.variant === 'builtin' ||
property.variant === 'enum' ||
property.variant === 'inline-enum' ||
property.variant === 'scalar'
) {
let type = computeAPIType(
property,
nativeTypeSubstitues,
basePackageName,
fqn
);
if (property.nullable || property.optional) {
type = primitiveToObject(type);
}
node.append(
`public PatchBuilder ${property.name}(${type} ${property.name});`,
NL
);
} else {
node.append(
`public PatchBuilder ${property.name}(${computeAPIType(
property,
nativeTypeSubstitues,
basePackageName,
fqn
)} ${property.name});`,
NL
);
if (!property.array) {
const Function = fqn('java.util.function.Function');
node.append(
NL,
`public <T extends ${
property.type
}.DataBuilder> PatchBuilder with${toFirstUpper(
property.name
)}(Class<T> clazz, ${Function}<T, ${property.type}.Data> block);`,
NL
);
}
}
return node;
}
Loading

0 comments on commit c41ecb2

Please sign in to comment.