From 4556bd8739e0808b922183268d4cd83bb5f3b9f6 Mon Sep 17 00:00:00 2001 From: Kolja Dummann <407216+coolya@users.noreply.github.com> Date: Thu, 6 Jul 2023 15:06:17 +0000 Subject: [PATCH 1/2] feat!: expose language metadata as const Exposing the LanguageMetadata as const with satisfies allows the values of its members like `languageId` or `fileExtensions` to be exposed statically. This allows for patterns like ``` type MyFileExtensions = typeof MyFancyDSLLanguageMetaData.fileExtensions ``` Where then MyFileExtensions is not typed to a generic `string[]` but to `['.myDsl']` which makes it easier to avoid mistakes. Unfortunately this is a breaking change because it requires the fileExtensions on the LanguageMetaData to be readonly to work. --- examples/arithmetics/src/cli/cli-util.ts | 2 +- examples/domainmodel/src/cli/cli-util.ts | 4 ++-- examples/statemachine/src/cli/cli-util.ts | 4 ++-- packages/langium-cli/src/generator/module-generator.ts | 4 ++-- packages/langium/src/grammar/language-meta-data.ts | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/arithmetics/src/cli/cli-util.ts b/examples/arithmetics/src/cli/cli-util.ts index 2039830fd..7d46ed838 100644 --- a/examples/arithmetics/src/cli/cli-util.ts +++ b/examples/arithmetics/src/cli/cli-util.ts @@ -10,7 +10,7 @@ import path from 'path'; import chalk from 'chalk'; import { URI } from 'vscode-uri'; -export async function extractDocument(fileName: string, extensions: string[], services: LangiumServices): Promise> { +export async function extractDocument(fileName: string, extensions: readonly string[], services: LangiumServices): Promise> { if (!extensions.includes(path.extname(fileName))) { console.error(chalk.yellow(`Please, choose a file with one of these extensions: ${extensions}.`)); process.exit(1); diff --git a/examples/domainmodel/src/cli/cli-util.ts b/examples/domainmodel/src/cli/cli-util.ts index e7cc714cc..2d0fe7419 100644 --- a/examples/domainmodel/src/cli/cli-util.ts +++ b/examples/domainmodel/src/cli/cli-util.ts @@ -11,7 +11,7 @@ import path from 'path'; import chalk from 'chalk'; import { URI } from 'vscode-uri'; -export async function extractDocument(fileName: string, extensions: string[], services: LangiumServices): Promise> { +export async function extractDocument(fileName: string, extensions: readonly string[], services: LangiumServices): Promise> { if (!extensions.includes(path.extname(fileName))) { console.error(chalk.yellow(`Please, choose a file with one of these extensions: ${extensions}.`)); process.exit(1); @@ -39,7 +39,7 @@ export async function extractDocument(fileName: string, exten return document as LangiumDocument; } -export async function extractAstNode(fileName: string, extensions: string[], services: LangiumServices): Promise { +export async function extractAstNode(fileName: string, extensions: readonly string[], services: LangiumServices): Promise { return (await extractDocument(fileName, extensions, services)).parseResult.value as T; } diff --git a/examples/statemachine/src/cli/cli-util.ts b/examples/statemachine/src/cli/cli-util.ts index ff7aa9260..fde557dd8 100644 --- a/examples/statemachine/src/cli/cli-util.ts +++ b/examples/statemachine/src/cli/cli-util.ts @@ -10,7 +10,7 @@ import chalk from 'chalk'; import type { AstNode, LangiumDocument, LangiumServices } from 'langium'; import { URI } from 'vscode-uri'; -export async function extractDocument(fileName: string, extensions: string[], services: LangiumServices): Promise { +export async function extractDocument(fileName: string, extensions: readonly string[], services: LangiumServices): Promise { if (!extensions.includes(path.extname(fileName))) { console.error(chalk.yellow(`Please, choose a file with one of these extensions: ${extensions}.`)); process.exit(1); @@ -38,7 +38,7 @@ export async function extractDocument(fileName: string, extensions: string[], se return document; } -export async function extractAstNode(fileName: string, extensions: string[], services: LangiumServices): Promise { +export async function extractAstNode(fileName: string, extensions: readonly string[], services: LangiumServices): Promise { return (await extractDocument(fileName, extensions, services)).parseResult?.value as T; } diff --git a/packages/langium-cli/src/generator/module-generator.ts b/packages/langium-cli/src/generator/module-generator.ts index 9b7d191a4..9e2d30737 100644 --- a/packages/langium-cli/src/generator/module-generator.ts +++ b/packages/langium-cli/src/generator/module-generator.ts @@ -47,13 +47,13 @@ export function generateModule(grammars: Grammar[], config: LangiumConfig, gramm for (const grammar of grammars) { if (grammar.name) { const config = grammarConfigMap.get(grammar)!; - node.append('export const ', grammar.name, 'LanguageMetaData: LanguageMetaData = {', NL); + node.append('export const ', grammar.name, 'LanguageMetaData = {', NL); node.indent(metaData => { metaData.append(`languageId: '${config.id}',`, NL); metaData.append(`fileExtensions: [${config.fileExtensions && config.fileExtensions.map(e => appendQuotesAndDot(e)).join(', ')}],`, NL); metaData.append(`caseInsensitive: ${Boolean(config.caseInsensitive)}`, NL); }); - node.append('};', NL, NL); + node.append('} as const satisfies LanguageMetaData;', NL, NL); } } diff --git a/packages/langium/src/grammar/language-meta-data.ts b/packages/langium/src/grammar/language-meta-data.ts index a43651c70..aa6f5d987 100644 --- a/packages/langium/src/grammar/language-meta-data.ts +++ b/packages/langium/src/grammar/language-meta-data.ts @@ -6,6 +6,6 @@ export interface LanguageMetaData { languageId: string; - fileExtensions: string[]; + fileExtensions: readonly string[]; caseInsensitive: boolean; } From a1aeb1b125c228c753ab7a376f1c90b009f29cd1 Mon Sep 17 00:00:00 2001 From: Kolja Dummann <407216+coolya@users.noreply.github.com> Date: Thu, 6 Jul 2023 15:14:36 +0000 Subject: [PATCH 2/2] update generated files --- .../arithmetics/src/language-server/generated/module.ts | 4 ++-- .../domainmodel/src/language-server/generated/module.ts | 4 ++-- .../requirements/src/language-server/generated/module.ts | 8 ++++---- .../statemachine/src/language-server/generated/module.ts | 4 ++-- packages/langium/src/grammar/generated/module.ts | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/arithmetics/src/language-server/generated/module.ts b/examples/arithmetics/src/language-server/generated/module.ts index 8ba72e28c..fe559b458 100644 --- a/examples/arithmetics/src/language-server/generated/module.ts +++ b/examples/arithmetics/src/language-server/generated/module.ts @@ -7,11 +7,11 @@ import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumS import { ArithmeticsAstReflection } from './ast'; import { ArithmeticsGrammar } from './grammar'; -export const ArithmeticsLanguageMetaData: LanguageMetaData = { +export const ArithmeticsLanguageMetaData = { languageId: 'arithmetics', fileExtensions: ['.calc'], caseInsensitive: true -}; +} as const satisfies LanguageMetaData; export const ArithmeticsGeneratedSharedModule: Module = { AstReflection: () => new ArithmeticsAstReflection() diff --git a/examples/domainmodel/src/language-server/generated/module.ts b/examples/domainmodel/src/language-server/generated/module.ts index 4fcb465e4..871f2b917 100644 --- a/examples/domainmodel/src/language-server/generated/module.ts +++ b/examples/domainmodel/src/language-server/generated/module.ts @@ -7,11 +7,11 @@ import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumS import { DomainModelAstReflection } from './ast'; import { DomainModelGrammar } from './grammar'; -export const DomainModelLanguageMetaData: LanguageMetaData = { +export const DomainModelLanguageMetaData = { languageId: 'domain-model', fileExtensions: ['.dmodel'], caseInsensitive: false -}; +} as const satisfies LanguageMetaData; export const parserConfig: IParserConfig = { recoveryEnabled: true, diff --git a/examples/requirements/src/language-server/generated/module.ts b/examples/requirements/src/language-server/generated/module.ts index a0e968f90..7d1219461 100644 --- a/examples/requirements/src/language-server/generated/module.ts +++ b/examples/requirements/src/language-server/generated/module.ts @@ -7,17 +7,17 @@ import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumS import { RequirementsAndTestsAstReflection } from './ast'; import { RequirementsGrammar, TestsGrammar } from './grammar'; -export const RequirementsLanguageMetaData: LanguageMetaData = { +export const RequirementsLanguageMetaData = { languageId: 'requirements-lang', fileExtensions: ['.req'], caseInsensitive: false -}; +} as const satisfies LanguageMetaData; -export const TestsLanguageMetaData: LanguageMetaData = { +export const TestsLanguageMetaData = { languageId: 'tests-lang', fileExtensions: ['.tst'], caseInsensitive: false -}; +} as const satisfies LanguageMetaData; export const RequirementsAndTestsGeneratedSharedModule: Module = { AstReflection: () => new RequirementsAndTestsAstReflection() diff --git a/examples/statemachine/src/language-server/generated/module.ts b/examples/statemachine/src/language-server/generated/module.ts index bcac098d7..8d442a094 100644 --- a/examples/statemachine/src/language-server/generated/module.ts +++ b/examples/statemachine/src/language-server/generated/module.ts @@ -7,11 +7,11 @@ import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumS import { StatemachineAstReflection } from './ast'; import { StatemachineGrammar } from './grammar'; -export const StatemachineLanguageMetaData: LanguageMetaData = { +export const StatemachineLanguageMetaData = { languageId: 'statemachine', fileExtensions: ['.statemachine'], caseInsensitive: false -}; +} as const satisfies LanguageMetaData; export const StatemachineGeneratedSharedModule: Module = { AstReflection: () => new StatemachineAstReflection() diff --git a/packages/langium/src/grammar/generated/module.ts b/packages/langium/src/grammar/generated/module.ts index eba1f9a38..f902eab12 100644 --- a/packages/langium/src/grammar/generated/module.ts +++ b/packages/langium/src/grammar/generated/module.ts @@ -10,11 +10,11 @@ import type { IParserConfig } from '../../parser/parser-config'; import { LangiumGrammarAstReflection } from './ast'; import { LangiumGrammarGrammar } from './grammar'; -export const LangiumGrammarLanguageMetaData: LanguageMetaData = { +export const LangiumGrammarLanguageMetaData = { languageId: 'langium', fileExtensions: ['.langium'], caseInsensitive: false -}; +} as const satisfies LanguageMetaData; export const LangiumGrammarParserConfig: IParserConfig = { maxLookahead: 3,