mirror of
https://github.com/eMoflon/model-modeling-language.git
synced 2024-05-20 20:00:39 +00:00
Initial commit
- basic grammar and references
This commit is contained in:
parent
b335fdb03c
commit
40ea38f596
13
.eslintrc.json
Normal file
13
.eslintrc.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
}
|
||||
}
|
9
.vscode/extensions.json
vendored
Normal file
9
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"langium.langium-vscode"
|
||||
]
|
||||
}
|
31
.vscode/launch.json
vendored
Normal file
31
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// A launch configuration that launches the extension inside a new window
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Run Extension",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Attach to Language Server",
|
||||
"type": "node",
|
||||
"port": 6009,
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js",
|
||||
"${workspaceFolder}/node_modules/langium"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
4
.vscodeignore
Normal file
4
.vscodeignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
.vscode/**
|
||||
.vscode-test/**
|
||||
.gitignore
|
||||
langium-quickstart.md
|
4
build.sh
Normal file
4
build.sh
Normal file
|
@ -0,0 +1,4 @@
|
|||
npm run langium:generate
|
||||
#npm run build
|
||||
|
||||
vsce package
|
12
langium-config.json
Normal file
12
langium-config.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"projectName": "ModelModelingLanguage",
|
||||
"languages": [{
|
||||
"id": "model-modeling-language",
|
||||
"grammar": "src/language-server/model-modeling-language.langium",
|
||||
"fileExtensions": [".mml"],
|
||||
"textMate": {
|
||||
"out": "syntaxes/model-modeling-language.tmLanguage.json"
|
||||
}
|
||||
}],
|
||||
"out": "src/language-server/generated"
|
||||
}
|
40
langium-quickstart.md
Normal file
40
langium-quickstart.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Welcome to your Langium VS Code Extension
|
||||
|
||||
## What's in the folder
|
||||
|
||||
This folder contains all necessary files for your language extension.
|
||||
* `package.json` - the manifest file in which you declare your language support.
|
||||
* `language-configuration.json` - the language configuration used in the VS Code editor, defining the tokens that are used for comments and brackets.
|
||||
* `src/extension.ts` - the main code of the extension, which is responsible for launching a language server and client.
|
||||
* `src/language-server/model-modeling-language.langium` - the grammar definition of your language.
|
||||
* `src/language-server/main.ts` - the entry point of the language server process.
|
||||
* `src/language-server/model-modeling-language-module.ts` - the dependency injection module of your language implementation. Use this to register overridden and added services.
|
||||
* `src/language-server/model-modeling-language-validator.ts` - an example validator. You should change it to reflect the semantics of your language.
|
||||
* `src/cli/index.ts` - the entry point of the command line interface (CLI) of your language.
|
||||
* `src/cli/generator.ts` - the code generator used by the CLI to write output files from DSL documents.
|
||||
* `src/cli/cli-util.ts` - utility code for the CLI.
|
||||
|
||||
## Get up and running straight away
|
||||
|
||||
* Run `npm run langium:generate` to generate TypeScript code from the grammar definition.
|
||||
* Run `npm run build` to compile all TypeScript code.
|
||||
* Press `F5` to open a new window with your extension loaded.
|
||||
* Create a new file with a file name suffix matching your language.
|
||||
* Verify that syntax highlighting, validation, completion etc. are working as expected.
|
||||
* Run `./bin/cli` to see options for the CLI; `./bin/cli generate <file>` generates code for a given DSL file.
|
||||
|
||||
## Make changes
|
||||
|
||||
* Run `npm run watch` to have the TypeScript compiler run automatically after every change of the source files.
|
||||
* Run `npm run langium:watch` to have the Langium generator run automatically afer every change of the grammar declaration.
|
||||
* You can relaunch the extension from the debug toolbar after making changes to the files listed above.
|
||||
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
|
||||
|
||||
## Install your extension
|
||||
|
||||
* To start using your extension with VS Code, copy it into the `<user home>/.vscode/extensions` folder and restart Code.
|
||||
* To share your extension with the world, read the [VS Code documentation](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) about publishing an extension.
|
||||
|
||||
## To Go Further
|
||||
|
||||
Documentation about the Langium framework is available at https://langium.org
|
30
language-configuration.json
Normal file
30
language-configuration.json
Normal file
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"comments": {
|
||||
// symbol used for single line comment. Remove this entry if your language does not support line comments
|
||||
"lineComment": "//",
|
||||
// symbols used for start and end a block comment. Remove this entry if your language does not support block comments
|
||||
"blockComment": [ "/*", "*/" ]
|
||||
},
|
||||
// symbols used as brackets
|
||||
"brackets": [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"]
|
||||
],
|
||||
// symbols that are auto closed when typing
|
||||
"autoClosingPairs": [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"],
|
||||
["\"", "\""],
|
||||
["'", "'"]
|
||||
],
|
||||
// symbols that can be used to surround a selection
|
||||
"surroundingPairs": [
|
||||
["{", "}"],
|
||||
["[", "]"],
|
||||
["(", ")"],
|
||||
["\"", "\""],
|
||||
["'", "'"]
|
||||
]
|
||||
}
|
2230
package-lock.json
generated
Normal file
2230
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
73
package.json
Normal file
73
package.json
Normal file
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"name": "model-modeling-language",
|
||||
"displayName": "model-modeling-language",
|
||||
"description": "Please enter a brief description here",
|
||||
"version": "0.0.1",
|
||||
"engines": {
|
||||
"vscode": "^1.67.0"
|
||||
},
|
||||
"categories": [
|
||||
"Programming Languages"
|
||||
],
|
||||
"contributes": {
|
||||
"languages": [
|
||||
{
|
||||
"id": "model-modeling-language",
|
||||
"aliases": [
|
||||
"Model modeling language",
|
||||
"model-modeling-language"
|
||||
],
|
||||
"extensions": [
|
||||
".mml"
|
||||
],
|
||||
"configuration": "./language-configuration.json"
|
||||
}
|
||||
],
|
||||
"grammars": [
|
||||
{
|
||||
"language": "model-modeling-language",
|
||||
"scopeName": "source.model-modeling-language",
|
||||
"path": "./syntaxes/model-modeling-language.tmLanguage.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"activationEvents": [
|
||||
"onLanguage:model-modeling-language"
|
||||
],
|
||||
"files": [
|
||||
"bin",
|
||||
"out",
|
||||
"src"
|
||||
],
|
||||
"bin": {
|
||||
"model-modeling-language-cli": "./bin/cli"
|
||||
},
|
||||
"main": "./out/extension.js",
|
||||
"scripts": {
|
||||
"vscode:prepublish": "npm run build && npm run lint",
|
||||
"build": "tsc -b tsconfig.json",
|
||||
"watch": "tsc -b tsconfig.json --watch",
|
||||
"lint": "eslint src --ext ts",
|
||||
"langium:generate": "langium generate",
|
||||
"langium:watch": "langium generate --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "~4.1.2",
|
||||
"chevrotain": "~10.4.2",
|
||||
"commander": "~10.0.0",
|
||||
"langium": "~1.1.0",
|
||||
"vscode-languageclient": "~8.0.2",
|
||||
"vscode-languageserver": "~8.0.2",
|
||||
"vscode-uri": "~3.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "~16.18.11",
|
||||
"@types/vscode": "~1.67.0",
|
||||
"@typescript-eslint/eslint-plugin": "~5.51.0",
|
||||
"@typescript-eslint/parser": "~5.51.0",
|
||||
"esbuild": "^0.17.18",
|
||||
"eslint": "~8.33.0",
|
||||
"langium-cli": "~1.1.0",
|
||||
"typescript": "~4.9.5"
|
||||
}
|
||||
}
|
51
src/cli/cli-util.ts
Normal file
51
src/cli/cli-util.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import chalk from 'chalk';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { AstNode, LangiumDocument, LangiumServices } from 'langium';
|
||||
import { URI } from 'vscode-uri';
|
||||
|
||||
export async function extractDocument(fileName: string, services: LangiumServices): Promise<LangiumDocument> {
|
||||
const extensions = services.LanguageMetaData.fileExtensions;
|
||||
if (!extensions.includes(path.extname(fileName))) {
|
||||
console.error(chalk.yellow(`Please choose a file with one of these extensions: ${extensions}.`));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(fileName)) {
|
||||
console.error(chalk.red(`File ${fileName} does not exist.`));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const document = services.shared.workspace.LangiumDocuments.getOrCreateDocument(URI.file(path.resolve(fileName)));
|
||||
await services.shared.workspace.DocumentBuilder.build([document], { validationChecks: 'all' });
|
||||
|
||||
const validationErrors = (document.diagnostics ?? []).filter(e => e.severity === 1);
|
||||
if (validationErrors.length > 0) {
|
||||
console.error(chalk.red('There are validation errors:'));
|
||||
for (const validationError of validationErrors) {
|
||||
console.error(chalk.red(
|
||||
`line ${validationError.range.start.line + 1}: ${validationError.message} [${document.textDocument.getText(validationError.range)}]`
|
||||
));
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
export async function extractAstNode<T extends AstNode>(fileName: string, services: LangiumServices): Promise<T> {
|
||||
return (await extractDocument(fileName, services)).parseResult?.value as T;
|
||||
}
|
||||
|
||||
interface FilePathData {
|
||||
destination: string,
|
||||
name: string
|
||||
}
|
||||
|
||||
export function extractDestinationAndName(filePath: string, destination: string | undefined): FilePathData {
|
||||
filePath = path.basename(filePath, path.extname(filePath)).replace(/[.-]/g, '');
|
||||
return {
|
||||
destination: destination ?? path.join(path.dirname(filePath), 'generated'),
|
||||
name: path.basename(filePath)
|
||||
};
|
||||
}
|
19
src/cli/generator.ts
Normal file
19
src/cli/generator.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import fs from 'fs';
|
||||
import { CompositeGeneratorNode, NL, toString } from 'langium';
|
||||
import path from 'path';
|
||||
import { Model } from '../language-server/generated/ast';
|
||||
import { extractDestinationAndName } from './cli-util';
|
||||
|
||||
export function generateJavaScript(model: Model, filePath: string, destination: string | undefined): string {
|
||||
const data = extractDestinationAndName(filePath, destination);
|
||||
const generatedFilePath = `${path.join(data.destination, data.name)}.js`;
|
||||
|
||||
const fileNode = new CompositeGeneratorNode();
|
||||
fileNode.append('"use strict";', NL, NL);
|
||||
|
||||
if (!fs.existsSync(data.destination)) {
|
||||
fs.mkdirSync(data.destination, { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(generatedFilePath, toString(fileNode));
|
||||
return generatedFilePath;
|
||||
}
|
37
src/cli/index.ts
Normal file
37
src/cli/index.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import chalk from 'chalk';
|
||||
import { Command } from 'commander';
|
||||
import { Model } from '../language-server/generated/ast';
|
||||
import { ModelModelingLanguageLanguageMetaData } from '../language-server/generated/module';
|
||||
import { createModelModelingLanguageServices } from '../language-server/model-modeling-language-module';
|
||||
import { extractAstNode } from './cli-util';
|
||||
import { generateJavaScript } from './generator';
|
||||
import { NodeFileSystem } from 'langium/node';
|
||||
|
||||
export const generateAction = async (fileName: string, opts: GenerateOptions): Promise<void> => {
|
||||
const services = createModelModelingLanguageServices(NodeFileSystem).ModelModelingLanguage;
|
||||
const model = await extractAstNode<Model>(fileName, services);
|
||||
const generatedFilePath = generateJavaScript(model, fileName, opts.destination);
|
||||
console.log(chalk.green(`JavaScript code generated successfully: ${generatedFilePath}`));
|
||||
};
|
||||
|
||||
export type GenerateOptions = {
|
||||
destination?: string;
|
||||
}
|
||||
|
||||
export default function(): void {
|
||||
const program = new Command();
|
||||
|
||||
program
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
.version(require('../../package.json').version);
|
||||
|
||||
const fileExtensions = ModelModelingLanguageLanguageMetaData.fileExtensions.join(', ');
|
||||
program
|
||||
.command('generate')
|
||||
.argument('<file>', `source file (possible file extensions: ${fileExtensions})`)
|
||||
.option('-d, --destination <dir>', 'destination directory of generating')
|
||||
.description('generates JavaScript code that prints "Hello, {name}!" for each greeting in a source file')
|
||||
.action(generateAction);
|
||||
|
||||
program.parse(process.argv);
|
||||
}
|
59
src/extension.ts
Normal file
59
src/extension.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
LanguageClient, LanguageClientOptions, ServerOptions, TransportKind
|
||||
} from 'vscode-languageclient/node';
|
||||
|
||||
let client: LanguageClient;
|
||||
|
||||
// This function is called when the extension is activated.
|
||||
export function activate(context: vscode.ExtensionContext): void {
|
||||
client = startLanguageClient(context);
|
||||
}
|
||||
|
||||
// This function is called when the extension is deactivated.
|
||||
export function deactivate(): Thenable<void> | undefined {
|
||||
if (client) {
|
||||
return client.stop();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function startLanguageClient(context: vscode.ExtensionContext): LanguageClient {
|
||||
const serverModule = context.asAbsolutePath(path.join('out', 'language-server', 'main'));
|
||||
// The debug options for the server
|
||||
// --inspect=6009: runs the server in Node's Inspector mode so VS Code can attach to the server for debugging.
|
||||
// By setting `process.env.DEBUG_BREAK` to a truthy value, the language server will wait until a debugger is attached.
|
||||
const debugOptions = { execArgv: ['--nolazy', `--inspect${process.env.DEBUG_BREAK ? '-brk' : ''}=${process.env.DEBUG_SOCKET || '6009'}`] };
|
||||
|
||||
// If the extension is launched in debug mode then the debug server options are used
|
||||
// Otherwise the run options are used
|
||||
const serverOptions: ServerOptions = {
|
||||
run: { module: serverModule, transport: TransportKind.ipc },
|
||||
debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions }
|
||||
};
|
||||
|
||||
const fileSystemWatcher = vscode.workspace.createFileSystemWatcher('**/*.mml');
|
||||
context.subscriptions.push(fileSystemWatcher);
|
||||
|
||||
// Options to control the language client
|
||||
const clientOptions: LanguageClientOptions = {
|
||||
documentSelector: [{ scheme: 'file', language: 'model-modeling-language' }],
|
||||
synchronize: {
|
||||
// Notify the server about file changes to files contained in the workspace
|
||||
fileEvents: fileSystemWatcher
|
||||
}
|
||||
};
|
||||
|
||||
// Create the language client and start the client.
|
||||
const client = new LanguageClient(
|
||||
'model-modeling-language',
|
||||
'Model modeling language',
|
||||
serverOptions,
|
||||
clientOptions
|
||||
);
|
||||
|
||||
// Start the client. This will also launch the server
|
||||
client.start();
|
||||
return client;
|
||||
}
|
385
src/language-server/generated/ast.ts
Normal file
385
src/language-server/generated/ast.ts
Normal file
|
@ -0,0 +1,385 @@
|
|||
/******************************************************************************
|
||||
* This file was generated by langium-cli 1.1.0.
|
||||
* DO NOT EDIT MANUALLY!
|
||||
******************************************************************************/
|
||||
|
||||
/* eslint-disable */
|
||||
import { AstNode, AbstractAstReflection, Reference, ReferenceInfo, TypeMetaData } from 'langium';
|
||||
|
||||
export type AbstractElement = Class | Enum | Interface;
|
||||
|
||||
export const AbstractElement = 'AbstractElement';
|
||||
|
||||
export function isAbstractElement(item: unknown): item is AbstractElement {
|
||||
return reflection.isInstance(item, AbstractElement);
|
||||
}
|
||||
|
||||
export type BoolVal = boolean;
|
||||
|
||||
export type DataType = 'bool' | 'double' | 'float' | 'int' | 'string';
|
||||
|
||||
export type Statement = Attribute | CReference;
|
||||
|
||||
export const Statement = 'Statement';
|
||||
|
||||
export function isStatement(item: unknown): item is Statement {
|
||||
return reflection.isInstance(item, Statement);
|
||||
}
|
||||
|
||||
export interface Attribute extends AstNode {
|
||||
readonly $container: Class | Interface;
|
||||
readonly $type: 'Attribute';
|
||||
defaultValue?: BoolVal | number | string
|
||||
modifiers?: AttributeModifiers
|
||||
name: string
|
||||
type: DataType
|
||||
}
|
||||
|
||||
export const Attribute = 'Attribute';
|
||||
|
||||
export function isAttribute(item: unknown): item is Attribute {
|
||||
return reflection.isInstance(item, Attribute);
|
||||
}
|
||||
|
||||
export interface AttributeModifiers extends AstNode {
|
||||
readonly $container: Attribute;
|
||||
readonly $type: 'AttributeModifiers';
|
||||
derived: boolean
|
||||
id: boolean
|
||||
ordered: boolean
|
||||
readonly: boolean
|
||||
transient: boolean
|
||||
unique: boolean
|
||||
unsettable: boolean
|
||||
volatile: boolean
|
||||
}
|
||||
|
||||
export const AttributeModifiers = 'AttributeModifiers';
|
||||
|
||||
export function isAttributeModifiers(item: unknown): item is AttributeModifiers {
|
||||
return reflection.isInstance(item, AttributeModifiers);
|
||||
}
|
||||
|
||||
export interface Class extends AstNode {
|
||||
readonly $container: Package;
|
||||
readonly $type: 'Class';
|
||||
abstract: boolean
|
||||
body: Array<Statement>
|
||||
extendedClasses: Array<Reference<Class>>
|
||||
implementedInterfaces: Array<Reference<Interface>>
|
||||
name: string
|
||||
}
|
||||
|
||||
export const Class = 'Class';
|
||||
|
||||
export function isClass(item: unknown): item is Class {
|
||||
return reflection.isInstance(item, Class);
|
||||
}
|
||||
|
||||
export interface CReference extends AstNode {
|
||||
readonly $container: Class | Interface;
|
||||
readonly $type: 'CReference';
|
||||
modifiers?: ReferenceModifiers
|
||||
multiplicity: Multiplicity
|
||||
name: string
|
||||
opposite?: OppositeAnnotation
|
||||
type: Reference<Class>
|
||||
}
|
||||
|
||||
export const CReference = 'CReference';
|
||||
|
||||
export function isCReference(item: unknown): item is CReference {
|
||||
return reflection.isInstance(item, CReference);
|
||||
}
|
||||
|
||||
export interface Enum extends AstNode {
|
||||
readonly $container: Package;
|
||||
readonly $type: 'Enum' | 'EnumEntry';
|
||||
name: string
|
||||
}
|
||||
|
||||
export const Enum = 'Enum';
|
||||
|
||||
export function isEnum(item: unknown): item is Enum {
|
||||
return reflection.isInstance(item, Enum);
|
||||
}
|
||||
|
||||
export interface Import extends AstNode {
|
||||
readonly $container: Model;
|
||||
readonly $type: 'Import';
|
||||
aliases: Array<ImportAlias>
|
||||
target: string
|
||||
}
|
||||
|
||||
export const Import = 'Import';
|
||||
|
||||
export function isImport(item: unknown): item is Import {
|
||||
return reflection.isInstance(item, Import);
|
||||
}
|
||||
|
||||
export interface ImportAlias extends AstNode {
|
||||
readonly $container: Import;
|
||||
readonly $type: 'ImportAlias';
|
||||
alias: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export const ImportAlias = 'ImportAlias';
|
||||
|
||||
export function isImportAlias(item: unknown): item is ImportAlias {
|
||||
return reflection.isInstance(item, ImportAlias);
|
||||
}
|
||||
|
||||
export interface Interface extends AstNode {
|
||||
readonly $container: Package;
|
||||
readonly $type: 'Interface';
|
||||
abstract: boolean
|
||||
body: Array<Statement>
|
||||
extendedInterfaces: Array<Reference<Interface>>
|
||||
name: string
|
||||
}
|
||||
|
||||
export const Interface = 'Interface';
|
||||
|
||||
export function isInterface(item: unknown): item is Interface {
|
||||
return reflection.isInstance(item, Interface);
|
||||
}
|
||||
|
||||
export interface Model extends AstNode {
|
||||
readonly $type: 'Model';
|
||||
imports: Array<Import>
|
||||
packages: Array<Package>
|
||||
}
|
||||
|
||||
export const Model = 'Model';
|
||||
|
||||
export function isModel(item: unknown): item is Model {
|
||||
return reflection.isInstance(item, Model);
|
||||
}
|
||||
|
||||
export interface Multiplicity extends AstNode {
|
||||
readonly $container: CReference;
|
||||
readonly $type: 'Multiplicity';
|
||||
mult?: number | string
|
||||
upperMult?: number | string
|
||||
}
|
||||
|
||||
export const Multiplicity = 'Multiplicity';
|
||||
|
||||
export function isMultiplicity(item: unknown): item is Multiplicity {
|
||||
return reflection.isInstance(item, Multiplicity);
|
||||
}
|
||||
|
||||
export interface OppositeAnnotation extends AstNode {
|
||||
readonly $container: CReference;
|
||||
readonly $type: 'OppositeAnnotation';
|
||||
reference: Reference<CReference>
|
||||
}
|
||||
|
||||
export const OppositeAnnotation = 'OppositeAnnotation';
|
||||
|
||||
export function isOppositeAnnotation(item: unknown): item is OppositeAnnotation {
|
||||
return reflection.isInstance(item, OppositeAnnotation);
|
||||
}
|
||||
|
||||
export interface Package extends AstNode {
|
||||
readonly $container: Model | Package;
|
||||
readonly $type: 'Package';
|
||||
body: Array<AbstractElement>
|
||||
name: string
|
||||
subPackages: Array<Package>
|
||||
}
|
||||
|
||||
export const Package = 'Package';
|
||||
|
||||
export function isPackage(item: unknown): item is Package {
|
||||
return reflection.isInstance(item, Package);
|
||||
}
|
||||
|
||||
export interface ReferenceModifiers extends AstNode {
|
||||
readonly $container: CReference;
|
||||
readonly $type: 'ReferenceModifiers';
|
||||
derived: boolean
|
||||
ordered: boolean
|
||||
readonly: boolean
|
||||
resolve: boolean
|
||||
transient: boolean
|
||||
unique: boolean
|
||||
unsettable: boolean
|
||||
volatile: boolean
|
||||
}
|
||||
|
||||
export const ReferenceModifiers = 'ReferenceModifiers';
|
||||
|
||||
export function isReferenceModifiers(item: unknown): item is ReferenceModifiers {
|
||||
return reflection.isInstance(item, ReferenceModifiers);
|
||||
}
|
||||
|
||||
export interface EnumEntry extends Enum {
|
||||
readonly $container: Package;
|
||||
readonly $type: 'EnumEntry';
|
||||
name: string
|
||||
value?: number | string
|
||||
}
|
||||
|
||||
export const EnumEntry = 'EnumEntry';
|
||||
|
||||
export function isEnumEntry(item: unknown): item is EnumEntry {
|
||||
return reflection.isInstance(item, EnumEntry);
|
||||
}
|
||||
|
||||
export interface ModelModelingLanguageAstType {
|
||||
AbstractElement: AbstractElement
|
||||
Attribute: Attribute
|
||||
AttributeModifiers: AttributeModifiers
|
||||
CReference: CReference
|
||||
Class: Class
|
||||
Enum: Enum
|
||||
EnumEntry: EnumEntry
|
||||
Import: Import
|
||||
ImportAlias: ImportAlias
|
||||
Interface: Interface
|
||||
Model: Model
|
||||
Multiplicity: Multiplicity
|
||||
OppositeAnnotation: OppositeAnnotation
|
||||
Package: Package
|
||||
ReferenceModifiers: ReferenceModifiers
|
||||
Statement: Statement
|
||||
}
|
||||
|
||||
export class ModelModelingLanguageAstReflection extends AbstractAstReflection {
|
||||
|
||||
getAllTypes(): string[] {
|
||||
return ['AbstractElement', 'Attribute', 'AttributeModifiers', 'CReference', 'Class', 'Enum', 'EnumEntry', 'Import', 'ImportAlias', 'Interface', 'Model', 'Multiplicity', 'OppositeAnnotation', 'Package', 'ReferenceModifiers', 'Statement'];
|
||||
}
|
||||
|
||||
protected override computeIsSubtype(subtype: string, supertype: string): boolean {
|
||||
switch (subtype) {
|
||||
case Attribute:
|
||||
case CReference: {
|
||||
return this.isSubtype(Statement, supertype);
|
||||
}
|
||||
case Class:
|
||||
case Enum:
|
||||
case Interface: {
|
||||
return this.isSubtype(AbstractElement, supertype);
|
||||
}
|
||||
case EnumEntry: {
|
||||
return this.isSubtype(Enum, supertype);
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getReferenceType(refInfo: ReferenceInfo): string {
|
||||
const referenceId = `${refInfo.container.$type}:${refInfo.property}`;
|
||||
switch (referenceId) {
|
||||
case 'Class:extendedClasses':
|
||||
case 'CReference:type': {
|
||||
return Class;
|
||||
}
|
||||
case 'Class:implementedInterfaces':
|
||||
case 'Interface:extendedInterfaces': {
|
||||
return Interface;
|
||||
}
|
||||
case 'OppositeAnnotation:reference': {
|
||||
return CReference;
|
||||
}
|
||||
default: {
|
||||
throw new Error(`${referenceId} is not a valid reference id.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getTypeMetaData(type: string): TypeMetaData {
|
||||
switch (type) {
|
||||
case 'AttributeModifiers': {
|
||||
return {
|
||||
name: 'AttributeModifiers',
|
||||
mandatory: [
|
||||
{ name: 'derived', type: 'boolean' },
|
||||
{ name: 'id', type: 'boolean' },
|
||||
{ name: 'ordered', type: 'boolean' },
|
||||
{ name: 'readonly', type: 'boolean' },
|
||||
{ name: 'transient', type: 'boolean' },
|
||||
{ name: 'unique', type: 'boolean' },
|
||||
{ name: 'unsettable', type: 'boolean' },
|
||||
{ name: 'volatile', type: 'boolean' }
|
||||
]
|
||||
};
|
||||
}
|
||||
case 'Class': {
|
||||
return {
|
||||
name: 'Class',
|
||||
mandatory: [
|
||||
{ name: 'abstract', type: 'boolean' },
|
||||
{ name: 'body', type: 'array' },
|
||||
{ name: 'extendedClasses', type: 'array' },
|
||||
{ name: 'implementedInterfaces', type: 'array' }
|
||||
]
|
||||
};
|
||||
}
|
||||
case 'Import': {
|
||||
return {
|
||||
name: 'Import',
|
||||
mandatory: [
|
||||
{ name: 'aliases', type: 'array' }
|
||||
]
|
||||
};
|
||||
}
|
||||
case 'Interface': {
|
||||
return {
|
||||
name: 'Interface',
|
||||
mandatory: [
|
||||
{ name: 'abstract', type: 'boolean' },
|
||||
{ name: 'body', type: 'array' },
|
||||
{ name: 'extendedInterfaces', type: 'array' }
|
||||
]
|
||||
};
|
||||
}
|
||||
case 'Model': {
|
||||
return {
|
||||
name: 'Model',
|
||||
mandatory: [
|
||||
{ name: 'imports', type: 'array' },
|
||||
{ name: 'packages', type: 'array' }
|
||||
]
|
||||
};
|
||||
}
|
||||
case 'Package': {
|
||||
return {
|
||||
name: 'Package',
|
||||
mandatory: [
|
||||
{ name: 'body', type: 'array' },
|
||||
{ name: 'subPackages', type: 'array' }
|
||||
]
|
||||
};
|
||||
}
|
||||
case 'ReferenceModifiers': {
|
||||
return {
|
||||
name: 'ReferenceModifiers',
|
||||
mandatory: [
|
||||
{ name: 'derived', type: 'boolean' },
|
||||
{ name: 'ordered', type: 'boolean' },
|
||||
{ name: 'readonly', type: 'boolean' },
|
||||
{ name: 'resolve', type: 'boolean' },
|
||||
{ name: 'transient', type: 'boolean' },
|
||||
{ name: 'unique', type: 'boolean' },
|
||||
{ name: 'unsettable', type: 'boolean' },
|
||||
{ name: 'volatile', type: 'boolean' }
|
||||
]
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return {
|
||||
name: type,
|
||||
mandatory: []
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const reflection = new ModelModelingLanguageAstReflection();
|
1791
src/language-server/generated/grammar.ts
Normal file
1791
src/language-server/generated/grammar.ts
Normal file
File diff suppressed because it is too large
Load diff
24
src/language-server/generated/module.ts
Normal file
24
src/language-server/generated/module.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/******************************************************************************
|
||||
* This file was generated by langium-cli 1.1.0.
|
||||
* DO NOT EDIT MANUALLY!
|
||||
******************************************************************************/
|
||||
|
||||
import { LangiumGeneratedServices, LangiumGeneratedSharedServices, LangiumSharedServices, LangiumServices, LanguageMetaData, Module } from 'langium';
|
||||
import { ModelModelingLanguageAstReflection } from './ast';
|
||||
import { ModelModelingLanguageGrammar } from './grammar';
|
||||
|
||||
export const ModelModelingLanguageLanguageMetaData: LanguageMetaData = {
|
||||
languageId: 'model-modeling-language',
|
||||
fileExtensions: ['.mml'],
|
||||
caseInsensitive: false
|
||||
};
|
||||
|
||||
export const ModelModelingLanguageGeneratedSharedModule: Module<LangiumSharedServices, LangiumGeneratedSharedServices> = {
|
||||
AstReflection: () => new ModelModelingLanguageAstReflection()
|
||||
};
|
||||
|
||||
export const ModelModelingLanguageGeneratedModule: Module<LangiumServices, LangiumGeneratedServices> = {
|
||||
Grammar: () => ModelModelingLanguageGrammar(),
|
||||
LanguageMetaData: () => ModelModelingLanguageLanguageMetaData,
|
||||
parser: {}
|
||||
};
|
13
src/language-server/main.ts
Normal file
13
src/language-server/main.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { startLanguageServer } from 'langium';
|
||||
import { NodeFileSystem } from 'langium/node';
|
||||
import { createConnection, ProposedFeatures } from 'vscode-languageserver/node';
|
||||
import { createModelModelingLanguageServices } from './model-modeling-language-module';
|
||||
|
||||
// Create a connection to the client
|
||||
const connection = createConnection(ProposedFeatures.all);
|
||||
|
||||
// Inject the shared services and language-specific services
|
||||
const { shared } = createModelModelingLanguageServices({ connection, ...NodeFileSystem });
|
||||
|
||||
// Start the language server with the shared services
|
||||
startLanguageServer(shared);
|
75
src/language-server/model-modeling-language-module.ts
Normal file
75
src/language-server/model-modeling-language-module.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
import {
|
||||
createDefaultModule,
|
||||
createDefaultSharedModule,
|
||||
DefaultSharedModuleContext,
|
||||
inject,
|
||||
LangiumServices,
|
||||
LangiumSharedServices,
|
||||
Module,
|
||||
PartialLangiumServices
|
||||
} from 'langium';
|
||||
import {ModelModelingLanguageGeneratedModule, ModelModelingLanguageGeneratedSharedModule} from './generated/module';
|
||||
import {ModelModelingLanguageValidator, registerValidationChecks} from './model-modeling-language-validator';
|
||||
import {ModelModelingLanguageScopeComputation} from "./model-modeling-language-scope-computation";
|
||||
|
||||
/**
|
||||
* Declaration of custom services - add your own service classes here.
|
||||
*/
|
||||
export type ModelModelingLanguageAddedServices = {
|
||||
validation: {
|
||||
ModelModelingLanguageValidator: ModelModelingLanguageValidator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Union of Langium default services and your custom services - use this as constructor parameter
|
||||
* of custom service classes.
|
||||
*/
|
||||
export type ModelModelingLanguageServices = LangiumServices & ModelModelingLanguageAddedServices
|
||||
|
||||
/**
|
||||
* Dependency injection module that overrides Langium default services and contributes the
|
||||
* declared custom services. The Langium defaults can be partially specified to override only
|
||||
* selected services, while the custom services must be fully specified.
|
||||
*/
|
||||
export const ModelModelingLanguageModule: Module<ModelModelingLanguageServices, PartialLangiumServices & ModelModelingLanguageAddedServices> = {
|
||||
validation: {
|
||||
ModelModelingLanguageValidator: () => new ModelModelingLanguageValidator()
|
||||
},
|
||||
references: {
|
||||
ScopeComputation: (services) => new ModelModelingLanguageScopeComputation(services)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the full set of services required by Langium.
|
||||
*
|
||||
* First inject the shared services by merging two modules:
|
||||
* - Langium default shared services
|
||||
* - Services generated by langium-cli
|
||||
*
|
||||
* Then inject the language-specific services by merging three modules:
|
||||
* - Langium default language-specific services
|
||||
* - Services generated by langium-cli
|
||||
* - Services specified in this file
|
||||
*
|
||||
* @param context Optional module context with the LSP connection
|
||||
* @returns An object wrapping the shared services and the language-specific services
|
||||
*/
|
||||
export function createModelModelingLanguageServices(context: DefaultSharedModuleContext): {
|
||||
shared: LangiumSharedServices,
|
||||
ModelModelingLanguage: ModelModelingLanguageServices
|
||||
} {
|
||||
const shared = inject(
|
||||
createDefaultSharedModule(context),
|
||||
ModelModelingLanguageGeneratedSharedModule
|
||||
);
|
||||
const ModelModelingLanguage = inject(
|
||||
createDefaultModule({shared}),
|
||||
ModelModelingLanguageGeneratedModule,
|
||||
ModelModelingLanguageModule
|
||||
);
|
||||
shared.ServiceRegistry.register(ModelModelingLanguage);
|
||||
registerValidationChecks(ModelModelingLanguage);
|
||||
return {shared, ModelModelingLanguage};
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import {AstNode, AstNodeDescription, DefaultScopeComputation, LangiumDocument, streamAllContents} from "langium";
|
||||
import {isClass, isCReference, isInterface, isPackage} from "./generated/ast";
|
||||
|
||||
export class ModelModelingLanguageScopeComputation extends DefaultScopeComputation {
|
||||
|
||||
override async computeExports(document: LangiumDocument): Promise<AstNodeDescription[]> {
|
||||
const exportedDescriptions: AstNodeDescription[] = [];
|
||||
for (const childNode of streamAllContents(document.parseResult.value)) {
|
||||
if (isCReference(childNode)) {
|
||||
const fullyQualifiedName = this.getQualifiedRefName(childNode, childNode.name);
|
||||
// `descriptions` is our `AstNodeDescriptionProvider` defined in `DefaultScopeComputation`
|
||||
// It allows us to easily create descriptions that point to elements using a name.
|
||||
exportedDescriptions.push(this.descriptions.createDescription(childNode, fullyQualifiedName, document));
|
||||
} else if (isClass(childNode) || isInterface(childNode)) {
|
||||
const fullyQualifiedName = this.getQualifiedClassName(childNode, childNode.name);
|
||||
// `descriptions` is our `AstNodeDescriptionProvider` defined in `DefaultScopeComputation`
|
||||
// It allows us to easily create descriptions that point to elements using a name.
|
||||
exportedDescriptions.push(this.descriptions.createDescription(childNode, fullyQualifiedName, document));
|
||||
}
|
||||
}
|
||||
return exportedDescriptions;
|
||||
}
|
||||
|
||||
private getQualifiedRefName(node: AstNode, name: string): string {
|
||||
let parent: AstNode | undefined = node.$container;
|
||||
if (isClass(parent)) {
|
||||
name = `${parent.name}::${name}`;
|
||||
parent = parent.$container;
|
||||
}
|
||||
while (isPackage(parent)) {
|
||||
// Iteratively prepend the name of the parent namespace
|
||||
// This allows us to work with nested namespaces
|
||||
name = `${parent.name}.${name}`;
|
||||
parent = parent.$container;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private getQualifiedClassName(node: AstNode, name: string): string {
|
||||
let parent: AstNode | undefined = node.$container;
|
||||
while (isPackage(parent)) {
|
||||
// Iteratively prepend the name of the parent namespace
|
||||
// This allows us to work with nested namespaces
|
||||
name = `${parent.name}.${name}`;
|
||||
parent = parent.$container;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
31
src/language-server/model-modeling-language-validator.ts
Normal file
31
src/language-server/model-modeling-language-validator.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { ValidationChecks } from 'langium';
|
||||
import { ModelModelingLanguageAstType} from './generated/ast';
|
||||
import type { ModelModelingLanguageServices } from './model-modeling-language-module';
|
||||
|
||||
/**
|
||||
* Register custom validation checks.
|
||||
*/
|
||||
export function registerValidationChecks(services: ModelModelingLanguageServices) {
|
||||
const registry = services.validation.ValidationRegistry;
|
||||
const validator = services.validation.ModelModelingLanguageValidator;
|
||||
const checks: ValidationChecks<ModelModelingLanguageAstType> = {
|
||||
//Person: validator.checkPersonStartsWithCapital
|
||||
};
|
||||
registry.register(checks, validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of custom validations.
|
||||
*/
|
||||
export class ModelModelingLanguageValidator {
|
||||
|
||||
/* checkPersonStartsWithCapital(person: Person, accept: ValidationAcceptor): void {
|
||||
if (person.name) {
|
||||
const firstChar = person.name.substring(0, 1);
|
||||
if (firstChar.toUpperCase() !== firstChar) {
|
||||
accept('warning', 'Person name should start with a capital.', { node: person, property: 'name' });
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
103
src/language-server/model-modeling-language.langium
Normal file
103
src/language-server/model-modeling-language.langium
Normal file
|
@ -0,0 +1,103 @@
|
|||
grammar ModelModelingLanguage
|
||||
|
||||
entry Model:
|
||||
(imports+=Import | packages+=Package)*;
|
||||
|
||||
DataType returns string:
|
||||
'int' | 'string' | 'bool' | 'double' | 'float';
|
||||
|
||||
BoolVal returns boolean:
|
||||
'true' | 'false';
|
||||
|
||||
Import:
|
||||
'import' target=STRING ('using' aliases+=ImportAlias (',' aliases+=ImportAlias)*)? ';';
|
||||
|
||||
ImportAlias:
|
||||
name=QNAME 'as' alias=ID;
|
||||
|
||||
Multiplicity:
|
||||
('[' (mult=NUM | mult=MULTIPLICITYSYMBOL) ('..' (upperMult=NUM | upperMult=MULTIPLICITYSYMBOL))? ']')?;
|
||||
|
||||
Package:
|
||||
'package' name=ID '{' (subPackages+=Package | body+=AbstractElement)* '}';
|
||||
|
||||
AbstractElement:
|
||||
Class | Interface | Enum;
|
||||
|
||||
fragment ClassModifier:
|
||||
(abstract?='abstract')?;
|
||||
|
||||
fragment ClassBody:
|
||||
'{'
|
||||
(body+=Statement)*
|
||||
'}';
|
||||
|
||||
fragment ClassExtension:
|
||||
('extends' (extendedClasses+=[Class:ID] | extendedClasses+=[Class:QNAME]) (',' (extendedClasses+=[Class:ID] | extendedClasses+=[Class:QNAME]))*)?;
|
||||
|
||||
fragment InterfaceExtension:
|
||||
('extends' (extendedInterfaces+=[Interface:ID] | extendedInterfaces+=[Interface:QNAME]) (',' (extendedInterfaces+=[Interface:ID] | extendedInterfaces+=[Interface:QNAME]))*)?;
|
||||
|
||||
fragment ClassImplements:
|
||||
('implements' (implementedInterfaces+=[Interface:ID] | implementedInterfaces+=[Interface:QNAME]) (',' (implementedInterfaces+=[Interface:ID] | implementedInterfaces+=[Interface:QNAME]))*)?;
|
||||
|
||||
Class:
|
||||
ClassModifier 'class' name=ID ClassExtension ClassImplements ClassBody;
|
||||
|
||||
Interface:
|
||||
ClassModifier 'interface' name=ID InterfaceExtension ClassBody;
|
||||
|
||||
Statement:
|
||||
Attribute | CReference;
|
||||
|
||||
AttributeModifiers:
|
||||
readonly?='readonly' &
|
||||
volatile?='volatile' &
|
||||
transient?='transient' &
|
||||
unsettable?='unsettable' &
|
||||
derived?='derived' &
|
||||
unique?='unique' &
|
||||
ordered?='ordered' &
|
||||
id?='id';
|
||||
|
||||
Attribute:
|
||||
'attribute' type=DataType name=ID ('=' (defaultValue=STRING | defaultValue=NUM | defaultValue=DOUBLE | defaultValue=BoolVal))? ('{'modifiers=AttributeModifiers'}')?';';
|
||||
|
||||
ReferenceModifiers:
|
||||
readonly?='readonly' &
|
||||
volatile?='volatile' &
|
||||
transient?='transient' &
|
||||
unsettable?='unsettable' &
|
||||
derived?='derived' &
|
||||
unique?='unique' &
|
||||
ordered?='ordered' &
|
||||
resolve?='resolve';
|
||||
|
||||
OppositeAnnotation:
|
||||
'@opposite' reference=[CReference:FQNAME];
|
||||
|
||||
CReference:
|
||||
(opposite=OppositeAnnotation)? 'reference' (type=[Class:QNAME] | type=[Class:ID]) multiplicity=Multiplicity name=ID ('{' modifiers=ReferenceModifiers '}')?';';
|
||||
|
||||
Enum:
|
||||
'enum' name=ID '{'
|
||||
(EnumEntry ',')*
|
||||
EnumEntry
|
||||
'}';
|
||||
|
||||
EnumEntry:
|
||||
name=ID | name=ID '=' (value=STRING | value=NUM);
|
||||
|
||||
|
||||
hidden terminal WS: /\s+/;
|
||||
terminal MULTIPLICITYSYMBOL: /[\*?+]/;
|
||||
terminal DOUBLE returns number: NUM '.' NUM;
|
||||
terminal NUM returns number: /[0-9]+/;
|
||||
terminal STRING returns string: /"[^"]*"/;
|
||||
terminal FQNAME returns string: QNAME '::' ID;
|
||||
terminal QNAME returns string: ID ('.' ID)+;
|
||||
terminal ID returns string: /[a-zA-Z_][\w_]*/;
|
||||
|
||||
|
||||
hidden terminal ML_COMMENT: /\/\*[\s\S]*?\*\//;
|
||||
hidden terminal SL_COMMENT: /[^:]\/\/[^\n\r]*/;
|
61
syntaxes/model-modeling-language.tmLanguage.json
Normal file
61
syntaxes/model-modeling-language.tmLanguage.json
Normal file
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"name": "model-modeling-language",
|
||||
"scopeName": "source.model-modeling-language",
|
||||
"fileTypes": [
|
||||
".mml"
|
||||
],
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.model-modeling-language",
|
||||
"match": "\\b(abstract|as|attribute|bool|class|derived|double|enum|extends|false|float|id|implements|import|int|interface|ordered|package|readonly|reference|resolve|string|transient|true|unique|unsettable|using|volatile)\\b|\\B(@opposite)\\b"
|
||||
},
|
||||
{
|
||||
"name": "string.quoted.double.model-modeling-language",
|
||||
"begin": "\"",
|
||||
"end": "\"",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#string-character-escape"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"comments": {
|
||||
"patterns": [
|
||||
{
|
||||
"name": "comment.block.model-modeling-language",
|
||||
"begin": "/\\*",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.comment.model-modeling-language"
|
||||
}
|
||||
},
|
||||
"end": "\\*/",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.comment.model-modeling-language"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"begin": "[^:]//",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.whitespace.comment.leading.model-modeling-language"
|
||||
}
|
||||
},
|
||||
"end": "(?=$)",
|
||||
"name": "comment.line.model-modeling-language"
|
||||
}
|
||||
]
|
||||
},
|
||||
"string-character-escape": {
|
||||
"name": "constant.character.escape.model-modeling-language",
|
||||
"match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)"
|
||||
}
|
||||
}
|
||||
}
|
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "commonjs",
|
||||
"lib": ["ESNext"],
|
||||
"sourceMap": true,
|
||||
"outDir": "out",
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitOverride": true,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"out",
|
||||
"node_modules"
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue