Skip to content

Commit

Permalink
Make /textmate export more bundler-friendly
Browse files Browse the repository at this point in the history
  • Loading branch information
Lotes committed Apr 10, 2024
1 parent f14d517 commit 4482eb5
Show file tree
Hide file tree
Showing 17 changed files with 160 additions and 145 deletions.
8 changes: 5 additions & 3 deletions packages/langium-cli/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
******************************************************************************/

import type { AstNode, Grammar, LangiumDocument, Mutable } from 'langium';
import type { LangiumConfig, LangiumLanguageConfig} from './package.js';
import type { LangiumConfig, LangiumLanguageConfig} from './package-types.js';
import { URI } from 'langium';
import { loadConfig } from './package.js';
import { AstUtils, GrammarAST } from 'langium';
Expand All @@ -17,8 +17,10 @@ import { generateModule } from './generator/module-generator.js';
import { generateTextMate } from './generator/highlighting/textmate-generator.js';
import { generateMonarch } from './generator/highlighting/monarch-generator.js';
import { generatePrismHighlighting } from './generator/highlighting/prism-generator.js';
import { elapsedTime, getTime, getUserChoice, log, schema } from './generator/util.js';
import { getFilePath, RelativePath } from './package.js';
import { elapsedTime, getTime, log } from './generator/langium-util.js';
import { getUserChoice, schema } from './generator/node-util.js';
import { RelativePath } from './package-types.js';
import { getFilePath } from './package.js';
import { validateParser } from './parser-validation.js';
import { generateTypesFile } from './generator/types-generator.js';
import { createGrammarDiagramHtml, createGrammarDiagramSvg } from 'langium-railroad';
Expand Down
5 changes: 3 additions & 2 deletions packages/langium-cli/src/generator/ast-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
import type { Grammar, LangiumCoreServices } from 'langium';
import { type Generated, expandToNode, joinToNode, toString } from 'langium/generate';
import type { AstTypes, Property, PropertyDefaultValue } from 'langium/grammar';
import type { LangiumConfig } from '../package.js';
import type { LangiumConfig } from '../package-types.js';
import { AstUtils, MultiMap, GrammarAST } from 'langium';
import { collectAst, collectTypeHierarchy, findReferenceTypes, isAstType, mergeTypesAndInterfaces } from 'langium/grammar';
import { collectTerminalRegexps, generatedHeader } from './util.js';
import { generatedHeader } from './node-util.js';
import { collectTerminalRegexps } from './langium-util.js';

