zenstack 0.3.9 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6205,4 +6205,4 @@ See: https://chevrotain.io/docs/changes/BREAKING_CHANGES.html#_7-0-0`)}return r}
6205
6205
  "imports": [],
6206
6206
  "interfaces": [],
6207
6207
  "usedGrammars": []
6208
- }`);var QL={languageId:"zmodel",fileExtensions:[".zmodel"],caseInsensitive:!1},NE={AstReflection:()=>new ms},DE={Grammar:()=>SE(),LanguageMetaData:()=>QL,parser:{}};var an=St(Dn()),IE=St(fn());function bi(r,e){let t=r.reduce((n,i)=>{var o;return n[i.name]=(o=n[i.name])!=null?o:[],n[i.name].push(i),n},{});for(let[n,i]of Object.entries(t))i.length>1&&e("error",`Duplicated declaration name "${n}"`,{node:i[1]})}function Ol(r){if(Dl(r)&&typeof r.value=="string")return r.value}function eF(r,e){switch(r){case"Any":return!0;case"Float":return e==="Any"||e==="Int"||e==="Float";default:return e==="Any"||e===r}}function ny(r){switch(r){case"Any":case"Boolean":case"String":case"DateTime":case"Int":case"Float":case"Null":return r;case"BigInt":return"Int";case"Decimal":return"Float";case"Json":case"Bytes":return"Any"}}function wE(r,e,t){var s,u;let n=r.$resolvedType;if(!n)return!1;let i=e.type.type,o=e.type.array,a=e.type.reference;if(i){if(typeof(n==null?void 0:n.decl)!="string")return!1;if(i==="FieldReference")return o?RE(r.value)&&!r.value.items.find(c=>!ey(c)||!ea(c.target.ref)):ey(r.value)&&ea(r.value.target.ref);if(i==="ContextType")if(ea(t.$container)){if(!((u=(s=t.$container)==null?void 0:s.type)!=null&&u.type))return!1;i=ny(t.$container.type.type)}else i="Any";return eF(i,n.decl)&&o===n.array}else return(a==null?void 0:a.ref)===n.decl&&o===n.array}var $l=class extends an.DefaultLinker{constructor(t){super(t);this.descriptions=t.workspace.AstNodeDescriptionProvider}link(i){return no(this,arguments,function*(t,n=IE.CancellationToken.None){var o,a;if(!(((o=t.parseResult.lexerErrors)==null?void 0:o.length)>0||((a=t.parseResult.parserErrors)==null?void 0:a.length)>0)){for(let s of(0,an.streamContents)(t.parseResult.value))yield(0,an.interruptAndCheck)(n),this.resolve(s,t);t.state=an.DocumentState.Linked}})}linkReference(t,n,i,o){if(!this.resolveFromScopeProviders(t,n,i,o)){let a=t[n];this.doLink({reference:a,container:t,property:n},i)}}resolveFromScopeProviders(t,n,i,o){let a=t[n];for(let s of o){let u=s(a.$refText);if(u)return a._ref=u,a._nodeDescription=this.descriptions.createDescription(u,u.name,i),u}return null}resolve(t,n,i=[]){if(!t.$resolvedType)switch(t.$type){case Nl:this.resolveLiteral(t);break;case Sl:this.resolveInvocation(t,n,i);break;case kl:this.resolveArray(t,n,i);break;case wl:this.resolveReference(t,n,i);break;case Zh:this.resolveMemberAccess(t,n,i);break;case ry:this.resolveUnary(t,n,i);break;case Jh:this.resolveBinary(t,n,i);break;case ty:this.resolveThis(t,n,i);break;case Qh:this.resolveNull(t,n,i);break;case AE:this.resolveAttributeArg(t,n,i);break;default:this.resolveDefault(t,n,i);break}}resolveBinary(t,n,i){switch(t.operator){case">":case">=":case"<":case"<=":case"==":case"!=":case"&&":case"||":this.resolve(t.left,n,i),this.resolve(t.right,n,i),this.resolveToBuiltinTypeOrDecl(t,"Boolean");break;case"?":case"!":case"^":this.resolveCollectionPredicate(t,n,i);break;default:throw Error(`Unsupported binary operator: ${t.operator}`)}}resolveUnary(t,n,i){this.resolve(t.operand,n,i),t.$resolvedType=t.operand.$resolvedType}resolveReference(t,n,i){this.linkReference(t,"target",n,i),t.args.forEach(o=>this.resolve(o,n,i)),t.target.ref&&(t.target.ref.$type===xl?this.resolveToBuiltinTypeOrDecl(t,t.target.ref.$container):this.resolveToDeclaredType(t,t.target.ref.type))}resolveArray(t,n,i){t.items.forEach(a=>this.resolve(a,n,i));let o=t.items[0].$resolvedType;o!=null&&o.decl&&this.resolveToBuiltinTypeOrDecl(t,o.decl,!0)}resolveInvocation(t,n,i){if(this.linkReference(t,"function",n,i),t.args.forEach(o=>this.resolve(o,n,i)),t.function.ref){let o=t.function.ref;this.resolveToDeclaredType(t,o.returnType)}}resolveLiteral(t){let n=typeof t.value=="string"?"String":typeof t.value=="boolean"?"Boolean":typeof t.value=="number"?"Int":void 0;n&&this.resolveToBuiltinTypeOrDecl(t,n)}resolveMemberAccess(t,n,i){this.resolve(t.operand,n,i);let o=t.operand.$resolvedType;if(o&&!o.array&&Vi(o.decl)){let a=o.decl;i=[u=>a.fields.find(c=>c.name===u),...i]}this.linkReference(t,"member",n,i),t.member.ref&&this.resolveToDeclaredType(t,t.member.ref.type)}resolveCollectionPredicate(t,n,i){this.resolve(t.left,n,i);let o=t.left.$resolvedType;if(o&&Vi(o.decl)&&o.array){let a=o.decl;i=[u=>a.fields.find(c=>c.name===u),...i],this.resolve(t.right,n,i),this.resolveToBuiltinTypeOrDecl(t,"Boolean")}else console.warn("Unresolved collection predicate")}resolveThis(t,n,i){let o=t.$container;for(;o&&!Vi(o);)o=o.$container;o&&this.resolveToBuiltinTypeOrDecl(t,o)}resolveNull(t,n,i){this.resolveToBuiltinTypeOrDecl(t,"Null")}resolveAttributeArg(t,n,i){this.resolve(t.value,n,i),t.$resolvedType=t.value.$resolvedType}resolveDefault(t,n,i){for(let[o,a]of Object.entries(t))o.startsWith("$")||(0,an.isReference)(a)&&this.linkReference(t,o,n,i);for(let o of(0,an.streamContents)(t))this.resolve(o,n,i)}resolveToDeclaredType(t,n){if(n.type){let i=ny(n.type);t.$resolvedType={decl:i,array:n.array}}else n.reference&&(t.$resolvedType={decl:n.reference.ref,array:n.array})}resolveToBuiltinTypeOrDecl(t,n,i=!1){t.$resolvedType={decl:n,array:i}}};var ra=St(Dn());var ta=class extends ra.DefaultScopeComputation{constructor(t){super(t);this.services=t}computeExports(t,n){return no(this,null,function*(){let i=yield As(ta.prototype,this,"computeExports").call(this,t,n);for(let o of(0,ra.streamAllContents)(t.parseResult.value))if(n&&(yield(0,ra.interruptAndCheck)(n)),PE(o)){let a=this.services.workspace.AstNodeDescriptionProvider.createDescription(o,o.name,t);i.push(a)}return i})}};var LE=St(Dn());var iy=["postgresql","mysql","sqlite","sqlserver"],OE=["String","Int","Float","Decimal","BigInt","Boolean","Bytes","DateTime"],Ml="stdlib.zmodel";var hs=class{validate(e,t){var n;bi(e.declarations,t),(n=e.$document)!=null&&n.uri.path.endsWith(Ml)||this.validateDataSources(e,t)}validateDataSources(e,t){let n=e.declarations.filter(i=>CE(i));n.length===0?t("error","Model must define a datasource",{node:e}):n.length>1&&t("error","Multiple datasource declarations are not allowed",{node:n[1]})}};var tF=["provider","url","shadowDatabaseUrl","relationMode"],ys=class{validate(e,t){bi(e.fields,t),this.validateFields(e,t),this.validateProvider(e,t),this.validateUrl(e,t),this.validateRelationMode(e,t)}validateFields(e,t){e.fields.forEach(n=>{tF.includes(n.name)||t("error",`Unexpected field "${n.name}"`,{node:n})})}validateProvider(e,t){let n=e.fields.find(o=>o.name==="provider");if(!n){t("error",'datasource must include a "provider" field',{node:e});return}let i=Ol(n.value);i?iy.includes(i)||t("error",`Provider "${i}" is not supported. Choose from ${iy.map(o=>'"'+o+'"').join(" | ")}.`,{node:n.value}):t("error",'"provider" must be set to a string literal',{node:n.value})}validateUrl(e,t){var i;e.fields.find(o=>o.name==="url")||t("error",'datasource must include a "url" field',{node:e});for(let o of["url","shadowDatabaseUrl"]){let a=e.fields.find(u=>u.name===o);if(!a)continue;!Ol(a.value)&&!(kE(a.value)&&((i=a.value.function.ref)==null?void 0:i.name)==="env")&&t("error",`"${o}" must be set to a string literal or an invocation of "env" function`,{node:a.value})}}validateRelationMode(e,t){let n=e.fields.find(i=>i.name==="relationMode");if(n){let i=Ol(n.value);(!i||!["foreignKeys","prisma"].includes(i))&&t("error",'"relationMode" must be set to "foreignKeys" or "prisma"',{node:n.value})}}};var ME=St($E()),gs=class{validate(e,t){bi(e.fields,t),this.validateFields(e,t),this.validateAttributes(e,t)}validateFields(e,t){let n=e.fields.filter(i=>i.attributes.find(o=>{var a;return((a=o.decl.ref)==null?void 0:a.name)==="@id"}));n.length===0?t("error","Model must include a field with @id attribute",{node:e}):n.length>1?t("error","Model can include at most one field with @id attribute",{node:e}):(n[0].type.optional&&t("error","Field with @id attribute must not be optional",{node:n[0]}),(n[0].type.array||!n[0].type.type||!OE.includes(n[0].type.type))&&t("error","Field with @id attribute must be of scalar type",{node:n[0]})),e.fields.forEach(i=>this.validateField(i,t))}validateField(e,t){var n;e.type.array&&e.type.optional&&t("error","Optional lists are not supported. Use either `Type[]` or `Type?`",{node:e.type}),e.attributes.forEach(i=>this.validateAttributeApplication(i,t)),Vi((n=e.type.reference)==null?void 0:n.ref)&&this.validateRelationField(e,t)}validateAttributes(e,t){e.attributes.forEach(n=>{this.validateAttributeApplication(n,t)})}validateAttributeApplication(e,t){let n=e.decl.ref;if(!n)return;let i=e.$container;if(n.name==="@@@targetField"&&!_E(i)){t("error",`attribute "${n.name}" can only be used on attribute declarations`,{node:e});return}ea(i)&&!this.isValidAttributeTarget(n,i)&&t("error",`attribute "${n.name}" cannot be used on this type of field`,{node:e});let o=new Set;for(let s of e.args){let u;if(s.name){if(u=n.params.find(c=>c.name===s.name),!u)return t("error",`Attribute "${n.name}" doesn't have a parameter named "${s.name}"`,{node:s}),!1}else if(u=n.params.find(c=>c.default&&!o.has(c)),!u)return t("error","Unexpected unnamed argument",{node:s}),!1;if(!wE(s,u,e))return t("error","Value is not assignable to parameter",{node:s}),!1;if(o.has(u))return t("error",`Parameter "${u.name}" is already provided`,{node:s}),!1;o.add(u),s.$resolvedParam=u}let a=n.params.filter(s=>!s.type.optional&&!o.has(s));return a.length>0?(t("error",`Required ${(0,ME.default)("parameter",a.length)} not provided: ${a.map(s=>s.name).join(", ")}`,{node:e}),!1):!0}isValidAttributeTarget(e,t){var a;let n=e.attributes.find(s=>{var u;return((u=s.decl.ref)==null?void 0:u.name)==="@@@targetField"});if(!n)return!0;let i=n.args[0].value.items.map(s=>{var u;return(u=s.target.ref)==null?void 0:u.name}),o=!1;for(let s of i){switch(s){case"StringField":o=o||t.type.type==="String";break;case"IntField":o=o||t.type.type==="Int";break;case"FloatField":o=o||t.type.type==="Float";break;case"DecimalField":o=o||t.type.type==="Decimal";break;case"BooleanField":o=o||t.type.type==="Boolean";break;case"DateTimeField":o=o||t.type.type==="DateTime";break;case"JsonField":o=o||t.type.type==="Json";break;case"BytesField":o=o||t.type.type==="Bytes";break;case"ModelField":o=o||Vi((a=t.type.reference)==null?void 0:a.ref);break;default:break}if(o)break}return o}parseRelation(e,t){let n=e.attributes.find(u=>{var c;return((c=u.decl.ref)==null?void 0:c.name)==="@relation"}),i,o,a,s=!0;if(!n)return{attr:n,name:i,fields:o,references:a,valid:!0};for(let u of n.args)!u.name||u.name==="name"?Dl(u.value)&&(i=u.value.value):u.name==="fields"?(o=u.value.items,o.length===0&&(t&&t("error",'"fields" value cannot be emtpy',{node:u}),s=!1)):u.name==="references"&&(a=u.value.items,a.length===0&&(t&&t("error",'"references" value cannot be emtpy',{node:u}),s=!1));return{attr:n,name:i,fields:o,references:a,valid:s}}validateRelationField(e,t){var c,l,d,g;let n=this.parseRelation(e,t);if(!n.valid)return;let i=e.type.reference.ref,o=i.fields.filter(h=>{var p;return((p=h.type.reference)==null?void 0:p.ref)===e.$container});if(o=o.filter(h=>{let p=this.parseRelation(h);return p.valid&&p.name===n.name}),o.length===0){t("error",`The relation field "${e.name}" on model "${e.$container.name}" is missing an opposite relation field on model "${i.name}"`,{node:e});return}else if(o.length>1){o.forEach(h=>t("error",`Fields ${o.map(p=>'"'+p.name+'"').join(", ")} on model "${i.name}" refer to the same relation to model "${e.$container.name}"`,{node:h}));return}let a=o[0],s=this.parseRelation(a),u;if(((c=n==null?void 0:n.references)==null?void 0:c.length)&&((l=n.fields)==null?void 0:l.length))if((s==null?void 0:s.references)||(s==null?void 0:s.fields)){t("error",'"fields" and "references" must be provided only on one side of relation field',{node:a});return}else u=a;else if(((d=s==null?void 0:s.references)==null?void 0:d.length)&&((g=s.fields)==null?void 0:g.length))if((n==null?void 0:n.references)||(n==null?void 0:n.fields)){t("error",'"fields" and "references" must be provided only on one side of relation field',{node:e});return}else u=e;else{[e,a].forEach(h=>t("error",'Field for one side of relation must carry @relation attribute with both "fields" and "references" fields',{node:h}));return}if(!u.type.array&&!u.type.optional){t("error","Relation field needs to be list or optional",{node:u});return}}};var vs=class{validate(e,t){}};var Ts=class{validate(e,t){bi(e.fields,t)}};var Ll=class extends LE.ValidationRegistry{constructor(e){super(e);let t=e.validation.ZModelValidator,n={Model:t.checkModel,DataSource:t.checkDataSource,DataModel:t.checkDataModel,Enum:t.checkEnum,Attribute:t.checkAttribute};this.register(n,t)}},Fl=class{shouldCheck(e){let t,n=e;for(;n;){if(n.$document){t=n.$document;break}n=n.$container}return(t==null?void 0:t.parseResult.lexerErrors.length)===0&&(t==null?void 0:t.parseResult.parserErrors.length)===0}checkModel(e,t){this.shouldCheck(e)&&new hs().validate(e,t)}checkDataSource(e,t){this.shouldCheck(e)&&new ys().validate(e,t)}checkDataModel(e,t){this.shouldCheck(e)&&new gs().validate(e,t)}checkEnum(e,t){this.shouldCheck(e)&&new Ts().validate(e,t)}checkAttribute(e,t){this.shouldCheck(e)&&new vs().validate(e,t)}};var UE=St(Ne()),HE=St(yu());var FE=St(Dn()),qE=St(require("path")),jE=St(gn());var Yi=class extends FE.DefaultWorkspaceManager{loadAdditionalDocuments(e,t){return no(this,null,function*(){yield As(Yi.prototype,this,"loadAdditionalDocuments").call(this,e,t);let n=jE.URI.file(qE.default.join(__dirname,"../res",Ml));console.log(`Adding stdlib document from ${n}`);let i=this.langiumDocuments.getOrCreateDocument(n);t(i)})}};var ql=St(Dn()),GE=St(Ne()),Rs=class{constructor(e){this.nameProvider=e.references.NameProvider,this.references=e.references.References,this.grammarConfig=e.parser.GrammarConfig}getDefinition(e,t){let n=e.parseResult.value;if(n.$cstNode){let i=n.$cstNode,o=(0,ql.findDeclarationNodeAtOffset)(i,e.textDocument.offsetAt(t.position),this.grammarConfig.nameRegexp);if(o)return this.collectLocationLinks(o,t)}}collectLocationLinks(e,t){var i;let n=this.findLink(e);if(n&&!n.targetDocument.textDocument.uri.endsWith("stdlib.zmodel"))return[GE.LocationLink.create(n.targetDocument.textDocument.uri,((i=n.target.element.$cstNode)!=null?i:n.target).range,n.target.range,n.source.range)]}findLink(e){let t=this.references.findDeclarationNode(e);if(t!=null&&t.element){let n=(0,ql.getDocument)(t.element);if(t&&n)return{source:e,target:t,targetDocument:n}}}};var rF={references:{ScopeComputation:r=>new ta(r),Linker:r=>new $l(r)},validation:{ValidationRegistry:r=>new Ll(r),ZModelValidator:()=>new Fl},lsp:{DefinitionProvider:r=>new Rs(r)}};function nF(r){return{ServiceRegistry:()=>new st.DefaultServiceRegistry,lsp:{Connection:()=>r.connection,LanguageServer:e=>new st.DefaultLanguageServer(e)},workspace:{LangiumDocuments:e=>new st.DefaultLangiumDocuments(e),LangiumDocumentFactory:e=>new st.DefaultLangiumDocumentFactory(e),DocumentBuilder:e=>new st.DefaultDocumentBuilder(e),TextDocuments:()=>new UE.TextDocuments(HE.TextDocument),TextDocumentFactory:e=>new st.DefaultTextDocumentFactory(e),IndexManager:e=>new st.DefaultIndexManager(e),WorkspaceManager:e=>new Yi(e),FileSystemProvider:e=>r.fileSystemProvider(e),MutexLock:()=>new st.MutexLock,ConfigurationProvider:e=>new st.DefaultConfigurationProvider(e)}}}function WE(r){let e=(0,st.inject)(nF(r),NE),t=(0,st.inject)((0,st.createDefaultModule)({shared:e}),DE,rF);return e.ServiceRegistry.register(t),{shared:e,ZModel:t}}var iF=(0,jl.createConnection)(jl.ProposedFeatures.all),{shared:oF}=WE(fy({connection:iF},BE.NodeFileSystem));(0,KE.startLanguageServer)(oF);
6208
+ }`);var QL={languageId:"zmodel",fileExtensions:[".zmodel"],caseInsensitive:!1},NE={AstReflection:()=>new ms},DE={Grammar:()=>SE(),LanguageMetaData:()=>QL,parser:{}};var an=St(Dn()),IE=St(fn());function bi(r,e){let t=r.reduce((n,i)=>{var o;return n[i.name]=(o=n[i.name])!=null?o:[],n[i.name].push(i),n},{});for(let[n,i]of Object.entries(t))i.length>1&&e("error",`Duplicated declaration name "${n}"`,{node:i[1]})}function Ol(r){if(Dl(r)&&typeof r.value=="string")return r.value}function eF(r,e){switch(r){case"Any":return!0;case"Float":return e==="Any"||e==="Int"||e==="Float";default:return e==="Any"||e===r}}function ny(r){switch(r){case"Any":case"Boolean":case"String":case"DateTime":case"Int":case"Float":case"Null":return r;case"BigInt":return"Int";case"Decimal":return"Float";case"Json":case"Bytes":return"Any"}}function wE(r,e,t){var s,u;let n=r.$resolvedType;if(!n)return!1;let i=e.type.type,o=e.type.array,a=e.type.reference;if(i){if(typeof(n==null?void 0:n.decl)!="string")return!1;if(i==="FieldReference")return o?RE(r.value)&&!r.value.items.find(c=>!ey(c)||!ea(c.target.ref)):ey(r.value)&&ea(r.value.target.ref);if(i==="ContextType")if(ea(t.$container)){if(!((u=(s=t.$container)==null?void 0:s.type)!=null&&u.type))return!1;i=ny(t.$container.type.type)}else i="Any";return eF(i,n.decl)&&o===n.array}else return(a==null?void 0:a.ref)===n.decl&&o===n.array}var $l=class extends an.DefaultLinker{constructor(t){super(t);this.descriptions=t.workspace.AstNodeDescriptionProvider}link(i){return no(this,arguments,function*(t,n=IE.CancellationToken.None){var o,a;if(!(((o=t.parseResult.lexerErrors)==null?void 0:o.length)>0||((a=t.parseResult.parserErrors)==null?void 0:a.length)>0)){for(let s of(0,an.streamContents)(t.parseResult.value))yield(0,an.interruptAndCheck)(n),this.resolve(s,t);t.state=an.DocumentState.Linked}})}linkReference(t,n,i,o){if(!this.resolveFromScopeProviders(t,n,i,o)){let a=t[n];this.doLink({reference:a,container:t,property:n},i)}}resolveFromScopeProviders(t,n,i,o){let a=t[n];for(let s of o){let u=s(a.$refText);if(u)return a._ref=u,a._nodeDescription=this.descriptions.createDescription(u,u.name,i),u}return null}resolve(t,n,i=[]){if(!t.$resolvedType)switch(t.$type){case Nl:this.resolveLiteral(t);break;case Sl:this.resolveInvocation(t,n,i);break;case kl:this.resolveArray(t,n,i);break;case wl:this.resolveReference(t,n,i);break;case Zh:this.resolveMemberAccess(t,n,i);break;case ry:this.resolveUnary(t,n,i);break;case Jh:this.resolveBinary(t,n,i);break;case ty:this.resolveThis(t,n,i);break;case Qh:this.resolveNull(t,n,i);break;case AE:this.resolveAttributeArg(t,n,i);break;default:this.resolveDefault(t,n,i);break}}resolveBinary(t,n,i){switch(t.operator){case">":case">=":case"<":case"<=":case"==":case"!=":case"&&":case"||":this.resolve(t.left,n,i),this.resolve(t.right,n,i),this.resolveToBuiltinTypeOrDecl(t,"Boolean");break;case"?":case"!":case"^":this.resolveCollectionPredicate(t,n,i);break;default:throw Error(`Unsupported binary operator: ${t.operator}`)}}resolveUnary(t,n,i){this.resolve(t.operand,n,i),t.$resolvedType=t.operand.$resolvedType}resolveReference(t,n,i){this.linkReference(t,"target",n,i),t.args.forEach(o=>this.resolve(o,n,i)),t.target.ref&&(t.target.ref.$type===xl?this.resolveToBuiltinTypeOrDecl(t,t.target.ref.$container):this.resolveToDeclaredType(t,t.target.ref.type))}resolveArray(t,n,i){t.items.forEach(a=>this.resolve(a,n,i));let o=t.items[0].$resolvedType;o!=null&&o.decl&&this.resolveToBuiltinTypeOrDecl(t,o.decl,!0)}resolveInvocation(t,n,i){if(this.linkReference(t,"function",n,i),t.args.forEach(o=>this.resolve(o,n,i)),t.function.ref){let o=t.function.ref;this.resolveToDeclaredType(t,o.returnType)}}resolveLiteral(t){let n=typeof t.value=="string"?"String":typeof t.value=="boolean"?"Boolean":typeof t.value=="number"?"Int":void 0;n&&this.resolveToBuiltinTypeOrDecl(t,n)}resolveMemberAccess(t,n,i){this.resolve(t.operand,n,i);let o=t.operand.$resolvedType;if(o&&!o.array&&Vi(o.decl)){let a=o.decl;i=[u=>a.fields.find(c=>c.name===u),...i]}this.linkReference(t,"member",n,i),t.member.ref&&this.resolveToDeclaredType(t,t.member.ref.type)}resolveCollectionPredicate(t,n,i){this.resolve(t.left,n,i);let o=t.left.$resolvedType;if(o&&Vi(o.decl)&&o.array){let a=o.decl;i=[u=>a.fields.find(c=>c.name===u),...i],this.resolve(t.right,n,i),this.resolveToBuiltinTypeOrDecl(t,"Boolean")}else console.warn("Unresolved collection predicate")}resolveThis(t,n,i){let o=t.$container;for(;o&&!Vi(o);)o=o.$container;o&&this.resolveToBuiltinTypeOrDecl(t,o)}resolveNull(t,n,i){this.resolveToBuiltinTypeOrDecl(t,"Null")}resolveAttributeArg(t,n,i){this.resolve(t.value,n,i),t.$resolvedType=t.value.$resolvedType}resolveDefault(t,n,i){for(let[o,a]of Object.entries(t))o.startsWith("$")||(0,an.isReference)(a)&&this.linkReference(t,o,n,i);for(let o of(0,an.streamContents)(t))this.resolve(o,n,i)}resolveToDeclaredType(t,n){if(n.type){let i=ny(n.type);t.$resolvedType={decl:i,array:n.array}}else n.reference&&(t.$resolvedType={decl:n.reference.ref,array:n.array})}resolveToBuiltinTypeOrDecl(t,n,i=!1){t.$resolvedType={decl:n,array:i}}};var ra=St(Dn());var ta=class extends ra.DefaultScopeComputation{constructor(t){super(t);this.services=t}computeExports(t,n){return no(this,null,function*(){let i=yield As(ta.prototype,this,"computeExports").call(this,t,n);for(let o of(0,ra.streamAllContents)(t.parseResult.value))if(n&&(yield(0,ra.interruptAndCheck)(n)),PE(o)){let a=this.services.workspace.AstNodeDescriptionProvider.createDescription(o,o.name,t);i.push(a)}return i})}};var LE=St(Dn());var iy=["sqlite","postgresql","mysql","sqlserver","cockroachdb"],OE=["String","Int","Float","Decimal","BigInt","Boolean","Bytes","DateTime"],Ml="stdlib.zmodel";var hs=class{validate(e,t){var n;bi(e.declarations,t),(n=e.$document)!=null&&n.uri.path.endsWith(Ml)||this.validateDataSources(e,t)}validateDataSources(e,t){let n=e.declarations.filter(i=>CE(i));n.length===0?t("error","Model must define a datasource",{node:e}):n.length>1&&t("error","Multiple datasource declarations are not allowed",{node:n[1]})}};var tF=["provider","url","shadowDatabaseUrl","relationMode"],ys=class{validate(e,t){bi(e.fields,t),this.validateFields(e,t),this.validateProvider(e,t),this.validateUrl(e,t),this.validateRelationMode(e,t)}validateFields(e,t){e.fields.forEach(n=>{tF.includes(n.name)||t("error",`Unexpected field "${n.name}"`,{node:n})})}validateProvider(e,t){let n=e.fields.find(o=>o.name==="provider");if(!n){t("error",'datasource must include a "provider" field',{node:e});return}let i=Ol(n.value);i?iy.includes(i)||t("error",`Provider "${i}" is not supported. Choose from ${iy.map(o=>'"'+o+'"').join(" | ")}.`,{node:n.value}):t("error",'"provider" must be set to a string literal',{node:n.value})}validateUrl(e,t){var i;e.fields.find(o=>o.name==="url")||t("error",'datasource must include a "url" field',{node:e});for(let o of["url","shadowDatabaseUrl"]){let a=e.fields.find(u=>u.name===o);if(!a)continue;!Ol(a.value)&&!(kE(a.value)&&((i=a.value.function.ref)==null?void 0:i.name)==="env")&&t("error",`"${o}" must be set to a string literal or an invocation of "env" function`,{node:a.value})}}validateRelationMode(e,t){let n=e.fields.find(i=>i.name==="relationMode");if(n){let i=Ol(n.value);(!i||!["foreignKeys","prisma"].includes(i))&&t("error",'"relationMode" must be set to "foreignKeys" or "prisma"',{node:n.value})}}};var ME=St($E()),gs=class{validate(e,t){bi(e.fields,t),this.validateFields(e,t),this.validateAttributes(e,t)}validateFields(e,t){let n=e.fields.filter(i=>i.attributes.find(o=>{var a;return((a=o.decl.ref)==null?void 0:a.name)==="@id"}));n.length===0?t("error","Model must include a field with @id attribute",{node:e}):n.length>1?t("error","Model can include at most one field with @id attribute",{node:e}):(n[0].type.optional&&t("error","Field with @id attribute must not be optional",{node:n[0]}),(n[0].type.array||!n[0].type.type||!OE.includes(n[0].type.type))&&t("error","Field with @id attribute must be of scalar type",{node:n[0]})),e.fields.forEach(i=>this.validateField(i,t))}validateField(e,t){var n;e.type.array&&e.type.optional&&t("error","Optional lists are not supported. Use either `Type[]` or `Type?`",{node:e.type}),e.attributes.forEach(i=>this.validateAttributeApplication(i,t)),Vi((n=e.type.reference)==null?void 0:n.ref)&&this.validateRelationField(e,t)}validateAttributes(e,t){e.attributes.forEach(n=>{this.validateAttributeApplication(n,t)})}validateAttributeApplication(e,t){let n=e.decl.ref;if(!n)return;let i=e.$container;if(n.name==="@@@targetField"&&!_E(i)){t("error",`attribute "${n.name}" can only be used on attribute declarations`,{node:e});return}ea(i)&&!this.isValidAttributeTarget(n,i)&&t("error",`attribute "${n.name}" cannot be used on this type of field`,{node:e});let o=new Set;for(let s of e.args){let u;if(s.name){if(u=n.params.find(c=>c.name===s.name),!u)return t("error",`Attribute "${n.name}" doesn't have a parameter named "${s.name}"`,{node:s}),!1}else if(u=n.params.find(c=>c.default&&!o.has(c)),!u)return t("error","Unexpected unnamed argument",{node:s}),!1;if(!wE(s,u,e))return t("error","Value is not assignable to parameter",{node:s}),!1;if(o.has(u))return t("error",`Parameter "${u.name}" is already provided`,{node:s}),!1;o.add(u),s.$resolvedParam=u}let a=n.params.filter(s=>!s.type.optional&&!o.has(s));return a.length>0?(t("error",`Required ${(0,ME.default)("parameter",a.length)} not provided: ${a.map(s=>s.name).join(", ")}`,{node:e}),!1):!0}isValidAttributeTarget(e,t){var a;let n=e.attributes.find(s=>{var u;return((u=s.decl.ref)==null?void 0:u.name)==="@@@targetField"});if(!n)return!0;let i=n.args[0].value.items.map(s=>{var u;return(u=s.target.ref)==null?void 0:u.name}),o=!1;for(let s of i){switch(s){case"StringField":o=o||t.type.type==="String";break;case"IntField":o=o||t.type.type==="Int";break;case"FloatField":o=o||t.type.type==="Float";break;case"DecimalField":o=o||t.type.type==="Decimal";break;case"BooleanField":o=o||t.type.type==="Boolean";break;case"DateTimeField":o=o||t.type.type==="DateTime";break;case"JsonField":o=o||t.type.type==="Json";break;case"BytesField":o=o||t.type.type==="Bytes";break;case"ModelField":o=o||Vi((a=t.type.reference)==null?void 0:a.ref);break;default:break}if(o)break}return o}parseRelation(e,t){let n=e.attributes.find(u=>{var c;return((c=u.decl.ref)==null?void 0:c.name)==="@relation"}),i,o,a,s=!0;if(!n)return{attr:n,name:i,fields:o,references:a,valid:!0};for(let u of n.args)!u.name||u.name==="name"?Dl(u.value)&&(i=u.value.value):u.name==="fields"?(o=u.value.items,o.length===0&&(t&&t("error",'"fields" value cannot be emtpy',{node:u}),s=!1)):u.name==="references"&&(a=u.value.items,a.length===0&&(t&&t("error",'"references" value cannot be emtpy',{node:u}),s=!1));return{attr:n,name:i,fields:o,references:a,valid:s}}validateRelationField(e,t){var c,l,d,g;let n=this.parseRelation(e,t);if(!n.valid)return;let i=e.type.reference.ref,o=i.fields.filter(h=>{var p;return((p=h.type.reference)==null?void 0:p.ref)===e.$container});if(o=o.filter(h=>{let p=this.parseRelation(h);return p.valid&&p.name===n.name}),o.length===0){t("error",`The relation field "${e.name}" on model "${e.$container.name}" is missing an opposite relation field on model "${i.name}"`,{node:e});return}else if(o.length>1){o.forEach(h=>t("error",`Fields ${o.map(p=>'"'+p.name+'"').join(", ")} on model "${i.name}" refer to the same relation to model "${e.$container.name}"`,{node:h}));return}let a=o[0],s=this.parseRelation(a),u;if(((c=n==null?void 0:n.references)==null?void 0:c.length)&&((l=n.fields)==null?void 0:l.length))if((s==null?void 0:s.references)||(s==null?void 0:s.fields)){t("error",'"fields" and "references" must be provided only on one side of relation field',{node:a});return}else u=a;else if(((d=s==null?void 0:s.references)==null?void 0:d.length)&&((g=s.fields)==null?void 0:g.length))if((n==null?void 0:n.references)||(n==null?void 0:n.fields)){t("error",'"fields" and "references" must be provided only on one side of relation field',{node:e});return}else u=e;else{[e,a].forEach(h=>t("error",'Field for one side of relation must carry @relation attribute with both "fields" and "references" fields',{node:h}));return}if(!u.type.array&&!u.type.optional){t("error","Relation field needs to be list or optional",{node:u});return}}};var vs=class{validate(e,t){}};var Ts=class{validate(e,t){bi(e.fields,t)}};var Ll=class extends LE.ValidationRegistry{constructor(e){super(e);let t=e.validation.ZModelValidator,n={Model:t.checkModel,DataSource:t.checkDataSource,DataModel:t.checkDataModel,Enum:t.checkEnum,Attribute:t.checkAttribute};this.register(n,t)}},Fl=class{shouldCheck(e){let t,n=e;for(;n;){if(n.$document){t=n.$document;break}n=n.$container}return(t==null?void 0:t.parseResult.lexerErrors.length)===0&&(t==null?void 0:t.parseResult.parserErrors.length)===0}checkModel(e,t){this.shouldCheck(e)&&new hs().validate(e,t)}checkDataSource(e,t){this.shouldCheck(e)&&new ys().validate(e,t)}checkDataModel(e,t){this.shouldCheck(e)&&new gs().validate(e,t)}checkEnum(e,t){this.shouldCheck(e)&&new Ts().validate(e,t)}checkAttribute(e,t){this.shouldCheck(e)&&new vs().validate(e,t)}};var UE=St(Ne()),HE=St(yu());var FE=St(Dn()),qE=St(require("path")),jE=St(gn());var Yi=class extends FE.DefaultWorkspaceManager{loadAdditionalDocuments(e,t){return no(this,null,function*(){yield As(Yi.prototype,this,"loadAdditionalDocuments").call(this,e,t);let n=jE.URI.file(qE.default.join(__dirname,"../res",Ml));console.log(`Adding stdlib document from ${n}`);let i=this.langiumDocuments.getOrCreateDocument(n);t(i)})}};var ql=St(Dn()),GE=St(Ne()),Rs=class{constructor(e){this.nameProvider=e.references.NameProvider,this.references=e.references.References,this.grammarConfig=e.parser.GrammarConfig}getDefinition(e,t){let n=e.parseResult.value;if(n.$cstNode){let i=n.$cstNode,o=(0,ql.findDeclarationNodeAtOffset)(i,e.textDocument.offsetAt(t.position),this.grammarConfig.nameRegexp);if(o)return this.collectLocationLinks(o,t)}}collectLocationLinks(e,t){var i;let n=this.findLink(e);if(n&&!n.targetDocument.textDocument.uri.endsWith("stdlib.zmodel"))return[GE.LocationLink.create(n.targetDocument.textDocument.uri,((i=n.target.element.$cstNode)!=null?i:n.target).range,n.target.range,n.source.range)]}findLink(e){let t=this.references.findDeclarationNode(e);if(t!=null&&t.element){let n=(0,ql.getDocument)(t.element);if(t&&n)return{source:e,target:t,targetDocument:n}}}};var rF={references:{ScopeComputation:r=>new ta(r),Linker:r=>new $l(r)},validation:{ValidationRegistry:r=>new Ll(r),ZModelValidator:()=>new Fl},lsp:{DefinitionProvider:r=>new Rs(r)}};function nF(r){return{ServiceRegistry:()=>new st.DefaultServiceRegistry,lsp:{Connection:()=>r.connection,LanguageServer:e=>new st.DefaultLanguageServer(e)},workspace:{LangiumDocuments:e=>new st.DefaultLangiumDocuments(e),LangiumDocumentFactory:e=>new st.DefaultLangiumDocumentFactory(e),DocumentBuilder:e=>new st.DefaultDocumentBuilder(e),TextDocuments:()=>new UE.TextDocuments(HE.TextDocument),TextDocumentFactory:e=>new st.DefaultTextDocumentFactory(e),IndexManager:e=>new st.DefaultIndexManager(e),WorkspaceManager:e=>new Yi(e),FileSystemProvider:e=>r.fileSystemProvider(e),MutexLock:()=>new st.MutexLock,ConfigurationProvider:e=>new st.DefaultConfigurationProvider(e)}}}function WE(r){let e=(0,st.inject)(nF(r),NE),t=(0,st.inject)((0,st.createDefaultModule)({shared:e}),DE,rF);return e.ServiceRegistry.register(t),{shared:e,ZModel:t}}var iF=(0,jl.createConnection)(jl.ProposedFeatures.all),{shared:oF}=WE(fy({connection:iF},BE.NodeFileSystem));(0,KE.startLanguageServer)(oF);
@@ -7,6 +7,30 @@ enum ReferentialAction {
7
7
  * Used with "onUpdate": updates the relation scalar fields if the referenced scalar fields of the dependent record are updated.
8
8
  */
9
9
  Cascade
10
+
11
+ /*
12
+ * Used with "onDelete": prevents the deletion if any referencing records exist.
13
+ * Used with "onUpdate": prevents the identifier of a referenced record from being changed.
14
+ */
15
+ Restrict
16
+
17
+ /*
18
+ * Similar to 'Restrict', the difference between the two is dependent on the database being used.
19
+ * See details: https://www.prisma.io/docs/concepts/components/prisma-schema/relations/referential-actions#noaction
20
+ */
21
+ NoAction
22
+
23
+ /*
24
+ * Used with "onDelete": the scalar field of the referencing object will be set to NULL.
25
+ * Used with "onUpdate": when updating the identifier of a referenced object, the scalar fields of the referencing objects will be set to NULL.
26
+ */
27
+ SetNull
28
+
29
+ /*
30
+ * Used with "onDelete": the scalar field of the referencing object will be set to the fields default value.
31
+ * Used with "onUpdate": the scalar field of the referencing object will be set to the fields default value.
32
+ */
33
+ SetDefault
10
34
  }
