Skip to content

Commit 4ea7753

Browse files
committed
add an option to generate optional properties in ast
1 parent c3afb24 commit 4ea7753

File tree

4 files changed

+13
-5
lines changed

4 files changed

+13
-5
lines changed

packages/langium-cli/langium-config-schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@
171171
"langiumInternal": {
172172
"description": "A flag to determine whether langium uses itself to bootstrap",
173173
"type": "boolean"
174+
},
175+
"optionalProperties": {
176+
"description": "Use optional properties in generated ast (except for boolean and arrays properties)",
177+
"type": "boolean"
174178
}
175179
},
176180
"required": [

packages/langium-cli/src/generator/ast-generator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export function generateAst(services: LangiumCoreServices, grammars: Grammar[],
1616
const astTypes = collectAst(grammars, services.shared.workspace.LangiumDocuments);
1717
const crossRef = grammars.some(grammar => hasCrossReferences(grammar));
1818
const importFrom = config.langiumInternal ? `../../syntax-tree${config.importExtension}` : 'langium';
19+
1920
/* eslint-disable @typescript-eslint/indent */
2021
const fileNode = expandToNode`
2122
${generatedHeader}
@@ -27,7 +28,7 @@ export function generateAst(services: LangiumCoreServices, grammars: Grammar[],
2728
${generateTerminalConstants(grammars, config)}
2829
2930
${joinToNode(astTypes.unions, union => union.toAstTypesString(isAstType(union.type)), { appendNewLineIfNotEmpty: true })}
30-
${joinToNode(astTypes.interfaces, iFace => iFace.toAstTypesString(true), { appendNewLineIfNotEmpty: true })}
31+
${joinToNode(astTypes.interfaces, iFace => iFace.toAstTypesString(true, config.optionalProperties), { appendNewLineIfNotEmpty: true })}
3132
${
3233
astTypes.unions = astTypes.unions.filter(e => isAstType(e.type)),
3334
generateAstReflection(config, astTypes)

packages/langium-cli/src/package-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export interface LangiumConfig {
3030
chevrotainParserConfig?: IParserConfig,
3131
/** The following option is meant to be used only by Langium itself */
3232
langiumInternal?: boolean
33+
/** Use optional properties in generated ast (except for boolean and arrays properties) */
34+
optionalProperties?: boolean
3335
}
3436

3537
export interface LangiumLanguageConfig {

packages/langium/src/grammar/type-system/type-collector/types.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ export class InterfaceType {
218218
this.abstract = abstract;
219219
}
220220

221-
toAstTypesString(reflectionInfo: boolean): string {
221+
toAstTypesString(reflectionInfo: boolean, optionalProperties?: boolean): string {
222222
const interfaceSuperTypes = this.interfaceSuperTypes.map(e => e.name);
223223
const superTypes = interfaceSuperTypes.length > 0 ? distinctAndSorted([...interfaceSuperTypes]) : ['AstNode'];
224224
const interfaceNode = expandToNode`
@@ -233,7 +233,7 @@ export class InterfaceType {
233233
body.append(`readonly $type: ${distinctAndSorted([...this.typeNames]).map(e => `'${e}'`).join(' | ')};`).appendNewLine();
234234
}
235235
body.append(
236-
pushProperties(this.properties, 'AstType')
236+
pushProperties(this.properties, 'AstType', optionalProperties)
237237
);
238238
});
239239
interfaceNode.append('}').appendNewLine();
@@ -253,7 +253,7 @@ export class InterfaceType {
253253
return toString(
254254
expandToNode`
255255
interface ${name}${superTypes.length > 0 ? ` extends ${superTypes}` : ''} {
256-
${pushProperties(this.properties, 'DeclaredType', reservedWords)}
256+
${pushProperties(this.properties, 'DeclaredType', undefined, reservedWords)}
257257
}
258258
`.appendNewLine()
259259
);
@@ -408,12 +408,13 @@ function typeParenthesis(type: PropertyType, name: string): string {
408408
function pushProperties(
409409
properties: Property[],
410410
mode: 'AstType' | 'DeclaredType',
411+
optionalProperties?: boolean,
411412
reserved = new Set<string>()
412413
): Generated {
413414

414415
function propertyToString(property: Property): string {
415416
const name = mode === 'AstType' ? property.name : escapeReservedWords(property.name, reserved);
416-
const optional = property.optional && !isMandatoryPropertyType(property.type);
417+
const optional = !isMandatoryPropertyType(property.type) && (property.optional || optionalProperties);
417418
const propType = propertyTypeToString(property.type, mode);
418419
return `${name}${optional ? '?' : ''}: ${propType};`;
419420
}

0 commit comments

Comments
 (0)