export function generateAst(services: LangiumCoreServices, grammars: Grammar[], config: LangiumConfig): string {
const astTypes = collectAst(grammars, services.shared.workspace.LangiumDocuments);
Expand Down
4 changes: 2 additions & 2 deletions packages/langium-cli/src/generator/grammar-serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
import type { Grammar, LangiumCoreServices, Reference } from 'langium';
import { expandToNode, joinToNode, normalizeEOL, toString } from 'langium/generate';
import type { URI } from 'vscode-uri';
import type { LangiumConfig } from '../package.js';
import { generatedHeader } from './util.js';
import type { LangiumConfig } from '../package-types.js';
import { generatedHeader } from './node-util.js';

export function serializeGrammar(services: LangiumCoreServices, grammars: Grammar[], config: LangiumConfig): string {
const node = expandToNode`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

import { type Grammar, GrammarAST, GrammarUtils, RegExpUtils } from 'langium';
import { type Generated, expandToNode, joinToNode, toString } from 'langium/generate';
import type { LangiumLanguageConfig } from '../../package.js';
import { collectKeywords } from '../util.js';
import type { LangiumLanguageConfig } from '../../package-types.js';
import { collectKeywords } from '../langium-util.js';

/**
* Monarch Language Definition, describes aspects & token categories of target language
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import { GrammarAST, type Grammar, GrammarUtils, RegExpUtils } from 'langium';
import { expandToNode, joinToNode, toString, type Generated } from 'langium/generate';
import _ from 'lodash';
import type { LangiumLanguageConfig } from '../../package.js';
import { collectKeywords } from '../util.js';
import type { LangiumLanguageConfig } from '../../package-types.js';
import { collectKeywords } from '../langium-util.js';

interface HighlightElement {
pattern: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
******************************************************************************/
import type { Grammar } from 'langium';
import { GrammarAST, GrammarUtils, RegExpUtils, stream } from 'langium';
import type { LangiumLanguageConfig } from '../../package.js';
import { collectKeywords } from '../util.js';
import type { LangiumLanguageConfig } from '../../package-types.js';
import { collectKeywords } from '../langium-util.js';

/* eslint-disable dot-notation */

Expand Down
57 changes: 57 additions & 0 deletions packages/langium-cli/src/generator/langium-util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/******************************************************************************
* Copyright 2021 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { AstUtils, type Grammar, GrammarAST, GrammarUtils, stream } from 'langium';
import chalk from 'chalk';

//eslint-disable-next-line @typescript-eslint/no-explicit-any
export function log(level: 'log' | 'warn' | 'error', options: { watch?: boolean }, message: string, ...args: any[]): void {
if (options.watch) {
console[level](getTime() + message, ...args);
} else {
console[level](message, ...args);
}
}

let start = process.hrtime();

export function elapsedTime(): string {
const elapsed = process.hrtime(start)[1] / 1000000; // divide by a million to get nano to milli
start = process.hrtime(); // reset the timer
return elapsed.toFixed();
}

export function getTime(): string {
const date = new Date();
return `[${chalk.gray(`${padZeroes(date.getHours())}:${padZeroes(date.getMinutes())}:${padZeroes(date.getSeconds())}`)}] `;
}

function padZeroes(i: number): string {
return i.toString().padStart(2, '0');
}

export function collectKeywords(grammar: Grammar): string[] {
const keywords = new Set<string>();
const reachableRules = GrammarUtils.getAllReachableRules(grammar, false);

for (const keyword of stream(reachableRules)
.filter(GrammarAST.isParserRule)
.flatMap(rule => AstUtils.streamAllContents(rule).filter(GrammarAST.isKeyword))) {
keywords.add(keyword.value);
}

return Array.from(keywords).sort();
}

export function collectTerminalRegexps(grammar: Grammar): Record<string, RegExp> {
const result: Record<string, RegExp> = {};
const reachableRules = GrammarUtils.getAllReachableRules(grammar, false);
for (const terminalRule of stream(reachableRules).filter(GrammarAST.isTerminalRule)) {
const name = terminalRule.name;
const regexp = GrammarUtils.terminalRegex(terminalRule);
result[name] = regexp;
}
return result;
}
4 changes: 2 additions & 2 deletions packages/langium-cli/src/generator/module-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

import type { Grammar, IParserConfig } from 'langium';
import { type Generated, expandToNode, joinToNode, toString } from 'langium/generate';
import type { LangiumConfig, LangiumLanguageConfig } from '../package.js';
import { generatedHeader } from './util.js';
import type { LangiumConfig, LangiumLanguageConfig } from '../package-types.js';
import { generatedHeader } from './node-util.js';

export function generateModule(grammars: Grammar[], config: LangiumConfig, grammarConfigMap: Map<Grammar, LangiumLanguageConfig>): string {
const grammarsWithName = grammars.filter(grammar => !!grammar.name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,17 @@
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import { AstUtils, type Grammar, GrammarAST, GrammarUtils, stream } from 'langium';
import { type Generated, expandToNode } from 'langium/generate';
import fs from 'fs-extra';
import * as path from 'node:path';
import * as url from 'node:url';
import * as readline from 'node:readline';
import chalk from 'chalk';
import { type Generated, expandToNode } from 'langium/generate';

// This is a replacement for `__dirname`
function getDirname(): string {
return url.fileURLToPath(new URL('.', import.meta.url));
}

//eslint-disable-next-line @typescript-eslint/no-explicit-any
export function log(level: 'log' | 'warn' | 'error', options: { watch?: boolean }, message: string, ...args: any[]): void {
if (options.watch) {
console[level](getTime() + message, ...args);
} else {
console[level](message, ...args);
}
}

let start = process.hrtime();

export function elapsedTime(): string {
const elapsed = process.hrtime(start)[1] / 1000000; // divide by a million to get nano to milli
start = process.hrtime(); // reset the timer
return elapsed.toFixed();
}

export function getTime(): string {
const date = new Date();
return `[${chalk.gray(`${padZeroes(date.getHours())}:${padZeroes(date.getMinutes())}:${padZeroes(date.getSeconds())}`)}] `;
}

function padZeroes(i: number): string {
return i.toString().padStart(2, '0');
}

function getLangiumCliVersion(): string {
const ownPackagePath = path.resolve(getDirname(), '..', '..', 'package.json');
const pack = fs.readJsonSync(ownPackagePath, { encoding: 'utf-8' });
Expand All @@ -57,19 +29,6 @@ function getGeneratedHeader(): Generated {
`;
}

export function collectKeywords(grammar: Grammar): string[] {
const keywords = new Set<string>();
const reachableRules = GrammarUtils.getAllReachableRules(grammar, false);

for (const keyword of stream(reachableRules)
.filter(GrammarAST.isParserRule)
.flatMap(rule => AstUtils.streamAllContents(rule).filter(GrammarAST.isKeyword))) {
keywords.add(keyword.value);
}

return Array.from(keywords).sort();
}

export function getUserInput(text: string): Promise<string> {
return new Promise(resolve => {
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
Expand All @@ -95,17 +54,6 @@ export async function getUserChoice<R extends string>(text: string, values: R[],
return defaultValue;
}

export function collectTerminalRegexps(grammar: Grammar): Record<string, RegExp> {
const result: Record<string, RegExp> = {};
const reachableRules = GrammarUtils.getAllReachableRules(grammar, false);
for (const terminalRule of stream(reachableRules).filter(GrammarAST.isTerminalRule)) {
const name = terminalRule.name;
const regexp = GrammarUtils.terminalRegex(terminalRule);
result[name] = regexp;
}
return result;
}

export const cliVersion = getLangiumCliVersion();
export const generatedHeader = getGeneratedHeader();
export const schema = fs.readJson(path.resolve(getDirname(), '../../langium-config-schema.json'), { encoding: 'utf-8' });
2 changes: 1 addition & 1 deletion packages/langium-cli/src/generator/types-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import type { Grammar, LangiumCoreServices } from 'langium';
import { joinToNode, toString } from 'langium/generate';
import { collectAst, LangiumGrammarGrammar } from 'langium/grammar';
import { collectKeywords } from './util.js';
import { collectKeywords } from './langium-util.js';

export function generateTypesFile(services: LangiumCoreServices, grammars: Grammar[]): string {
const { unions, interfaces } = collectAst(grammars, services.shared.workspace.LangiumDocuments);
Expand Down
2 changes: 1 addition & 1 deletion packages/langium-cli/src/langium.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { Command, Option } from 'commander';
import type { ExtractTypesOptions, GenerateOptions} from './generate.js';
import { generate, generateTypes } from './generate.js';
import { cliVersion } from './generator/util.js';
import { cliVersion } from './generator/node-util.js';

const program = new Command();

Expand Down
70 changes: 70 additions & 0 deletions packages/langium-cli/src/package-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/******************************************************************************
* Copyright 2021 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/
import type { IParserConfig } from 'langium';

export interface Package {
name: string
version: string
langium: LangiumConfig
}

export const RelativePath = Symbol('RelativePath');

export interface LangiumConfig {
/** Relative path to the directory of the config */
[RelativePath]: string
/** Name of the language project */
projectName: string
/** Array of language configurations */
languages: LangiumLanguageConfig[]
/** Main output directory for TypeScript code */
out?: string
/** File extension for import statements of generated files */
importExtension?: string
/** Mode used to generate optimized files for development or production environments */
mode?: 'development' | 'production';
/** Configure the chevrotain parser for all languages */
chevrotainParserConfig?: IParserConfig,
/** The following option is meant to be used only by Langium itself */
langiumInternal?: boolean
}

export interface LangiumLanguageConfig {
/** The identifier of your language as used in vscode */
id: string
/** Path to the grammar file */
grammar: string
/** File extensions with leading `.` */
fileExtensions?: string[]
/** Enable case-insensitive keywords parsing */
caseInsensitive?: boolean
/** Enable generating a TextMate syntax highlighting file */
textMate?: {
/** Output path to syntax highlighting file */
out: string
}
/** Enable generating a Monarch syntax highlighting file */
monarch?: {
/** Output path to syntax highlighting file */
out: string
}
/** Enable generating a Prism syntax highlighting file */
prism?: {
/** Output path to syntax highlighting file */
out: string
}
/** Enable generating railroad syntax diagrams */
railroad?: {
/** Output path for railroad diagrams */
out: string;
/** Whether to print diagrams all into a single html file or in separate svg files */
mode?: 'html' | 'svg';
/** Path to a css file that will be included in the generated output files */
css?: string;
}
/** Configure the chevrotain parser for a single language */
chevrotainParserConfig?: IParserConfig
}
Loading

0 comments on commit 4482eb5

Please sign in to comment.