Skip to content

Commit

Permalink
Add importExtension to LangiumConfig (#1072)
Browse files Browse the repository at this point in the history
When downstream projects are using `nodenext` module resolution, file extensions are mandatory.
Developers can use `importExtension` to specify the extension used in generated import statements.

---------

Co-authored-by: Mark Sujew <mark.sujew@typefox.io>
  • Loading branch information
2 people authored and spoenemann committed Aug 15, 2023
1 parent df21799 commit 45e8c5d
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 3 deletions.
4 changes: 4 additions & 0 deletions packages/langium-cli/langium-config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@
"description": "The relative directory to the code generated by the langium-cli",
"type": "string"
},
"importExtension": {
"description": "File extension used for TypeScript import statements. Empty by default",
"type": "string"
},
"chevrotainParserConfig": {
"$ref": "#/$defs/chevrotainParserConfig"
},
Expand Down
9 changes: 6 additions & 3 deletions packages/langium-cli/src/generator/module-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function generateModule(grammars: Grammar[], config: LangiumConfig, gramm
const parserConfig = config.chevrotainParserConfig;
const hasIParserConfigImport = Boolean(parserConfig) || grammars.some(grammar => grammarConfigMap.get(grammar)?.chevrotainParserConfig !== undefined);
const node = new CompositeGeneratorNode();
const importExtension = config.importExtension ?? '';

node.append(generatedHeader);
if (config.langiumInternal) {
Expand All @@ -25,9 +26,11 @@ export function generateModule(grammars: Grammar[], config: LangiumConfig, gramm
} else {
node.append(`import type { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumSharedServices, LangiumServices, LanguageMetaData, Module${hasIParserConfigImport ? ', IParserConfig' : ''} } from 'langium';`, NL);
}

node.append(
'import { ', config.projectName, "AstReflection } from './ast';", NL,
'import { ',
config.projectName,
`AstReflection } from './ast${importExtension}';`,
NL,
'import { '
);
for (let i = 0; i < grammars.length; i++) {
Expand All @@ -39,7 +42,7 @@ export function generateModule(grammars: Grammar[], config: LangiumConfig, gramm
}
}
}
node.append(" } from './grammar';", NL, NL);
node.append(` } from './grammar${importExtension}';`, NL, NL);

for (const grammar of grammars) {
if (grammar.name) {
Expand Down
2 changes: 2 additions & 0 deletions packages/langium-cli/src/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export interface LangiumConfig {
languages: LangiumLanguageConfig[]
/** Main output directory for TypeScript code */
out?: string
/** File extension for import statements of generated files */
importExtension?: string
/** Configure the chevrotain parser for all languages */
chevrotainParserConfig?: IParserConfig,
/** The following option is meant to be used only by Langium itself */
Expand Down
41 changes: 41 additions & 0 deletions packages/langium-cli/test/generator/module-generator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,45 @@ describe('Module generator', () => {
expect(moduleString).toMatch(/^import .* IParserConfig/gm);
});
});

describe('File extension inclusion', () => {
test('should not include .js extension in imports', () => {
// arrange
const config = {
projectName: 'Magic',
languages: [],
[RelativePath]: '/path/to/magic',
};

// act
const moduleString = generateModule([], config, new Map());

// assert
expect(moduleString.includes("from './grammar';")).toBeTruthy();
expect(moduleString.includes("from './ast';")).toBeTruthy();

expect(moduleString.includes("from './grammar.js';")).toBeFalsy();
expect(moduleString.includes("from './ast.js';")).toBeFalsy();
});

test('should include .js extension in imports', () => {
// arrange
const config: LangiumConfig = {
projectName: 'Magic',
languages: [],
[RelativePath]: '/path/to/magic',
importExtension: '.js'
};

// act
const moduleString = generateModule([], config, new Map());

// assert
expect(moduleString.includes("from './grammar.js';")).toBeTruthy();
expect(moduleString.includes("from './ast.js';")).toBeTruthy();

expect(moduleString.includes("from './grammar';")).toBeFalsy();
expect(moduleString.includes("from './ast';")).toBeFalsy();
});
});
});

0 comments on commit 45e8c5d

Please sign in to comment.