11
35
 
12
36
  /*
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publisher": "zenstack",
4
4
  "displayName": "ZenStack Language Tools",
5
5
  "description": "A toolkit for modeling data and access policies in full-stack development with Next.js and Typescript",
6
- "version": "0.3.9",
6
+ "version": "0.3.10",
7
7
  "author": {
8
8
  "name": "ZenStack Team"
9
9
  },
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "main": "./bundle/extension.js",
67
67
  "dependencies": {
68
- "@zenstackhq/internal": "0.3.9",
68
+ "@zenstackhq/internal": "0.3.10",
69
69
  "async-exit-hook": "^2.0.1",
70
70
  "change-case": "^4.1.2",
71
71
  "chevrotain": "^9.1.0",
@@ -12,6 +12,93 @@ import { GENERATED_CODE_PATH } from '../generator/constants';
12
12
  import { Context, GeneratorError } from '../generator/types';
13
13
  import { CliError } from './cli-error';
14
14
 
15
+ /**
16
+ * Initializes an existing project for ZenStack
17
+ */
18
+ export async function initProject(projectPath: string) {
19
+ const schema = path.join(projectPath, 'zenstack', 'schema.zmodel');
20
+ if (fs.existsSync(schema)) {
21
+ console.warn(colors.yellow(`Model already exists: ${schema}`));
22
+ throw new CliError(`schema file already exists`);
23
+ }
24
+
25
+ // create a default model
26
+ if (!fs.existsSync(path.join(projectPath, 'zenstack'))) {
27
+ fs.mkdirSync(path.join(projectPath, 'zenstack'));
28
+ }
29
+
30
+ fs.writeFileSync(
31
+ schema,
32
+ `// This is a sample model to get you started.
33
+ // Learn how to model you app: https://zenstack.dev/#/modeling-your-app.
34
+
35
+ /*
36
+ * A sample data source using local sqlite db.
37
+ * See how to use a different db: https://zenstack.dev/#/zmodel-data-source.
38
+ */
39
+ datasource db {
40
+ provider = 'sqlite'
41
+ url = 'file:./todo.db'
42
+ }
43
+
44
+ /*
45
+ * User model
46
+ */
47
+ model User {
48
+ id String @id @default(cuid())
49
+ email String @unique @email
50
+ password String @password @omit @length(8, 16)
51
+ posts Post[]
52
+
53
+ // everybody can signup
54
+ @@allow('create', true)
55
+
56
+ // full access by self
57
+ @@allow('all', auth() == this)
58
+ }
59
+
60
+ /*
61
+ * Post model
62
+ */
63
+ model Post {
64
+ id String @id @default(cuid())
65
+ createdAt DateTime @default(now())
66
+ updatedAt DateTime @updatedAt
67
+ title String @length(1, 256)
68
+ content String
69
+ published Boolean @default(false)
70
+ author User? @relation(fields: [authorId], references: [id])
71
+ authorId String?
72
+
73
+ // allow read for all signin users
74
+ @@allow('read', auth() != null && published)
75
+
76
+ // full access by author
77
+ @@allow('all', author == auth())
78
+ }
79
+ `
80
+ );
81
+
82
+ // add zenstack/schema.prisma to .gitignore
83
+ const gitIgnorePath = path.join(projectPath, '.gitignore');
84
+ let gitIgnoreContent = '';
85
+ if (fs.existsSync(gitIgnorePath)) {
86
+ gitIgnoreContent =
87
+ fs.readFileSync(gitIgnorePath, { encoding: 'utf-8' }) + '\n';
88
+ }
89
+
90
+ if (!gitIgnoreContent.includes('zenstack/schema.prisma')) {
91
+ gitIgnoreContent += 'zenstack/schema.prisma\n';
92
+ fs.writeFileSync(gitIgnorePath, gitIgnoreContent);
93
+ }
94
+
95
+ console.log(`Sample model generated at: ${colors.green(schema)}
96
+
97
+ Please check the following guide on how to model your app:
98
+ https://zenstack.dev/#/modeling-your-app.
99
+ `);
100
+ }
101
+
15
102
  /**
16
103
  * Loads a zmodel document from a file.
17
104
  * @param fileName File name
package/src/cli/index.ts CHANGED
@@ -1,13 +1,23 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { Command, Option } from 'commander';
3
- import { ZModelLanguageMetaData } from '../language-server/generated/module';
4
- import colors from 'colors';
5
- import { execSync } from '../utils/exec-utils';
6
2
  import { paramCase } from 'change-case';
3
+ import colors from 'colors';
4
+ import { Command, Option } from 'commander';
7
5
  import path from 'path';
8
- import { runGenerator } from './cli-util';
6
+ import { ZModelLanguageMetaData } from '../language-server/generated/module';
9
7
  import telemetry from '../telemetry';
8
+ import { execSync } from '../utils/exec-utils';
10
9
  import { CliError } from './cli-error';
10
+ import { initProject, runGenerator } from './cli-util';
11
+
12
+ export const initAction = async (projectPath: string): Promise<void> => {
13
+ await telemetry.trackSpan(
14
+ 'cli:command:start',
15
+ 'cli:command:complete',
16
+ 'cli:command:error',
17
+ { command: 'init' },
18
+ () => initProject(projectPath)
19
+ );
20
+ };
11
21
 
12
22
  export const generateAction = async (options: {
13
23
  schema: string;
@@ -74,7 +84,6 @@ function prismaAction(prismaCmd: string): (...args: any[]) => Promise<void> {
74
84
  }
75
85
 
76
86
  export default async function (): Promise<void> {
77
- // try {
78
87
  await telemetry.trackSpan(
79
88
  'cli:start',
80
89
  'cli:complete',
@@ -97,7 +106,7 @@ export default async function (): Promise<void> {
97
106
  .description(
98
107
  `${colors.bold.blue(
99
108
  'ζ'
100
- )} ZenStack simplifies fullstack development by generating backend services and Typescript clients from a data model.\n\nDocumentation: https://go.zenstack.dev/doc.`
109
+ )} ZenStack is a toolkit for building secure CRUD apps with Next.js + Typescript.\n\nDocumentation: https://go.zenstack.dev/doc.`
101
110
  )
102
111
  .showHelpAfterError()
103
112
  .showSuggestionAfterError();
@@ -109,10 +118,16 @@ export default async function (): Promise<void> {
109
118
 
110
119
  //#region wraps Prisma commands
111
120
 
121
+ program
122
+ .command('init')
123
+ .description('Set up a new ZenStack project.')
124
+ .argument('<path>', 'project path')
125
+ .action(initAction);
126
+
112
127
  program
113
128
  .command('generate')
114
129
  .description(
115
- 'generates RESTful API and Typescript client for your data model'
130
+ 'Generates RESTful API and Typescript client for your data model.'
116
131
  )
117
132
  .addOption(schemaOption)
118
133
  .action(generateAction);
@@ -120,15 +135,17 @@ export default async function (): Promise<void> {
120
135
  const migrate = program
121
136
  .command('migrate')
122
137
  .description(
123
- `wraps Prisma's ${colors.cyan('migrate')} command`
138
+ `Updates the database schema with migrations\nAlias for ${colors.cyan(
139
+ 'prisma migrate'
140
+ )}.`
124
141
  );
125
142
 
126
143
  migrate
127
144
  .command('dev')
128
145
  .description(
129
- `alias for ${colors.cyan(
146
+ `Creates a migration, apply it to the database, generate db client\nAlias for ${colors.cyan(
130
147
  'prisma migrate dev'
131
- )}\nCreate a migration, apply it to the database, generate db client.`
148
+ )}.`
132
149
  )
133
150
  .addOption(schemaOption)
134
151
  .option(
@@ -142,9 +159,9 @@ export default async function (): Promise<void> {
142
159
  migrate
143
160
  .command('reset')
144
161
  .description(
145
- `alias for ${colors.cyan(
162
+ `Resets your database and apply all migrations\nAlias for ${colors.cyan(
146
163
  'prisma migrate reset'
147
- )}\nReset your database and apply all migrations.`
164
+ )}.`
148
165
  )
149
166
  .addOption(schemaOption)
150
167
  .option('--force', 'Skip the confirmation prompt')
@@ -153,9 +170,9 @@ export default async function (): Promise<void> {
153
170
  migrate
154
171
  .command('deploy')
155
172
  .description(
156
- `alias for ${colors.cyan(
173
+ `Applies pending migrations to the database in production/staging\nAlias for ${colors.cyan(
157
174
  'prisma migrate deploy'
158
- )}\nApply pending migrations to the database in production/staging.`
175
+ )}.`
159
176
  )
160
177
  .addOption(schemaOption)
161
178
  .action(prismaAction('migrate'));
@@ -163,22 +180,26 @@ export default async function (): Promise<void> {
163
180
  migrate
164
181
  .command('status')
165
182
  .description(
166
- `alias for ${colors.cyan(
183
+ `Checks the status of migrations in the production/staging database\nAlias for ${colors.cyan(
167
184
  'prisma migrate status'
168
- )}\nCheck the status of migrations in the production/staging database.`
185
+ )}.`
169
186
  )
170
187
  .addOption(schemaOption)
171
188
  .action(prismaAction('migrate'));
172
189
 
173
190
  const db = program
174
191
  .command('db')
175
- .description(`wraps Prisma's ${colors.cyan('db')} command`);
192
+ .description(
193
+ `Manages your database schema and lifecycle during development\nAlias for ${colors.cyan(
194
+ 'prisma db'
195
+ )}.`
196
+ );
176
197
 
177
198
  db.command('push')
178
199
  .description(
179
- `alias for ${colors.cyan(
200
+ `Pushes the Prisma schema state to the database\nAlias for ${colors.cyan(
180
201
  'prisma db push'
181
- )}\nPush the Prisma schema state to the database.`
202
+ )}.`
182
203
  )
183
204
  .addOption(schemaOption)
184
205
  .option('--accept-data-loss', 'Ignore data loss warnings')
@@ -187,9 +208,9 @@ export default async function (): Promise<void> {
187
208
  program
188
209
  .command('studio')
189
210
  .description(
190
- `wraps Prisma's ${colors.cyan(
191
- 'studio'
192
- )} command. Browse your data with Prisma Studio.`
211
+ `Browses your data with Prisma Studio\nAlias for ${colors.cyan(
212
+ 'prisma studio'
213
+ )}.`
193
214
  )
194
215
  .addOption(schemaOption)
195
216
  .option('-p --port <port>', 'Port to start Studio in')
@@ -2,10 +2,11 @@
2
2
  * Supported Prisma db providers
3
3
  */
