diff --git a/packages/schema/.gitignore b/packages/schema/.gitignore new file mode 100644 index 000000000..6a3417b8d --- /dev/null +++ b/packages/schema/.gitignore @@ -0,0 +1 @@ +/out/ diff --git a/packages/schema/asset/logo-dark.png b/packages/schema/asset/logo-dark.png new file mode 100644 index 000000000..d884fdcf0 Binary files /dev/null and b/packages/schema/asset/logo-dark.png differ diff --git a/packages/schema/asset/logo-light.png b/packages/schema/asset/logo-light.png new file mode 100644 index 000000000..6b3d4e0d9 Binary files /dev/null and b/packages/schema/asset/logo-light.png differ diff --git a/packages/schema/out/cli/cli-util.js b/packages/schema/out/cli/cli-util.js deleted file mode 100644 index dcf3fb812..000000000 --- a/packages/schema/out/cli/cli-util.js +++ /dev/null @@ -1,61 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.extractDestinationAndName = exports.extractAstNode = exports.extractDocument = void 0; -const colors_1 = __importDefault(require("colors")); -const path_1 = __importDefault(require("path")); -const fs_1 = __importDefault(require("fs")); -const vscode_uri_1 = require("vscode-uri"); -function extractDocument(fileName, services) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - const extensions = services.LanguageMetaData.fileExtensions; - if (!extensions.includes(path_1.default.extname(fileName))) { - console.error(colors_1.default.yellow(`Please choose a file with one of these extensions: ${extensions}.`)); - process.exit(1); - } - if (!fs_1.default.existsSync(fileName)) { - console.error(colors_1.default.red(`File ${fileName} does not exist.`)); - process.exit(1); - } - const document = services.shared.workspace.LangiumDocuments.getOrCreateDocument(vscode_uri_1.URI.file(path_1.default.resolve(fileName))); - yield services.shared.workspace.DocumentBuilder.build([document], { validationChecks: 'all' }); - const validationErrors = ((_a = document.diagnostics) !== null && _a !== void 0 ? _a : []).filter(e => e.severity === 1); - if (validationErrors.length > 0) { - console.error(colors_1.default.red('There are validation errors:')); - for (const validationError of validationErrors) { - console.error(colors_1.default.red(`line ${validationError.range.start.line + 1}: ${validationError.message} [${document.textDocument.getText(validationError.range)}]`)); - } - process.exit(1); - } - return document; - }); -} -exports.extractDocument = extractDocument; -function extractAstNode(fileName, services) { - var _a; - return __awaiter(this, void 0, void 0, function* () { - return (_a = (yield extractDocument(fileName, services)).parseResult) === null || _a === void 0 ? void 0 : _a.value; - }); -} -exports.extractAstNode = extractAstNode; -function extractDestinationAndName(filePath, destination) { - filePath = filePath.replace(/\..*$/, '').replace(/[.-]/g, ''); - return { - destination: destination !== null && destination !== void 0 ? destination : path_1.default.join(path_1.default.dirname(filePath), 'generated'), - name: path_1.default.basename(filePath) - }; -} -exports.extractDestinationAndName = extractDestinationAndName; -//# sourceMappingURL=cli-util.js.map \ No newline at end of file diff --git a/packages/schema/out/cli/cli-util.js.map b/packages/schema/out/cli/cli-util.js.map deleted file mode 100644 index d545d06e0..000000000 --- a/packages/schema/out/cli/cli-util.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"cli-util.js","sourceRoot":"","sources":["../../src/cli/cli-util.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,oDAA4B;AAC5B,gDAAwB;AACxB,4CAAoB;AAEpB,2CAAiC;AAEjC,SAAsB,eAAe,CAAC,QAAgB,EAAE,QAAyB;;;QAC7E,MAAM,UAAU,GAAG,QAAQ,CAAC,gBAAgB,CAAC,cAAc,CAAC;QAC5D,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE;YAC9C,OAAO,CAAC,KAAK,CAAC,gBAAM,CAAC,MAAM,CAAC,sDAAsD,UAAU,GAAG,CAAC,CAAC,CAAC;YAClG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACnB;QAED,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;YAC1B,OAAO,CAAC,KAAK,CAAC,gBAAM,CAAC,GAAG,CAAC,QAAQ,QAAQ,kBAAkB,CAAC,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACnB;QAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,gBAAG,CAAC,IAAI,CAAC,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClH,MAAM,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC;QAE/F,MAAM,gBAAgB,GAAG,CAAC,MAAA,QAAQ,CAAC,WAAW,mCAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC;QACpF,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE;YAC7B,OAAO,CAAC,KAAK,CAAC,gBAAM,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC,CAAC;YAC1D,KAAK,MAAM,eAAe,IAAI,gBAAgB,EAAE;gBAC5C,OAAO,CAAC,KAAK,CAAC,gBAAM,CAAC,GAAG,CACpB,QAAQ,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,eAAe,CAAC,OAAO,KAAK,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,CACvI,CAAC,CAAC;aACN;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACnB;QAED,OAAO,QAAQ,CAAC;;CACnB;AA3BD,0CA2BC;AAED,SAAsB,cAAc,CAAoB,QAAgB,EAAE,QAAyB;;;QAC/F,OAAO,MAAA,CAAC,MAAM,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,WAAW,0CAAE,KAAU,CAAC;;CAC9E;AAFD,wCAEC;AAOD,SAAgB,yBAAyB,CAAC,QAAgB,EAAE,WAA+B;IACvF,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC9D,OAAO;QACH,WAAW,EAAE,WAAW,aAAX,WAAW,cAAX,WAAW,GAAI,cAAI,CAAC,IAAI,CAAC,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC;QAC1E,IAAI,EAAE,cAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;KAChC,CAAC;AACN,CAAC;AAND,8DAMC"} \ No newline at end of file diff --git a/packages/schema/out/cli/generator.js b/packages/schema/out/cli/generator.js deleted file mode 100644 index d30cd2d46..000000000 --- a/packages/schema/out/cli/generator.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.generateJavaScript = void 0; -const fs_1 = __importDefault(require("fs")); -const langium_1 = require("langium"); -const path_1 = __importDefault(require("path")); -const cli_util_1 = require("./cli-util"); -function generateJavaScript(model, filePath, destination) { - const data = (0, cli_util_1.extractDestinationAndName)(filePath, destination); - const generatedFilePath = `${path_1.default.join(data.destination, data.name)}.js`; - const fileNode = new langium_1.CompositeGeneratorNode(); - fileNode.append('"use strict";', langium_1.NL, langium_1.NL); - // model.greetings.forEach(greeting => fileNode.append(`console.log('Hello, ${greeting.person.ref?.name}!');`, NL)); - if (!fs_1.default.existsSync(data.destination)) { - fs_1.default.mkdirSync(data.destination, { recursive: true }); - } - fs_1.default.writeFileSync(generatedFilePath, (0, langium_1.processGeneratorNode)(fileNode)); - return generatedFilePath; -} -exports.generateJavaScript = generateJavaScript; -//# sourceMappingURL=generator.js.map \ No newline at end of file diff --git a/packages/schema/out/cli/generator.js.map b/packages/schema/out/cli/generator.js.map deleted file mode 100644 index 07c96109d..000000000 --- a/packages/schema/out/cli/generator.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/cli/generator.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAoB;AACpB,qCAA2E;AAC3E,gDAAwB;AAExB,yCAAuD;AAEvD,SAAgB,kBAAkB,CAC9B,KAAY,EACZ,QAAgB,EAChB,WAA+B;IAE/B,MAAM,IAAI,GAAG,IAAA,oCAAyB,EAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC9D,MAAM,iBAAiB,GAAG,GAAG,cAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IAEzE,MAAM,QAAQ,GAAG,IAAI,gCAAsB,EAAE,CAAC;IAC9C,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,YAAE,EAAE,YAAE,CAAC,CAAC;IACzC,oHAAoH;IAEpH,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;QAClC,YAAE,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;KACvD;IACD,YAAE,CAAC,aAAa,CAAC,iBAAiB,EAAE,IAAA,8BAAoB,EAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,OAAO,iBAAiB,CAAC;AAC7B,CAAC;AAjBD,gDAiBC"} \ No newline at end of file diff --git a/packages/schema/out/cli/index.js b/packages/schema/out/cli/index.js deleted file mode 100644 index 2cbd0bd69..000000000 --- a/packages/schema/out/cli/index.js +++ /dev/null @@ -1,44 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.generateAction = void 0; -const colors_1 = __importDefault(require("colors")); -const commander_1 = require("commander"); -const module_1 = require("../language-server/generated/module"); -const zmodel_module_1 = require("../language-server/zmodel-module"); -const cli_util_1 = require("./cli-util"); -const generator_1 = require("./generator"); -const generateAction = (fileName, opts) => __awaiter(void 0, void 0, void 0, function* () { - const services = (0, zmodel_module_1.createZModelServices)().ZModel; - const model = yield (0, cli_util_1.extractAstNode)(fileName, services); - const generatedFilePath = (0, generator_1.generateJavaScript)(model, fileName, opts.destination); - console.log(colors_1.default.green(`JavaScript code generated successfully: ${generatedFilePath}`)); -}); -exports.generateAction = generateAction; -function default_1() { - const program = new commander_1.Command(); - program - // eslint-disable-next-line @typescript-eslint/no-var-requires - .version(require('../../package.json').version); - const fileExtensions = module_1.ZModelLanguageMetaData.fileExtensions.join(', '); - program - .command('generate') - .argument('', `source file (possible file extensions: ${fileExtensions})`) - .option('-d, --destination ', 'destination directory of generating') - .description('generates JavaScript code that prints "Hello, {name}!" for each greeting in a source file') - .action(exports.generateAction); - program.parse(process.argv); -} -exports.default = default_1; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/schema/out/cli/index.js.map b/packages/schema/out/cli/index.js.map deleted file mode 100644 index 0293f48b3..000000000 --- a/packages/schema/out/cli/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,oDAA4B;AAC5B,yCAAoC;AAEpC,gEAA6E;AAC7E,oEAAwE;AACxE,yCAA4C;AAC5C,2CAAiD;AAE1C,MAAM,cAAc,GAAG,CAC1B,QAAgB,EAChB,IAAqB,EACR,EAAE;IACf,MAAM,QAAQ,GAAG,IAAA,oCAAoB,GAAE,CAAC,MAAM,CAAC;IAC/C,MAAM,KAAK,GAAG,MAAM,IAAA,yBAAc,EAAQ,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC9D,MAAM,iBAAiB,GAAG,IAAA,8BAAkB,EACxC,KAAK,EACL,QAAQ,EACR,IAAI,CAAC,WAAW,CACnB,CAAC;IACF,OAAO,CAAC,GAAG,CACP,gBAAM,CAAC,KAAK,CACR,2CAA2C,iBAAiB,EAAE,CACjE,CACJ,CAAC;AACN,CAAC,CAAA,CAAC;AAhBW,QAAA,cAAc,kBAgBzB;AAMF;IACI,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;IAE9B,OAAO;QACH,8DAA8D;SAC7D,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,CAAC;IAEpD,MAAM,cAAc,GAAG,+BAAsB,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxE,OAAO;SACF,OAAO,CAAC,UAAU,CAAC;SACnB,QAAQ,CACL,QAAQ,EACR,0CAA0C,cAAc,GAAG,CAC9D;SACA,MAAM,CACH,yBAAyB,EACzB,qCAAqC,CACxC;SACA,WAAW,CACR,2FAA2F,CAC9F;SACA,MAAM,CAAC,sBAAc,CAAC,CAAC;IAE5B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAxBD,4BAwBC"} \ No newline at end of file diff --git a/packages/schema/out/extension.js b/packages/schema/out/extension.js deleted file mode 100644 index 2c985d64f..000000000 --- a/packages/schema/out/extension.js +++ /dev/null @@ -1,81 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.deactivate = exports.activate = void 0; -const vscode = __importStar(require("vscode")); -const path = __importStar(require("path")); -const node_1 = require("vscode-languageclient/node"); -let client; -// This function is called when the extension is activated. -function activate(context) { - client = startLanguageClient(context); -} -exports.activate = activate; -// This function is called when the extension is deactivated. -function deactivate() { - if (client) { - return client.stop(); - } - return undefined; -} -exports.deactivate = deactivate; -function startLanguageClient(context) { - 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 = { - run: { module: serverModule, transport: node_1.TransportKind.ipc }, - debug: { - module: serverModule, - transport: node_1.TransportKind.ipc, - options: debugOptions, - }, - }; - const fileSystemWatcher = vscode.workspace.createFileSystemWatcher('**/*.zmodel'); - context.subscriptions.push(fileSystemWatcher); - // Options to control the language client - const clientOptions = { - documentSelector: [{ scheme: 'file', language: 'zmodel' }], - 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 node_1.LanguageClient('zmodel', 'ZenStack Model', serverOptions, clientOptions); - // Start the client. This will also launch the server - client.start(); - return client; -} -//# sourceMappingURL=extension.js.map \ No newline at end of file diff --git a/packages/schema/out/extension.js.map b/packages/schema/out/extension.js.map deleted file mode 100644 index efc599158..000000000 --- a/packages/schema/out/extension.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AACjC,2CAA6B;AAC7B,qDAKoC;AAEpC,IAAI,MAAsB,CAAC;AAE3B,2DAA2D;AAC3D,SAAgB,QAAQ,CAAC,OAAgC;IACrD,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC;AAFD,4BAEC;AAED,6DAA6D;AAC7D,SAAgB,UAAU;IACtB,IAAI,MAAM,EAAE;QACR,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;KACxB;IACD,OAAO,SAAS,CAAC;AACrB,CAAC;AALD,gCAKC;AAED,SAAS,mBAAmB,CAAC,OAAgC;IACzD,MAAM,YAAY,GAAG,OAAO,CAAC,cAAc,CACvC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAC9C,CAAC;IACF,mCAAmC;IACnC,8GAA8G;IAC9G,sHAAsH;IACtH,MAAM,YAAY,GAAG;QACjB,QAAQ,EAAE;YACN,UAAU;YACV,YAAY,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAC7C,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,MAChC,EAAE;SACL;KACJ,CAAC;IAEF,oFAAoF;IACpF,qCAAqC;IACrC,MAAM,aAAa,GAAkB;QACjC,GAAG,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,oBAAa,CAAC,GAAG,EAAE;QAC3D,KAAK,EAAE;YACH,MAAM,EAAE,YAAY;YACpB,SAAS,EAAE,oBAAa,CAAC,GAAG;YAC5B,OAAO,EAAE,YAAY;SACxB;KACJ,CAAC;IAEF,MAAM,iBAAiB,GACnB,MAAM,CAAC,SAAS,CAAC,uBAAuB,CAAC,aAAa,CAAC,CAAC;IAC5D,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAE9C,yCAAyC;IACzC,MAAM,aAAa,GAA0B;QACzC,gBAAgB,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;QAC1D,WAAW,EAAE;YACT,2EAA2E;YAC3E,UAAU,EAAE,iBAAiB;SAChC;KACJ,CAAC;IAEF,mDAAmD;IACnD,MAAM,MAAM,GAAG,IAAI,qBAAc,CAC7B,QAAQ,EACR,gBAAgB,EAChB,aAAa,EACb,aAAa,CAChB,CAAC;IAEF,qDAAqD;IACrD,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,OAAO,MAAM,CAAC;AAClB,CAAC"} \ No newline at end of file diff --git a/packages/schema/out/language-server/generated/ast.js b/packages/schema/out/language-server/generated/ast.js deleted file mode 100644 index d98cf5683..000000000 --- a/packages/schema/out/language-server/generated/ast.js +++ /dev/null @@ -1,215 +0,0 @@ -"use strict"; -/****************************************************************************** - * This file was generated by langium-cli 0.4.0. - * DO NOT EDIT MANUALLY! - ******************************************************************************/ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.reflection = exports.ZModelAstReflection = exports.isSimpleInvocationExpr = exports.SimpleInvocationExpr = exports.isModel = exports.Model = exports.isLiteralExpr = exports.LiteralExpr = exports.isFragmentExpansion = exports.FragmentExpansion = exports.isFragment = exports.Fragment = exports.isEnumField = exports.EnumField = exports.isEnum = exports.Enum = exports.isDataSourceField = exports.DataSourceField = exports.isDataSource = exports.DataSource = exports.isDataModelFieldType = exports.DataModelFieldType = exports.isDataModelFieldAttribute = exports.DataModelFieldAttribute = exports.isDataModelField = exports.DataModelField = exports.isDataModel = exports.DataModel = exports.isSimpleExpr = exports.SimpleExpr = exports.isDeclaration = exports.Declaration = void 0; -/* eslint-disable @typescript-eslint/array-type */ -/* eslint-disable @typescript-eslint/no-empty-interface */ -const langium_1 = require("langium"); -exports.Declaration = 'Declaration'; -function isDeclaration(item) { - return exports.reflection.isInstance(item, exports.Declaration); -} -exports.isDeclaration = isDeclaration; -exports.SimpleExpr = 'SimpleExpr'; -function isSimpleExpr(item) { - return exports.reflection.isInstance(item, exports.SimpleExpr); -} -exports.isSimpleExpr = isSimpleExpr; -exports.DataModel = 'DataModel'; -function isDataModel(item) { - return exports.reflection.isInstance(item, exports.DataModel); -} -exports.isDataModel = isDataModel; -exports.DataModelField = 'DataModelField'; -function isDataModelField(item) { - return exports.reflection.isInstance(item, exports.DataModelField); -} -exports.isDataModelField = isDataModelField; -exports.DataModelFieldAttribute = 'DataModelFieldAttribute'; -function isDataModelFieldAttribute(item) { - return exports.reflection.isInstance(item, exports.DataModelFieldAttribute); -} -exports.isDataModelFieldAttribute = isDataModelFieldAttribute; -exports.DataModelFieldType = 'DataModelFieldType'; -function isDataModelFieldType(item) { - return exports.reflection.isInstance(item, exports.DataModelFieldType); -} -exports.isDataModelFieldType = isDataModelFieldType; -exports.DataSource = 'DataSource'; -function isDataSource(item) { - return exports.reflection.isInstance(item, exports.DataSource); -} -exports.isDataSource = isDataSource; -exports.DataSourceField = 'DataSourceField'; -function isDataSourceField(item) { - return exports.reflection.isInstance(item, exports.DataSourceField); -} -exports.isDataSourceField = isDataSourceField; -exports.Enum = 'Enum'; -function isEnum(item) { - return exports.reflection.isInstance(item, exports.Enum); -} -exports.isEnum = isEnum; -exports.EnumField = 'EnumField'; -function isEnumField(item) { - return exports.reflection.isInstance(item, exports.EnumField); -} -exports.isEnumField = isEnumField; -exports.Fragment = 'Fragment'; -function isFragment(item) { - return exports.reflection.isInstance(item, exports.Fragment); -} -exports.isFragment = isFragment; -exports.FragmentExpansion = 'FragmentExpansion'; -function isFragmentExpansion(item) { - return exports.reflection.isInstance(item, exports.FragmentExpansion); -} -exports.isFragmentExpansion = isFragmentExpansion; -exports.LiteralExpr = 'LiteralExpr'; -function isLiteralExpr(item) { - return exports.reflection.isInstance(item, exports.LiteralExpr); -} -exports.isLiteralExpr = isLiteralExpr; -exports.Model = 'Model'; -function isModel(item) { - return exports.reflection.isInstance(item, exports.Model); -} -exports.isModel = isModel; -exports.SimpleInvocationExpr = 'SimpleInvocationExpr'; -function isSimpleInvocationExpr(item) { - return exports.reflection.isInstance(item, exports.SimpleInvocationExpr); -} -exports.isSimpleInvocationExpr = isSimpleInvocationExpr; -class ZModelAstReflection { - getAllTypes() { - return ['DataModel', 'DataModelField', 'DataModelFieldAttribute', 'DataModelFieldType', 'DataSource', 'DataSourceField', 'Declaration', 'Enum', 'EnumField', 'Fragment', 'FragmentExpansion', 'LiteralExpr', 'Model', 'SimpleExpr', 'SimpleInvocationExpr']; - } - isInstance(node, type) { - return (0, langium_1.isAstNode)(node) && this.isSubtype(node.$type, type); - } - isSubtype(subtype, supertype) { - if (subtype === supertype) { - return true; - } - switch (subtype) { - case exports.DataModel: - case exports.Enum: - case exports.Fragment: { - return this.isSubtype(exports.Declaration, supertype); - } - case exports.LiteralExpr: - case exports.SimpleInvocationExpr: { - return this.isSubtype(exports.SimpleExpr, supertype); - } - default: { - return false; - } - } - } - getReferenceType(referenceId) { - switch (referenceId) { - case 'DataModelFieldType:reference': { - return exports.Declaration; - } - case 'FragmentExpansion:value': { - return exports.Fragment; - } - default: { - throw new Error(`${referenceId} is not a valid reference id.`); - } - } - } - getTypeMetaData(type) { - switch (type) { - case 'DataModel': { - return { - name: 'DataModel', - mandatory: [ - { name: 'fields', type: 'array' }, - { name: 'fragments', type: 'array' } - ] - }; - } - case 'DataModelField': { - return { - name: 'DataModelField', - mandatory: [ - { name: 'attributes', type: 'array' } - ] - }; - } - case 'DataModelFieldAttribute': { - return { - name: 'DataModelFieldAttribute', - mandatory: [ - { name: 'args', type: 'array' } - ] - }; - } - case 'DataModelFieldType': { - return { - name: 'DataModelFieldType', - mandatory: [ - { name: 'array', type: 'boolean' }, - { name: 'optional', type: 'boolean' } - ] - }; - } - case 'DataSource': { - return { - name: 'DataSource', - mandatory: [ - { name: 'fields', type: 'array' } - ] - }; - } - case 'Enum': { - return { - name: 'Enum', - mandatory: [ - { name: 'fields', type: 'array' } - ] - }; - } - case 'Fragment': { - return { - name: 'Fragment', - mandatory: [ - { name: 'fields', type: 'array' } - ] - }; - } - case 'Model': { - return { - name: 'Model', - mandatory: [ - { name: 'datasources', type: 'array' }, - { name: 'enums', type: 'array' }, - { name: 'fragments', type: 'array' }, - { name: 'models', type: 'array' } - ] - }; - } - case 'SimpleInvocationExpr': { - return { - name: 'SimpleInvocationExpr', - mandatory: [ - { name: 'args', type: 'array' } - ] - }; - } - default: { - return { - name: type, - mandatory: [] - }; - } - } - } -} -exports.ZModelAstReflection = ZModelAstReflection; -exports.reflection = new ZModelAstReflection(); -//# sourceMappingURL=ast.js.map \ No newline at end of file diff --git a/packages/schema/out/language-server/generated/ast.js.map b/packages/schema/out/language-server/generated/ast.js.map deleted file mode 100644 index d9fbe15dd..000000000 --- a/packages/schema/out/language-server/generated/ast.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ast.js","sourceRoot":"","sources":["../../../src/language-server/generated/ast.ts"],"names":[],"mappings":";AAAA;;;gFAGgF;;;AAEhF,kDAAkD;AAClD,0DAA0D;AAC1D,qCAAqF;AAIxE,QAAA,WAAW,GAAG,aAAa,CAAC;AAEzC,SAAgB,aAAa,CAAC,IAAa;IACvC,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,mBAAW,CAAC,CAAC;AACpD,CAAC;AAFD,sCAEC;AAIY,QAAA,UAAU,GAAG,YAAY,CAAC;AAEvC,SAAgB,YAAY,CAAC,IAAa;IACtC,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,kBAAU,CAAC,CAAC;AACnD,CAAC;AAFD,oCAEC;AASY,QAAA,SAAS,GAAG,WAAW,CAAC;AAErC,SAAgB,WAAW,CAAC,IAAa;IACrC,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,iBAAS,CAAC,CAAC;AAClD,CAAC;AAFD,kCAEC;AASY,QAAA,cAAc,GAAG,gBAAgB,CAAC;AAE/C,SAAgB,gBAAgB,CAAC,IAAa;IAC1C,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,sBAAc,CAAC,CAAC;AACvD,CAAC;AAFD,4CAEC;AAQY,QAAA,uBAAuB,GAAG,yBAAyB,CAAC;AAEjE,SAAgB,yBAAyB,CAAC,IAAa;IACnD,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,+BAAuB,CAAC,CAAC;AAChE,CAAC;AAFD,8DAEC;AAUY,QAAA,kBAAkB,GAAG,oBAAoB,CAAC;AAEvD,SAAgB,oBAAoB,CAAC,IAAa;IAC9C,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,0BAAkB,CAAC,CAAC;AAC3D,CAAC;AAFD,oDAEC;AAOY,QAAA,UAAU,GAAG,YAAY,CAAC;AAEvC,SAAgB,YAAY,CAAC,IAAa;IACtC,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,kBAAU,CAAC,CAAC;AACnD,CAAC;AAFD,oCAEC;AAQY,QAAA,eAAe,GAAG,iBAAiB,CAAC;AAEjD,SAAgB,iBAAiB,CAAC,IAAa;IAC3C,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,uBAAe,CAAC,CAAC;AACxD,CAAC;AAFD,8CAEC;AAQY,QAAA,IAAI,GAAG,MAAM,CAAC;AAE3B,SAAgB,MAAM,CAAC,IAAa;IAChC,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,YAAI,CAAC,CAAC;AAC7C,CAAC;AAFD,wBAEC;AAOY,QAAA,SAAS,GAAG,WAAW,CAAC;AAErC,SAAgB,WAAW,CAAC,IAAa;IACrC,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,iBAAS,CAAC,CAAC;AAClD,CAAC;AAFD,kCAEC;AAQY,QAAA,QAAQ,GAAG,UAAU,CAAC;AAEnC,SAAgB,UAAU,CAAC,IAAa;IACpC,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,gBAAQ,CAAC,CAAC;AACjD,CAAC;AAFD,gCAEC;AAOY,QAAA,iBAAiB,GAAG,mBAAmB,CAAC;AAErD,SAAgB,mBAAmB,CAAC,IAAa;IAC7C,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,yBAAiB,CAAC,CAAC;AAC1D,CAAC;AAFD,kDAEC;AAOY,QAAA,WAAW,GAAG,aAAa,CAAC;AAEzC,SAAgB,aAAa,CAAC,IAAa;IACvC,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,mBAAW,CAAC,CAAC;AACpD,CAAC;AAFD,sCAEC;AASY,QAAA,KAAK,GAAG,OAAO,CAAC;AAE7B,SAAgB,OAAO,CAAC,IAAa;IACjC,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,aAAK,CAAC,CAAC;AAC9C,CAAC;AAFD,0BAEC;AAQY,QAAA,oBAAoB,GAAG,sBAAsB,CAAC;AAE3D,SAAgB,sBAAsB,CAAC,IAAa;IAChD,OAAO,kBAAU,CAAC,UAAU,CAAC,IAAI,EAAE,4BAAoB,CAAC,CAAC;AAC7D,CAAC;AAFD,wDAEC;AAMD,MAAa,mBAAmB;IAE5B,WAAW;QACP,OAAO,CAAC,WAAW,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,mBAAmB,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,sBAAsB,CAAC,CAAC;IAChQ,CAAC;IAED,UAAU,CAAC,IAAa,EAAE,IAAY;QAClC,OAAO,IAAA,mBAAS,EAAC,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC/D,CAAC;IAED,SAAS,CAAC,OAAe,EAAE,SAAiB;QACxC,IAAI,OAAO,KAAK,SAAS,EAAE;YACvB,OAAO,IAAI,CAAC;SACf;QACD,QAAQ,OAAO,EAAE;YACb,KAAK,iBAAS,CAAC;YACf,KAAK,YAAI,CAAC;YACV,KAAK,gBAAQ,CAAC,CAAC;gBACX,OAAO,IAAI,CAAC,SAAS,CAAC,mBAAW,EAAE,SAAS,CAAC,CAAC;aACjD;YACD,KAAK,mBAAW,CAAC;YACjB,KAAK,4BAAoB,CAAC,CAAC;gBACvB,OAAO,IAAI,CAAC,SAAS,CAAC,kBAAU,EAAE,SAAS,CAAC,CAAC;aAChD;YACD,OAAO,CAAC,CAAC;gBACL,OAAO,KAAK,CAAC;aAChB;SACJ;IACL,CAAC;IAED,gBAAgB,CAAC,WAA+B;QAC5C,QAAQ,WAAW,EAAE;YACjB,KAAK,8BAA8B,CAAC,CAAC;gBACjC,OAAO,mBAAW,CAAC;aACtB;YACD,KAAK,yBAAyB,CAAC,CAAC;gBAC5B,OAAO,gBAAQ,CAAC;aACnB;YACD,OAAO,CAAC,CAAC;gBACL,MAAM,IAAI,KAAK,CAAC,GAAG,WAAW,+BAA+B,CAAC,CAAC;aAClE;SACJ;IACL,CAAC;IAED,eAAe,CAAC,IAAY;QACxB,QAAQ,IAAI,EAAE;YACV,KAAK,WAAW,CAAC,CAAC;gBACd,OAAO;oBACH,IAAI,EAAE,WAAW;oBACjB,SAAS,EAAE;wBACP,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE;wBACjC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE;qBACvC;iBACJ,CAAC;aACL;YACD,KAAK,gBAAgB,CAAC,CAAC;gBACnB,OAAO;oBACH,IAAI,EAAE,gBAAgB;oBACtB,SAAS,EAAE;wBACP,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;qBACxC;iBACJ,CAAC;aACL;YACD,KAAK,yBAAyB,CAAC,CAAC;gBAC5B,OAAO;oBACH,IAAI,EAAE,yBAAyB;oBAC/B,SAAS,EAAE;wBACP,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE;qBAClC;iBACJ,CAAC;aACL;YACD,KAAK,oBAAoB,CAAC,CAAC;gBACvB,OAAO;oBACH,IAAI,EAAE,oBAAoB;oBAC1B,SAAS,EAAE;wBACP,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;wBAClC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;qBACxC;iBACJ,CAAC;aACL;YACD,KAAK,YAAY,CAAC,CAAC;gBACf,OAAO;oBACH,IAAI,EAAE,YAAY;oBAClB,SAAS,EAAE;wBACP,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE;qBACpC;iBACJ,CAAC;aACL;YACD,KAAK,MAAM,CAAC,CAAC;gBACT,OAAO;oBACH,IAAI,EAAE,MAAM;oBACZ,SAAS,EAAE;wBACP,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE;qBACpC;iBACJ,CAAC;aACL;YACD,KAAK,UAAU,CAAC,CAAC;gBACb,OAAO;oBACH,IAAI,EAAE,UAAU;oBAChB,SAAS,EAAE;wBACP,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE;qBACpC;iBACJ,CAAC;aACL;YACD,KAAK,OAAO,CAAC,CAAC;gBACV,OAAO;oBACH,IAAI,EAAE,OAAO;oBACb,SAAS,EAAE;wBACP,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE;wBACtC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE;wBAChC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE;wBACpC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE;qBACpC;iBACJ,CAAC;aACL;YACD,KAAK,sBAAsB,CAAC,CAAC;gBACzB,OAAO;oBACH,IAAI,EAAE,sBAAsB;oBAC5B,SAAS,EAAE;wBACP,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE;qBAClC;iBACJ,CAAC;aACL;YACD,OAAO,CAAC,CAAC;gBACL,OAAO;oBACH,IAAI,EAAE,IAAI;oBACV,SAAS,EAAE,EAAE;iBAChB,CAAC;aACL;SACJ;IACL,CAAC;CACJ;AAnID,kDAmIC;AAEY,QAAA,UAAU,GAAG,IAAI,mBAAmB,EAAE,CAAC"} \ No newline at end of file diff --git a/packages/schema/out/language-server/generated/grammar.js b/packages/schema/out/language-server/generated/grammar.js deleted file mode 100644 index 596a899bf..000000000 --- a/packages/schema/out/language-server/generated/grammar.js +++ /dev/null @@ -1,900 +0,0 @@ -"use strict"; -/****************************************************************************** - * This file was generated by langium-cli 0.4.0. - * DO NOT EDIT MANUALLY! - ******************************************************************************/ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ZModelGrammar = void 0; -const langium_1 = require("langium"); -let loadedZModelGrammar; -const ZModelGrammar = () => loadedZModelGrammar || (loadedZModelGrammar = (0, langium_1.loadGrammar)(`{ - "$type": "Grammar", - "isDeclared": true, - "name": "ZModel", - "rules": [ - { - "$type": "ParserRule", - "name": "Model", - "entry": true, - "alternatives": { - "$type": "Alternatives", - "elements": [ - { - "$type": "Assignment", - "feature": "datasources", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataSource" - }, - "arguments": [] - } - }, - { - "$type": "Assignment", - "feature": "models", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataModel" - }, - "arguments": [] - } - }, - { - "$type": "Assignment", - "feature": "enums", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "Enum" - }, - "arguments": [] - } - }, - { - "$type": "Assignment", - "feature": "fragments", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "Fragment" - }, - "arguments": [] - } - } - ], - "cardinality": "*" - }, - "definesHiddenTokens": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "DataSource", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Keyword", - "value": "datasource" - }, - { - "$type": "Keyword", - "value": "{" - }, - { - "$type": "Assignment", - "feature": "fields", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataSourceField" - }, - "arguments": [] - }, - "cardinality": "+" - }, - { - "$type": "Keyword", - "value": "}" - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "DataSourceField", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Assignment", - "feature": "name", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": "=" - }, - { - "$type": "Assignment", - "feature": "value", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "SimpleExpr" - }, - "arguments": [] - } - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "SimpleExpr", - "alternatives": { - "$type": "Alternatives", - "elements": [ - { - "$type": "RuleCall", - "rule": { - "$refText": "SimpleInvocationExpr" - }, - "arguments": [] - }, - { - "$type": "RuleCall", - "rule": { - "$refText": "LiteralExpr" - }, - "arguments": [] - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "SimpleInvocationExpr", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Assignment", - "feature": "function", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": "(" - }, - { - "$type": "Group", - "elements": [ - { - "$type": "Assignment", - "feature": "args", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "SimpleExpr" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": "," - } - ], - "cardinality": "*" - }, - { - "$type": "Assignment", - "feature": "args", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "SimpleExpr" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": ")" - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "LiteralExpr", - "alternatives": { - "$type": "Assignment", - "feature": "value", - "operator": "=", - "terminal": { - "$type": "Alternatives", - "elements": [ - { - "$type": "RuleCall", - "rule": { - "$refText": "BOOLEAN" - }, - "arguments": [] - }, - { - "$type": "RuleCall", - "rule": { - "$refText": "INT" - }, - "arguments": [] - }, - { - "$type": "RuleCall", - "rule": { - "$refText": "STRING" - }, - "arguments": [] - } - ] - } - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "Enum", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Keyword", - "value": "enum" - }, - { - "$type": "Assignment", - "feature": "name", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": "{" - }, - { - "$type": "Assignment", - "feature": "fields", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "EnumField" - }, - "arguments": [] - }, - "cardinality": "+" - }, - { - "$type": "Keyword", - "value": "}" - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "EnumField", - "alternatives": { - "$type": "Assignment", - "feature": "value", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - } - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "DataModel", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Keyword", - "value": "model" - }, - { - "$type": "Assignment", - "feature": "name", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": "{" - }, - { - "$type": "Assignment", - "feature": "fragments", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "FragmentExpansion" - }, - "arguments": [] - }, - "cardinality": "*" - }, - { - "$type": "Assignment", - "feature": "fields", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataModelField" - }, - "arguments": [] - }, - "cardinality": "+" - }, - { - "$type": "Keyword", - "value": "}" - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "FragmentExpansion", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Keyword", - "value": "..." - }, - { - "$type": "Assignment", - "feature": "value", - "operator": "=", - "terminal": { - "$type": "CrossReference", - "type": { - "$refText": "Fragment" - }, - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - }, - "deprecatedSyntax": false - } - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "DataModelField", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Assignment", - "feature": "name", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - } - }, - { - "$type": "Assignment", - "feature": "fieldType", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataModelFieldType" - }, - "arguments": [] - } - }, - { - "$type": "Assignment", - "feature": "attributes", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataModelFieldAttribute" - }, - "arguments": [] - }, - "cardinality": "*" - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "DataModelFieldType", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Alternatives", - "elements": [ - { - "$type": "RuleCall", - "rule": { - "$refText": "FieldType" - }, - "arguments": [] - }, - { - "$type": "Assignment", - "feature": "reference", - "operator": "=", - "terminal": { - "$type": "CrossReference", - "type": { - "$refText": "Declaration" - }, - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - }, - "deprecatedSyntax": false - } - } - ] - }, - { - "$type": "Assignment", - "feature": "array", - "operator": "?=", - "terminal": { - "$type": "Keyword", - "value": "[]" - }, - "cardinality": "?" - }, - { - "$type": "Assignment", - "feature": "optional", - "operator": "?=", - "terminal": { - "$type": "Keyword", - "value": "?" - }, - "cardinality": "?" - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "Declaration", - "alternatives": { - "$type": "Alternatives", - "elements": [ - { - "$type": "RuleCall", - "rule": { - "$refText": "DataModel" - }, - "arguments": [] - }, - { - "$type": "RuleCall", - "rule": { - "$refText": "Fragment" - }, - "arguments": [] - }, - { - "$type": "RuleCall", - "rule": { - "$refText": "Enum" - }, - "arguments": [] - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "DataModelFieldAttribute", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Keyword", - "value": "@" - }, - { - "$type": "Assignment", - "feature": "name", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - } - }, - { - "$type": "Group", - "elements": [ - { - "$type": "Keyword", - "value": "(" - }, - { - "$type": "Group", - "elements": [ - { - "$type": "Group", - "elements": [ - { - "$type": "Assignment", - "feature": "args", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "LiteralExpr" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": "," - } - ], - "cardinality": "*" - }, - { - "$type": "Assignment", - "feature": "args", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "LiteralExpr" - }, - "arguments": [] - } - } - ], - "cardinality": "?" - }, - { - "$type": "Keyword", - "value": ")" - } - ], - "cardinality": "?" - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "Fragment", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Keyword", - "value": "fragment" - }, - { - "$type": "Assignment", - "feature": "name", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": "{" - }, - { - "$type": "Assignment", - "feature": "fields", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataModelField" - }, - "arguments": [] - }, - "cardinality": "+" - }, - { - "$type": "Keyword", - "value": "}" - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "FieldType", - "fragment": true, - "alternatives": { - "$type": "Assignment", - "feature": "type", - "operator": "=", - "terminal": { - "$type": "Alternatives", - "elements": [ - { - "$type": "Keyword", - "value": "String" - }, - { - "$type": "Keyword", - "value": "Boolean" - }, - { - "$type": "Keyword", - "value": "Int" - }, - { - "$type": "Keyword", - "value": "Float" - }, - { - "$type": "Keyword", - "value": "DateTime" - }, - { - "$type": "Keyword", - "value": "JSON" - } - ] - } - }, - "definesHiddenTokens": false, - "entry": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "TerminalRule", - "hidden": true, - "name": "WS", - "terminal": { - "$type": "RegexToken", - "regex": "\\\\s+" - }, - "fragment": false - }, - { - "$type": "TerminalRule", - "name": "BOOLEAN", - "type": { - "$type": "ReturnType", - "name": "boolean" - }, - "terminal": { - "$type": "RegexToken", - "regex": "true|false" - }, - "fragment": false, - "hidden": false - }, - { - "$type": "TerminalRule", - "name": "ID", - "terminal": { - "$type": "RegexToken", - "regex": "[_a-zA-Z][\\\\w_]*" - }, - "fragment": false, - "hidden": false - }, - { - "$type": "TerminalRule", - "name": "STRING", - "terminal": { - "$type": "RegexToken", - "regex": "\\"[^\\"]*\\"|'[^']*'" - }, - "fragment": false, - "hidden": false - }, - { - "$type": "TerminalRule", - "name": "INT", - "type": { - "$type": "ReturnType", - "name": "number" - }, - "terminal": { - "$type": "RegexToken", - "regex": "[0-9]+" - }, - "fragment": false, - "hidden": false - }, - { - "$type": "TerminalRule", - "hidden": true, - "name": "ML_COMMENT", - "terminal": { - "$type": "RegexToken", - "regex": "\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\/" - }, - "fragment": false - }, - { - "$type": "TerminalRule", - "hidden": true, - "name": "SL_COMMENT", - "terminal": { - "$type": "RegexToken", - "regex": "\\\\/\\\\/[^\\\\n\\\\r]*" - }, - "fragment": false - } - ], - "definesHiddenTokens": false, - "hiddenTokens": [], - "imports": [], - "interfaces": [], - "types": [], - "usedGrammars": [] -}`)); -exports.ZModelGrammar = ZModelGrammar; -//# sourceMappingURL=grammar.js.map \ No newline at end of file diff --git a/packages/schema/out/language-server/generated/grammar.js.map b/packages/schema/out/language-server/generated/grammar.js.map deleted file mode 100644 index cbf60d100..000000000 --- a/packages/schema/out/language-server/generated/grammar.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"grammar.js","sourceRoot":"","sources":["../../../src/language-server/generated/grammar.ts"],"names":[],"mappings":";AAAA;;;gFAGgF;;;AAEhF,qCAA+C;AAE/C,IAAI,mBAAwC,CAAC;AACtC,MAAM,aAAa,GAAG,GAAY,EAAE,CAAC,mBAAmB,IAAG,CAAC,mBAAmB,GAAG,IAAA,qBAAW,EAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAw3BnG,CAAC,CAAC,CAAC;AAx3BQ,QAAA,aAAa,iBAw3BrB"} \ No newline at end of file diff --git a/packages/schema/out/language-server/generated/module.js b/packages/schema/out/language-server/generated/module.js deleted file mode 100644 index 552e10fac..000000000 --- a/packages/schema/out/language-server/generated/module.js +++ /dev/null @@ -1,23 +0,0 @@ -"use strict"; -/****************************************************************************** - * This file was generated by langium-cli 0.4.0. - * DO NOT EDIT MANUALLY! - ******************************************************************************/ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ZModelGeneratedModule = exports.ZModelGeneratedSharedModule = exports.ZModelLanguageMetaData = void 0; -const ast_1 = require("./ast"); -const grammar_1 = require("./grammar"); -exports.ZModelLanguageMetaData = { - languageId: 'zmodel', - fileExtensions: ['.zmodel'], - caseInsensitive: false -}; -exports.ZModelGeneratedSharedModule = { - AstReflection: () => new ast_1.ZModelAstReflection() -}; -exports.ZModelGeneratedModule = { - Grammar: () => (0, grammar_1.ZModelGrammar)(), - LanguageMetaData: () => exports.ZModelLanguageMetaData, - parser: {} -}; -//# sourceMappingURL=module.js.map \ No newline at end of file diff --git a/packages/schema/out/language-server/generated/module.js.map b/packages/schema/out/language-server/generated/module.js.map deleted file mode 100644 index 9ee12c7f2..000000000 --- a/packages/schema/out/language-server/generated/module.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"module.js","sourceRoot":"","sources":["../../../src/language-server/generated/module.ts"],"names":[],"mappings":";AAAA;;;gFAGgF;;;AAGhF,+BAA4C;AAC5C,uCAA0C;AAE7B,QAAA,sBAAsB,GAAqB;IACpD,UAAU,EAAE,QAAQ;IACpB,cAAc,EAAE,CAAC,SAAS,CAAC;IAC3B,eAAe,EAAE,KAAK;CACzB,CAAC;AAEW,QAAA,2BAA2B,GAAkE;IACtG,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,yBAAmB,EAAE;CACjD,CAAC;AAEW,QAAA,qBAAqB,GAAsD;IACpF,OAAO,EAAE,GAAG,EAAE,CAAC,IAAA,uBAAa,GAAE;IAC9B,gBAAgB,EAAE,GAAG,EAAE,CAAC,8BAAsB;IAC9C,MAAM,EAAE,EAAE;CACb,CAAC"} \ No newline at end of file diff --git a/packages/schema/out/language-server/main.js b/packages/schema/out/language-server/main.js deleted file mode 100644 index fd4549151..000000000 --- a/packages/schema/out/language-server/main.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const langium_1 = require("langium"); -const node_1 = require("vscode-languageserver/node"); -const zmodel_module_1 = require("./zmodel-module"); -// Create a connection to the client -const connection = (0, node_1.createConnection)(node_1.ProposedFeatures.all); -// Inject the shared services and language-specific services -const { shared } = (0, zmodel_module_1.createZModelServices)({ connection }); -// Start the language server with the shared services -(0, langium_1.startLanguageServer)(shared); -//# sourceMappingURL=main.js.map \ No newline at end of file diff --git a/packages/schema/out/language-server/main.js.map b/packages/schema/out/language-server/main.js.map deleted file mode 100644 index 4a761c11b..000000000 --- a/packages/schema/out/language-server/main.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/language-server/main.ts"],"names":[],"mappings":";;AAAA,qCAA8C;AAC9C,qDAAgF;AAChF,mDAAuD;AAEvD,oCAAoC;AACpC,MAAM,UAAU,GAAG,IAAA,uBAAgB,EAAC,uBAAgB,CAAC,GAAG,CAAC,CAAC;AAE1D,4DAA4D;AAC5D,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,oCAAoB,EAAC,EAAE,UAAU,EAAE,CAAC,CAAC;AAExD,qDAAqD;AACrD,IAAA,6BAAmB,EAAC,MAAM,CAAC,CAAC"} \ No newline at end of file diff --git a/packages/schema/out/language-server/zmodel-module.js b/packages/schema/out/language-server/zmodel-module.js deleted file mode 100644 index 7ccb1d0de..000000000 --- a/packages/schema/out/language-server/zmodel-module.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createZModelServices = exports.ZModelModule = void 0; -const langium_1 = require("langium"); -const module_1 = require("./generated/module"); -const zmodel_validator_1 = require("./zmodel-validator"); -/** - * 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. - */ -exports.ZModelModule = { - validation: { - ValidationRegistry: (services) => new zmodel_validator_1.ZModelValidationRegistry(services), - ZModelValidator: () => new zmodel_validator_1.ZModelValidator(), - }, -}; -/** - * 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 - */ -function createZModelServices(context) { - const shared = (0, langium_1.inject)((0, langium_1.createDefaultSharedModule)(context), module_1.ZModelGeneratedSharedModule); - const ZModel = (0, langium_1.inject)((0, langium_1.createDefaultModule)({ shared }), module_1.ZModelGeneratedModule, exports.ZModelModule); - shared.ServiceRegistry.register(ZModel); - return { shared, ZModel }; -} -exports.createZModelServices = createZModelServices; -//# sourceMappingURL=zmodel-module.js.map \ No newline at end of file diff --git a/packages/schema/out/language-server/zmodel-module.js.map b/packages/schema/out/language-server/zmodel-module.js.map deleted file mode 100644 index fbe1336c4..000000000 --- a/packages/schema/out/language-server/zmodel-module.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"zmodel-module.js","sourceRoot":"","sources":["../../src/language-server/zmodel-module.ts"],"names":[],"mappings":";;;AAAA,qCASiB;AACjB,+CAG4B;AAC5B,yDAA+E;AAiB/E;;;;GAIG;AACU,QAAA,YAAY,GAGrB;IACA,UAAU,EAAE;QACR,kBAAkB,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC7B,IAAI,2CAAwB,CAAC,QAAQ,CAAC;QAC1C,eAAe,EAAE,GAAG,EAAE,CAAC,IAAI,kCAAe,EAAE;KAC/C;CACJ,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,SAAgB,oBAAoB,CAAC,OAAoC;IAIrE,MAAM,MAAM,GAAG,IAAA,gBAAM,EACjB,IAAA,mCAAyB,EAAC,OAAO,CAAC,EAClC,oCAA2B,CAC9B,CAAC;IACF,MAAM,MAAM,GAAG,IAAA,gBAAM,EACjB,IAAA,6BAAmB,EAAC,EAAE,MAAM,EAAE,CAAC,EAC/B,8BAAqB,EACrB,oBAAY,CACf,CAAC;IACF,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC9B,CAAC;AAfD,oDAeC"} \ No newline at end of file diff --git a/packages/schema/out/language-server/zmodel-validator.js b/packages/schema/out/language-server/zmodel-validator.js deleted file mode 100644 index a474a1e0a..000000000 --- a/packages/schema/out/language-server/zmodel-validator.js +++ /dev/null @@ -1,25 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ZModelValidator = exports.ZModelValidationRegistry = void 0; -const langium_1 = require("langium"); -/** - * Registry for validation checks. - */ -class ZModelValidationRegistry extends langium_1.ValidationRegistry { - constructor(services) { - super(services); - const validator = services.validation.ZModelValidator; - const checks = { - // Person: validator.checkPersonStartsWithCapital - }; - this.register(checks, validator); - } -} -exports.ZModelValidationRegistry = ZModelValidationRegistry; -/** - * Implementation of custom validations. - */ -class ZModelValidator { -} -exports.ZModelValidator = ZModelValidator; -//# sourceMappingURL=zmodel-validator.js.map \ No newline at end of file diff --git a/packages/schema/out/language-server/zmodel-validator.js.map b/packages/schema/out/language-server/zmodel-validator.js.map deleted file mode 100644 index 8554d5963..000000000 --- a/packages/schema/out/language-server/zmodel-validator.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"zmodel-validator.js","sourceRoot":"","sources":["../../src/language-server/zmodel-validator.ts"],"names":[],"mappings":";;;AAAA,qCAIiB;AAIjB;;GAEG;AACH,MAAa,wBAAyB,SAAQ,4BAAkB;IAC5D,YAAY,QAAwB;QAChC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,MAAM,SAAS,GAAG,QAAQ,CAAC,UAAU,CAAC,eAAe,CAAC;QACtD,MAAM,MAAM,GAAoC;QAC5C,iDAAiD;SACpD,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrC,CAAC;CACJ;AATD,4DASC;AAED;;GAEG;AACH,MAAa,eAAe;CAS3B;AATD,0CASC"} \ No newline at end of file diff --git a/packages/schema/package.json b/packages/schema/package.json index 48f4facc7..7cb259f6c 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -20,7 +20,11 @@ "extensions": [ ".zmodel" ], - "configuration": "./language-configuration.json" + "configuration": "./language-configuration.json", + "icon": { + "light": "./asset/logo-light.png", + "dark": "./asset/logo-dark.png" + } } ], "grammars": [ @@ -65,7 +69,8 @@ }, "devDependencies": { "@types/jest": "^29.0.3", - "@types/node": "^14.17.3", + "@types/node": "^14.18.29", + "@types/tmp": "^0.2.3", "@types/uuid": "^8.3.4", "@types/vscode": "^1.56.0", "@typescript-eslint/eslint-plugin": "^4.14.1", @@ -74,6 +79,7 @@ "eslint": "^7.19.0", "jest": "^29.0.3", "langium-cli": "^0.4.0", + "tmp": "^0.2.1", "ts-jest": "^29.0.1", "ts-node": "^10.9.1", "typescript": "^4.6.2" diff --git a/packages/schema/src/language-server/generated/ast.ts b/packages/schema/src/language-server/generated/ast.ts index 800ccd7e7..7fc948c51 100644 --- a/packages/schema/src/language-server/generated/ast.ts +++ b/packages/schema/src/language-server/generated/ast.ts @@ -7,26 +7,78 @@ /* eslint-disable @typescript-eslint/no-empty-interface */ import { AstNode, AstReflection, Reference, isAstNode, TypeMetaData } from 'langium'; -export type Declaration = DataModel | Enum | Fragment; +export type AbstractDeclaration = Attribute | DataModel | DataSource | Enum | Function; -export const Declaration = 'Declaration'; +export const AbstractDeclaration = 'AbstractDeclaration'; -export function isDeclaration(item: unknown): item is Declaration { - return reflection.isInstance(item, Declaration); +export function isAbstractDeclaration(item: unknown): item is AbstractDeclaration { + return reflection.isInstance(item, AbstractDeclaration); } -export type SimpleExpr = LiteralExpr | SimpleInvocationExpr; +export type Expression = ArrayExpr | BinaryExpr | InvocationExpr | LiteralExpr | MemberAccessExpr | ReferenceExpr | ThisExpr | UnaryExpr; -export const SimpleExpr = 'SimpleExpr'; +export const Expression = 'Expression'; -export function isSimpleExpr(item: unknown): item is SimpleExpr { - return reflection.isInstance(item, SimpleExpr); +export function isExpression(item: unknown): item is Expression { + return reflection.isInstance(item, Expression); +} + +export type ReferenceTarget = DataModelField | EnumField | FunctionParam; + +export const ReferenceTarget = 'ReferenceTarget'; + +export function isReferenceTarget(item: unknown): item is ReferenceTarget { + return reflection.isInstance(item, ReferenceTarget); +} + +export type TypeDeclaration = DataModel | Enum; + +export const TypeDeclaration = 'TypeDeclaration'; + +export function isTypeDeclaration(item: unknown): item is TypeDeclaration { + return reflection.isInstance(item, TypeDeclaration); +} + +export interface ArrayExpr extends AstNode { + readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + items: Array +} + +export const ArrayExpr = 'ArrayExpr'; + +export function isArrayExpr(item: unknown): item is ArrayExpr { + return reflection.isInstance(item, ArrayExpr); +} + +export interface Attribute extends AstNode { + readonly $container: Model; + name: string + params: Array +} + +export const Attribute = 'Attribute'; + +export function isAttribute(item: unknown): item is Attribute { + return reflection.isInstance(item, Attribute); +} + +export interface BinaryExpr extends AstNode { + readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + left: Expression + operator: '!' | '!=' | '&&' | '*' | '+' | '-' | '/' | '<' | '<=' | '==' | '>' | '>=' | '?' | '||' + right: Expression +} + +export const BinaryExpr = 'BinaryExpr'; + +export function isBinaryExpr(item: unknown): item is BinaryExpr { + return reflection.isInstance(item, BinaryExpr); } export interface DataModel extends AstNode { readonly $container: Model; + attributes: Array fields: Array - fragments: Array name: string } @@ -36,11 +88,23 @@ export function isDataModel(item: unknown): item is DataModel { return reflection.isInstance(item, DataModel); } +export interface DataModelAttribute extends AstNode { + readonly $container: DataModel; + args: Array + decl: Reference +} + +export const DataModelAttribute = 'DataModelAttribute'; + +export function isDataModelAttribute(item: unknown): item is DataModelAttribute { + return reflection.isInstance(item, DataModelAttribute); +} + export interface DataModelField extends AstNode { - readonly $container: DataModel | Fragment; + readonly $container: DataModel; attributes: Array - fieldType: DataModelFieldType name: string + type: DataModelFieldType } export const DataModelField = 'DataModelField'; @@ -51,8 +115,8 @@ export function isDataModelField(item: unknown): item is DataModelField { export interface DataModelFieldAttribute extends AstNode { readonly $container: DataModelField; - args: Array - name: string + args: Array + decl: Reference } export const DataModelFieldAttribute = 'DataModelFieldAttribute'; @@ -65,8 +129,8 @@ export interface DataModelFieldType extends AstNode { readonly $container: DataModelField; array: boolean optional: boolean - reference?: Reference - type?: 'Boolean' | 'DateTime' | 'Float' | 'Int' | 'JSON' | 'String' + reference?: Reference + type?: 'Boolean' | 'DateTime' | 'Int' | 'JSON' | 'String' } export const DataModelFieldType = 'DataModelFieldType'; @@ -78,6 +142,7 @@ export function isDataModelFieldType(item: unknown): item is DataModelFieldType export interface DataSource extends AstNode { readonly $container: Model; fields: Array + name: string } export const DataSource = 'DataSource'; @@ -89,7 +154,7 @@ export function isDataSource(item: unknown): item is DataSource { export interface DataSourceField extends AstNode { readonly $container: DataSource; name: string - value: SimpleExpr + value: InvocationExpr | LiteralExpr } export const DataSourceField = 'DataSourceField'; @@ -112,7 +177,7 @@ export function isEnum(item: unknown): item is Enum { export interface EnumField extends AstNode { readonly $container: Enum; - value: string + name: string } export const EnumField = 'EnumField'; @@ -121,31 +186,59 @@ export function isEnumField(item: unknown): item is EnumField { return reflection.isInstance(item, EnumField); } -export interface Fragment extends AstNode { +export interface Function extends AstNode { readonly $container: Model; - fields: Array + expression?: Expression name: string + params: Array + returnType: FunctionParamType } -export const Fragment = 'Fragment'; +export const Function = 'Function'; -export function isFragment(item: unknown): item is Fragment { - return reflection.isInstance(item, Fragment); +export function isFunction(item: unknown): item is Function { + return reflection.isInstance(item, Function); } -export interface FragmentExpansion extends AstNode { - readonly $container: DataModel; - value: Reference +export interface FunctionParam extends AstNode { + readonly $container: Attribute | Function; + name: string + type: FunctionParamType } -export const FragmentExpansion = 'FragmentExpansion'; +export const FunctionParam = 'FunctionParam'; -export function isFragmentExpansion(item: unknown): item is FragmentExpansion { - return reflection.isInstance(item, FragmentExpansion); +export function isFunctionParam(item: unknown): item is FunctionParam { + return reflection.isInstance(item, FunctionParam); +} + +export interface FunctionParamType extends AstNode { + readonly $container: Function | FunctionParam; + array: boolean + reference?: Reference + type?: 'Boolean' | 'DateTime' | 'Int' | 'JSON' | 'String' +} + +export const FunctionParamType = 'FunctionParamType'; + +export function isFunctionParamType(item: unknown): item is FunctionParamType { + return reflection.isInstance(item, FunctionParamType); +} + +export interface InvocationExpr extends AstNode { + readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + args: Array + function: Reference +} + +export const InvocationExpr = 'InvocationExpr'; + +export function isInvocationExpr(item: unknown): item is InvocationExpr { + return reflection.isInstance(item, InvocationExpr); } export interface LiteralExpr extends AstNode { - readonly $container: DataModelFieldAttribute | DataSourceField | SimpleInvocationExpr; + readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; value: boolean | number | string } @@ -155,11 +248,20 @@ export function isLiteralExpr(item: unknown): item is LiteralExpr { return reflection.isInstance(item, LiteralExpr); } +export interface MemberAccessExpr extends AstNode { + readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + member: Reference + operand: Expression +} + +export const MemberAccessExpr = 'MemberAccessExpr'; + +export function isMemberAccessExpr(item: unknown): item is MemberAccessExpr { + return reflection.isInstance(item, MemberAccessExpr); +} + export interface Model extends AstNode { - datasources: Array - enums: Array - fragments: Array - models: Array + declarations: Array } export const Model = 'Model'; @@ -168,26 +270,48 @@ export function isModel(item: unknown): item is Model { return reflection.isInstance(item, Model); } -export interface SimpleInvocationExpr extends AstNode { - readonly $container: DataModelFieldAttribute | DataSourceField | SimpleInvocationExpr; - args: Array - function: string +export interface ReferenceExpr extends AstNode { + readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + target: Reference +} + +export const ReferenceExpr = 'ReferenceExpr'; + +export function isReferenceExpr(item: unknown): item is ReferenceExpr { + return reflection.isInstance(item, ReferenceExpr); +} + +export interface ThisExpr extends AstNode { + readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + value: string +} + +export const ThisExpr = 'ThisExpr'; + +export function isThisExpr(item: unknown): item is ThisExpr { + return reflection.isInstance(item, ThisExpr); +} + +export interface UnaryExpr extends AstNode { + readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + arg: Expression + operator: '!' | '+' | '-' } -export const SimpleInvocationExpr = 'SimpleInvocationExpr'; +export const UnaryExpr = 'UnaryExpr'; -export function isSimpleInvocationExpr(item: unknown): item is SimpleInvocationExpr { - return reflection.isInstance(item, SimpleInvocationExpr); +export function isUnaryExpr(item: unknown): item is UnaryExpr { + return reflection.isInstance(item, UnaryExpr); } -export type ZModelAstType = 'DataModel' | 'DataModelField' | 'DataModelFieldAttribute' | 'DataModelFieldType' | 'DataSource' | 'DataSourceField' | 'Declaration' | 'Enum' | 'EnumField' | 'Fragment' | 'FragmentExpansion' | 'LiteralExpr' | 'Model' | 'SimpleExpr' | 'SimpleInvocationExpr'; +export type ZModelAstType = 'AbstractDeclaration' | 'ArrayExpr' | 'Attribute' | 'BinaryExpr' | 'DataModel' | 'DataModelAttribute' | 'DataModelField' | 'DataModelFieldAttribute' | 'DataModelFieldType' | 'DataSource' | 'DataSourceField' | 'Enum' | 'EnumField' | 'Expression' | 'Function' | 'FunctionParam' | 'FunctionParamType' | 'InvocationExpr' | 'LiteralExpr' | 'MemberAccessExpr' | 'Model' | 'ReferenceExpr' | 'ReferenceTarget' | 'ThisExpr' | 'TypeDeclaration' | 'UnaryExpr'; -export type ZModelAstReference = 'DataModelFieldType:reference' | 'FragmentExpansion:value'; +export type ZModelAstReference = 'DataModelAttribute:decl' | 'DataModelFieldAttribute:decl' | 'DataModelFieldType:reference' | 'FunctionParamType:reference' | 'InvocationExpr:function' | 'MemberAccessExpr:member' | 'ReferenceExpr:target'; export class ZModelAstReflection implements AstReflection { getAllTypes(): string[] { - return ['DataModel', 'DataModelField', 'DataModelFieldAttribute', 'DataModelFieldType', 'DataSource', 'DataSourceField', 'Declaration', 'Enum', 'EnumField', 'Fragment', 'FragmentExpansion', 'LiteralExpr', 'Model', 'SimpleExpr', 'SimpleInvocationExpr']; + return ['AbstractDeclaration', 'ArrayExpr', 'Attribute', 'BinaryExpr', 'DataModel', 'DataModelAttribute', 'DataModelField', 'DataModelFieldAttribute', 'DataModelFieldType', 'DataSource', 'DataSourceField', 'Enum', 'EnumField', 'Expression', 'Function', 'FunctionParam', 'FunctionParamType', 'InvocationExpr', 'LiteralExpr', 'MemberAccessExpr', 'Model', 'ReferenceExpr', 'ReferenceTarget', 'ThisExpr', 'TypeDeclaration', 'UnaryExpr']; } isInstance(node: unknown, type: string): boolean { @@ -199,14 +323,29 @@ export class ZModelAstReflection implements AstReflection { return true; } switch (subtype) { + case ArrayExpr: + case BinaryExpr: + case InvocationExpr: + case LiteralExpr: + case MemberAccessExpr: + case ReferenceExpr: + case ThisExpr: + case UnaryExpr: { + return this.isSubtype(Expression, supertype); + } + case Attribute: + case DataSource: + case Function: { + return this.isSubtype(AbstractDeclaration, supertype); + } case DataModel: - case Enum: - case Fragment: { - return this.isSubtype(Declaration, supertype); + case Enum: { + return this.isSubtype(AbstractDeclaration, supertype) || this.isSubtype(TypeDeclaration, supertype); } - case LiteralExpr: - case SimpleInvocationExpr: { - return this.isSubtype(SimpleExpr, supertype); + case DataModelField: + case EnumField: + case FunctionParam: { + return this.isSubtype(ReferenceTarget, supertype); } default: { return false; @@ -216,11 +355,26 @@ export class ZModelAstReflection implements AstReflection { getReferenceType(referenceId: ZModelAstReference): string { switch (referenceId) { + case 'DataModelAttribute:decl': { + return Attribute; + } + case 'DataModelFieldAttribute:decl': { + return Attribute; + } case 'DataModelFieldType:reference': { - return Declaration; + return TypeDeclaration; + } + case 'FunctionParamType:reference': { + return TypeDeclaration; + } + case 'InvocationExpr:function': { + return Function; } - case 'FragmentExpansion:value': { - return Fragment; + case 'MemberAccessExpr:member': { + return DataModelField; + } + case 'ReferenceExpr:target': { + return ReferenceTarget; } default: { throw new Error(`${referenceId} is not a valid reference id.`); @@ -230,12 +384,36 @@ export class ZModelAstReflection implements AstReflection { getTypeMetaData(type: string): TypeMetaData { switch (type) { + case 'ArrayExpr': { + return { + name: 'ArrayExpr', + mandatory: [ + { name: 'items', type: 'array' } + ] + }; + } + case 'Attribute': { + return { + name: 'Attribute', + mandatory: [ + { name: 'params', type: 'array' } + ] + }; + } case 'DataModel': { return { name: 'DataModel', mandatory: [ - { name: 'fields', type: 'array' }, - { name: 'fragments', type: 'array' } + { name: 'attributes', type: 'array' }, + { name: 'fields', type: 'array' } + ] + }; + } + case 'DataModelAttribute': { + return { + name: 'DataModelAttribute', + mandatory: [ + { name: 'args', type: 'array' } ] }; } @@ -280,33 +458,38 @@ export class ZModelAstReflection implements AstReflection { ] }; } - case 'Fragment': { + case 'Function': { return { - name: 'Fragment', + name: 'Function', mandatory: [ - { name: 'fields', type: 'array' } + { name: 'params', type: 'array' } ] }; } - case 'Model': { + case 'FunctionParamType': { return { - name: 'Model', + name: 'FunctionParamType', mandatory: [ - { name: 'datasources', type: 'array' }, - { name: 'enums', type: 'array' }, - { name: 'fragments', type: 'array' }, - { name: 'models', type: 'array' } + { name: 'array', type: 'boolean' } ] }; } - case 'SimpleInvocationExpr': { + case 'InvocationExpr': { return { - name: 'SimpleInvocationExpr', + name: 'InvocationExpr', mandatory: [ { name: 'args', type: 'array' } ] }; } + case 'Model': { + return { + name: 'Model', + mandatory: [ + { name: 'declarations', type: 'array' } + ] + }; + } default: { return { name: type, diff --git a/packages/schema/src/language-server/generated/grammar.ts b/packages/schema/src/language-server/generated/grammar.ts index ac84c1365..1d3fc98dd 100644 --- a/packages/schema/src/language-server/generated/grammar.ts +++ b/packages/schema/src/language-server/generated/grammar.ts @@ -16,57 +16,16 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "name": "Model", "entry": true, "alternatives": { - "$type": "Alternatives", - "elements": [ - { - "$type": "Assignment", - "feature": "datasources", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataSource" - }, - "arguments": [] - } - }, - { - "$type": "Assignment", - "feature": "models", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataModel" - }, - "arguments": [] - } - }, - { - "$type": "Assignment", - "feature": "enums", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "Enum" - }, - "arguments": [] - } + "$type": "Assignment", + "feature": "declarations", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "AbstractDeclaration" }, - { - "$type": "Assignment", - "feature": "fragments", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "Fragment" - }, - "arguments": [] - } - } - ], + "arguments": [] + }, "cardinality": "*" }, "definesHiddenTokens": false, @@ -77,34 +36,44 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "DataSource", + "name": "AbstractDeclaration", "alternatives": { - "$type": "Group", + "$type": "Alternatives", "elements": [ { - "$type": "Keyword", - "value": "datasource" + "$type": "RuleCall", + "rule": { + "$refText": "DataSource" + }, + "arguments": [] }, { - "$type": "Keyword", - "value": "{" + "$type": "RuleCall", + "rule": { + "$refText": "DataModel" + }, + "arguments": [] }, { - "$type": "Assignment", - "feature": "fields", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataSourceField" - }, - "arguments": [] + "$type": "RuleCall", + "rule": { + "$refText": "Enum" }, - "cardinality": "+" + "arguments": [] }, { - "$type": "Keyword", - "value": "}" + "$type": "RuleCall", + "rule": { + "$refText": "Function" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "Attribute" + }, + "arguments": [] } ] }, @@ -117,10 +86,14 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "DataSourceField", + "name": "DataSource", "alternatives": { "$type": "Group", "elements": [ + { + "$type": "Keyword", + "value": "datasource" + }, { "$type": "Assignment", "feature": "name", @@ -135,48 +108,24 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "Keyword", - "value": "=" + "value": "{" }, { "$type": "Assignment", - "feature": "value", - "operator": "=", + "feature": "fields", + "operator": "+=", "terminal": { "$type": "RuleCall", "rule": { - "$refText": "SimpleExpr" + "$refText": "DataSourceField" }, "arguments": [] - } - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "SimpleExpr", - "alternatives": { - "$type": "Alternatives", - "elements": [ - { - "$type": "RuleCall", - "rule": { - "$refText": "SimpleInvocationExpr" }, - "arguments": [] + "cardinality": "+" }, { - "$type": "RuleCall", - "rule": { - "$refText": "LiteralExpr" - }, - "arguments": [] + "$type": "Keyword", + "value": "}" } ] }, @@ -189,13 +138,13 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "SimpleInvocationExpr", + "name": "DataSourceField", "alternatives": { "$type": "Group", "elements": [ { "$type": "Assignment", - "feature": "function", + "feature": "name", "operator": "=", "terminal": { "$type": "RuleCall", @@ -207,45 +156,31 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "Keyword", - "value": "(" + "value": "=" }, { - "$type": "Group", - "elements": [ - { - "$type": "Assignment", - "feature": "args", - "operator": "+=", - "terminal": { + "$type": "Assignment", + "feature": "value", + "operator": "=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$refText": "LiteralExpr" + }, + "arguments": [] + }, + { "$type": "RuleCall", "rule": { - "$refText": "SimpleExpr" + "$refText": "InvocationExpr" }, "arguments": [] } - }, - { - "$type": "Keyword", - "value": "," - } - ], - "cardinality": "*" - }, - { - "$type": "Assignment", - "feature": "args", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "SimpleExpr" - }, - "arguments": [] + ] } - }, - { - "$type": "Keyword", - "value": ")" } ] }, @@ -256,6 +191,23 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "parameters": [], "wildcard": false }, + { + "$type": "ParserRule", + "name": "Expression", + "alternatives": { + "$type": "RuleCall", + "rule": { + "$refText": "LogicalExpr" + }, + "arguments": [] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, { "$type": "ParserRule", "name": "LiteralExpr", @@ -286,6 +238,13 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "$refText": "STRING" }, "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "NULL" + }, + "arguments": [] } ] } @@ -299,46 +258,57 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "Enum", + "name": "ArrayExpr", "alternatives": { "$type": "Group", "elements": [ { "$type": "Keyword", - "value": "enum" - }, - { - "$type": "Assignment", - "feature": "name", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": "{" + "value": "[" }, { - "$type": "Assignment", - "feature": "fields", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "EnumField" + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "items", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "Expression" + }, + "arguments": [] + } }, - "arguments": [] - }, - "cardinality": "+" + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "," + }, + { + "$type": "Assignment", + "feature": "items", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "Expression" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ], + "cardinality": "?" }, { "$type": "Keyword", - "value": "}" + "value": "]" } ] }, @@ -351,7 +321,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "EnumField", + "name": "ThisExpr", "alternatives": { "$type": "Assignment", "feature": "value", @@ -359,7 +329,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "terminal": { "$type": "RuleCall", "rule": { - "$refText": "ID" + "$refText": "THIS" }, "arguments": [] } @@ -373,22 +343,1098 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "DataModel", + "name": "ReferenceExpr", "alternatives": { - "$type": "Group", - "elements": [ + "$type": "Assignment", + "feature": "target", + "operator": "=", + "terminal": { + "$type": "CrossReference", + "type": { + "$refText": "ReferenceTarget" + }, + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + }, + "deprecatedSyntax": false + } + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "InvocationExpr", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "function", + "operator": "=", + "terminal": { + "$type": "CrossReference", + "type": { + "$refText": "Function" + }, + "deprecatedSyntax": false + } + }, + { + "$type": "Keyword", + "value": "(" + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "ArgumentList" + }, + "arguments": [], + "cardinality": "?" + }, + { + "$type": "Keyword", + "value": ")" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "UnaryExpr", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "operator", + "operator": "=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "Keyword", + "value": "+" + }, + { + "$type": "Keyword", + "value": "-" + }, + { + "$type": "Keyword", + "value": "!" + } + ] + } + }, + { + "$type": "Assignment", + "feature": "arg", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "Expression" + }, + "arguments": [] + } + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "MemberAccessExpr", + "inferredType": { + "$type": "InferredType", + "name": "Expression" + }, + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$refText": "PrimaryExpr" + }, + "arguments": [] + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Action", + "inferredType": { + "$type": "InferredType", + "name": "MemberAccessExpr" + }, + "feature": "operand", + "operator": "=" + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "." + }, + { + "$type": "Assignment", + "feature": "member", + "operator": "=", + "terminal": { + "$type": "CrossReference", + "type": { + "$refText": "DataModelField" + }, + "deprecatedSyntax": false + } + } + ] + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "CollectionPredicateExpr", + "inferredType": { + "$type": "InferredType", + "name": "Expression" + }, + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$refText": "MemberAccessExpr" + }, + "arguments": [] + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Action", + "inferredType": { + "$type": "InferredType", + "name": "BinaryExpr" + }, + "feature": "left", + "operator": "=" + }, + { + "$type": "Assignment", + "feature": "operator", + "operator": "=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "Keyword", + "value": "?" + }, + { + "$type": "Keyword", + "value": "!" + } + ] + } + }, + { + "$type": "Keyword", + "value": "[" + }, + { + "$type": "Assignment", + "feature": "right", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "Expression" + }, + "arguments": [] + } + }, + { + "$type": "Keyword", + "value": "]" + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "MultDivExpr", + "inferredType": { + "$type": "InferredType", + "name": "Expression" + }, + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$refText": "CollectionPredicateExpr" + }, + "arguments": [] + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Action", + "inferredType": { + "$type": "InferredType", + "name": "BinaryExpr" + }, + "feature": "left", + "operator": "=" + }, + { + "$type": "Assignment", + "feature": "operator", + "operator": "=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "Keyword", + "value": "*" + }, + { + "$type": "Keyword", + "value": "/" + } + ] + } + }, + { + "$type": "Assignment", + "feature": "right", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "CollectionPredicateExpr" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "AddSubExpr", + "inferredType": { + "$type": "InferredType", + "name": "Expression" + }, + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$refText": "MultDivExpr" + }, + "arguments": [] + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Action", + "inferredType": { + "$type": "InferredType", + "name": "BinaryExpr" + }, + "feature": "left", + "operator": "=" + }, + { + "$type": "Assignment", + "feature": "operator", + "operator": "=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "Keyword", + "value": "+" + }, + { + "$type": "Keyword", + "value": "-" + } + ] + } + }, + { + "$type": "Assignment", + "feature": "right", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "MultDivExpr" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "ComparisonExpr", + "inferredType": { + "$type": "InferredType", + "name": "Expression" + }, + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$refText": "AddSubExpr" + }, + "arguments": [] + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Action", + "inferredType": { + "$type": "InferredType", + "name": "BinaryExpr" + }, + "feature": "left", + "operator": "=" + }, + { + "$type": "Assignment", + "feature": "operator", + "operator": "=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "Keyword", + "value": ">" + }, + { + "$type": "Keyword", + "value": "<" + }, + { + "$type": "Keyword", + "value": ">=" + }, + { + "$type": "Keyword", + "value": "<=" + } + ] + } + }, + { + "$type": "Assignment", + "feature": "right", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "AddSubExpr" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "EqualityExpr", + "inferredType": { + "$type": "InferredType", + "name": "Expression" + }, + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$refText": "ComparisonExpr" + }, + "arguments": [] + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Action", + "inferredType": { + "$type": "InferredType", + "name": "BinaryExpr" + }, + "feature": "left", + "operator": "=" + }, + { + "$type": "Assignment", + "feature": "operator", + "operator": "=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "Keyword", + "value": "==" + }, + { + "$type": "Keyword", + "value": "!=" + } + ] + } + }, + { + "$type": "Assignment", + "feature": "right", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ComparisonExpr" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "LogicalExpr", + "inferredType": { + "$type": "InferredType", + "name": "Expression" + }, + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$refText": "EqualityExpr" + }, + "arguments": [] + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Action", + "inferredType": { + "$type": "InferredType", + "name": "BinaryExpr" + }, + "feature": "left", + "operator": "=" + }, + { + "$type": "Assignment", + "feature": "operator", + "operator": "=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "Keyword", + "value": "&&" + }, + { + "$type": "Keyword", + "value": "||" + } + ] + } + }, + { + "$type": "Assignment", + "feature": "right", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "EqualityExpr" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "PrimaryExpr", + "inferredType": { + "$type": "InferredType", + "name": "Expression" + }, + "alternatives": { + "$type": "Alternatives", + "elements": [ + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "(" + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "Expression" + }, + "arguments": [] + }, + { + "$type": "Keyword", + "value": ")" + } + ] + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "ThisExpr" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "LiteralExpr" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "InvocationExpr" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "ArrayExpr" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "ReferenceExpr" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "UnaryExpr" + }, + "arguments": [] + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "ArgumentList", + "fragment": true, + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "args", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "Expression" + }, + "arguments": [] + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "," + }, + { + "$type": "Assignment", + "feature": "args", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "Expression" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "DataModel", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "model" + }, + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + } + }, + { + "$type": "Keyword", + "value": "{" + }, + { + "$type": "Alternatives", + "elements": [ + { + "$type": "Assignment", + "feature": "fields", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "DataModelField" + }, + "arguments": [] + } + }, + { + "$type": "Assignment", + "feature": "attributes", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "DataModelAttribute" + }, + "arguments": [] + } + } + ], + "cardinality": "+" + }, + { + "$type": "Keyword", + "value": "}" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "DataModelField", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + } + }, + { + "$type": "Assignment", + "feature": "type", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "DataModelFieldType" + }, + "arguments": [] + } + }, + { + "$type": "Assignment", + "feature": "attributes", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "DataModelFieldAttribute" + }, + "arguments": [] + }, + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "DataModelFieldType", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Alternatives", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$refText": "BuiltinType" + }, + "arguments": [] + }, + { + "$type": "Assignment", + "feature": "reference", + "operator": "=", + "terminal": { + "$type": "CrossReference", + "type": { + "$refText": "TypeDeclaration" + }, + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + }, + "deprecatedSyntax": false + } + } + ] + }, + { + "$type": "Assignment", + "feature": "array", + "operator": "?=", + "terminal": { + "$type": "Keyword", + "value": "[]" + }, + "cardinality": "?" + }, + { + "$type": "Assignment", + "feature": "optional", + "operator": "?=", + "terminal": { + "$type": "Keyword", + "value": "?" + }, + "cardinality": "?" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "Enum", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "enum" + }, + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + } + }, + { + "$type": "Keyword", + "value": "{" + }, + { + "$type": "Assignment", + "feature": "fields", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "EnumField" + }, + "arguments": [] + }, + "cardinality": "+" + }, + { + "$type": "Keyword", + "value": "}" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "EnumField", + "alternatives": { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + } + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "Function", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "function" + }, + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + } + }, + { + "$type": "Keyword", + "value": "(" + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "params", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "FunctionParam" + }, + "arguments": [] + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "," + }, + { + "$type": "Assignment", + "feature": "params", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "FunctionParam" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ], + "cardinality": "?" + }, { "$type": "Keyword", - "value": "model" + "value": ")" }, { "$type": "Assignment", - "feature": "name", + "feature": "returnType", "operator": "=", "terminal": { "$type": "RuleCall", "rule": { - "$refText": "ID" + "$refText": "FunctionParamType" }, "arguments": [] } @@ -399,29 +1445,16 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "Assignment", - "feature": "fragments", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "FragmentExpansion" - }, - "arguments": [] - }, - "cardinality": "*" - }, - { - "$type": "Assignment", - "feature": "fields", - "operator": "+=", + "feature": "expression", + "operator": "=", "terminal": { "$type": "RuleCall", "rule": { - "$refText": "DataModelField" + "$refText": "Expression" }, "arguments": [] }, - "cardinality": "+" + "cardinality": "?" }, { "$type": "Keyword", @@ -438,45 +1471,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "FragmentExpansion", - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "Keyword", - "value": "..." - }, - { - "$type": "Assignment", - "feature": "value", - "operator": "=", - "terminal": { - "$type": "CrossReference", - "type": { - "$refText": "Fragment" - }, - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - }, - "deprecatedSyntax": false - } - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "DataModelField", + "name": "FunctionParam", "alternatives": { "$type": "Group", "elements": [ @@ -494,28 +1489,15 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "Assignment", - "feature": "fieldType", + "feature": "type", "operator": "=", "terminal": { "$type": "RuleCall", "rule": { - "$refText": "DataModelFieldType" + "$refText": "FunctionParamType" }, "arguments": [] } - }, - { - "$type": "Assignment", - "feature": "attributes", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataModelFieldAttribute" - }, - "arguments": [] - }, - "cardinality": "*" } ] }, @@ -528,7 +1510,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "DataModelFieldType", + "name": "FunctionParamType", "alternatives": { "$type": "Group", "elements": [ @@ -538,7 +1520,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG { "$type": "RuleCall", "rule": { - "$refText": "FieldType" + "$refText": "BuiltinType" }, "arguments": [] }, @@ -549,7 +1531,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "terminal": { "$type": "CrossReference", "type": { - "$refText": "Declaration" + "$refText": "TypeDeclaration" }, "terminal": { "$type": "RuleCall", @@ -572,16 +1554,6 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "value": "[]" }, "cardinality": "?" - }, - { - "$type": "Assignment", - "feature": "optional", - "operator": "?=", - "terminal": { - "$type": "Keyword", - "value": "?" - }, - "cardinality": "?" } ] }, @@ -594,30 +1566,73 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "Declaration", + "name": "Attribute", "alternatives": { - "$type": "Alternatives", + "$type": "Group", "elements": [ { - "$type": "RuleCall", - "rule": { - "$refText": "DataModel" - }, - "arguments": [] + "$type": "Keyword", + "value": "attribute" }, { - "$type": "RuleCall", - "rule": { - "$refText": "Fragment" - }, - "arguments": [] + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + } }, { - "$type": "RuleCall", - "rule": { - "$refText": "Enum" - }, - "arguments": [] + "$type": "Keyword", + "value": "(" + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "params", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "FunctionParam" + }, + "arguments": [] + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "," + }, + { + "$type": "Assignment", + "feature": "params", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "FunctionParam" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ], + "cardinality": "?" + }, + { + "$type": "Keyword", + "value": ")" } ] }, @@ -640,14 +1655,14 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "Assignment", - "feature": "name", + "feature": "decl", "operator": "=", "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" + "$type": "CrossReference", + "type": { + "$refText": "Attribute" }, - "arguments": [] + "deprecatedSyntax": false } }, { @@ -658,43 +1673,11 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "value": "(" }, { - "$type": "Group", - "elements": [ - { - "$type": "Group", - "elements": [ - { - "$type": "Assignment", - "feature": "args", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "LiteralExpr" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": "," - } - ], - "cardinality": "*" - }, - { - "$type": "Assignment", - "feature": "args", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "LiteralExpr" - }, - "arguments": [] - } - } - ], + "$type": "RuleCall", + "rule": { + "$refText": "ArgumentList" + }, + "arguments": [], "cardinality": "?" }, { @@ -715,46 +1698,47 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "Fragment", + "name": "DataModelAttribute", "alternatives": { "$type": "Group", "elements": [ { "$type": "Keyword", - "value": "fragment" + "value": "@@" }, { "$type": "Assignment", - "feature": "name", + "feature": "decl", "operator": "=", "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" + "$type": "CrossReference", + "type": { + "$refText": "Attribute" }, - "arguments": [] + "deprecatedSyntax": false } }, { - "$type": "Keyword", - "value": "{" - }, - { - "$type": "Assignment", - "feature": "fields", - "operator": "+=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "DataModelField" + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "(" }, - "arguments": [] - }, - "cardinality": "+" - }, - { - "$type": "Keyword", - "value": "}" + { + "$type": "RuleCall", + "rule": { + "$refText": "ArgumentList" + }, + "arguments": [], + "cardinality": "?" + }, + { + "$type": "Keyword", + "value": ")" + } + ], + "cardinality": "?" } ] }, @@ -767,7 +1751,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "FieldType", + "name": "BuiltinType", "fragment": true, "alternatives": { "$type": "Assignment", @@ -788,10 +1772,6 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "$type": "Keyword", "value": "Int" }, - { - "$type": "Keyword", - "value": "Float" - }, { "$type": "Keyword", "value": "DateTime" @@ -833,6 +1813,32 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "fragment": false, "hidden": false }, + { + "$type": "TerminalRule", + "name": "NULL", + "terminal": { + "$type": "CharacterRange", + "left": { + "$type": "Keyword", + "value": "null" + } + }, + "fragment": false, + "hidden": false + }, + { + "$type": "TerminalRule", + "name": "THIS", + "terminal": { + "$type": "CharacterRange", + "left": { + "$type": "Keyword", + "value": "this" + } + }, + "fragment": false, + "hidden": false + }, { "$type": "TerminalRule", "name": "ID", @@ -862,7 +1868,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, "terminal": { "$type": "RegexToken", - "regex": "[0-9]+" + "regex": "[+-]?[0-9]+" }, "fragment": false, "hidden": false @@ -888,10 +1894,63 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "fragment": false } ], + "types": [ + { + "$type": "Type", + "typeAlternatives": [ + { + "$type": "AtomType", + "refType": { + "$refText": "FunctionParam" + }, + "isArray": false, + "isRef": false + }, + { + "$type": "AtomType", + "refType": { + "$refText": "DataModelField" + }, + "isArray": false, + "isRef": false + }, + { + "$type": "AtomType", + "refType": { + "$refText": "EnumField" + }, + "isArray": false, + "isRef": false + } + ], + "name": "ReferenceTarget" + }, + { + "$type": "Type", + "typeAlternatives": [ + { + "$type": "AtomType", + "refType": { + "$refText": "DataModel" + }, + "isArray": false, + "isRef": false + }, + { + "$type": "AtomType", + "refType": { + "$refText": "Enum" + }, + "isArray": false, + "isRef": false + } + ], + "name": "TypeDeclaration" + } + ], "definesHiddenTokens": false, "hiddenTokens": [], "imports": [], "interfaces": [], - "types": [], "usedGrammars": [] }`)); diff --git a/packages/schema/src/language-server/stdlib.zmodel b/packages/schema/src/language-server/stdlib.zmodel new file mode 100644 index 000000000..da8deb07b --- /dev/null +++ b/packages/schema/src/language-server/stdlib.zmodel @@ -0,0 +1,14 @@ +function env() String {} +function auth() User {} + +attribute id() +attribute default() +attribute createdAt() +attribute updatedAt() +attribute unique() +attribute cascade() +attribute allow() +attribute deny() +attribute email() +attribute url() +attribute length() diff --git a/packages/schema/src/language-server/zmodel-linker.ts b/packages/schema/src/language-server/zmodel-linker.ts new file mode 100644 index 000000000..a5c5c6eed --- /dev/null +++ b/packages/schema/src/language-server/zmodel-linker.ts @@ -0,0 +1,369 @@ +import { + AstNode, + AstNodeDescription, + AstNodeDescriptionProvider, + DefaultLinker, + DocumentState, + interruptAndCheck, + isReference, + LangiumDocument, + LangiumServices, + LinkingError, + Reference, + streamContents, +} from 'langium'; +import { CancellationToken } from 'vscode-jsonrpc'; +import { + AbstractDeclaration, + isDataModel, + isEnumField, + Function, + FunctionParamType, + DataModelFieldType, + ReferenceTarget, + MemberAccessExpr, + DataModel, + LiteralExpr, + InvocationExpr, + ArrayExpr, + ReferenceExpr, + UnaryExpr, + BinaryExpr, +} from './generated/ast'; + +interface DefaultReference extends Reference { + _ref?: AstNode | LinkingError; + _nodeDescription?: AstNodeDescription; +} + +type TypedNode = AstNode & { + $resolvedType?: { + decl?: string | AbstractDeclaration; + array?: boolean; + }; +}; + +type ScopeProvider = (name: string) => ReferenceTarget | undefined; + +export class ZModelLinker extends DefaultLinker { + private readonly descriptions: AstNodeDescriptionProvider; + + constructor(services: LangiumServices) { + super(services); + this.descriptions = services.workspace.AstNodeDescriptionProvider; + } + + async link( + document: LangiumDocument, + cancelToken = CancellationToken.None + ): Promise { + if ( + document.parseResult.lexerErrors?.length > 0 || + document.parseResult.parserErrors?.length > 0 + ) { + return; + } + + for (const node of streamContents(document.parseResult.value)) { + await interruptAndCheck(cancelToken); + this.resolve(node, document); + } + document.state = DocumentState.Linked; + } + + linkReference( + container: AstNode, + property: string, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + if ( + !this.resolveFromScopeProviders( + container, + property, + document, + extraScopes + ) + ) { + const reference: Reference = (container as any)[property]; + this.doLink({ reference, container, property }, document); + } + } + + resolveFromScopeProviders( + node: AstNode, + property: string, + document: LangiumDocument, + providers: ScopeProvider[] + ) { + const reference: DefaultReference = (node as any)[property]; + for (const provider of providers) { + const target = provider(reference.$refText); + if (target) { + reference._ref = target; + reference._nodeDescription = + this.descriptions.createDescription( + target, + target.name, + document + ); + return target; + } + } + return null; + } + + resolve( + node: AstNode, + document: LangiumDocument, + extraScopes: ScopeProvider[] = [] + ) { + switch (node.$type) { + case LiteralExpr: + this.resolveLiteral(node as LiteralExpr); + break; + + case InvocationExpr: + this.resolveInvocation( + node as InvocationExpr, + document, + extraScopes + ); + break; + + case ArrayExpr: + this.resolveArray(node as ArrayExpr, document, extraScopes); + break; + + case ReferenceExpr: + this.resolveReference( + node as ReferenceExpr, + document, + extraScopes + ); + break; + + case MemberAccessExpr: + this.resolveMemberAccess( + node as MemberAccessExpr, + document, + extraScopes + ); + break; + + case UnaryExpr: + this.resolveUnary(node as UnaryExpr, document, extraScopes); + break; + + case BinaryExpr: + this.resolveBinary(node as BinaryExpr, document, extraScopes); + break; + + default: + this.resolveDefault(node, document, extraScopes); + break; + } + } + + resolveDefault( + node: AstNode, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + for (const property of Object.keys(node)) { + if (!property.startsWith('$')) { + const value = (node as any)[property]; + if (isReference(value)) { + this.linkReference(node, property, document, extraScopes); + } + } + } + for (const child of streamContents(node)) { + this.resolve(child, document, extraScopes); + } + } + + resolveBinary( + node: BinaryExpr, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + this.resolve(node.left, document, extraScopes); + this.resolve(node.right, document, extraScopes); + switch (node.operator) { + case '+': + case '-': + case '*': + case '/': + this.resolveToBuiltinTypeOrDecl(node, 'Int'); + break; + + case '>': + case '>=': + case '<': + case '<=': + case '==': + case '!=': + case '&&': + case '||': + this.resolveToBuiltinTypeOrDecl(node, 'Boolean'); + break; + + case '?': + this.resolveCollectionPredicate(node, document, extraScopes); + break; + + default: + throw Error(`Unsupported binary operator: ${node.operator}`); + } + } + + resolveUnary( + node: UnaryExpr, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + this.resolve(node.arg, document, extraScopes); + (node as TypedNode).$resolvedType = ( + node.arg as TypedNode + ).$resolvedType; + } + + resolveReference( + node: ReferenceExpr, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + this.linkReference(node, 'target', document, extraScopes); + + if (node.target.ref) { + // resolve type + if (isEnumField(node.target.ref)) { + this.resolveToBuiltinTypeOrDecl( + node, + node.target.ref.$container + ); + } else { + this.resolveToDeclaredType(node, node.target.ref.type); + } + } + } + + resolveArray( + node: ArrayExpr, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + node.items.forEach((item) => this.resolve(item, document, extraScopes)); + + const itemType = (node.items[0] as TypedNode).$resolvedType; + if (itemType?.decl) { + this.resolveToBuiltinTypeOrDecl(node, itemType.decl, true); + } + } + + resolveInvocation( + node: InvocationExpr, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + this.linkReference(node, 'function', document, extraScopes); + node.args.forEach((arg) => this.resolve(arg, document, extraScopes)); + const funcDecl = node.function.ref as Function; + this.resolveToDeclaredType(node, funcDecl.returnType); + } + + resolveLiteral(node: LiteralExpr) { + const type = + typeof node.value === 'string' + ? 'String' + : typeof node.value === 'boolean' + ? 'Boolean' + : typeof node.value === 'number' + ? 'Int' + : undefined; + + if (type) { + this.resolveToBuiltinTypeOrDecl(node, type); + } + } + + resolveMemberAccess( + node: MemberAccessExpr, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + this.resolve(node.operand, document, extraScopes); + const operandResolved = (node.operand as TypedNode).$resolvedType; + + if ( + operandResolved && + !operandResolved.array && + isDataModel(operandResolved.decl) + ) { + const modelDecl = operandResolved.decl as DataModel; + const provider = (name: string) => + modelDecl.fields.find((f) => f.name === name); + extraScopes = [provider, ...extraScopes]; + } + + this.linkReference(node, 'member', document, extraScopes); + if (node.member.ref) { + this.resolveToDeclaredType(node, node.member.ref.type); + } + } + + resolveCollectionPredicate( + node: BinaryExpr, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + this.resolve(node.left, document, extraScopes); + + const resolvedType = this.getResolvedType(node.left); + if ( + resolvedType && + isDataModel(resolvedType.decl) && + resolvedType.array + ) { + const dataModelDecl = resolvedType.decl; + const provider = (name: string) => + dataModelDecl.fields.find((f) => f.name === name); + extraScopes = [provider, ...extraScopes]; + this.resolve(node.right, document, extraScopes); + this.resolveToBuiltinTypeOrDecl(node, 'Boolean'); + } else { + // TODO: how to attach type-checking error? + throw new Error(`Unresolved collection predicate`); + } + } + + // utils + + getResolvedType(node: AstNode) { + return (node as TypedNode).$resolvedType; + } + + resolveToDeclaredType( + node: AstNode, + type: FunctionParamType | DataModelFieldType + ) { + const _node: TypedNode = node; + if (type.type) { + _node.$resolvedType = { decl: type.type, array: type.array }; + } else if (type.reference) { + _node.$resolvedType = { + decl: type.reference.ref, + array: type.array, + }; + } + } + + resolveToBuiltinTypeOrDecl( + node: AstNode, + type: string | AbstractDeclaration, + array = false + ) { + (node as TypedNode).$resolvedType = { decl: type, array }; + } +} diff --git a/packages/schema/src/language-server/zmodel-module.ts b/packages/schema/src/language-server/zmodel-module.ts index 76fc332f6..14e7850ad 100644 --- a/packages/schema/src/language-server/zmodel-module.ts +++ b/packages/schema/src/language-server/zmodel-module.ts @@ -12,6 +12,8 @@ import { ZModelGeneratedModule, ZModelGeneratedSharedModule, } from './generated/module'; +import { ZModelLinker } from './zmodel-linker'; +import { ZModelScopeComputation } from './zmodel-scope'; import { ZModelValidationRegistry, ZModelValidator } from './zmodel-validator'; /** @@ -38,6 +40,11 @@ export const ZModelModule: Module< ZModelServices, PartialLangiumServices & ZModelAddedServices > = { + references: { + ScopeComputation: (services) => new ZModelScopeComputation(services), + Linker: (services) => new ZModelLinker(services), + // NameProvider: () => new ZModelNameProvider(), + }, validation: { ValidationRegistry: (services) => new ZModelValidationRegistry(services), diff --git a/packages/schema/src/language-server/zmodel-scope.ts b/packages/schema/src/language-server/zmodel-scope.ts new file mode 100644 index 000000000..2d59b6a6b --- /dev/null +++ b/packages/schema/src/language-server/zmodel-scope.ts @@ -0,0 +1,46 @@ +import { + DefaultScopeComputation, + LangiumDocument, + LangiumServices, + PrecomputedScopes, + streamAllContents, +} from 'langium'; +import { CancellationToken } from 'vscode-jsonrpc'; +import { Model, isEnum, Enum, isReferenceExpr } from './generated/ast'; + +export class ZModelScopeComputation extends DefaultScopeComputation { + constructor(services: LangiumServices) { + super(services); + } + + async computeScope( + document: LangiumDocument, + cancelToken = CancellationToken.None + ): Promise { + const scopes = await super.computeScope(document, cancelToken); + + const model = document.parseResult.value as Model; + + const enumDecls = model.declarations.filter((d) => isEnum(d)) as Enum[]; + const enumFieldDescriptions = enumDecls + .map((d) => + d.fields.map((f) => + this.descriptions.createDescription(f, f.name, document) + ) + ) + .flat(); + + // add enum field names to scopes of containers of any ReferenceExpr so that + // fully qualified references can be resolved + const refContainers = streamAllContents(model) + .filter((node) => isReferenceExpr(node) && node.$container) + .map((node) => node.$container!) + .distinct(); + + refContainers.forEach((c) => { + enumFieldDescriptions.forEach((desc) => scopes.add(c, desc)); + }); + + return scopes; + } +} diff --git a/packages/schema/src/language-server/zmodel.langium b/packages/schema/src/language-server/zmodel.langium index dc40d1a7d..0b547c5f6 100644 --- a/packages/schema/src/language-server/zmodel.langium +++ b/packages/schema/src/language-server/zmodel.langium @@ -1,64 +1,162 @@ grammar ZModel entry Model: - (datasources+=DataSource | models+=DataModel | enums+=Enum | fragments+=Fragment )*; + ( + declarations+=AbstractDeclaration + )*; + +AbstractDeclaration: + DataSource | DataModel | Enum | Function | Attribute; // datasource DataSource: - 'datasource' '{' (fields+=DataSourceField)+ '}'; + 'datasource' name=ID '{' (fields+=DataSourceField)+ '}'; DataSourceField: - (name=ID '=' value=SimpleExpr); - -SimpleExpr: - SimpleInvocationExpr | LiteralExpr; + (name=ID '=' value=(LiteralExpr|InvocationExpr)); -SimpleInvocationExpr: - function=ID '(' (args+=SimpleExpr ',')* args+=SimpleExpr ')'; +// expression +Expression: + LogicalExpr; LiteralExpr: - value=(BOOLEAN | INT | STRING); + value=(BOOLEAN | INT | STRING | NULL); + +ArrayExpr: + '[' (items+=Expression (',' items+=Expression)*)? ']'; + +type ReferenceTarget = FunctionParam | DataModelField | EnumField; + +ThisExpr: + value=THIS; + +ReferenceExpr: + target=[ReferenceTarget:ID]; + +InvocationExpr: + function=[Function] '(' ArgumentList? ')'; + +UnaryExpr: + operator=('+'|'-'|'!') arg=Expression; + +// binary operator precedence follow Javascript's rules: +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table + +MemberAccessExpr infers Expression: + PrimaryExpr ( + {infer MemberAccessExpr.operand=current} + ('.' member=[DataModelField]) + )*; + +CollectionPredicateExpr infers Expression: + MemberAccessExpr ( + {infer BinaryExpr.left=current} + operator=('?'|'!') + '[' right=Expression ']' + )*; + +MultDivExpr infers Expression: + CollectionPredicateExpr ( + {infer BinaryExpr.left=current} + operator=('*'|'/') + right=CollectionPredicateExpr + )*; + +AddSubExpr infers Expression: + MultDivExpr ( + {infer BinaryExpr.left=current} + operator=('+'|'-') + right=MultDivExpr + )*; + +ComparisonExpr infers Expression: + AddSubExpr ( + {infer BinaryExpr.left=current} + operator=('>'|'<'|'>='|'<=') + right=AddSubExpr + )*; + +EqualityExpr infers Expression: + ComparisonExpr ( + {infer BinaryExpr.left=current} + operator=('=='|'!=') + right=ComparisonExpr + )*; + +LogicalExpr infers Expression: + EqualityExpr ( + {infer BinaryExpr.left=current} + operator=('&&'|'||') + right=EqualityExpr + )*; + +PrimaryExpr infers Expression: + '(' Expression ')' | + ThisExpr | + LiteralExpr | + InvocationExpr | + ArrayExpr| + ReferenceExpr | + UnaryExpr; + +fragment ArgumentList: + args+=Expression (',' args+=Expression)*; + +// model +DataModel: + 'model' name=ID '{' ( + fields+=DataModelField + | attributes+=DataModelAttribute + )+ + '}'; + +DataModelField: + name=ID type=DataModelFieldType (attributes+=DataModelFieldAttribute)*; + +DataModelFieldType: + (BuiltinType | reference=[TypeDeclaration:ID]) (array?='[]')? (optional?='?')?; // enum Enum: 'enum' name=ID '{' (fields+=EnumField)+ '}'; EnumField: - value=ID; + name=ID; -// model -DataModel: - 'model' name=ID '{' (fragments+=FragmentExpansion)* (fields+=DataModelField)+ '}'; +// function +Function: + 'function' name=ID '(' (params+=FunctionParam (',' params+=FunctionParam)*)? ')' returnType=FunctionParamType '{' (expression=Expression)? '}'; -FragmentExpansion: - '...' value=[Fragment:ID]; +FunctionParam: + name=ID type=FunctionParamType; -DataModelField: - name=ID fieldType=DataModelFieldType (attributes+=DataModelFieldAttribute)*; +FunctionParamType: + (BuiltinType | reference=[TypeDeclaration:ID]) (array?='[]')?; -DataModelFieldType: - (FieldType - | reference=[Declaration:ID] - ) (array?='[]')? (optional?='?')?; +// attribute +Attribute: + 'attribute' name=ID '(' (params+=FunctionParam (',' params+=FunctionParam)*)? ')'; -Declaration: - DataModel | Fragment | Enum; +type TypeDeclaration = DataModel | Enum; DataModelFieldAttribute: - '@' name=ID - ('(' ((args+=LiteralExpr ',')* args+=LiteralExpr)? ')')?; + '@' decl=[Attribute] ('(' ArgumentList? ')')?; + +DataModelAttribute: + '@@' decl=[Attribute] ('(' ArgumentList? ')')?; -// fragment -Fragment: - 'fragment' name=ID '{' (fields+=DataModelField)+ '}'; +fragment BuiltinType: + type=('String'|'Boolean'|'Int'|'DateTime'|'JSON'); -fragment FieldType: - type=('String'|'Boolean'|'Int'|'Float'|'DateTime'|'JSON'); +// QualifiedName returns string: +// ID ('.' ID)*; hidden terminal WS: /\s+/; terminal BOOLEAN returns boolean: /true|false/; +terminal NULL: 'null'; +terminal THIS: 'this'; terminal ID: /[_a-zA-Z][\w_]*/; terminal STRING: /"[^"]*"|'[^']*'/; -terminal INT returns number: /[0-9]+/; +terminal INT returns number: /[+-]?[0-9]+/; hidden terminal ML_COMMENT: /\/\*[\s\S]*?\*\//; hidden terminal SL_COMMENT: /\/\/[^\n\r]*/; diff --git a/packages/schema/syntaxes/zmodel.tmLanguage.json b/packages/schema/syntaxes/zmodel.tmLanguage.json index e21238bc3..552dee1a3 100644 --- a/packages/schema/syntaxes/zmodel.tmLanguage.json +++ b/packages/schema/syntaxes/zmodel.tmLanguage.json @@ -10,7 +10,7 @@ }, { "name": "keyword.control.zmodel", - "match": "\\b(Boolean|datasource|DateTime|enum|Float|fragment|Int|JSON|model|String)\\b" + "match": "\\b(attribute|Boolean|datasource|DateTime|enum|function|Int|JSON|model|String)\\b" }, { "name": "string.quoted.double.zmodel", diff --git a/packages/schema/tests/basic.test.ts b/packages/schema/tests/basic.test.ts deleted file mode 100644 index 01fb32f69..000000000 --- a/packages/schema/tests/basic.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { parse } from './utils'; - -describe('Basic Tests', () => { - it('functions', async () => { - const content = ` - function userInSpace(user, space) { - exists(SpaceUser, $.space == space && $.user == user) - } - `; - await parse(content); - }); - - it('feature coverage', async () => { - const content = ` - datasource { - provider = 'postgresql' - url = env('DATABASE_URL') - } - - fragment CommonFields { - id String @id - createdBy User @createdBy - updatedBy User @updatedBy - createdAt DateTime @createdAt - updatedAt DateTime @updatedAt - } - - model Space - @deny('all', auth() == null) - @allow('create', true) - @allow('read', userInSpace(auth(), $this)) - @allow('update,delete', userIsSpaceAdmin(auth(), $this)) { - ...CommonFields - name String - slug String @unique - members SpaceUser[] @cascade - todoLists TodoList[] @cascade - } - - enum SpaceUserRole { - USER - ADMIN - } - - model SpaceUser - @deny('all', auth() == null) - @allow('create,update,delete', userIsSpaceAdmin(auth(), $this.space)) - @allow('read', userInSpace(auth(), $this.space)) { - ...CommonFields - space Space - user User - role SpaceUserRole - } - - model User - @deny('all', auth() == null) - @allow('create', true) - @allow('read', userInAnySpace(auth(), spaces)) - @allow('update,delete', auth() == $this) { - ...CommonFields - email String @unique - name String? - todoList TodoList[] - spaces SpaceUser[] @cascade - profile Profile? @cascade - } - - model Profile - @deny('all', auth() == null) - @allow('read', userInAnySpace(auth(), $this.user.spaces)) - @allow('create,update,delete', $this.user == auth()) { - ...CommonFields - user User @unique - avatar String? - } - - model TodoList - @deny('all', auth() == null) - @allow('read', $this.owner == auth() || (userInSpace(auth(), $this.space) && !$this.private)) - @allow('create,update,delete', $this.owner == auth() && userInSpace(auth(), $this.space)) { - ...CommonFields - space Space - owner User - title String - content String - private Boolean @default(true) - todos Todo[] @cascade - } - - model Todo - @deny('all', auth() == null) - @allow('all', $this.todoList.owner == auth() || (userInSpace(auth(), $this.todoList.space) && !$this.todoList.private)) { - ...CommonFields - owner User - todoList TodoList - title String - completedAt DateTime? - } - - function userInSpace(user, space) { - exists(SpaceUser, $.space == space && $.user == user) - } - - function userIsSpaceAdmin(user, space) { - exists(SpaceUser, $.space == space && $.user == user && $.role == ADMIN) - } - - function userInAnySpace(user, spaces) { - find(spaces, $.user == user) - } - `; - - const model = await parse(content); - - console.log('Dump AST:', model); - }); -}); diff --git a/packages/schema/tests/parser.test.ts b/packages/schema/tests/parser.test.ts new file mode 100644 index 000000000..a076992d9 --- /dev/null +++ b/packages/schema/tests/parser.test.ts @@ -0,0 +1,365 @@ +import { + ArrayExpr, + BinaryExpr, + ReferenceExpr, + LiteralExpr, + UnaryExpr, + InvocationExpr, + DataSource, + Enum, + DataModel, + Function, +} from '../src/language-server/generated/ast'; +import { parse } from './utils'; + +describe('Basic Tests', () => { + it('data source', async () => { + const content = ` + datasource db { + provider = 'postgresql' + url = env('DATABASE_URL') + } + `; + const doc = await parse(content); + expect(doc.declarations).toHaveLength(1); + const ds = doc.declarations[0] as DataSource; + + expect(ds.name).toBe('db'); + expect(ds.fields).toHaveLength(2); + + expect(ds.fields[0]).toEqual( + expect.objectContaining({ + name: 'provider', + value: expect.objectContaining({ value: 'postgresql' }), + }) + ); + expect(ds.fields[1].name).toBe('url'); + expect((ds.fields[1].value as InvocationExpr).function.ref?.name).toBe( + 'env' + ); + expect((ds.fields[1].value as InvocationExpr).args[0].$type).toBe( + LiteralExpr + ); + }); + + it('enum', async () => { + const content = ` + enum UserRole { + USER + ADMIN + } + + model User { + role UserRole @default(USER) + } + `; + const doc = await parse(content); + const enumDecl = doc.declarations[0] as Enum; + expect(enumDecl).toEqual( + expect.objectContaining({ + name: 'UserRole', + fields: expect.arrayContaining([ + expect.objectContaining({ + name: 'USER', + }), + expect.objectContaining({ + name: 'ADMIN', + }), + ]), + }) + ); + + const model = doc.declarations[1] as DataModel; + expect(model.fields[0].type.reference?.ref?.name).toBe('UserRole'); + + const attrVal = model.fields[0].attributes[0].args[0] as ReferenceExpr; + expect(attrVal.$type).toBe(ReferenceExpr); + expect(attrVal.target.ref?.name).toBe('USER'); + expect((attrVal.target.ref?.$container as Enum).name).toBe('UserRole'); + }); + + it('model field types', async () => { + const content = ` + model User { + id String + age Int + activated Boolean + createdAt DateTime + metadata JSON + } + `; + const doc = await parse(content); + const model = doc.declarations[0] as DataModel; + expect(model.fields).toHaveLength(5); + expect(model.fields.map((f) => f.type.type)).toEqual( + expect.arrayContaining([ + 'String', + 'Int', + 'Boolean', + 'JSON', + 'DateTime', + ]) + ); + }); + + it('model field modifiers', async () => { + const content = ` + model User { + name String? + tags String[] + } + `; + const doc = await parse(content); + const model = doc.declarations[0] as DataModel; + expect(model.fields[0].type.optional).toBeTruthy(); + expect(model.fields[1].type.array).toBeTruthy(); + }); + + it('model field attributes', async () => { + const content = ` + model User { + id String @id + activated Boolean @default(false) @unique + } + `; + const doc = await parse(content); + const model = doc.declarations[0] as DataModel; + expect(model.fields[0].attributes[0].decl.ref?.name).toBe('id'); + expect(model.fields[1].attributes[0]).toEqual( + expect.objectContaining({ + args: expect.arrayContaining([ + expect.objectContaining({ value: false }), + ]), + }) + ); + expect(model.fields[1].attributes[1].decl.ref?.name).toBe('unique'); + }); + + it('model attributes', async () => { + const content = ` + model Model { + a String + b String + @@unique([a, b]) + } + `; + const doc = await parse(content); + const model = doc.declarations[0] as DataModel; + expect(model.attributes).toHaveLength(1); + expect(model.attributes[0].decl.ref?.name).toBe('unique'); + expect( + (model.attributes[0].args[0] as ArrayExpr).items.map( + (item: any) => item.target?.ref?.name + ) + ).toEqual(expect.arrayContaining(['a', 'b'])); + }); + + it('model relation', async () => { + const content = ` + model User { + id String + posts Post[] + } + + model Post { + id String + owner User @cascade + } + `; + const doc = await parse(content); + const models = doc.declarations as DataModel[]; + expect(models[0].fields[1].type.reference?.ref?.name === 'Post'); + expect(models[1].fields[1].type.reference?.ref?.name === 'User'); + }); + + it('policy expressions', async () => { + const content = ` + model Model { + a Int + b Int + c Boolean + + @@deny(!c) + @@deny(a < 0) + @@deny(a + b < 10) + } + `; + const doc = await parse(content); + const model = doc.declarations[0] as DataModel; + const attrs = model.attributes; + + expect(attrs[0].args[0].$type).toBe(UnaryExpr); + expect((attrs[0].args[0] as UnaryExpr).arg.$type).toBe(ReferenceExpr); + + expect(attrs[1].args[0].$type).toBe(BinaryExpr); + expect((attrs[1].args[0] as BinaryExpr).left.$type).toBe(ReferenceExpr); + expect((attrs[1].args[0] as BinaryExpr).right.$type).toBe(LiteralExpr); + + expect(attrs[1].args[0].$type).toBe(BinaryExpr); + expect((attrs[1].args[0] as BinaryExpr).left.$type).toBe(ReferenceExpr); + expect((attrs[1].args[0] as BinaryExpr).right.$type).toBe(LiteralExpr); + + expect(attrs[2].args[0].$type).toBe(BinaryExpr); + expect((attrs[2].args[0] as BinaryExpr).left.$type).toBe(BinaryExpr); + }); + + it('policy expression precedence', async () => { + const content = ` + model Model { + a Int + b Int + @@deny(a + b * 2 > 0) + @@deny((a + b) * 2 > 0) + @@deny(a > 0 && b < 0) + @@deny(a >= 0 && b <= 0) + @@deny(a == 0 || b != 0) + } + `; + const doc = await parse(content); + const attrs = (doc.declarations[0] as DataModel).attributes; + + expect(attrs[0].args[0].$type).toBe(BinaryExpr); + + // 1: a + b * 2 > 0 + + // > + expect((attrs[0].args[0] as BinaryExpr).operator).toBe('>'); + + // a + b * 2 + expect((attrs[0].args[0] as BinaryExpr).left.$type).toBe(BinaryExpr); + + // 0 + expect((attrs[0].args[0] as BinaryExpr).right.$type).toBe(LiteralExpr); + + // + + expect( + ((attrs[0].args[0] as BinaryExpr).left as BinaryExpr).operator + ).toBe('+'); + + // a + expect( + ((attrs[0].args[0] as BinaryExpr).left as BinaryExpr).left.$type + ).toBe(ReferenceExpr); + + // b * 2 + expect( + ((attrs[0].args[0] as BinaryExpr).left as BinaryExpr).right.$type + ).toBe(BinaryExpr); + + // 2: (a + b) * 2 > 0 + + // > + expect((attrs[1].args[0] as BinaryExpr).operator).toBe('>'); + + // (a + b) * 2 + expect((attrs[1].args[0] as BinaryExpr).left.$type).toBe(BinaryExpr); + + // 0 + expect((attrs[1].args[0] as BinaryExpr).right.$type).toBe(LiteralExpr); + + // * + expect( + ((attrs[1].args[0] as BinaryExpr).left as BinaryExpr).operator + ).toBe('*'); + + // (a + b) + expect( + ((attrs[1].args[0] as BinaryExpr).left as BinaryExpr).left.$type + ).toBe(BinaryExpr); + + // a + expect( + ( + ((attrs[1].args[0] as BinaryExpr).left as BinaryExpr) + .left as BinaryExpr + ).left.$type + ).toBe(ReferenceExpr); + + // b + expect( + ( + ((attrs[1].args[0] as BinaryExpr).left as BinaryExpr) + .left as BinaryExpr + ).right.$type + ).toBe(ReferenceExpr); + + // 2 + expect( + ((attrs[1].args[0] as BinaryExpr).left as BinaryExpr).right.$type + ).toBe(LiteralExpr); + }); + + it('function', async () => { + const content = ` + model M { + a Int + b Int + c N[] + @@deny(foo(a, b)) + @@deny(bar(c)) + } + + model N { + x Int + } + + function foo(a Int, b Int) Boolean { + } + + function bar(items N[]) Boolean { + } + `; + const doc = await parse(content); + const model = doc.declarations[0] as DataModel; + const foo = doc.declarations[2] as Function; + const bar = doc.declarations[3] as Function; + + expect(foo.name).toBe('foo'); + expect(foo.params.map((p) => p.type.type)).toEqual( + expect.arrayContaining(['Int', 'Int']) + ); + + expect(bar.name).toBe('bar'); + expect(bar.params[0].type.reference?.ref?.name).toBe('N'); + expect(bar.params[0].type.array).toBeTruthy(); + + expect(model.attributes[0].args[0].$type).toBe(InvocationExpr); + }); + + it('member access', async () => { + const content = ` + model M { + a N + @@deny(a.x.y < 0) + @@deny(foo(a)) + } + + model N { + x P + } + + model P { + y Int + } + + function foo(n N) Boolean { + n.x < 0 + } + `; + await parse(content); + }); + + it('collection predicate', async () => { + const content = ` + model M { + a N[] + @@deny(a?[x < 0]) + } + + model N { + x Int + } + `; + await parse(content); + }); +}); diff --git a/packages/schema/tests/todo-sample.test.ts b/packages/schema/tests/todo-sample.test.ts new file mode 100644 index 000000000..5619027bc --- /dev/null +++ b/packages/schema/tests/todo-sample.test.ts @@ -0,0 +1,120 @@ +import { parse } from './utils'; + +describe('Basic Tests', () => { + it('sample todo schema', async () => { + const content = ` + /* + * A sample model for a collaborative Todo app + */ + + // Datasource + datasource db { + provider = 'postgresql' + url = env('DATABASE_URL') + } + + enum SpaceUserRole { + USER + ADMIN + } + + model Space { + id String @id + createdAt DateTime @createdAt + updatedAt DateTime @updatedAt + name String @length(1, 100) + slug String @unique @length(1, 20) + members SpaceUser[] + + // require login + @@deny('all', auth() == null) + // everyone can create a space + @@allow('create', true) + + // any user in the space can read the space + @@allow('read', members?[user == auth()]) + + // space admin can update and delete + @@allow('update,delete', members?[user == auth() && role == ADMIN]) + } + + model SpaceUser { + id String @id + createdAt DateTime @createdAt + updatedAt DateTime @updatedAt + space Space @cascade + user User @cascade + role SpaceUserRole + todoLists TodoList[] + + @@unique([user, space]) + + // require login + @@deny('all', auth() == null) + + // space admin can create/update/delete + @@allow('create,update,delete', space.members?[user == auth() && role == ADMIN]) + + // user can read entries for spaces which he's a member of + @@allow('read', space.members?[user == auth()]) + } + + model User { + id String @id + createdAt DateTime @createdAt + updatedAt DateTime @updatedAt + email String @unique @email + name String? @length(1, 100) + spaces SpaceUser[] + image String? @url + todoLists TodoList[] + + // can be created by anyone, even not logged in + @@allow('create', true) + + // can be read by users sharing any space + @@allow('read', spaces?[auth() == user]) + + // can only be updated and deleted by himeself + @@allow('update,delete', auth() == this) + } + + model TodoList { + id String @id + createdAt DateTime @createdAt + updatedAt DateTime @updatedAt + space Space @cascade + owner User + title String @length(1, 20) + private Boolean @default(false) + todos Todo[] + + // require login + @@deny('all', auth() == null) + + // can be read by owner or space members (only if not private) + @@allow('read', owner == auth() || (space.members?[user == auth()] && !private)) + + // can be created/updated/deleted by owner + @@allow('create,update,delete', owner == auth() && space.members?[user == auth()]) + } + + model Todo { + id String @id + createdAt DateTime @createdAt + updatedAt DateTime @updatedAt + owner User + todoList TodoList @cascade + title String + completedAt DateTime? + + // require login + @@deny('all', auth() == null) + + // owner has full access, also space members have full access (if the parent TodoList is not private) + @@allow('all', todoList.owner == auth() || (todoList.space.members?[user == auth()] && !todoList.private)) + } + `; + await parse(content); + }); +}); diff --git a/packages/schema/tests/utils.ts b/packages/schema/tests/utils.ts index c8166a1ce..7a835f207 100644 --- a/packages/schema/tests/utils.ts +++ b/packages/schema/tests/utils.ts @@ -1,14 +1,26 @@ import { DefaultLangiumDocumentFactory } from 'langium'; import { createZModelServices } from '../src/language-server/zmodel-module'; import { URI } from 'vscode-uri'; -import { v4 as uuid } from 'uuid'; +import * as fs from 'fs'; +import * as path from 'path'; import { Model } from '../src/language-server/generated/ast'; +import * as tmp from 'tmp'; export async function parse(content: string) { + const { name: docPath } = tmp.fileSync({ postfix: '.zmodel' }); + fs.writeFileSync(docPath, content); const { shared } = createZModelServices(); const factory = new DefaultLangiumDocumentFactory(shared); - const doc = factory.fromString(content, URI.parse(`zmodel://${uuid()}`)); - await shared.workspace.DocumentBuilder.build([doc], { + const stdLib = factory.fromString( + fs.readFileSync('src/language-server/stdlib.zmodel', { + encoding: 'utf-8', + }), + URI.file(path.resolve('src/language-server/stdlib.zmodel')) + ); + const doc = factory.fromString(content, URI.file(docPath)); + shared.workspace.LangiumDocuments.addDocument(stdLib); + shared.workspace.LangiumDocuments.addDocument(doc); + await shared.workspace.DocumentBuilder.build([stdLib, doc], { validationChecks: 'all', }); diff --git a/packages/schema/tsconfig.json b/packages/schema/tsconfig.json index ca965e342..7e1e74338 100644 --- a/packages/schema/tsconfig.json +++ b/packages/schema/tsconfig.json @@ -1,23 +1,18 @@ { - "compilerOptions": { - "target": "ES6", - "module": "commonjs", - "lib": ["ESNext"], - "sourceMap": true, - "outDir": "out", - "strict": true, - "noUnusedLocals": true, - "noImplicitReturns": true, - "moduleResolution": "node", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": [ - "src/**/*.ts" - ], - "exclude": [ - "out", - "node_modules" - ] + "compilerOptions": { + "target": "ES6", + "module": "commonjs", + "lib": ["ESNext"], + "sourceMap": true, + "outDir": "out", + "strict": true, + "noUnusedLocals": true, + "noImplicitReturns": true, + "moduleResolution": "node", + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*.ts"], + "exclude": ["out", "node_modules"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7c9d2c3f0..05919c30c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,7 +29,8 @@ importers: packages/schema: specifiers: '@types/jest': ^29.0.3 - '@types/node': ^14.17.3 + '@types/node': ^14.18.29 + '@types/tmp': ^0.2.3 '@types/uuid': ^8.3.4 '@types/vscode': ^1.56.0 '@typescript-eslint/eslint-plugin': ^4.14.1 @@ -42,6 +43,7 @@ importers: jest: ^29.0.3 langium: ^0.4.0 langium-cli: ^0.4.0 + tmp: ^0.2.1 ts-jest: ^29.0.1 ts-node: ^10.9.1 typescript: ^4.6.2 @@ -61,6 +63,7 @@ importers: devDependencies: '@types/jest': 29.0.3 '@types/node': 14.18.29 + '@types/tmp': 0.2.3 '@types/uuid': 8.3.4 '@types/vscode': 1.71.0 '@typescript-eslint/eslint-plugin': 4.33.0_qkm6m2dvh7633pj2jigehwm774 @@ -69,7 +72,8 @@ importers: eslint: 7.32.0 jest: 29.0.3_johvxhudwcpndp4mle25vwrlq4 langium-cli: 0.4.0 - ts-jest: 29.0.1_3v2of4mknskhifwzp4doj5a3fa + tmp: 0.2.1 + ts-jest: 29.0.1_poggjixajg6vd6yquly7s7dsj4 ts-node: 10.9.1_ck2axrxkiif44rdbzjywaqjysa typescript: 4.8.3 @@ -142,6 +146,11 @@ packages: engines: {node: '>=6.9.0'} dev: true + /@babel/compat-data/7.19.3: + resolution: {integrity: sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/core/7.19.1: resolution: {integrity: sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==} engines: {node: '>=6.9.0'} @@ -165,6 +174,29 @@ packages: - supports-color dev: true + /@babel/core/7.19.3: + resolution: {integrity: sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.0 + '@babel/code-frame': 7.18.6 + '@babel/generator': 7.19.3 + '@babel/helper-compilation-targets': 7.19.3_@babel+core@7.19.3 + '@babel/helper-module-transforms': 7.19.0 + '@babel/helpers': 7.19.0 + '@babel/parser': 7.19.3 + '@babel/template': 7.18.10 + '@babel/traverse': 7.19.3 + '@babel/types': 7.19.3 + convert-source-map: 1.8.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.1 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/generator/7.19.0: resolution: {integrity: sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==} engines: {node: '>=6.9.0'} @@ -174,6 +206,15 @@ packages: jsesc: 2.5.2 dev: true + /@babel/generator/7.19.3: + resolution: {integrity: sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.3 + '@jridgewell/gen-mapping': 0.3.2 + jsesc: 2.5.2 + dev: true + /@babel/helper-compilation-targets/7.19.1_@babel+core@7.19.1: resolution: {integrity: sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==} engines: {node: '>=6.9.0'} @@ -187,6 +228,19 @@ packages: semver: 6.3.0 dev: true + /@babel/helper-compilation-targets/7.19.3_@babel+core@7.19.3: + resolution: {integrity: sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.19.3 + '@babel/core': 7.19.3 + '@babel/helper-validator-option': 7.18.6 + browserslist: 4.21.4 + semver: 6.3.0 + dev: true + /@babel/helper-environment-visitor/7.18.9: resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} engines: {node: '>=6.9.0'} @@ -292,6 +346,14 @@ packages: '@babel/types': 7.19.0 dev: true + /@babel/parser/7.19.3: + resolution: {integrity: sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.19.3 + dev: true + /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.19.1: resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: @@ -462,6 +524,24 @@ packages: - supports-color dev: true + /@babel/traverse/7.19.3: + resolution: {integrity: sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/generator': 7.19.3 + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-function-name': 7.19.0 + '@babel/helper-hoist-variables': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/parser': 7.19.3 + '@babel/types': 7.19.3 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/types/7.19.0: resolution: {integrity: sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==} engines: {node: '>=6.9.0'} @@ -471,6 +551,15 @@ packages: to-fast-properties: 2.0.0 dev: true + /@babel/types/7.19.3: + resolution: {integrity: sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.18.10 + '@babel/helper-validator-identifier': 7.19.1 + to-fast-properties: 2.0.0 + dev: true + /@bcoe/v8-coverage/0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true @@ -1135,6 +1224,10 @@ packages: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true + /@types/tmp/0.2.3: + resolution: {integrity: sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==} + dev: true + /@types/uuid/8.3.4: resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} dev: true @@ -4382,6 +4475,13 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /tmp/0.2.1: + resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} + engines: {node: '>=8.17.0'} + dependencies: + rimraf: 3.0.2 + dev: true + /tmpl/1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} dev: true @@ -4402,7 +4502,7 @@ packages: hasBin: true dev: true - /ts-jest/29.0.1_3v2of4mknskhifwzp4doj5a3fa: + /ts-jest/29.0.1_poggjixajg6vd6yquly7s7dsj4: resolution: {integrity: sha512-htQOHshgvhn93QLxrmxpiQPk69+M1g7govO1g6kf6GsjCv4uvRV0znVmDrrvjUrVCnTYeY4FBxTYYYD4airyJA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -4423,7 +4523,7 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 jest: 29.0.3_johvxhudwcpndp4mle25vwrlq4 diff --git a/samples/todo/.zenstack/server/data/todo-list.ts b/samples/todo/.zenstack/server/data/todo-list.ts index e77b08c81..5d036d329 100644 --- a/samples/todo/.zenstack/server/data/todo-list.ts +++ b/samples/todo/.zenstack/server/data/todo-list.ts @@ -90,8 +90,8 @@ async function handlePut( } const r = await client.prisma.todoList.update({ - where: { id: path[0] }, ...body, + where: { id: path[0] }, }); res.status(200).send(r); diff --git a/samples/todo/.zenstack/types.ts b/samples/todo/.zenstack/types.ts index 9bbbbf323..9ba1eeef5 100644 --- a/samples/todo/.zenstack/types.ts +++ b/samples/todo/.zenstack/types.ts @@ -33,14 +33,14 @@ export type TodoListGetArgs = P.SelectSubset< TodoListGetArgsInput >; -export type TodoListUpdateArgs = P.TodoListUpdateArgs; +export type TodoListUpdateArgs = Omit; export type TodoListUpdateResult = P.CheckSelect< T, TodoList, P.TodoListGetPayload >; -export type TodoListDeleteArgs = P.TodoListDeleteArgs; +export type TodoListDeleteArgs = Omit; export type TodoListDeleteResult = P.CheckSelect< T, TodoList, diff --git a/samples/todo/schema.zmodel b/samples/todo/schema.zmodel index c21e8f5c4..b004eb066 100644 --- a/samples/todo/schema.zmodel +++ b/samples/todo/schema.zmodel @@ -1,8 +1,7 @@ /* - * A sample model for a collaborative Todo app - */ +* A sample model for a collaborative Todo app +*/ -// Datasource datasource db { provider = 'postgresql' url = env('DATABASE_URL') @@ -13,95 +12,72 @@ enum SpaceUserRole { ADMIN } -// Fragments are used to define fields shared across data models -fragment CommonFields { +model Space { id String @id createdAt DateTime @createdAt updatedAt DateTime @updatedAt -} - -model Space { - ...CommonFields - - // @length is a field validation rule, enforced at create/update time name String @length(1, 100) - - // @unique denotes single field unique index slug String @unique @length(1, 20) - members SpaceUser[] - todoLists TodoList[] - - // auth() is a built-in function which returns current user identity - // @@allow and @@deny are for defining access policies: - // - a request is denied if any @@deny rule evaluates to true - // - a request is denied if there isn't any @@allow rule evaluating to true - // - // Policies are enforced at db query/update/delete time // require login @@deny('all', auth() == null) - + // everyone can create a space @@allow('create', true) // any user in the space can read the space - // $this denotes current entity - // 'userInSpace' is a helper function defined subsequently - @@allow('read', userInSpace(auth(), $this)) + @@allow('read', members?[user == auth()]) // space admin can update and delete - @@allow('update,delete', userIsSpaceAdmin(auth(), $this)) + @@allow('update,delete', members?[user == auth() && role == ADMIN]) } -// SpaceUser is a 'join table' which models many-to-many relationship between -// Space and User model SpaceUser { - ...CommonFields - - // @cascade indicates cascading deletion from Space + id String @id + createdAt DateTime @createdAt + updatedAt DateTime @updatedAt space Space @cascade user User @cascade role SpaceUserRole - - // multi-field unique index + todoLists TodoList[] + @@unique([user, space]) // require login @@deny('all', auth() == null) // space admin can create/update/delete - @@allow('create,update,delete', userIsSpaceAdmin(auth(), space)) + @@allow('create,update,delete', space.members?[user == auth() && role == ADMIN]) // user can read entries for spaces which he's a member of - @@allow('read', userInSpace(auth(), space)) + @@allow('read', space.members?[user == auth()]) } model User { - ...CommonFields - - // @email is another validation rule + id String @id + createdAt DateTime @createdAt + updatedAt DateTime @updatedAt email String @unique @email - name String? @length(1, 100) - todoList TodoList[] spaces SpaceUser[] - - // @url is another validation rule image String? @url + todoLists TodoList[] // can be created by anyone, even not logged in @@allow('create', true) // can be read by users sharing any space - @@allow('read', userInAnySpace(auth(), spaces)) + @@allow('read', spaces?[auth() == user]) // can only be updated and deleted by himeself - @@allow('update,delete', auth() == $this) + @@allow('update,delete', auth() == this) } model TodoList { - ...CommonFields + id String @id + createdAt DateTime @createdAt + updatedAt DateTime @updatedAt space Space @cascade owner User title String @length(1, 20) @@ -112,14 +88,16 @@ model TodoList { @@deny('all', auth() == null) // can be read by owner or space members (only if not private) - @@allow('read', owner == auth() || (userInSpace(auth(), space) && !private)) + @@allow('read', owner == auth() || (space.members?[user == auth()] && !private)) // can be created/updated/deleted by owner - @@allow('create,update,delete', owner == auth() && userInSpace(auth(), space)) + @@allow('create,update,delete', owner == auth() && space.members?[user == auth()]) } model Todo { - ...CommonFields + id String @id + createdAt DateTime @createdAt + updatedAt DateTime @updatedAt owner User todoList TodoList @cascade title String @@ -129,22 +107,5 @@ model Todo { @@deny('all', auth() == null) // owner has full access, also space members have full access (if the parent TodoList is not private) - @@allow('all', todoList.owner == auth() || (userInSpace(auth(), todoList.space) && !todoList.private)) -} - -// Functions are for reusing policy rules, and are inlined during code generation - -// if the user is in the space -function userInSpace(user, space) { - some(space.members, $.user == user) -} - -// if the user is the admin of the space -function userIsSpaceAdmin(user, space) { - some(space.members, $.user == user && $.role == ADMIN) + @@allow('all', todoList.owner == auth() || (todoList.space.members?[user == auth()] && !todoList.private)) } - -// if the user is a member of any of the given spaces -function userInAnySpace(user, spaces) { - some(spaces, $.user == user) -} \ No newline at end of file