Skip to content

Commit 26fbd04

Browse files
authored
Add ZModel language (#7065)
* Add ZenStack language support * fix: fix readme * fix: fix wrong tm_scope * fix: resolve comments * fix: change zenstack to Zmodel in README * Update zenstack to latest version * fix: update grammar list * fix: move xBase after Zmodel * fix: move wisp after Zmodel * fix: fix the build error * fix: make the Zmodel right position * fix: update zenstack submodule to latest
1 parent b854c47 commit 26fbd04

File tree

9 files changed

+409
-0
lines changed

9 files changed

+409
-0
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,9 @@
14851485
[submodule "vendor/grammars/zeek-sublime"]
14861486
path = vendor/grammars/zeek-sublime
14871487
url = https://github.com/zeek/zeek-sublime
1488+
[submodule "vendor/grammars/zenstack"]
1489+
path = vendor/grammars/zenstack
1490+
url = https://github.com/zenstackhq/zenstack.git
14881491
[submodule "vendor/grammars/zephir-sublime"]
14891492
path = vendor/grammars/zephir-sublime
14901493
url = https://github.com/phalcon/zephir-sublime

grammars.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,5 +1338,7 @@ vendor/grammars/xml.tmbundle:
13381338
- text.xml.xsl
13391339
vendor/grammars/zeek-sublime:
13401340
- source.zeek
1341+
vendor/grammars/zenstack:
1342+
- source.zmodel
13411343
vendor/grammars/zephir-sublime:
13421344
- source.php.zephir

lib/linguist/languages.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8648,6 +8648,14 @@ Zimpl:
86488648
tm_scope: none
86498649
ace_mode: text
86508650
language_id: 411
8651+
Zmodel:
8652+
type: data
8653+
color: "#ff7100"
8654+
extensions:
8655+
- ".zmodel"
8656+
tm_scope: source.zmodel
8657+
ace_mode: text
8658+
language_id: 803760908
86518659
cURL Config:
86528660
type: data
86538661
group: INI

samples/Zmodel/blog.zmodel

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// This is your Prisma schema file,
2+
// learn more about it in the docs: https://pris.ly/d/prisma-schema
3+
4+
generator client {
5+
provider = "prisma-client-js"
6+
}
7+
8+
datasource db {
9+
provider = "sqlite"
10+
// NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below
11+
// Further reading:
12+
// https://next-auth.js.org/adapters/prisma#create-the-prisma-schema
13+
// https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string
14+
url = env("DATABASE_URL")
15+
}
16+
17+
plugin hooks {
18+
provider = '@zenstackhq/tanstack-query'
19+
target = 'react'
20+
version = 'v5'
21+
output = "./src/lib/hooks"
22+
}
23+
24+
model Post {
25+
id Int @id @default(autoincrement())
26+
name String
27+
createdAt DateTime @default(now())
28+
updatedAt DateTime @updatedAt
29+
30+
createdBy User @relation(fields: [createdById], references: [id])
31+
createdById String
32+
33+
@@index([name])
34+
}
35+
36+
// Necessary for Next auth
37+
model Account {
38+
id String @id @default(cuid())
39+
userId String
40+
type String
41+
provider String
42+
providerAccountId String
43+
refresh_token String? // @db.Text
44+
access_token String? // @db.Text
45+
expires_at Int?
46+
token_type String?
47+
scope String?
48+
id_token String? // @db.Text
49+
session_state String?
50+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
51+
refresh_token_expires_in Int?
52+
53+
@@unique([provider, providerAccountId])
54+
}
55+
56+
model Session {
57+
id String @id @default(cuid())
58+
sessionToken String @unique
59+
userId String
60+
expires DateTime
61+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
62+
}
63+
64+
model User {
65+
id String @id @default(cuid())
66+
name String?
67+
email String? @unique
68+
emailVerified DateTime?
69+
password String @password @omit
70+
image String?
71+
accounts Account[]
72+
sessions Session[]
73+
posts Post[]
74+
75+
// everyone can signup, and user profile is also publicly readable
76+
@@allow('create,read', true)
77+
78+
// only the user can update or delete their own profile
79+
@@allow('update,delete', auth() == this)
80+
}
81+
82+
model VerificationToken {
83+
identifier String
84+
token String @unique
85+
expires DateTime
86+
87+
@@unique([identifier, token])
88+
}

samples/Zmodel/saas.zmodel

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
datasource db {
2+
provider="sqlite"
3+
url="file:./dev.db"
4+
}
5+
6+
generator client {
7+
provider = "prisma-client-js"
8+
}
9+
10+
/**
11+
* Model for a user
12+
*/
13+
model User {
14+
id String @id @default(uuid())
15+
email String @unique
16+
password String? @password @omit
17+
name String?
18+
orgs Organization[]
19+
posts Post[]
20+
groups Group[]
21+
22+
// can be created by anyone, even not logged in
23+
@@allow('create', true)
24+
// can be read by users in the same organization
25+
@@allow('read', orgs?[members?[auth() == this]])
26+
// full access by oneself
27+
@@allow('all', auth() == this)
28+
}
29+
30+
/**
31+
* Model for a organization
32+
*/
33+
model Organization {
34+
id String @id @default(uuid())
35+
name String
36+
members User[]
37+
post Post[]
38+
groups Group[]
39+
40+
// everyone can create a organization
41+
@@allow('create', true)
42+
// any user in the organization can read the organization
43+
@@allow('read', members?[auth().id == id])
44+
}
45+
46+
/**
47+
* Base model for all entites in a organization
48+
*/
49+
abstract model organizationBaseEntity {
50+
id String @id @default(uuid())
51+
createdAt DateTime @default(now())
52+
updatedAt DateTime @updatedAt
53+
isDeleted Boolean @default(false) @omit
54+
isPublic Boolean @default(false)
55+
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
56+
ownerId String
57+
org Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
58+
orgId String
59+
groups Group[]
60+
61+
// when create, owner must be set to current user, and user must be in the organization
62+
@@allow('create', owner == auth() && org.members?[id == auth().id])
63+
// only the owner can update it and is not allowed to change the owner
64+
@@allow('update', owner == auth() && org.members?[id == auth().id] && future().owner == owner)
65+
// allow owner to read
66+
@@allow('read', owner == auth())
67+
// allow shared group members to read it
68+
@@allow('read', groups?[users?[id == auth().id]])
69+
// allow organization to access if public
70+
@@allow('read', isPublic && org.members?[id == auth().id])
71+
// can not be read if deleted
72+
@@deny('all', isDeleted == true)
73+
}
74+
75+
/**
76+
* Model for a post
77+
*/
78+
model Post extends organizationBaseEntity {
79+
title String
80+
content String
81+
}
82+
83+
/**
84+
* Model for a group
85+
*/
86+
model Group {
87+
id String @id @default(uuid())
88+
name String
89+
users User[]
90+
posts Post[]
91+
org Organization @relation(fields: [orgId], references: [id])
92+
orgId String
93+
94+
// group is shared by organization
95+
@@allow('all', org.members?[auth().id == id])
96+
}

samples/Zmodel/todo.zmodel

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
* Sample model for a collaborative Todo app
3+
*/
4+
5+
datasource db {
6+
provider = 'sqlite'
7+
url = 'file:./dev.db'
8+
}
9+
10+
generator js {
11+
provider = 'prisma-client-js'
12+
}
13+
14+
plugin enhancer {
15+
provider = '@core/enhancer'
16+
generatePermissionChecker = true
17+
}
18+
19+
plugin hooks {
20+
provider = '@zenstackhq/swr'
21+
output = 'lib/hooks'
22+
}
23+
24+
25+
/**
26+
* Model for a space in which users can collaborate on Lists and Todos
27+
*/
28+
model Space {
29+
id String @id @default(uuid())
30+
createdAt DateTime @default(now())
31+
updatedAt DateTime @updatedAt
32+
name String @length(4, 50)
33+
slug String @unique @regex('^[0-9a-zA-Z]{4,16}$')
34+
members SpaceUser[]
35+
lists List[]
36+
37+
// require login
38+
@@deny('all', auth() == null)
39+
40+
// everyone can create a space
41+
@@allow('create', true)
42+
43+
// any user in the space can read the space
44+
@@allow('read', members?[user == auth()])
45+
46+
// space admin can update and delete
47+
@@allow('update,delete', members?[user == auth() && role == 'ADMIN'])
48+
49+
@@deny('update', future().members?[user == auth()])
50+
}
51+
52+
/**
53+
* Model representing membership of a user in a space
54+
*/
55+
model SpaceUser {
56+
id String @id @default(uuid())
57+
createdAt DateTime @default(now())
58+
updatedAt DateTime @updatedAt
59+
space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade)
60+
spaceId String
61+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
62+
userId String
63+
role String
64+
@@unique([userId, spaceId])
65+
66+
// require login
67+
@@deny('all', auth() == null)
68+
69+
// space admin can create/update/delete
70+
@@allow('create,update,delete', space.members?[user == auth() && role == 'ADMIN'])
71+
72+
// user can read entries for spaces which he's a member of
73+
@@allow('read', space.members?[user == auth()])
74+
}
75+
76+
/**
77+
* Model for a user
78+
*/
79+
model User {
80+
id String @id @default(uuid())
81+
createdAt DateTime @default(now())
82+
updatedAt DateTime @updatedAt
83+
email String @unique @email
84+
emailVerified DateTime?
85+
password String? @password @omit
86+
name String?
87+
spaces SpaceUser[]
88+
image String? @url
89+
lists List[]
90+
todos Todo[]
91+
92+
// next-auth
93+
accounts Account[]
94+
95+
// can be created by anyone, even not logged in
96+
@@allow('create', true)
97+
98+
// can be read by users sharing any space
99+
@@allow('read', spaces?[space.members?[user == auth()]])
100+
101+
// full access by oneself
102+
@@allow('all', auth() == this)
103+
}
104+
105+
abstract model BaseEntity {
106+
id String @id @default(uuid())
107+
createdAt DateTime @default(now())
108+
updatedAt DateTime @updatedAt
109+
110+
space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade)
111+
spaceId String
112+
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
113+
ownerId String @default(auth().id)
114+
115+
// can be read by owner or space members
116+
@@allow('read', owner == auth() || (space.members?[user == auth()]))
117+
118+
// when create, owner must be set to current user, and user must be in the space
119+
@@allow('create', owner == auth() && space.members?[user == auth()])
120+
121+
// when create, owner must be set to current user, and user must be in the space
122+
// update is not allowed to change owner
123+
@@allow('update', owner == auth() && space.members?[user == auth()] && future().owner == owner)
124+
125+
// can be deleted by owner
126+
@@allow('delete', owner == auth())
127+
}
128+
129+
/**
130+
* Model for a Todo list
131+
*/
132+
model List extends BaseEntity {
133+
title String @length(1, 100)
134+
private Boolean @default(false)
135+
todos Todo[]
136+
137+
// can't be read by others if it's private
138+
@@deny('read', private == true && owner != auth())
139+
}
140+
141+
/**
142+
* Model for a single Todo
143+
*/
144+
model Todo {
145+
id String @id @default(uuid())
146+
createdAt DateTime @default(now())
147+
updatedAt DateTime @updatedAt
148+
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
149+
ownerId String @default(auth().id)
150+
list List @relation(fields: [listId], references: [id], onDelete: Cascade)
151+
listId String
152+
title String @length(1, 100)
153+
completedAt DateTime?
154+
155+
// full access if the parent list is readable
156+
@@allow('all', check(list, 'read'))
157+
}
158+
159+
/**
160+
* Next-auth user account
161+
*/
162+
model Account {
163+
id String @id @default(uuid())
164+
userId String
165+
type String
166+
provider String
167+
providerAccountId String
168+
refresh_token String?
169+
refresh_token_expires_in Int?
170+
access_token String?
171+
expires_at Int?
172+
token_type String?
173+
scope String?
174+
id_token String?
175+
session_state String?
176+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
177+
@@unique([provider, providerAccountId])
178+
}

0 commit comments

Comments
 (0)