Skip to content

Commit 10850c4

Browse files
committed
feat: support composable schemas
1 parent e3df93b commit 10850c4

File tree

7 files changed

+75
-80
lines changed

7 files changed

+75
-80
lines changed

download-wasm.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
wget https://github.com/authzed/spicedb/releases/download/v1.44.0/development.wasm -O src/check-watch-panel/public/main.wasm
1+
wget https://github.com/authzed/spicedb/releases/download/v1.49.2/development.wasm -O src/check-watch-panel/public/main.wasm
22
wget https://raw.githubusercontent.com/golang/go/c61e5e72447b568dd25367f592962c7ebf28b1c7/lib/wasm/wasm_exec.js -O src/check-watch-panel/public/wasm_exec.js

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@
8787
"icon": "$(watch-expressions-add)"
8888
}
8989
],
90+
"configuration": {
91+
"title": "SpiceDB",
92+
"properties": {
93+
"spicedb.binaryPath": {
94+
"type": "string",
95+
"default": "/Users/user/Documents/GitHub/spicedb/dist/main",
96+
"description": "Absolute path to a custom SpiceDB binary. If empty, the extension will look for 'spicedb' on your PATH."
97+
}
98+
}
99+
},
90100
"menus": {
91101
"view/title": [
92102
{

src/binary.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
import * as vscode from 'vscode';
22

33
import commandExists from 'command-exists';
4+
import * as fs from 'fs';
45

56
export async function languageServerBinaryPath(_context: vscode.ExtensionContext): Promise<string | undefined> {
7+
const config = vscode.workspace.getConfiguration('spicedb');
8+
const customPath = config.get<string>('binaryPath');
9+
if (customPath) {
10+
if (fs.existsSync(customPath)) {
11+
return customPath;
12+
}
13+
vscode.window.showErrorMessage(`SpiceDB binary not found at configured path: ${customPath}`);
14+
return undefined;
15+
}
16+
617
try {
718
return await commandExists('spicedb');
819
} catch (_e) {
@@ -13,7 +24,7 @@ export async function languageServerBinaryPath(_context: vscode.ExtensionContext
1324
const INSTALL_COMMANDS = {
1425
darwin: 'brew install spicedb',
1526
linux: '',
16-
win32: '',
27+
win32: 'choco install spicedb',
1728
aix: '',
1829
android: '',
1930
freebsd: '',
@@ -26,5 +37,5 @@ const INSTALL_COMMANDS = {
2637

2738
export function getInstallCommand() {
2839
const platform = process.platform;
29-
return INSTALL_COMMANDS[platform] || 'https://authzed.com/docs/spicedb/getting-started/installing-spicedb';
40+
return INSTALL_COMMANDS[platform] || 'https://authzed.com/docs/spicedb/getting-started/install/macos';
3041
}

src/extension.ts

Lines changed: 1 addition & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as vscode from 'vscode';
22
import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient/node';
33

4-
import { type ResolvedReference, Resolver, findReferenceNode, parse } from '@authzed/spicedb-parser-js';
4+
import { type ResolvedReference, Resolver, parse } from '@authzed/spicedb-parser-js';
55

66
import { getInstallCommand, languageServerBinaryPath } from './binary';
77
import { CheckWatchProvider } from './checkwatchprovider';
@@ -43,79 +43,6 @@ export function activate(context: vscode.ExtensionContext) {
4343
}),
4444
);
4545

46-
// TODO: Move this into the language server.
47-
vscode.languages.registerDefinitionProvider('spicedb', {
48-
provideDefinition: function (
49-
document: vscode.TextDocument,
50-
position: vscode.Position,
51-
_token: vscode.CancellationToken,
52-
): vscode.ProviderResult<vscode.Definition> {
53-
const text = document.getText();
54-
const parserResult = parse(text);
55-
if (parserResult.error) {
56-
return;
57-
}
58-
59-
// NOTE: the indexes from VSCode are 0-based, but the parser is 1-based.
60-
const found = findReferenceNode(parserResult.schema!, position.line + 1, position.character + 1);
61-
if (!found) {
62-
return;
63-
}
64-
65-
const resolution = new Resolver(parserResult.schema!);
66-
switch (found.node?.kind) {
67-
case 'typeref': {
68-
const def = resolution.lookupDefinition(found.node.path);
69-
if (def) {
70-
if (found.node.relationName) {
71-
const relation = def.lookupRelationOrPermission(found.node.relationName);
72-
if (relation) {
73-
return {
74-
uri: document.uri,
75-
range: new vscode.Range(
76-
relation.range.startIndex.line - 1,
77-
relation.range.startIndex.column - 1,
78-
relation.range.startIndex.line - 1,
79-
relation.range.startIndex.column - 1,
80-
),
81-
};
82-
}
83-
} else {
84-
return {
85-
uri: document.uri,
86-
range: new vscode.Range(
87-
def.definition.range.startIndex.line - 1,
88-
def.definition.range.startIndex.column - 1,
89-
def.definition.range.startIndex.line - 1,
90-
def.definition.range.startIndex.column - 1,
91-
),
92-
};
93-
}
94-
}
95-
break;
96-
}
97-
98-
case 'relationref': {
99-
const relation = resolution.resolveRelationOrPermission(found.node, found.def);
100-
if (relation) {
101-
return {
102-
uri: document.uri,
103-
range: new vscode.Range(
104-
relation.range.startIndex.line - 1,
105-
relation.range.startIndex.column - 1,
106-
relation.range.startIndex.line - 1,
107-
relation.range.startIndex.column - 1,
108-
),
109-
};
110-
}
111-
break;
112-
}
113-
}
114-
115-
return undefined;
116-
},
117-
});
118-
11946
// TODO: Move this into the language server.
12047
vscode.languages.registerDocumentSemanticTokensProvider(
12148
'spicedb',

syntaxes/spicedb.tmGrammar.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
"patterns": [
88
{ "include": "#comment" },
99
{ "include": "#use" },
10+
{ "include": "#import" },
11+
{ "include": "#partial" },
1012
{ "include": "#definition" },
1113
{ "include": "#caveat" },
1214
{ "include": "#relation" },
@@ -288,6 +290,30 @@
288290
}
289291
}
290292
},
293+
"import": {
294+
"comment": "import",
295+
"match": "\\s*(import)\\s*([\"a-zA-Z_]\\w*)\\s*",
296+
"captures": {
297+
"1": {
298+
"name": "keyword.class.definition"
299+
},
300+
"2": {
301+
"name": "entity.name.function"
302+
}
303+
}
304+
},
305+
"partial": {
306+
"comment": "partial",
307+
"match": "\\s*(partial)\\s*([\"a-zA-Z_]\\w*)\\s*",
308+
"captures": {
309+
"1": {
310+
"name": "keyword.class.definition"
311+
},
312+
"2": {
313+
"name": "entity.name.function"
314+
}
315+
}
316+
},
291317
"with_caveat": {
292318
"comment": "with_caveat",
293319
"match": "\\s*(with)\\s*(([a-z][\\w]{1,62}[a-z0-9]\\/)*[a-z][\\w]{1,62}[a-z0-9])\\s*",

syntaxes/test/full-standard.zed

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
// this is a standard schema that should have every available feature (wildcards, caveats, etc)
22
use expiration
3+
use partial
4+
use import
35

4-
definition user {}
6+
import "imported.zed"
57

68
definition group {
7-
relation member: user with non_expired_grant | user with expiration
9+
relation member: user with is_raining | user with expiration
810
relation member2: user:* with non_expired_grant
11+
...secret
12+
permission supersecret = secretview // defined in the partial
913
}
1014

1115
definition document {
@@ -15,7 +19,7 @@ definition document {
1519
relation bbb: user:*
1620
relation ccc: user:*
1721
relation ddd: user:*
18-
22+
...view_secret
1923

2024
// a comment
2125
permission view = aaa
@@ -34,3 +38,7 @@ definition document {
3438
caveat non_expired_grant(name string, description string) {
3539
name.matches("-$test") || size(description) >= 100
3640
}
41+
42+
partial view_secret {
43+
relation secret: user
44+
}

syntaxes/test/imported.zed

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use partial
2+
3+
definition mycustomtype {}
4+
5+
definition user {}
6+
7+
partial secret {
8+
relation secretview: user | mycustomtype
9+
}
10+
11+
caveat is_raining(day string) {
12+
day == "tues" || day == "mon"
13+
}

0 commit comments

Comments
 (0)