zenstack 0.3.8 → 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.
- package/bundle/cli/index.js +225 -169
- package/bundle/language-server/main.js +1 -1
- package/bundle/res/stdlib.zmodel +24 -0
- package/package.json +2 -2
- package/src/cli/cli-util.ts +87 -0
- package/src/cli/index.ts +44 -23
- package/src/generator/react-hooks/index.ts +1 -1
- package/src/language-server/constants.ts +2 -1
- package/src/res/stdlib.zmodel +24 -0
- package/src/telemetry.ts +9 -0
|
@@ -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);
|
package/bundle/res/stdlib.zmodel
CHANGED
|
@@ -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.
|
|
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.
|
|
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",
|
package/src/cli/cli-util.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
-
'
|
|
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
|
-
`
|
|
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
|
-
`
|
|
146
|
+
`Creates a migration, apply it to the database, generate db client\nAlias for ${colors.cyan(
|
|
130
147
|
'prisma migrate dev'
|
|
131
|
-
)}
|
|
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
|
-
`
|
|
162
|
+
`Resets your database and apply all migrations\nAlias for ${colors.cyan(
|
|
146
163
|
'prisma migrate reset'
|
|
147
|
-
)}
|
|
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
|
-
`
|
|
173
|
+
`Applies pending migrations to the database in production/staging\nAlias for ${colors.cyan(
|
|
157
174
|
'prisma migrate deploy'
|
|
158
|
-
)}
|
|
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
|
-
`
|
|
183
|
+
`Checks the status of migrations in the production/staging database\nAlias for ${colors.cyan(
|
|
167
184
|
'prisma migrate status'
|
|
168
|
-
)}
|
|
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(
|
|
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
|
-
`
|
|
200
|
+
`Pushes the Prisma schema state to the database\nAlias for ${colors.cyan(
|
|
180
201
|
'prisma db push'
|
|
181
|
-
)}
|
|
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
|
-
`
|
|
191
|
-
'studio'
|
|
192
|
-
)}
|
|
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')
|
package/src/res/stdlib.zmodel
CHANGED
|
@@ -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
|
}
|