4
4
  export const SUPPORTED_PROVIDERS = [
5
+ 'sqlite',
5
6
  'postgresql',
6
7
  'mysql',
7
- 'sqlite',
8
8
  'sqlserver',
9
+ 'cockroachdb',
9
10
  ];
10
11
 
11
12
  /**
@@ -7,6 +7,30 @@ enum ReferentialAction {
7
7
  * Used with "onUpdate": updates the relation scalar fields if the referenced scalar fields of the dependent record are updated.
8
8
  */
9
9
  Cascade
10
+
11
+ /*
12
+ * Used with "onDelete": prevents the deletion if any referencing records exist.
13
+ * Used with "onUpdate": prevents the identifier of a referenced record from being changed.
14
+ */
15
+ Restrict
16
+
17
+ /*
18
+ * Similar to 'Restrict', the difference between the two is dependent on the database being used.
19
+ * See details: https://www.prisma.io/docs/concepts/components/prisma-schema/relations/referential-actions#noaction
20
+ */
21
+ NoAction
22
+
23
+ /*
24
+ * Used with "onDelete": the scalar field of the referencing object will be set to NULL.
25
+ * Used with "onUpdate": when updating the identifier of a referenced object, the scalar fields of the referencing objects will be set to NULL.
26
+ */
27
+ SetNull
28
+
29
+ /*
30
+ * Used with "onDelete": the scalar field of the referencing object will be set to the fields default value.
31
+ * Used with "onUpdate": the scalar field of the referencing object will be set to the fields default value.
32
+ */
33
+ SetDefault
10
34
  }
11
35
 
12
36
  /*
package/src/telemetry.ts CHANGED
@@ -5,6 +5,8 @@ import cuid from 'cuid';
5
5
  import * as os from 'os';
6
6
  import sleep from 'sleep-promise';
7
7
  import exitHook from 'async-exit-hook';
8
+ import { CliError } from './cli/cli-error';
9
+ import { CommanderError } from 'commander';
8
10
 
9
11
  /**
10
12
  * Telemetry events
@@ -57,6 +59,13 @@ export class Telemetry {
57
59
  // a small delay to ensure telemetry is sent
58
60
  await sleep(this.exitWait);
59
61
  }
62
+
63
+ if (err instanceof CliError || err instanceof CommanderError) {
64
+ // error already handled
65
+ } else {
66
+ throw err;
67
+ }
68
+
60
69
  process.exit(1);
61
70
  });
62
71
  }