From a3f20667c6e25c117cf8e057dcd4e012aa7b3ccf Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Sat, 30 Sep 2023 21:23:03 -0700 Subject: [PATCH] fix: support postgres extensions --- packages/language/src/generated/ast.ts | 147 ++-- packages/language/src/generated/grammar.ts | 643 +++++++++++------- packages/language/src/zmodel.langium | 27 +- packages/schema/package.json | 2 + .../src/plugins/prisma/prisma-builder.ts | 44 +- .../src/plugins/prisma/schema-generator.ts | 136 ++-- .../tests/generator/prisma-builder.test.ts | 17 +- .../tests/generator/prisma-generator.test.ts | 20 +- packages/schema/tests/schema/parser.test.ts | 28 +- packages/sdk/src/utils.ts | 15 +- pnpm-lock.yaml | 52 +- 11 files changed, 694 insertions(+), 437 deletions(-) diff --git a/packages/language/src/generated/ast.ts b/packages/language/src/generated/ast.ts index da3cf220c..991ac6f59 100644 --- a/packages/language/src/generated/ast.ts +++ b/packages/language/src/generated/ast.ts @@ -32,6 +32,14 @@ export function isBuiltinType(item: unknown): item is BuiltinType { return item === 'String' || item === 'Boolean' || item === 'Int' || item === 'BigInt' || item === 'Float' || item === 'Decimal' || item === 'DateTime' || item === 'Json' || item === 'Bytes'; } +export type ConfigExpr = ConfigArrayExpr | InvocationExpr | LiteralExpr; + +export const ConfigExpr = 'ConfigExpr'; + +export function isConfigExpr(item: unknown): item is ConfigExpr { + return reflection.isInstance(item, ConfigExpr); +} + export type DataModelAttributeName = string; export function isDataModelAttributeName(item: unknown): item is DataModelAttributeName { @@ -114,7 +122,7 @@ export function isArgument(item: unknown): item is Argument { } export interface ArrayExpr extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'ArrayExpr'; items: Array } @@ -182,7 +190,7 @@ export function isAttributeParamType(item: unknown): item is AttributeParamType } export interface BinaryExpr extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'BinaryExpr'; left: Expression operator: '!' | '!=' | '&&' | '<' | '<=' | '==' | '>' | '>=' | '?' | '^' | 'in' | '||' @@ -196,7 +204,7 @@ export function isBinaryExpr(item: unknown): item is BinaryExpr { } export interface BooleanLiteral extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'BooleanLiteral'; value: Boolean } @@ -207,6 +215,57 @@ export function isBooleanLiteral(item: unknown): item is BooleanLiteral { return reflection.isInstance(item, BooleanLiteral); } +export interface ConfigArrayExpr extends AstNode { + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $type: 'ConfigArrayExpr'; + items: Array +} + +export const ConfigArrayExpr = 'ConfigArrayExpr'; + +export function isConfigArrayExpr(item: unknown): item is ConfigArrayExpr { + return reflection.isInstance(item, ConfigArrayExpr); +} + +export interface ConfigField extends AstNode { + readonly $container: DataSource | GeneratorDecl; + readonly $type: 'ConfigField'; + name: RegularID + value: ConfigExpr +} + +export const ConfigField = 'ConfigField'; + +export function isConfigField(item: unknown): item is ConfigField { + return reflection.isInstance(item, ConfigField); +} + +export interface ConfigInvocationArg extends AstNode { + readonly $container: ConfigInvocationExpr; + readonly $type: 'ConfigInvocationArg'; + name: string + value: LiteralExpr +} + +export const ConfigInvocationArg = 'ConfigInvocationArg'; + +export function isConfigInvocationArg(item: unknown): item is ConfigInvocationArg { + return reflection.isInstance(item, ConfigInvocationArg); +} + +export interface ConfigInvocationExpr extends AstNode { + readonly $container: ConfigArrayExpr; + readonly $type: 'ConfigInvocationExpr'; + args: Array + name: string +} + +export const ConfigInvocationExpr = 'ConfigInvocationExpr'; + +export function isConfigInvocationExpr(item: unknown): item is ConfigInvocationExpr { + return reflection.isInstance(item, ConfigInvocationExpr); +} + export interface DataModel extends AstNode { readonly $container: Model; readonly $type: 'DataModel'; @@ -285,7 +344,7 @@ export function isDataModelFieldType(item: unknown): item is DataModelFieldType export interface DataSource extends AstNode { readonly $container: Model; readonly $type: 'DataSource'; - fields: Array + fields: Array name: RegularID } @@ -295,19 +354,6 @@ export function isDataSource(item: unknown): item is DataSource { return reflection.isInstance(item, DataSource); } -export interface DataSourceField extends AstNode { - readonly $container: DataSource; - readonly $type: 'DataSourceField'; - name: RegularID - value: ArrayExpr | InvocationExpr | LiteralExpr -} - -export const DataSourceField = 'DataSourceField'; - -export function isDataSourceField(item: unknown): item is DataSourceField { - return reflection.isInstance(item, DataSourceField); -} - export interface Enum extends AstNode { readonly $container: Model; readonly $type: 'Enum'; @@ -397,7 +443,7 @@ export function isFunctionParamType(item: unknown): item is FunctionParamType { export interface GeneratorDecl extends AstNode { readonly $container: Model; readonly $type: 'GeneratorDecl'; - fields: Array + fields: Array name: RegularID } @@ -407,19 +453,6 @@ export function isGeneratorDecl(item: unknown): item is GeneratorDecl { return reflection.isInstance(item, GeneratorDecl); } -export interface GeneratorField extends AstNode { - readonly $container: GeneratorDecl; - readonly $type: 'GeneratorField'; - name: RegularID - value: ArrayExpr | LiteralExpr -} - -export const GeneratorField = 'GeneratorField'; - -export function isGeneratorField(item: unknown): item is GeneratorField { - return reflection.isInstance(item, GeneratorField); -} - export interface InternalAttribute extends AstNode { readonly $container: Attribute | FunctionDecl; readonly $type: 'InternalAttribute'; @@ -434,7 +467,7 @@ export function isInternalAttribute(item: unknown): item is InternalAttribute { } export interface InvocationExpr extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'InvocationExpr'; args: Array function: Reference @@ -447,7 +480,7 @@ export function isInvocationExpr(item: unknown): item is InvocationExpr { } export interface MemberAccessExpr extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'MemberAccessExpr'; member: Reference operand: Expression @@ -484,7 +517,7 @@ export function isModelImport(item: unknown): item is ModelImport { } export interface NullExpr extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'NullExpr'; value: string } @@ -496,7 +529,7 @@ export function isNullExpr(item: unknown): item is NullExpr { } export interface NumberLiteral extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'NumberLiteral'; value: string } @@ -508,7 +541,7 @@ export function isNumberLiteral(item: unknown): item is NumberLiteral { } export interface ObjectExpr extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'ObjectExpr'; fields: Array } @@ -559,7 +592,7 @@ export function isReferenceArg(item: unknown): item is ReferenceArg { } export interface ReferenceExpr extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'ReferenceExpr'; args: Array target: Reference @@ -572,7 +605,7 @@ export function isReferenceExpr(item: unknown): item is ReferenceExpr { } export interface StringLiteral extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'StringLiteral'; value: string } @@ -584,7 +617,7 @@ export function isStringLiteral(item: unknown): item is StringLiteral { } export interface ThisExpr extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'ThisExpr'; value: string } @@ -596,7 +629,7 @@ export function isThisExpr(item: unknown): item is ThisExpr { } export interface UnaryExpr extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | FieldInitializer | FunctionDecl | GeneratorField | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | ConfigArrayExpr | ConfigField | ConfigInvocationArg | FieldInitializer | FunctionDecl | MemberAccessExpr | PluginField | UnaryExpr | UnsupportedFieldType; readonly $type: 'UnaryExpr'; operand: Expression operator: '!' @@ -630,13 +663,17 @@ export type ZModelAstType = { AttributeParamType: AttributeParamType BinaryExpr: BinaryExpr BooleanLiteral: BooleanLiteral + ConfigArrayExpr: ConfigArrayExpr + ConfigExpr: ConfigExpr + ConfigField: ConfigField + ConfigInvocationArg: ConfigInvocationArg + ConfigInvocationExpr: ConfigInvocationExpr DataModel: DataModel DataModelAttribute: DataModelAttribute DataModelField: DataModelField DataModelFieldAttribute: DataModelFieldAttribute DataModelFieldType: DataModelFieldType DataSource: DataSource - DataSourceField: DataSourceField Enum: Enum EnumField: EnumField Expression: Expression @@ -645,7 +682,6 @@ export type ZModelAstType = { FunctionParam: FunctionParam FunctionParamType: FunctionParamType GeneratorDecl: GeneratorDecl - GeneratorField: GeneratorField InternalAttribute: InternalAttribute InvocationExpr: InvocationExpr LiteralExpr: LiteralExpr @@ -670,15 +706,13 @@ export type ZModelAstType = { export class ZModelAstReflection extends AbstractAstReflection { getAllTypes(): string[] { - return ['AbstractDeclaration', 'Argument', 'ArrayExpr', 'Attribute', 'AttributeArg', 'AttributeParam', 'AttributeParamType', 'BinaryExpr', 'BooleanLiteral', 'DataModel', 'DataModelAttribute', 'DataModelField', 'DataModelFieldAttribute', 'DataModelFieldType', 'DataSource', 'DataSourceField', 'Enum', 'EnumField', 'Expression', 'FieldInitializer', 'FunctionDecl', 'FunctionParam', 'FunctionParamType', 'GeneratorDecl', 'GeneratorField', 'InternalAttribute', 'InvocationExpr', 'LiteralExpr', 'MemberAccessExpr', 'Model', 'ModelImport', 'NullExpr', 'NumberLiteral', 'ObjectExpr', 'Plugin', 'PluginField', 'ReferenceArg', 'ReferenceExpr', 'ReferenceTarget', 'StringLiteral', 'ThisExpr', 'TypeDeclaration', 'UnaryExpr', 'UnsupportedFieldType']; + return ['AbstractDeclaration', 'Argument', 'ArrayExpr', 'Attribute', 'AttributeArg', 'AttributeParam', 'AttributeParamType', 'BinaryExpr', 'BooleanLiteral', 'ConfigArrayExpr', 'ConfigExpr', 'ConfigField', 'ConfigInvocationArg', 'ConfigInvocationExpr', 'DataModel', 'DataModelAttribute', 'DataModelField', 'DataModelFieldAttribute', 'DataModelFieldType', 'DataSource', 'Enum', 'EnumField', 'Expression', 'FieldInitializer', 'FunctionDecl', 'FunctionParam', 'FunctionParamType', 'GeneratorDecl', 'InternalAttribute', 'InvocationExpr', 'LiteralExpr', 'MemberAccessExpr', 'Model', 'ModelImport', 'NullExpr', 'NumberLiteral', 'ObjectExpr', 'Plugin', 'PluginField', 'ReferenceArg', 'ReferenceExpr', 'ReferenceTarget', 'StringLiteral', 'ThisExpr', 'TypeDeclaration', 'UnaryExpr', 'UnsupportedFieldType']; } protected override computeIsSubtype(subtype: string, supertype: string): boolean { switch (subtype) { case ArrayExpr: case BinaryExpr: - case InvocationExpr: - case LiteralExpr: case MemberAccessExpr: case NullExpr: case ObjectExpr: @@ -699,6 +733,9 @@ export class ZModelAstReflection extends AbstractAstReflection { case StringLiteral: { return this.isSubtype(LiteralExpr, supertype); } + case ConfigArrayExpr: { + return this.isSubtype(ConfigExpr, supertype); + } case DataModel: case Enum: { return this.isSubtype(AbstractDeclaration, supertype) || this.isSubtype(TypeDeclaration, supertype); @@ -708,6 +745,10 @@ export class ZModelAstReflection extends AbstractAstReflection { case FunctionParam: { return this.isSubtype(ReferenceTarget, supertype); } + case InvocationExpr: + case LiteralExpr: { + return this.isSubtype(ConfigExpr, supertype) || this.isSubtype(Expression, supertype); + } default: { return false; } @@ -781,6 +822,22 @@ export class ZModelAstReflection extends AbstractAstReflection { ] }; } + case 'ConfigArrayExpr': { + return { + name: 'ConfigArrayExpr', + mandatory: [ + { name: 'items', type: 'array' } + ] + }; + } + case 'ConfigInvocationExpr': { + return { + name: 'ConfigInvocationExpr', + mandatory: [ + { name: 'args', type: 'array' } + ] + }; + } case 'DataModel': { return { name: 'DataModel', diff --git a/packages/language/src/generated/grammar.ts b/packages/language/src/generated/grammar.ts index f29f11fdf..f62c3d091 100644 --- a/packages/language/src/generated/grammar.ts +++ b/packages/language/src/generated/grammar.ts @@ -69,7 +69,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@63" + "$ref": "#/rules@67" }, "arguments": [] } @@ -104,42 +104,42 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@5" + "$ref": "#/rules@4" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@7" + "$ref": "#/rules@6" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@33" + "$ref": "#/rules@37" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@37" + "$ref": "#/rules@41" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@39" + "$ref": "#/rules@43" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@48" + "$ref": "#/rules@52" }, "arguments": [] } @@ -161,7 +161,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [], "cardinality": "*" @@ -177,7 +177,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -193,7 +193,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@4" + "$ref": "#/rules@5" }, "arguments": [] }, @@ -212,76 +212,6 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "parameters": [], "wildcard": false }, - { - "$type": "ParserRule", - "name": "DataSourceField", - "definition": { - "$type": "Group", - "elements": [ - { - "$type": "RuleCall", - "rule": { - "$ref": "#/rules@65" - }, - "arguments": [], - "cardinality": "*" - }, - { - "$type": "Assignment", - "feature": "name", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$ref": "#/rules@43" - }, - "arguments": [] - } - }, - { - "$type": "Keyword", - "value": "=" - }, - { - "$type": "Assignment", - "feature": "value", - "operator": "=", - "terminal": { - "$type": "Alternatives", - "elements": [ - { - "$type": "RuleCall", - "rule": { - "$ref": "#/rules@13" - }, - "arguments": [] - }, - { - "$type": "RuleCall", - "rule": { - "$ref": "#/rules@22" - }, - "arguments": [] - }, - { - "$type": "RuleCall", - "rule": { - "$ref": "#/rules@14" - }, - "arguments": [] - } - ] - } - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, { "$type": "ParserRule", "name": "GeneratorDecl", @@ -291,7 +221,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [], "cardinality": "*" @@ -307,7 +237,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -323,7 +253,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@6" + "$ref": "#/rules@5" }, "arguments": [] }, @@ -344,14 +274,14 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel }, { "$type": "ParserRule", - "name": "GeneratorField", + "name": "ConfigField", "definition": { "$type": "Group", "elements": [ { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [], "cardinality": "*" @@ -363,7 +293,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -377,23 +307,11 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "feature": "value", "operator": "=", "terminal": { - "$type": "Alternatives", - "elements": [ - { - "$type": "RuleCall", - "rule": { - "$ref": "#/rules@13" - }, - "arguments": [] - }, - { - "$type": "RuleCall", - "rule": { - "$ref": "#/rules@14" - }, - "arguments": [] - } - ] + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@18" + }, + "arguments": [] } } ] @@ -414,7 +332,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [], "cardinality": "*" @@ -430,7 +348,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -446,7 +364,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@8" + "$ref": "#/rules@7" }, "arguments": [] }, @@ -474,7 +392,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [], "cardinality": "*" @@ -486,7 +404,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -505,21 +423,21 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@13" + "$ref": "#/rules@12" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@14" + "$ref": "#/rules@13" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@20" + "$ref": "#/rules@24" }, "arguments": [] } @@ -541,7 +459,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "definition": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@29" + "$ref": "#/rules@33" }, "arguments": [] }, @@ -562,7 +480,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@64" + "$ref": "#/rules@68" }, "arguments": [] } @@ -584,7 +502,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@63" + "$ref": "#/rules@67" }, "arguments": [] } @@ -606,7 +524,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@58" + "$ref": "#/rules@62" }, "arguments": [] } @@ -627,21 +545,21 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@10" + "$ref": "#/rules@9" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@11" + "$ref": "#/rules@10" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@12" + "$ref": "#/rules@11" }, "arguments": [] } @@ -674,7 +592,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@9" + "$ref": "#/rules@8" }, "arguments": [] } @@ -693,7 +611,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@9" + "$ref": "#/rules@8" }, "arguments": [] } @@ -717,6 +635,269 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "parameters": [], "wildcard": false }, + { + "$type": "ParserRule", + "name": "ConfigInvocationExpr", + "definition": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@66" + }, + "arguments": [] + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "(" + }, + { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@15" + }, + "arguments": [] + }, + { + "$type": "Keyword", + "value": ")" + } + ], + "cardinality": "?" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "ConfigInvocationArgList", + "fragment": true, + "definition": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "args", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@16" + }, + "arguments": [] + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "," + }, + { + "$type": "Assignment", + "feature": "args", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@16" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "ConfigInvocationArg", + "definition": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@66" + }, + "arguments": [] + } + }, + { + "$type": "Keyword", + "value": ":" + }, + { + "$type": "Assignment", + "feature": "value", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@12" + }, + "arguments": [] + } + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "ConfigArrayExpr", + "definition": { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "[" + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "items", + "operator": "+=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@12" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@14" + }, + "arguments": [] + } + ] + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "," + }, + { + "$type": "Assignment", + "feature": "items", + "operator": "+=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@12" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@14" + }, + "arguments": [] + } + ] + } + } + ], + "cardinality": "*" + } + ], + "cardinality": "?" + }, + { + "$type": "Keyword", + "value": "]" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "ConfigExpr", + "definition": { + "$type": "Alternatives", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@12" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@26" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$ref": "#/rules@17" + }, + "arguments": [] + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, { "$type": "ParserRule", "name": "ThisExpr", @@ -727,7 +908,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@61" + "$ref": "#/rules@65" }, "arguments": [] } @@ -749,7 +930,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@60" + "$ref": "#/rules@64" }, "arguments": [] } @@ -779,7 +960,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] }, @@ -796,7 +977,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@18" + "$ref": "#/rules@22" }, "arguments": [] }, @@ -830,7 +1011,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@19" + "$ref": "#/rules@23" }, "arguments": [] } @@ -849,7 +1030,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@19" + "$ref": "#/rules@23" }, "arguments": [] } @@ -931,7 +1112,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@21" + "$ref": "#/rules@25" }, "arguments": [] } @@ -950,7 +1131,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@21" + "$ref": "#/rules@25" }, "arguments": [] } @@ -992,7 +1173,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -1008,7 +1189,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@9" + "$ref": "#/rules@8" }, "arguments": [] } @@ -1035,7 +1216,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "CrossReference", "type": { - "$ref": "#/rules@39" + "$ref": "#/rules@43" }, "deprecatedSyntax": false } @@ -1047,7 +1228,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@31" + "$ref": "#/rules@35" }, "arguments": [], "cardinality": "?" @@ -1078,7 +1259,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@30" + "$ref": "#/rules@34" }, "arguments": [] }, @@ -1108,7 +1289,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "CrossReference", "type": { - "$ref": "#/rules@34" + "$ref": "#/rules@38" }, "deprecatedSyntax": false } @@ -1149,7 +1330,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@23" + "$ref": "#/rules@27" }, "arguments": [] } @@ -1176,7 +1357,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@23" + "$ref": "#/rules@27" }, "arguments": [] }, @@ -1225,7 +1406,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@9" + "$ref": "#/rules@8" }, "arguments": [] } @@ -1259,7 +1440,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@25" + "$ref": "#/rules@29" }, "arguments": [] }, @@ -1291,7 +1472,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@25" + "$ref": "#/rules@29" }, "arguments": [] } @@ -1321,7 +1502,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@26" + "$ref": "#/rules@30" }, "arguments": [] }, @@ -1370,7 +1551,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@26" + "$ref": "#/rules@30" }, "arguments": [] } @@ -1400,7 +1581,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@27" + "$ref": "#/rules@31" }, "arguments": [] }, @@ -1441,7 +1622,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@27" + "$ref": "#/rules@31" }, "arguments": [] } @@ -1471,7 +1652,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@28" + "$ref": "#/rules@32" }, "arguments": [] }, @@ -1512,7 +1693,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@28" + "$ref": "#/rules@32" }, "arguments": [] } @@ -1549,7 +1730,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@9" + "$ref": "#/rules@8" }, "arguments": [] }, @@ -1562,56 +1743,56 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@15" + "$ref": "#/rules@19" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@16" + "$ref": "#/rules@20" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@13" + "$ref": "#/rules@12" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@24" + "$ref": "#/rules@28" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@22" + "$ref": "#/rules@26" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@14" + "$ref": "#/rules@13" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@17" + "$ref": "#/rules@21" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@20" + "$ref": "#/rules@24" }, "arguments": [] } @@ -1638,7 +1819,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@32" + "$ref": "#/rules@36" }, "arguments": [] } @@ -1657,7 +1838,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@32" + "$ref": "#/rules@36" }, "arguments": [] } @@ -1689,7 +1870,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -1708,7 +1889,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@9" + "$ref": "#/rules@8" }, "arguments": [] } @@ -1735,7 +1916,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [] }, @@ -1768,7 +1949,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -1787,7 +1968,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "CrossReference", "type": { - "$ref": "#/rules@33" + "$ref": "#/rules@37" }, "deprecatedSyntax": false } @@ -1806,7 +1987,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "CrossReference", "type": { - "$ref": "#/rules@33" + "$ref": "#/rules@37" }, "deprecatedSyntax": false } @@ -1838,7 +2019,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -1861,7 +2042,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@34" + "$ref": "#/rules@38" }, "arguments": [] } @@ -1873,7 +2054,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@52" + "$ref": "#/rules@56" }, "arguments": [] } @@ -1907,7 +2088,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [] }, @@ -1920,7 +2101,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -1932,7 +2113,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@35" + "$ref": "#/rules@39" }, "arguments": [] } @@ -1944,7 +2125,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@51" + "$ref": "#/rules@55" }, "arguments": [] }, @@ -1975,7 +2156,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@57" + "$ref": "#/rules@61" }, "arguments": [] } @@ -1987,7 +2168,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@36" + "$ref": "#/rules@40" }, "arguments": [] } @@ -2004,7 +2185,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] }, @@ -2072,7 +2253,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@13" + "$ref": "#/rules@12" }, "arguments": [] } @@ -2103,7 +2284,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [] }, @@ -2120,7 +2301,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -2139,7 +2320,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@38" + "$ref": "#/rules@42" }, "arguments": [] } @@ -2151,7 +2332,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@52" + "$ref": "#/rules@56" }, "arguments": [] } @@ -2185,7 +2366,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [] }, @@ -2198,7 +2379,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -2210,7 +2391,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@51" + "$ref": "#/rules@55" }, "arguments": [] }, @@ -2234,7 +2415,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [], "cardinality": "*" @@ -2250,7 +2431,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -2269,7 +2450,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@40" + "$ref": "#/rules@44" }, "arguments": [] } @@ -2288,7 +2469,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@40" + "$ref": "#/rules@44" }, "arguments": [] } @@ -2314,7 +2495,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@41" + "$ref": "#/rules@45" }, "arguments": [] } @@ -2330,7 +2511,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@9" + "$ref": "#/rules@8" }, "arguments": [] }, @@ -2347,7 +2528,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@53" + "$ref": "#/rules@57" }, "arguments": [] }, @@ -2371,7 +2552,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [], "cardinality": "*" @@ -2383,7 +2564,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -2399,7 +2580,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@41" + "$ref": "#/rules@45" }, "arguments": [] } @@ -2439,7 +2620,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@56" + "$ref": "#/rules@60" }, "arguments": [] } @@ -2456,7 +2637,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] }, @@ -2503,7 +2684,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@62" + "$ref": "#/rules@66" }, "arguments": [] }, @@ -2520,14 +2701,14 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@62" + "$ref": "#/rules@66" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@57" + "$ref": "#/rules@61" }, "arguments": [] } @@ -2555,7 +2736,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@62" + "$ref": "#/rules@66" }, "arguments": [] }, @@ -2614,7 +2795,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@42" + "$ref": "#/rules@46" }, "arguments": [] } @@ -2641,7 +2822,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@42" + "$ref": "#/rules@46" }, "arguments": [] } @@ -2668,7 +2849,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@42" + "$ref": "#/rules@46" }, "arguments": [] } @@ -2691,21 +2872,21 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@45" + "$ref": "#/rules@49" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@46" + "$ref": "#/rules@50" }, "arguments": [] }, { "$type": "RuleCall", "rule": { - "$ref": "#/rules@44" + "$ref": "#/rules@48" }, "arguments": [] } @@ -2727,7 +2908,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [], "cardinality": "*" @@ -2743,7 +2924,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@47" + "$ref": "#/rules@51" }, "arguments": [] } @@ -2762,7 +2943,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@49" + "$ref": "#/rules@53" }, "arguments": [] } @@ -2781,7 +2962,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@49" + "$ref": "#/rules@53" }, "arguments": [] } @@ -2803,7 +2984,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@53" + "$ref": "#/rules@57" }, "arguments": [] }, @@ -2827,7 +3008,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [], "cardinality": "*" @@ -2849,7 +3030,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -2865,7 +3046,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@50" + "$ref": "#/rules@54" }, "arguments": [] } @@ -2898,7 +3079,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@56" + "$ref": "#/rules@60" }, "arguments": [] }, @@ -2929,7 +3110,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] }, @@ -2989,12 +3170,12 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "CrossReference", "type": { - "$ref": "#/rules@48" + "$ref": "#/rules@52" }, "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@46" + "$ref": "#/rules@50" }, "arguments": [] }, @@ -3011,7 +3192,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@54" + "$ref": "#/rules@58" }, "arguments": [], "cardinality": "?" @@ -3041,7 +3222,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@65" + "$ref": "#/rules@69" }, "arguments": [], "cardinality": "*" @@ -3053,12 +3234,12 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "CrossReference", "type": { - "$ref": "#/rules@48" + "$ref": "#/rules@52" }, "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@45" + "$ref": "#/rules@49" }, "arguments": [] }, @@ -3075,7 +3256,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@54" + "$ref": "#/rules@58" }, "arguments": [], "cardinality": "?" @@ -3109,12 +3290,12 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "CrossReference", "type": { - "$ref": "#/rules@48" + "$ref": "#/rules@52" }, "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@44" + "$ref": "#/rules@48" }, "arguments": [] }, @@ -3131,7 +3312,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "RuleCall", "rule": { - "$ref": "#/rules@54" + "$ref": "#/rules@58" }, "arguments": [], "cardinality": "?" @@ -3166,7 +3347,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@55" + "$ref": "#/rules@59" }, "arguments": [] } @@ -3185,7 +3366,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@55" + "$ref": "#/rules@59" }, "arguments": [] } @@ -3217,7 +3398,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@43" + "$ref": "#/rules@47" }, "arguments": [] } @@ -3236,7 +3417,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel "terminal": { "$type": "RuleCall", "rule": { - "$ref": "#/rules@9" + "$ref": "#/rules@8" }, "arguments": [] } @@ -3485,19 +3666,19 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "SimpleType", "typeRef": { - "$ref": "#/rules@40" + "$ref": "#/rules@44" } }, { "$type": "SimpleType", "typeRef": { - "$ref": "#/rules@34" + "$ref": "#/rules@38" } }, { "$type": "SimpleType", "typeRef": { - "$ref": "#/rules@38" + "$ref": "#/rules@42" } } ] @@ -3512,13 +3693,13 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ?? (loadedZModel { "$type": "SimpleType", "typeRef": { - "$ref": "#/rules@33" + "$ref": "#/rules@37" } }, { "$type": "SimpleType", "typeRef": { - "$ref": "#/rules@37" + "$ref": "#/rules@41" } } ] diff --git a/packages/language/src/zmodel.langium b/packages/language/src/zmodel.langium index 8a920cecb..b7f13466e 100644 --- a/packages/language/src/zmodel.langium +++ b/packages/language/src/zmodel.langium @@ -15,17 +15,14 @@ AbstractDeclaration: // datasource DataSource: - TRIPLE_SLASH_COMMENT* 'datasource' name=RegularID '{' (fields+=DataSourceField)* '}'; - -DataSourceField: - TRIPLE_SLASH_COMMENT* name=RegularID '=' value=(LiteralExpr | InvocationExpr | ArrayExpr); + TRIPLE_SLASH_COMMENT* 'datasource' name=RegularID '{' (fields+=ConfigField)* '}'; // generator GeneratorDecl: - TRIPLE_SLASH_COMMENT* 'generator' name=RegularID '{' (fields+=GeneratorField)* '}'; + TRIPLE_SLASH_COMMENT* 'generator' name=RegularID '{' (fields+=ConfigField)* '}'; -GeneratorField: - TRIPLE_SLASH_COMMENT* name=RegularID '=' value=(LiteralExpr | ArrayExpr); +ConfigField: + TRIPLE_SLASH_COMMENT* name=RegularID '=' value=ConfigExpr; // plugin Plugin: @@ -53,6 +50,22 @@ LiteralExpr: ArrayExpr: '[' (items+=Expression (',' items+=Expression)*)? ']'; +ConfigInvocationExpr: + name=ID ('(' ConfigInvocationArgList ')')?; + +fragment ConfigInvocationArgList: + args+=ConfigInvocationArg (',' args+=ConfigInvocationArg)*; + +ConfigInvocationArg: + name=ID ':' value=LiteralExpr; + +ConfigArrayExpr: + '[' (items+=(LiteralExpr|ConfigInvocationExpr) (',' items+=(LiteralExpr|ConfigInvocationExpr))*)? ']'; + +// expressions used in configuration fields (e.g. datasource, generator, plugin) +ConfigExpr: + LiteralExpr | InvocationExpr | ConfigArrayExpr; + type ReferenceTarget = FunctionParam | DataModelField | EnumField; ThisExpr: diff --git a/packages/schema/package.json b/packages/schema/package.json index 733ebf159..ee1ce21ff 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -112,6 +112,7 @@ "zod-validation-error": "^0.2.1" }, "devDependencies": { + "@prisma/client": "^4.8.0", "@types/async-exit-hook": "^2.0.0", "@types/jest": "^29.5.0", "@types/node": "^18.0.0", @@ -132,6 +133,7 @@ "eslint": "^8.27.0", "eslint-plugin-jest": "^27.1.7", "jest": "^29.5.0", + "prisma": "^4.8.0", "renamer": "^4.0.0", "rimraf": "^3.0.2", "tmp": "^0.2.1", diff --git a/packages/schema/src/plugins/prisma/prisma-builder.ts b/packages/schema/src/plugins/prisma/prisma-builder.ts index 15b9f0b20..19a545185 100644 --- a/packages/schema/src/plugins/prisma/prisma-builder.ts +++ b/packages/schema/src/plugins/prisma/prisma-builder.ts @@ -3,7 +3,7 @@ import indentString from './indent-string'; /** * Field used by datasource and generator declarations. */ -export type SimpleField = { name: string; value: string | string[] }; +export type SimpleField = { name: string; text: string }; /** * Prisma schema builder @@ -14,15 +14,8 @@ export class PrismaModel { private models: Model[] = []; private enums: Enum[] = []; - addDataSource( - name: string, - provider: string, - url: DataSourceUrl, - directUrl?: DataSourceUrl, - shadowDatabaseUrl?: DataSourceUrl, - restFields: SimpleField[] = [] - ): DataSource { - const ds = new DataSource(name, provider, url, directUrl, shadowDatabaseUrl, restFields); + addDataSource(name: string, fields: SimpleField[] = []): DataSource { + const ds = new DataSource(name, fields); this.datasources.push(ds); return ds; } @@ -59,47 +52,24 @@ export class PrismaModel { } export class DataSource { - constructor( - public name: string, - public provider: string, - public url: DataSourceUrl, - public directUrl?: DataSourceUrl, - public shadowDatabaseUrl?: DataSourceUrl, - public restFields: SimpleField[] = [] - ) {} + constructor(public name: string, public fields: SimpleField[] = []) {} toString(): string { - const restFields = - this.restFields.length > 0 - ? this.restFields.map((f) => indentString(`${f.name} = ${JSON.stringify(f.value)}`)).join('\n') - : ''; return ( `datasource ${this.name} {\n` + - indentString(`provider="${this.provider}"\n`) + - indentString(`url=${this.url}\n`) + - (this.directUrl ? indentString(`directUrl=${this.directUrl}\n`) : '') + - (this.shadowDatabaseUrl ? indentString(`shadowDatabaseUrl=${this.shadowDatabaseUrl}\n`) : '') + - (restFields ? restFields + '\n' : '') + - `}` + this.fields.map((f) => indentString(`${f.name} = ${f.text}`)).join('\n') + + `\n}` ); } } -export class DataSourceUrl { - constructor(public value: string, public isEnv: boolean) {} - - toString(): string { - return this.isEnv ? `env("${this.value}")` : `"${this.value}"`; - } -} - export class Generator { constructor(public name: string, public fields: SimpleField[]) {} toString(): string { return ( `generator ${this.name} {\n` + - this.fields.map((f) => indentString(`${f.name} = ${JSON.stringify(f.value)}`)).join('\n') + + this.fields.map((f) => indentString(`${f.name} = ${f.text}`)).join('\n') + `\n}` ); } diff --git a/packages/schema/src/plugins/prisma/schema-generator.ts b/packages/schema/src/plugins/prisma/schema-generator.ts index 7406bff3e..238c494e9 100644 --- a/packages/schema/src/plugins/prisma/schema-generator.ts +++ b/packages/schema/src/plugins/prisma/schema-generator.ts @@ -1,7 +1,9 @@ import { - ArrayExpr, AttributeArg, BooleanLiteral, + ConfigArrayExpr, + ConfigExpr, + ConfigInvocationArg, DataModel, DataModelAttribute, DataModelField, @@ -17,7 +19,6 @@ import { isInvocationExpr, isLiteralExpr, isReferenceExpr, - isStringLiteral, LiteralExpr, Model, NumberLiteral, @@ -29,7 +30,6 @@ import { PRISMA_MINIMUM_VERSION } from '@zenstackhq/runtime'; import { getDMMF, getLiteral, - getLiteralArray, getPrismaVersion, PluginError, PluginOptions, @@ -51,7 +51,6 @@ import { AttributeArgValue as PrismaAttributeArgValue, ContainerDeclaration as PrismaContainerDeclaration, Model as PrismaDataModel, - DataSourceUrl as PrismaDataSourceUrl, Enum as PrismaEnum, FieldAttribute as PrismaFieldAttribute, FieldReference as PrismaFieldReference, @@ -163,106 +162,67 @@ export default class PrismaSchemaGenerator { } private generateDataSource(prisma: PrismaModel, dataSource: DataSource) { - let provider: string | undefined = undefined; - let url: PrismaDataSourceUrl | undefined = undefined; - let directUrl: PrismaDataSourceUrl | undefined = undefined; - let shadowDatabaseUrl: PrismaDataSourceUrl | undefined = undefined; - const restFields: SimpleField[] = []; - - for (const f of dataSource.fields) { - switch (f.name) { - case 'provider': { - if (isStringLiteral(f.value)) { - provider = f.value.value; - } else { - throw new PluginError(name, 'Datasource provider must be set to a string'); - } - break; - } - - case 'url': { - const r = this.extractDataSourceUrl(f.value); - if (!r) { - throw new PluginError(name, 'Invalid value for datasource url'); - } - url = r; - break; - } - - case 'directUrl': { - const r = this.extractDataSourceUrl(f.value); - if (!r) { - throw new PluginError(name, 'Invalid value for directUrl'); - } - directUrl = r; - break; - } + const fields: SimpleField[] = dataSource.fields.map((f) => ({ + name: f.name, + text: this.configExprToText(f.value), + })); + prisma.addDataSource(dataSource.name, fields); + } - case 'shadowDatabaseUrl': { - const r = this.extractDataSourceUrl(f.value); - if (!r) { - throw new PluginError(name, 'Invalid value for shadowDatabaseUrl'); - } - shadowDatabaseUrl = r; - break; - } + private configExprToText(expr: ConfigExpr) { + if (isLiteralExpr(expr)) { + return this.literalToText(expr); + } else if (isInvocationExpr(expr)) { + const fc = this.makeFunctionCall(expr); + return fc.toString(); + } else { + return this.configArrayToText(expr); + } + } - default: { - // rest fields - const value = isArrayExpr(f.value) ? getLiteralArray(f.value) : getLiteral(f.value); - if (value === undefined) { - throw new PluginError( - name, - `Invalid value for datasource field ${f.name}: value must be a string or an array of strings` - ); + private configArrayToText(expr: ConfigArrayExpr) { + return ( + '[' + + expr.items + .map((item) => { + if (isLiteralExpr(item)) { + return this.literalToText(item); } else { - restFields.push({ name: f.name, value }); + return ( + item.name + + (item.args.length > 0 + ? '(' + item.args.map((arg) => this.configInvocationArgToText(arg)).join(', ') + ')' + : '') + ); } - break; - } - } - } - - if (!provider) { - throw new PluginError(name, 'Datasource is missing "provider" field'); - } - if (!url) { - throw new PluginError(name, 'Datasource is missing "url" field'); - } + }) + .join(', ') + + ']' + ); + } - prisma.addDataSource(dataSource.name, provider, url, directUrl, shadowDatabaseUrl, restFields); + private configInvocationArgToText(arg: ConfigInvocationArg) { + return `${arg.name}: ${this.literalToText(arg.value)}`; } - private extractDataSourceUrl(fieldValue: LiteralExpr | InvocationExpr | ArrayExpr) { - if (isStringLiteral(fieldValue)) { - return new PrismaDataSourceUrl(fieldValue.value, false); - } else if ( - isInvocationExpr(fieldValue) && - fieldValue.function.ref?.name === 'env' && - fieldValue.args.length === 1 && - isStringLiteral(fieldValue.args[0].value) - ) { - return new PrismaDataSourceUrl(fieldValue.args[0].value.value as string, true); - } else { - return null; - } + private literalToText(expr: LiteralExpr) { + return JSON.stringify(expr.value); } private generateGenerator(prisma: PrismaModel, decl: GeneratorDecl) { const generator = prisma.addGenerator( decl.name, - decl.fields.map((f) => { - const value = isArrayExpr(f.value) ? getLiteralArray(f.value) : getLiteral(f.value); - return { name: f.name, value }; - }) + decl.fields.map((f) => ({ name: f.name, text: this.configExprToText(f.value) })) ); // deal with configuring PrismaClient preview features const provider = generator.fields.find((f) => f.name === 'provider'); - if (provider?.value === 'prisma-client-js') { + if (provider?.text === JSON.stringify('prisma-client-js')) { const prismaVersion = getPrismaVersion(); if (prismaVersion) { - const previewFeatures = generator.fields.find((f) => f.name === 'previewFeatures')?.value ?? []; + const previewFeatures = JSON.parse( + generator.fields.find((f) => f.name === 'previewFeatures')?.text ?? '[]' + ); if (!Array.isArray(previewFeatures)) { throw new PluginError(name, 'option "previewFeatures" must be an array'); @@ -285,7 +245,9 @@ export default class PrismaSchemaGenerator { if (previewFeatures.length > 0) { const curr = generator.fields.find((f) => f.name === 'previewFeatures'); if (!curr) { - generator.fields.push({ name: 'previewFeatures', value: previewFeatures }); + generator.fields.push({ name: 'previewFeatures', text: JSON.stringify(previewFeatures) }); + } else { + curr.text = JSON.stringify(previewFeatures); } } } diff --git a/packages/schema/tests/generator/prisma-builder.test.ts b/packages/schema/tests/generator/prisma-builder.test.ts index c3badf6f1..12882a13f 100644 --- a/packages/schema/tests/generator/prisma-builder.test.ts +++ b/packages/schema/tests/generator/prisma-builder.test.ts @@ -2,7 +2,6 @@ import { getDMMF } from '@zenstackhq/sdk'; import { AttributeArg, AttributeArgValue, - DataSourceUrl, FieldAttribute, FieldReference, FieldReferenceArg, @@ -25,15 +24,17 @@ async function validate(model: PrismaModel) { describe('Prisma Builder Tests', () => { it('datasource', async () => { let model = new PrismaModel(); - model.addDataSource('db', 'postgresql', new DataSourceUrl('DATABASE_URL', true)); + model.addDataSource('db', [ + { name: 'provider', text: '"postgresql"' }, + { name: 'url', text: 'env("DATABASE_URL")' }, + ]); await validate(model); model = new PrismaModel(); - model.addDataSource( - 'db', - 'postgresql', - new DataSourceUrl('postgresql://postgres:abc123@localhost:5432/sample?schema=public', false) - ); + model.addDataSource('db', [ + { name: 'provider', text: '"postgresql"' }, + { name: 'url', text: '"postgresql://postgres:abc123@localhost:5432/sample?schema=public"' }, + ]); await validate(model); }); @@ -47,7 +48,7 @@ describe('Prisma Builder Tests', () => { it('generator', async () => { const model = new PrismaModel(); - model.addGenerator('client', [{ name: 'provider', value: 'prisma-client-js' }]); + model.addGenerator('client', [{ name: 'provider', text: '"prisma-client-js"' }]); await validate(model); }); diff --git a/packages/schema/tests/generator/prisma-generator.test.ts b/packages/schema/tests/generator/prisma-generator.test.ts index d95e78166..8ba127842 100644 --- a/packages/schema/tests/generator/prisma-generator.test.ts +++ b/packages/schema/tests/generator/prisma-generator.test.ts @@ -14,11 +14,21 @@ describe('Prisma generator test', () => { datasource db { provider = 'postgresql' url = env("DATABASE_URL") + directUrl = env("DATABASE_URL") shadowDatabaseUrl = env("DATABASE_URL") + extensions = [pg_trgm, postgis(version: "3.3.2"), uuid_ossp(map: "uuid-ossp", schema: "extensions")] + schemas = ["auth", "public"] + } + + generator client { + provider = "prisma-client-js" + previewFeatures = ["multiSchema", "postgresqlExtensions"] } model User { id String @id + + @@schema("auth") } `); @@ -31,6 +41,14 @@ describe('Prisma generator test', () => { }); const content = fs.readFileSync(name, 'utf-8'); + expect(content).toContain('provider = "postgresql"'); + expect(content).toContain('url = env("DATABASE_URL")'); + expect(content).toContain('directUrl = env("DATABASE_URL")'); + expect(content).toContain('shadowDatabaseUrl = env("DATABASE_URL")'); + expect(content).toContain( + 'extensions = [pg_trgm, postgis(version: "3.3.2"), uuid_ossp(map: "uuid-ossp", schema: "extensions")]' + ); + expect(content).toContain('schemas = ["auth", "public"]'); await getDMMF({ datamodel: content }); }); @@ -265,7 +283,7 @@ describe('Prisma generator test', () => { await getDMMF({ datamodel: content }); expect(content).toContain('@@schema("base")'); expect(content).toContain('@@schema("base")'); - expect(content).toContain('schemas = ["base","transactional"]'); + expect(content).toContain('schemas = ["base", "transactional"]'); }); it('abstract model', async () => { diff --git a/packages/schema/tests/schema/parser.test.ts b/packages/schema/tests/schema/parser.test.ts index b72749126..9b4150cd5 100644 --- a/packages/schema/tests/schema/parser.test.ts +++ b/packages/schema/tests/schema/parser.test.ts @@ -5,17 +5,20 @@ import { ArrayExpr, AttributeArg, BinaryExpr, + BooleanLiteral, + ConfigArrayExpr, + ConfigInvocationArg, + ConfigInvocationExpr, DataModel, DataSource, Enum, FunctionDecl, InvocationExpr, - ReferenceExpr, - UnaryExpr, MemberAccessExpr, - StringLiteral, - BooleanLiteral, NumberLiteral, + ReferenceExpr, + StringLiteral, + UnaryExpr, } from '@zenstackhq/language/ast'; import { loadModel } from '../utils'; @@ -25,6 +28,9 @@ describe('Parsing Tests', () => { datasource db { provider = 'postgresql' url = env('DATABASE_URL') + directUrl = env('DATABASE_URL') + extensions = [pg_trgm, postgis(version: "3.3.2"), uuid_ossp(map: "uuid-ossp", schema: "extensions")] + schemas = ["auth", "public"] } `; const doc = await loadModel(content, false); @@ -32,7 +38,7 @@ describe('Parsing Tests', () => { const ds = doc.declarations[0] as DataSource; expect(ds.name).toBe('db'); - expect(ds.fields).toHaveLength(2); + expect(ds.fields).toHaveLength(5); expect(ds.fields[0]).toEqual( expect.objectContaining({ @@ -43,6 +49,18 @@ describe('Parsing Tests', () => { 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].value.$type).toBe(StringLiteral); + + expect((ds.fields[3].value as ConfigArrayExpr).items[0].$type).toBe(ConfigInvocationExpr); + expect( + (((ds.fields[3].value as ConfigArrayExpr).items[1] as ConfigInvocationExpr).args[0] as ConfigInvocationArg) + .name + ).toBe('version'); + expect( + (((ds.fields[3].value as ConfigArrayExpr).items[1] as ConfigInvocationExpr).args[0] as ConfigInvocationArg) + .value.$type + ).toBe(StringLiteral); + + expect((ds.fields[4].value as ConfigArrayExpr).items[0].$type).toBe(StringLiteral); }); it('enum simple', async () => { diff --git a/packages/sdk/src/utils.ts b/packages/sdk/src/utils.ts index 7b3ae141a..2c515368c 100644 --- a/packages/sdk/src/utils.ts +++ b/packages/sdk/src/utils.ts @@ -1,5 +1,6 @@ import { AstNode, + ConfigExpr, DataModel, DataModelAttribute, DataModelField, @@ -11,9 +12,11 @@ import { GeneratorDecl, InternalAttribute, isArrayExpr, + isConfigArrayExpr, isDataModel, isDataModelField, isEnumField, + isExpression, isGeneratorDecl, isInvocationExpr, isLiteralExpr, @@ -44,7 +47,7 @@ export function resolved(ref: Reference): T { // eslint-disable-next-line @typescript-eslint/no-explicit-any export function getLiteral( - expr: Expression | undefined + expr: Expression | ConfigExpr | undefined ): T | undefined { if (!isLiteralExpr(expr)) { return getObjectLiteral(expr); @@ -52,22 +55,22 @@ export function getLiteral( return expr.value as T; } -export function getArray(expr: Expression | undefined): Expression[] | undefined { - return isArrayExpr(expr) ? expr.items : undefined; +export function getArray(expr: Expression | ConfigExpr | undefined) { + return isArrayExpr(expr) || isConfigArrayExpr(expr) ? expr.items : undefined; } export function getLiteralArray< // eslint-disable-next-line @typescript-eslint/no-explicit-any T extends string | number | boolean | any = any ->(expr: Expression | undefined): T[] | undefined { +>(expr: Expression | ConfigExpr | undefined): T[] | undefined { const arr = getArray(expr); if (!arr) { return undefined; } - return arr.map((item) => getLiteral(item)).filter((v): v is T => v !== undefined); + return arr.map((item) => isExpression(item) && getLiteral(item)).filter((v): v is T => v !== undefined); } -export function getObjectLiteral(expr: Expression | undefined): T | undefined { +export function getObjectLiteral(expr: Expression | ConfigExpr | undefined): T | undefined { if (!expr || !isObjectExpr(expr)) { return undefined; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83b27a82e..839afc5a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -124,7 +124,7 @@ importers: version: 0.2.1 ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.22.5)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.5) + version: 29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.5) typescript: specifier: ^4.9.5 version: 4.9.5 @@ -525,6 +525,9 @@ importers: specifier: ^0.2.1 version: 0.2.1(zod@3.21.1) devDependencies: + '@prisma/client': + specifier: ^4.8.0 + version: 4.16.2(prisma@4.16.2) '@types/async-exit-hook': specifier: ^2.0.0 version: 2.0.0 @@ -585,6 +588,9 @@ importers: jest: specifier: ^29.5.0 version: 29.5.0(@types/node@18.0.0)(ts-node@10.9.1) + prisma: + specifier: ^4.8.0 + version: 4.16.2 renamer: specifier: ^4.0.0 version: 4.0.0 @@ -596,7 +602,7 @@ importers: version: 0.2.1 ts-jest: specifier: ^29.0.3 - version: 29.0.3(@babel/core@7.22.9)(esbuild@0.15.12)(jest@29.5.0)(typescript@4.8.4) + version: 29.0.3(@babel/core@7.22.5)(esbuild@0.15.12)(jest@29.5.0)(typescript@4.8.4) ts-node: specifier: ^10.9.1 version: 10.9.1(@types/node@18.0.0)(typescript@4.8.4) @@ -2953,6 +2959,20 @@ packages: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} dev: true + /@prisma/client@4.16.2(prisma@4.16.2): + resolution: {integrity: sha512-qCoEyxv1ZrQ4bKy39GnylE8Zq31IRmm8bNhNbZx7bF2cU5aiCCnSa93J2imF88MBjn7J9eUQneNxUQVJdl/rPQ==} + engines: {node: '>=14.17'} + requiresBuild: true + peerDependencies: + prisma: '*' + peerDependenciesMeta: + prisma: + optional: true + dependencies: + '@prisma/engines-version': 4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81 + prisma: 4.16.2 + dev: true + /@prisma/debug@4.16.2: resolution: {integrity: sha512-7L7WbG0qNNZYgLpsVB8rCHCXEyHFyIycRlRDNwkVfjQmACC2OW6AWCYCbfdjQhkF/t7+S3njj8wAWAocSs+Brw==} dependencies: @@ -2973,10 +2993,13 @@ packages: - supports-color dev: false + /@prisma/engines-version@4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81: + resolution: {integrity: sha512-q617EUWfRIDTriWADZ4YiWRZXCa/WuhNgLTVd+HqWLffjMSPzyM5uOWoauX91wvQClSKZU4pzI4JJLQ9Kl62Qg==} + dev: true + /@prisma/engines@4.16.2: resolution: {integrity: sha512-vx1nxVvN4QeT/cepQce68deh/Turxy5Mr+4L4zClFuK1GlxN3+ivxfuv+ej/gvidWn1cE1uAhW7ALLNlYbRUAw==} requiresBuild: true - dev: false /@prisma/engines@5.0.0: resolution: {integrity: sha512-kyT/8fd0OpWmhAU5YnY7eP31brW1q1YrTGoblWrhQJDiN/1K+Z8S1kylcmtjqx5wsUGcP1HBWutayA/jtyt+sg==} @@ -9257,6 +9280,15 @@ packages: hasBin: true dev: true + /prisma@4.16.2: + resolution: {integrity: sha512-SYCsBvDf0/7XSJyf2cHTLjLeTLVXYfqp7pG5eEVafFLeT0u/hLFz/9W196nDRGUOo1JfPatAEb+uEnTQImQC1g==} + engines: {node: '>=14.17'} + hasBin: true + requiresBuild: true + dependencies: + '@prisma/engines': 4.16.2 + dev: true + /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -10564,7 +10596,7 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-jest@29.0.3(@babel/core@7.22.9)(esbuild@0.15.12)(jest@29.5.0)(typescript@4.8.4): + /ts-jest@29.0.3(@babel/core@7.22.5)(esbuild@0.15.12)(jest@29.5.0)(typescript@4.8.4): resolution: {integrity: sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -10585,7 +10617,7 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.22.9 + '@babel/core': 7.22.5 bs-logger: 0.2.6 esbuild: 0.15.12 fast-json-stable-stringify: 2.1.0 @@ -10599,7 +10631,7 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-jest@29.0.5(@babel/core@7.22.5)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.5): + /ts-jest@29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.4): resolution: {integrity: sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -10620,7 +10652,7 @@ packages: esbuild: optional: true dependencies: - '@babel/core': 7.22.5 + '@babel/core': 7.22.9 bs-logger: 0.2.6 esbuild: 0.18.13 fast-json-stable-stringify: 2.1.0 @@ -10630,11 +10662,11 @@ packages: lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.5.3 - typescript: 4.9.5 + typescript: 4.9.4 yargs-parser: 21.1.1 dev: true - /ts-jest@29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.4): + /ts-jest@29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.5): resolution: {integrity: sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -10665,7 +10697,7 @@ packages: lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.5.3 - typescript: 4.9.4 + typescript: 4.9.5 yargs-parser: 21.1.1 dev: true