Add queryable capability contracts and checked GraphQL artifacts
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { readFile, realpath } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { loadQxSources, resolveQxSources } from "./source-loader.js";
|
||||
import { compileRepositoryQuery } from "../query/compile.js";
|
||||
import { linkQueries } from "../query/link.js";
|
||||
import {
|
||||
capabilityId,
|
||||
compileWorkspaceRevision,
|
||||
@@ -231,6 +233,16 @@ const createResourceGraphResolver = (quixosCommit: string, resolveResource: Capa
|
||||
}
|
||||
assertImportsMatchLock(manifestPath, compiled.resource.imports, lockResult.lock.resources);
|
||||
if (compiled.resource.kind === "package") {
|
||||
const queryInterfaces = [
|
||||
...(environment.interfaceClosure ?? []),
|
||||
...(compiled.resource.specializations ?? []),
|
||||
];
|
||||
if (compiled.resource.revision.queries?.length)
|
||||
compiled.resource.revision.checkedQueries = await Promise.all(
|
||||
compiled.resource.revision.queries.map((query) =>
|
||||
compileRepositoryQuery(snapshot.directory, query, queryInterfaces),
|
||||
),
|
||||
);
|
||||
let catalogText: string | undefined;
|
||||
try {
|
||||
catalogText = await readFile(path.join(snapshot.directory, "quixos.migrations.json"), "utf8");
|
||||
@@ -389,6 +401,11 @@ export const compileWorkspaceRepository = async (options: {
|
||||
.join("\n")}`,
|
||||
);
|
||||
}
|
||||
const linkedQueries = linkQueries(workspace);
|
||||
if (linkedQueries.length) {
|
||||
workspace.linkedQueries = linkedQueries;
|
||||
checked.plan.source.linkedQueries = structuredClone(linkedQueries);
|
||||
}
|
||||
return {
|
||||
workspace,
|
||||
plan: checked.plan,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,229 +1,251 @@
|
||||
WORKSPACE=1
|
||||
TYPE=2
|
||||
OBJECT=3
|
||||
STORABLE=4
|
||||
IMPLEMENTS=5
|
||||
REF=6
|
||||
FRAGMENT=7
|
||||
IMPORT=8
|
||||
EXTERNAL=9
|
||||
ATOM=10
|
||||
INTERFACE=11
|
||||
INTERFACES=12
|
||||
PACKAGE=13
|
||||
VALUE=14
|
||||
RELATION=15
|
||||
OPERATION=16
|
||||
FUNCTION=17
|
||||
CONSTRUCTOR=18
|
||||
CONSTRUCTS=19
|
||||
INPUT=20
|
||||
CONFORM=21
|
||||
AS=22
|
||||
BIND=23
|
||||
STATIC=24
|
||||
TO=25
|
||||
PRIVATE=26
|
||||
SHARED=27
|
||||
STATE=28
|
||||
EDGE=29
|
||||
PROJECTION=30
|
||||
WITH=31
|
||||
USING=32
|
||||
VIA=33
|
||||
MATERIALIZE=34
|
||||
IF=35
|
||||
ABSENT=36
|
||||
ON=37
|
||||
POLICY=38
|
||||
DEFAULT=39
|
||||
SOURCE=40
|
||||
REPOSITORY=41
|
||||
COMMIT=42
|
||||
REVISION=43
|
||||
SEMANTIC_MAJOR=44
|
||||
ON_DELETE=45
|
||||
RETAIN_OTHER=46
|
||||
KEYED=47
|
||||
PUBLIC_TRAVERSAL=48
|
||||
ID=49
|
||||
DOC=50
|
||||
MODE=51
|
||||
EMITS=52
|
||||
RECEIVER=53
|
||||
REQUIRES=54
|
||||
ANY=55
|
||||
GET=56
|
||||
SET=57
|
||||
WATCH=58
|
||||
START=59
|
||||
STOP=60
|
||||
READ=61
|
||||
WRITE=62
|
||||
RESOLVE=63
|
||||
CONNECT=64
|
||||
DISCONNECT=65
|
||||
CALL=66
|
||||
WATCH_START=67
|
||||
WATCH_STOP=68
|
||||
SUBSCRIBE=69
|
||||
UNSUBSCRIBE=70
|
||||
OPTIMISTIC_REGISTER=71
|
||||
CRDT=72
|
||||
OPTIONAL_ONE=73
|
||||
EXACTLY_ONE=74
|
||||
MANY_UNIQUE=75
|
||||
MANY=76
|
||||
ORDERED=77
|
||||
UNIT=78
|
||||
WATCH_HANDLE=79
|
||||
MESSAGE=80
|
||||
ATOM_REF=81
|
||||
INTERFACE_REF=82
|
||||
OPTIONAL=83
|
||||
LIST=84
|
||||
RECORD=85
|
||||
BOOL=86
|
||||
BYTES=87
|
||||
DOUBLE=88
|
||||
INT32=89
|
||||
INT64=90
|
||||
STRING=91
|
||||
UINT32=92
|
||||
UINT64=93
|
||||
TRUE=94
|
||||
FALSE=95
|
||||
NULL=96
|
||||
ARROW=97
|
||||
COLON=98
|
||||
SEMI=99
|
||||
COMMA=100
|
||||
DOT=101
|
||||
LBRACE=102
|
||||
RBRACE=103
|
||||
LBRACK=104
|
||||
RBRACK=105
|
||||
LPAREN=106
|
||||
RPAREN=107
|
||||
LT=108
|
||||
GT=109
|
||||
AMP=110
|
||||
EQUAL=111
|
||||
INTEGER=112
|
||||
JSON_NUMBER=113
|
||||
IDENTIFIER=114
|
||||
STRING_LITERAL=115
|
||||
LINE_COMMENT=116
|
||||
BLOCK_COMMENT=117
|
||||
WS=118
|
||||
QUERY=2
|
||||
ROOT=3
|
||||
DOCUMENT=4
|
||||
FRAGMENTS=5
|
||||
VIEW=6
|
||||
MAX=7
|
||||
ALLOW=8
|
||||
POLL=9
|
||||
QUERYABLE=10
|
||||
RPC=11
|
||||
QUERY_REASON=12
|
||||
TYPE=13
|
||||
OBJECT=14
|
||||
STORABLE=15
|
||||
IMPLEMENTS=16
|
||||
REF=17
|
||||
FRAGMENT=18
|
||||
IMPORT=19
|
||||
EXTERNAL=20
|
||||
ATOM=21
|
||||
INTERFACE=22
|
||||
INTERFACES=23
|
||||
PACKAGE=24
|
||||
VALUE=25
|
||||
RELATION=26
|
||||
OPERATION=27
|
||||
FUNCTION=28
|
||||
CONSTRUCTOR=29
|
||||
CONSTRUCTS=30
|
||||
INPUT=31
|
||||
CONFORM=32
|
||||
AS=33
|
||||
BIND=34
|
||||
STATIC=35
|
||||
TO=36
|
||||
PRIVATE=37
|
||||
SHARED=38
|
||||
STATE=39
|
||||
EDGE=40
|
||||
PROJECTION=41
|
||||
WITH=42
|
||||
USING=43
|
||||
VIA=44
|
||||
MATERIALIZE=45
|
||||
IF=46
|
||||
ABSENT=47
|
||||
ON=48
|
||||
POLICY=49
|
||||
DEFAULT=50
|
||||
SOURCE=51
|
||||
REPOSITORY=52
|
||||
COMMIT=53
|
||||
REVISION=54
|
||||
SEMANTIC_MAJOR=55
|
||||
ON_DELETE=56
|
||||
RETAIN_OTHER=57
|
||||
KEYED=58
|
||||
PUBLIC_TRAVERSAL=59
|
||||
ID=60
|
||||
DOC=61
|
||||
MODE=62
|
||||
EMITS=63
|
||||
RECEIVER=64
|
||||
REQUIRES=65
|
||||
ANY=66
|
||||
GET=67
|
||||
SET=68
|
||||
WATCH=69
|
||||
START=70
|
||||
STOP=71
|
||||
READ=72
|
||||
WRITE=73
|
||||
RESOLVE=74
|
||||
CONNECT=75
|
||||
DISCONNECT=76
|
||||
CALL=77
|
||||
WATCH_START=78
|
||||
WATCH_STOP=79
|
||||
SUBSCRIBE=80
|
||||
UNSUBSCRIBE=81
|
||||
OPTIMISTIC_REGISTER=82
|
||||
CRDT=83
|
||||
OPTIONAL_ONE=84
|
||||
EXACTLY_ONE=85
|
||||
MANY_UNIQUE=86
|
||||
MANY=87
|
||||
ORDERED=88
|
||||
UNIT=89
|
||||
WATCH_HANDLE=90
|
||||
MESSAGE=91
|
||||
ATOM_REF=92
|
||||
INTERFACE_REF=93
|
||||
OPTIONAL=94
|
||||
LIST=95
|
||||
RECORD=96
|
||||
BOOL=97
|
||||
BYTES=98
|
||||
DOUBLE=99
|
||||
INT32=100
|
||||
INT64=101
|
||||
STRING=102
|
||||
UINT32=103
|
||||
UINT64=104
|
||||
TRUE=105
|
||||
FALSE=106
|
||||
NULL=107
|
||||
ARROW=108
|
||||
COLON=109
|
||||
SEMI=110
|
||||
COMMA=111
|
||||
DOT=112
|
||||
LBRACE=113
|
||||
RBRACE=114
|
||||
LBRACK=115
|
||||
RBRACK=116
|
||||
LPAREN=117
|
||||
RPAREN=118
|
||||
LT=119
|
||||
GT=120
|
||||
AMP=121
|
||||
EQUAL=122
|
||||
INTEGER=123
|
||||
JSON_NUMBER=124
|
||||
IDENTIFIER=125
|
||||
STRING_LITERAL=126
|
||||
LINE_COMMENT=127
|
||||
BLOCK_COMMENT=128
|
||||
WS=129
|
||||
'workspace'=1
|
||||
'type'=2
|
||||
'object'=3
|
||||
'storable'=4
|
||||
'implements'=5
|
||||
'ref'=6
|
||||
'fragment'=7
|
||||
'import'=8
|
||||
'external'=9
|
||||
'atom'=10
|
||||
'interface'=11
|
||||
'interfaces'=12
|
||||
'package'=13
|
||||
'value'=14
|
||||
'relation'=15
|
||||
'operation'=16
|
||||
'function'=17
|
||||
'constructor'=18
|
||||
'constructs'=19
|
||||
'input'=20
|
||||
'conform'=21
|
||||
'as'=22
|
||||
'bind'=23
|
||||
'static'=24
|
||||
'to'=25
|
||||
'private'=26
|
||||
'shared'=27
|
||||
'state'=28
|
||||
'edge'=29
|
||||
'projection'=30
|
||||
'with'=31
|
||||
'using'=32
|
||||
'via'=33
|
||||
'materialize'=34
|
||||
'if'=35
|
||||
'absent'=36
|
||||
'on'=37
|
||||
'policy'=38
|
||||
'default'=39
|
||||
'source'=40
|
||||
'repository'=41
|
||||
'commit'=42
|
||||
'revision'=43
|
||||
'semantic-major'=44
|
||||
'on-delete'=45
|
||||
'retain-other'=46
|
||||
'keyed'=47
|
||||
'public-traversal'=48
|
||||
'id'=49
|
||||
'doc'=50
|
||||
'mode'=51
|
||||
'emits'=52
|
||||
'receiver'=53
|
||||
'requires'=54
|
||||
'any'=55
|
||||
'get'=56
|
||||
'set'=57
|
||||
'watch'=58
|
||||
'start'=59
|
||||
'stop'=60
|
||||
'read'=61
|
||||
'write'=62
|
||||
'resolve'=63
|
||||
'connect'=64
|
||||
'disconnect'=65
|
||||
'call'=66
|
||||
'watch-start'=67
|
||||
'watch-stop'=68
|
||||
'subscribe'=69
|
||||
'unsubscribe'=70
|
||||
'optimistic-register'=71
|
||||
'crdt'=72
|
||||
'optional-one'=73
|
||||
'exactly-one'=74
|
||||
'many-unique'=75
|
||||
'many'=76
|
||||
'ordered'=77
|
||||
'unit'=78
|
||||
'watch-handle'=79
|
||||
'message'=80
|
||||
'atom-ref'=81
|
||||
'interface-ref'=82
|
||||
'optional'=83
|
||||
'list'=84
|
||||
'record'=85
|
||||
'bool'=86
|
||||
'bytes'=87
|
||||
'double'=88
|
||||
'int32'=89
|
||||
'int64'=90
|
||||
'string'=91
|
||||
'uint32'=92
|
||||
'uint64'=93
|
||||
'true'=94
|
||||
'false'=95
|
||||
'null'=96
|
||||
'->'=97
|
||||
':'=98
|
||||
';'=99
|
||||
','=100
|
||||
'.'=101
|
||||
'{'=102
|
||||
'}'=103
|
||||
'['=104
|
||||
']'=105
|
||||
'('=106
|
||||
')'=107
|
||||
'<'=108
|
||||
'>'=109
|
||||
'&'=110
|
||||
'='=111
|
||||
'query'=2
|
||||
'root'=3
|
||||
'document'=4
|
||||
'fragments'=5
|
||||
'view'=6
|
||||
'max'=7
|
||||
'allow'=8
|
||||
'poll'=9
|
||||
'queryable'=10
|
||||
'rpc'=11
|
||||
'query-reason'=12
|
||||
'type'=13
|
||||
'object'=14
|
||||
'storable'=15
|
||||
'implements'=16
|
||||
'ref'=17
|
||||
'fragment'=18
|
||||
'import'=19
|
||||
'external'=20
|
||||
'atom'=21
|
||||
'interface'=22
|
||||
'interfaces'=23
|
||||
'package'=24
|
||||
'value'=25
|
||||
'relation'=26
|
||||
'operation'=27
|
||||
'function'=28
|
||||
'constructor'=29
|
||||
'constructs'=30
|
||||
'input'=31
|
||||
'conform'=32
|
||||
'as'=33
|
||||
'bind'=34
|
||||
'static'=35
|
||||
'to'=36
|
||||
'private'=37
|
||||
'shared'=38
|
||||
'state'=39
|
||||
'edge'=40
|
||||
'projection'=41
|
||||
'with'=42
|
||||
'using'=43
|
||||
'via'=44
|
||||
'materialize'=45
|
||||
'if'=46
|
||||
'absent'=47
|
||||
'on'=48
|
||||
'policy'=49
|
||||
'default'=50
|
||||
'source'=51
|
||||
'repository'=52
|
||||
'commit'=53
|
||||
'revision'=54
|
||||
'semantic-major'=55
|
||||
'on-delete'=56
|
||||
'retain-other'=57
|
||||
'keyed'=58
|
||||
'public-traversal'=59
|
||||
'id'=60
|
||||
'doc'=61
|
||||
'mode'=62
|
||||
'emits'=63
|
||||
'receiver'=64
|
||||
'requires'=65
|
||||
'any'=66
|
||||
'get'=67
|
||||
'set'=68
|
||||
'watch'=69
|
||||
'start'=70
|
||||
'stop'=71
|
||||
'read'=72
|
||||
'write'=73
|
||||
'resolve'=74
|
||||
'connect'=75
|
||||
'disconnect'=76
|
||||
'call'=77
|
||||
'watch-start'=78
|
||||
'watch-stop'=79
|
||||
'subscribe'=80
|
||||
'unsubscribe'=81
|
||||
'optimistic-register'=82
|
||||
'crdt'=83
|
||||
'optional-one'=84
|
||||
'exactly-one'=85
|
||||
'many-unique'=86
|
||||
'many'=87
|
||||
'ordered'=88
|
||||
'unit'=89
|
||||
'watch-handle'=90
|
||||
'message'=91
|
||||
'atom-ref'=92
|
||||
'interface-ref'=93
|
||||
'optional'=94
|
||||
'list'=95
|
||||
'record'=96
|
||||
'bool'=97
|
||||
'bytes'=98
|
||||
'double'=99
|
||||
'int32'=100
|
||||
'int64'=101
|
||||
'string'=102
|
||||
'uint32'=103
|
||||
'uint64'=104
|
||||
'true'=105
|
||||
'false'=106
|
||||
'null'=107
|
||||
'->'=108
|
||||
':'=109
|
||||
';'=110
|
||||
','=111
|
||||
'.'=112
|
||||
'{'=113
|
||||
'}'=114
|
||||
'['=115
|
||||
']'=116
|
||||
'('=117
|
||||
')'=118
|
||||
'<'=119
|
||||
'>'=120
|
||||
'&'=121
|
||||
'='=122
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,229 +1,251 @@
|
||||
WORKSPACE=1
|
||||
TYPE=2
|
||||
OBJECT=3
|
||||
STORABLE=4
|
||||
IMPLEMENTS=5
|
||||
REF=6
|
||||
FRAGMENT=7
|
||||
IMPORT=8
|
||||
EXTERNAL=9
|
||||
ATOM=10
|
||||
INTERFACE=11
|
||||
INTERFACES=12
|
||||
PACKAGE=13
|
||||
VALUE=14
|
||||
RELATION=15
|
||||
OPERATION=16
|
||||
FUNCTION=17
|
||||
CONSTRUCTOR=18
|
||||
CONSTRUCTS=19
|
||||
INPUT=20
|
||||
CONFORM=21
|
||||
AS=22
|
||||
BIND=23
|
||||
STATIC=24
|
||||
TO=25
|
||||
PRIVATE=26
|
||||
SHARED=27
|
||||
STATE=28
|
||||
EDGE=29
|
||||
PROJECTION=30
|
||||
WITH=31
|
||||
USING=32
|
||||
VIA=33
|
||||
MATERIALIZE=34
|
||||
IF=35
|
||||
ABSENT=36
|
||||
ON=37
|
||||
POLICY=38
|
||||
DEFAULT=39
|
||||
SOURCE=40
|
||||
REPOSITORY=41
|
||||
COMMIT=42
|
||||
REVISION=43
|
||||
SEMANTIC_MAJOR=44
|
||||
ON_DELETE=45
|
||||
RETAIN_OTHER=46
|
||||
KEYED=47
|
||||
PUBLIC_TRAVERSAL=48
|
||||
ID=49
|
||||
DOC=50
|
||||
MODE=51
|
||||
EMITS=52
|
||||
RECEIVER=53
|
||||
REQUIRES=54
|
||||
ANY=55
|
||||
GET=56
|
||||
SET=57
|
||||
WATCH=58
|
||||
START=59
|
||||
STOP=60
|
||||
READ=61
|
||||
WRITE=62
|
||||
RESOLVE=63
|
||||
CONNECT=64
|
||||
DISCONNECT=65
|
||||
CALL=66
|
||||
WATCH_START=67
|
||||
WATCH_STOP=68
|
||||
SUBSCRIBE=69
|
||||
UNSUBSCRIBE=70
|
||||
OPTIMISTIC_REGISTER=71
|
||||
CRDT=72
|
||||
OPTIONAL_ONE=73
|
||||
EXACTLY_ONE=74
|
||||
MANY_UNIQUE=75
|
||||
MANY=76
|
||||
ORDERED=77
|
||||
UNIT=78
|
||||
WATCH_HANDLE=79
|
||||
MESSAGE=80
|
||||
ATOM_REF=81
|
||||
INTERFACE_REF=82
|
||||
OPTIONAL=83
|
||||
LIST=84
|
||||
RECORD=85
|
||||
BOOL=86
|
||||
BYTES=87
|
||||
DOUBLE=88
|
||||
INT32=89
|
||||
INT64=90
|
||||
STRING=91
|
||||
UINT32=92
|
||||
UINT64=93
|
||||
TRUE=94
|
||||
FALSE=95
|
||||
NULL=96
|
||||
ARROW=97
|
||||
COLON=98
|
||||
SEMI=99
|
||||
COMMA=100
|
||||
DOT=101
|
||||
LBRACE=102
|
||||
RBRACE=103
|
||||
LBRACK=104
|
||||
RBRACK=105
|
||||
LPAREN=106
|
||||
RPAREN=107
|
||||
LT=108
|
||||
GT=109
|
||||
AMP=110
|
||||
EQUAL=111
|
||||
INTEGER=112
|
||||
JSON_NUMBER=113
|
||||
IDENTIFIER=114
|
||||
STRING_LITERAL=115
|
||||
LINE_COMMENT=116
|
||||
BLOCK_COMMENT=117
|
||||
WS=118
|
||||
QUERY=2
|
||||
ROOT=3
|
||||
DOCUMENT=4
|
||||
FRAGMENTS=5
|
||||
VIEW=6
|
||||
MAX=7
|
||||
ALLOW=8
|
||||
POLL=9
|
||||
QUERYABLE=10
|
||||
RPC=11
|
||||
QUERY_REASON=12
|
||||
TYPE=13
|
||||
OBJECT=14
|
||||
STORABLE=15
|
||||
IMPLEMENTS=16
|
||||
REF=17
|
||||
FRAGMENT=18
|
||||
IMPORT=19
|
||||
EXTERNAL=20
|
||||
ATOM=21
|
||||
INTERFACE=22
|
||||
INTERFACES=23
|
||||
PACKAGE=24
|
||||
VALUE=25
|
||||
RELATION=26
|
||||
OPERATION=27
|
||||
FUNCTION=28
|
||||
CONSTRUCTOR=29
|
||||
CONSTRUCTS=30
|
||||
INPUT=31
|
||||
CONFORM=32
|
||||
AS=33
|
||||
BIND=34
|
||||
STATIC=35
|
||||
TO=36
|
||||
PRIVATE=37
|
||||
SHARED=38
|
||||
STATE=39
|
||||
EDGE=40
|
||||
PROJECTION=41
|
||||
WITH=42
|
||||
USING=43
|
||||
VIA=44
|
||||
MATERIALIZE=45
|
||||
IF=46
|
||||
ABSENT=47
|
||||
ON=48
|
||||
POLICY=49
|
||||
DEFAULT=50
|
||||
SOURCE=51
|
||||
REPOSITORY=52
|
||||
COMMIT=53
|
||||
REVISION=54
|
||||
SEMANTIC_MAJOR=55
|
||||
ON_DELETE=56
|
||||
RETAIN_OTHER=57
|
||||
KEYED=58
|
||||
PUBLIC_TRAVERSAL=59
|
||||
ID=60
|
||||
DOC=61
|
||||
MODE=62
|
||||
EMITS=63
|
||||
RECEIVER=64
|
||||
REQUIRES=65
|
||||
ANY=66
|
||||
GET=67
|
||||
SET=68
|
||||
WATCH=69
|
||||
START=70
|
||||
STOP=71
|
||||
READ=72
|
||||
WRITE=73
|
||||
RESOLVE=74
|
||||
CONNECT=75
|
||||
DISCONNECT=76
|
||||
CALL=77
|
||||
WATCH_START=78
|
||||
WATCH_STOP=79
|
||||
SUBSCRIBE=80
|
||||
UNSUBSCRIBE=81
|
||||
OPTIMISTIC_REGISTER=82
|
||||
CRDT=83
|
||||
OPTIONAL_ONE=84
|
||||
EXACTLY_ONE=85
|
||||
MANY_UNIQUE=86
|
||||
MANY=87
|
||||
ORDERED=88
|
||||
UNIT=89
|
||||
WATCH_HANDLE=90
|
||||
MESSAGE=91
|
||||
ATOM_REF=92
|
||||
INTERFACE_REF=93
|
||||
OPTIONAL=94
|
||||
LIST=95
|
||||
RECORD=96
|
||||
BOOL=97
|
||||
BYTES=98
|
||||
DOUBLE=99
|
||||
INT32=100
|
||||
INT64=101
|
||||
STRING=102
|
||||
UINT32=103
|
||||
UINT64=104
|
||||
TRUE=105
|
||||
FALSE=106
|
||||
NULL=107
|
||||
ARROW=108
|
||||
COLON=109
|
||||
SEMI=110
|
||||
COMMA=111
|
||||
DOT=112
|
||||
LBRACE=113
|
||||
RBRACE=114
|
||||
LBRACK=115
|
||||
RBRACK=116
|
||||
LPAREN=117
|
||||
RPAREN=118
|
||||
LT=119
|
||||
GT=120
|
||||
AMP=121
|
||||
EQUAL=122
|
||||
INTEGER=123
|
||||
JSON_NUMBER=124
|
||||
IDENTIFIER=125
|
||||
STRING_LITERAL=126
|
||||
LINE_COMMENT=127
|
||||
BLOCK_COMMENT=128
|
||||
WS=129
|
||||
'workspace'=1
|
||||
'type'=2
|
||||
'object'=3
|
||||
'storable'=4
|
||||
'implements'=5
|
||||
'ref'=6
|
||||
'fragment'=7
|
||||
'import'=8
|
||||
'external'=9
|
||||
'atom'=10
|
||||
'interface'=11
|
||||
'interfaces'=12
|
||||
'package'=13
|
||||
'value'=14
|
||||
'relation'=15
|
||||
'operation'=16
|
||||
'function'=17
|
||||
'constructor'=18
|
||||
'constructs'=19
|
||||
'input'=20
|
||||
'conform'=21
|
||||
'as'=22
|
||||
'bind'=23
|
||||
'static'=24
|
||||
'to'=25
|
||||
'private'=26
|
||||
'shared'=27
|
||||
'state'=28
|
||||
'edge'=29
|
||||
'projection'=30
|
||||
'with'=31
|
||||
'using'=32
|
||||
'via'=33
|
||||
'materialize'=34
|
||||
'if'=35
|
||||
'absent'=36
|
||||
'on'=37
|
||||
'policy'=38
|
||||
'default'=39
|
||||
'source'=40
|
||||
'repository'=41
|
||||
'commit'=42
|
||||
'revision'=43
|
||||
'semantic-major'=44
|
||||
'on-delete'=45
|
||||
'retain-other'=46
|
||||
'keyed'=47
|
||||
'public-traversal'=48
|
||||
'id'=49
|
||||
'doc'=50
|
||||
'mode'=51
|
||||
'emits'=52
|
||||
'receiver'=53
|
||||
'requires'=54
|
||||
'any'=55
|
||||
'get'=56
|
||||
'set'=57
|
||||
'watch'=58
|
||||
'start'=59
|
||||
'stop'=60
|
||||
'read'=61
|
||||
'write'=62
|
||||
'resolve'=63
|
||||
'connect'=64
|
||||
'disconnect'=65
|
||||
'call'=66
|
||||
'watch-start'=67
|
||||
'watch-stop'=68
|
||||
'subscribe'=69
|
||||
'unsubscribe'=70
|
||||
'optimistic-register'=71
|
||||
'crdt'=72
|
||||
'optional-one'=73
|
||||
'exactly-one'=74
|
||||
'many-unique'=75
|
||||
'many'=76
|
||||
'ordered'=77
|
||||
'unit'=78
|
||||
'watch-handle'=79
|
||||
'message'=80
|
||||
'atom-ref'=81
|
||||
'interface-ref'=82
|
||||
'optional'=83
|
||||
'list'=84
|
||||
'record'=85
|
||||
'bool'=86
|
||||
'bytes'=87
|
||||
'double'=88
|
||||
'int32'=89
|
||||
'int64'=90
|
||||
'string'=91
|
||||
'uint32'=92
|
||||
'uint64'=93
|
||||
'true'=94
|
||||
'false'=95
|
||||
'null'=96
|
||||
'->'=97
|
||||
':'=98
|
||||
';'=99
|
||||
','=100
|
||||
'.'=101
|
||||
'{'=102
|
||||
'}'=103
|
||||
'['=104
|
||||
']'=105
|
||||
'('=106
|
||||
')'=107
|
||||
'<'=108
|
||||
'>'=109
|
||||
'&'=110
|
||||
'='=111
|
||||
'query'=2
|
||||
'root'=3
|
||||
'document'=4
|
||||
'fragments'=5
|
||||
'view'=6
|
||||
'max'=7
|
||||
'allow'=8
|
||||
'poll'=9
|
||||
'queryable'=10
|
||||
'rpc'=11
|
||||
'query-reason'=12
|
||||
'type'=13
|
||||
'object'=14
|
||||
'storable'=15
|
||||
'implements'=16
|
||||
'ref'=17
|
||||
'fragment'=18
|
||||
'import'=19
|
||||
'external'=20
|
||||
'atom'=21
|
||||
'interface'=22
|
||||
'interfaces'=23
|
||||
'package'=24
|
||||
'value'=25
|
||||
'relation'=26
|
||||
'operation'=27
|
||||
'function'=28
|
||||
'constructor'=29
|
||||
'constructs'=30
|
||||
'input'=31
|
||||
'conform'=32
|
||||
'as'=33
|
||||
'bind'=34
|
||||
'static'=35
|
||||
'to'=36
|
||||
'private'=37
|
||||
'shared'=38
|
||||
'state'=39
|
||||
'edge'=40
|
||||
'projection'=41
|
||||
'with'=42
|
||||
'using'=43
|
||||
'via'=44
|
||||
'materialize'=45
|
||||
'if'=46
|
||||
'absent'=47
|
||||
'on'=48
|
||||
'policy'=49
|
||||
'default'=50
|
||||
'source'=51
|
||||
'repository'=52
|
||||
'commit'=53
|
||||
'revision'=54
|
||||
'semantic-major'=55
|
||||
'on-delete'=56
|
||||
'retain-other'=57
|
||||
'keyed'=58
|
||||
'public-traversal'=59
|
||||
'id'=60
|
||||
'doc'=61
|
||||
'mode'=62
|
||||
'emits'=63
|
||||
'receiver'=64
|
||||
'requires'=65
|
||||
'any'=66
|
||||
'get'=67
|
||||
'set'=68
|
||||
'watch'=69
|
||||
'start'=70
|
||||
'stop'=71
|
||||
'read'=72
|
||||
'write'=73
|
||||
'resolve'=74
|
||||
'connect'=75
|
||||
'disconnect'=76
|
||||
'call'=77
|
||||
'watch-start'=78
|
||||
'watch-stop'=79
|
||||
'subscribe'=80
|
||||
'unsubscribe'=81
|
||||
'optimistic-register'=82
|
||||
'crdt'=83
|
||||
'optional-one'=84
|
||||
'exactly-one'=85
|
||||
'many-unique'=86
|
||||
'many'=87
|
||||
'ordered'=88
|
||||
'unit'=89
|
||||
'watch-handle'=90
|
||||
'message'=91
|
||||
'atom-ref'=92
|
||||
'interface-ref'=93
|
||||
'optional'=94
|
||||
'list'=95
|
||||
'record'=96
|
||||
'bool'=97
|
||||
'bytes'=98
|
||||
'double'=99
|
||||
'int32'=100
|
||||
'int64'=101
|
||||
'string'=102
|
||||
'uint32'=103
|
||||
'uint64'=104
|
||||
'true'=105
|
||||
'false'=106
|
||||
'null'=107
|
||||
'->'=108
|
||||
':'=109
|
||||
';'=110
|
||||
','=111
|
||||
'.'=112
|
||||
'{'=113
|
||||
'}'=114
|
||||
'['=115
|
||||
']'=116
|
||||
'('=117
|
||||
')'=118
|
||||
'<'=119
|
||||
'>'=120
|
||||
'&'=121
|
||||
'='=122
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -24,10 +24,13 @@ import { OperationMemberContext } from "./QuixosCapabilityParser.js";
|
||||
import { ValueMemberContext } from "./QuixosCapabilityParser.js";
|
||||
import { ValueMemberOperationContext } from "./QuixosCapabilityParser.js";
|
||||
import { RelationshipMemberContext } from "./QuixosCapabilityParser.js";
|
||||
import { QueryReadContractContext } from "./QuixosCapabilityParser.js";
|
||||
import { RelationshipOperationContext } from "./QuixosCapabilityParser.js";
|
||||
import { TargetConstraintContext } from "./QuixosCapabilityParser.js";
|
||||
import { PackageResourceDeclContext } from "./QuixosCapabilityParser.js";
|
||||
import { PackageExportContext } from "./QuixosCapabilityParser.js";
|
||||
import { PackageQueryContext } from "./QuixosCapabilityParser.js";
|
||||
import { QueryClauseContext } from "./QuixosCapabilityParser.js";
|
||||
import { PackageOperationExportContext } from "./QuixosCapabilityParser.js";
|
||||
import { PackageFunctionExportContext } from "./QuixosCapabilityParser.js";
|
||||
import { PackageConstructorExportContext } from "./QuixosCapabilityParser.js";
|
||||
@@ -210,6 +213,12 @@ export class QuixosCapabilityVisitor<Result> extends AbstractParseTreeVisitor<Re
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitRelationshipMember?: (ctx: RelationshipMemberContext) => Result;
|
||||
/**
|
||||
* Visit a parse tree produced by `QuixosCapabilityParser.queryReadContract`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitQueryReadContract?: (ctx: QueryReadContractContext) => Result;
|
||||
/**
|
||||
* Visit a parse tree produced by `QuixosCapabilityParser.relationshipOperation`.
|
||||
* @param ctx the parse tree
|
||||
@@ -234,6 +243,18 @@ export class QuixosCapabilityVisitor<Result> extends AbstractParseTreeVisitor<Re
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitPackageExport?: (ctx: PackageExportContext) => Result;
|
||||
/**
|
||||
* Visit a parse tree produced by `QuixosCapabilityParser.packageQuery`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitPackageQuery?: (ctx: PackageQueryContext) => Result;
|
||||
/**
|
||||
* Visit a parse tree produced by `QuixosCapabilityParser.queryClause`.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
visitQueryClause?: (ctx: QueryClauseContext) => Result;
|
||||
/**
|
||||
* Visit a parse tree produced by `QuixosCapabilityParser.packageOperationExport`.
|
||||
* @param ctx the parse tree
|
||||
|
||||
@@ -46,6 +46,7 @@ import {
|
||||
specializePackageExport,
|
||||
} from "../capability-model/index.js";
|
||||
import { GenericSourceTypes } from "./generic-types.js";
|
||||
import { defaultQueryBudgets, type QueryDeclaration, type QueryBudgets, type QueryUse } from "../query/types.js";
|
||||
import { QuixosCapabilityLexer } from "./generated/QuixosCapabilityLexer.js";
|
||||
import {
|
||||
QuixosCapabilityParser,
|
||||
@@ -463,6 +464,13 @@ const lowerValueMember = (state: LoweringState, context: ValueMemberContext): In
|
||||
}
|
||||
return {
|
||||
kind: "value",
|
||||
...(context.queryReadContract()
|
||||
? {
|
||||
queryRead: {
|
||||
execution: context.queryReadContract()!.RPC() ? ("rpc-permitted" as const) : ("native" as const),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
id: capabilityId.member(stringValue(context.stringLiteral())),
|
||||
displayName: memberName,
|
||||
valueType: memberValueType,
|
||||
@@ -527,6 +535,13 @@ const lowerRelationshipMember = (
|
||||
}
|
||||
return {
|
||||
kind: "relationship",
|
||||
...(context.queryReadContract()
|
||||
? {
|
||||
queryRead: {
|
||||
execution: context.queryReadContract()!.RPC() ? ("rpc-permitted" as const) : ("native" as const),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
id: capabilityId.member(stringValue(context.stringLiteral())),
|
||||
displayName: identifier(context.identifier()),
|
||||
target,
|
||||
@@ -672,6 +687,13 @@ const lowerInterfaceTemplate = (
|
||||
const type = types.expression(value.valueType());
|
||||
return {
|
||||
kind: "value",
|
||||
...(value.queryReadContract()
|
||||
? {
|
||||
queryRead: {
|
||||
execution: value.queryReadContract()!.RPC() ? ("rpc-permitted" as const) : ("native" as const),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
id: capabilityId.member(stringValue(value.stringLiteral())),
|
||||
displayName: identifier(value.identifier()),
|
||||
valueType: type,
|
||||
@@ -725,6 +747,13 @@ const lowerInterfaceTemplate = (
|
||||
: { kind: cardinality === "optional-one" ? "optional" : "list", value: targetType };
|
||||
return {
|
||||
kind: "relationship",
|
||||
...(relationship.queryReadContract()
|
||||
? {
|
||||
queryRead: {
|
||||
execution: relationship.queryReadContract()!.RPC() ? ("rpc-permitted" as const) : ("native" as const),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
id: capabilityId.member(stringValue(relationship.stringLiteral())),
|
||||
displayName: identifier(relationship.identifier()),
|
||||
target,
|
||||
@@ -1130,7 +1159,91 @@ const lowerPackage = (
|
||||
): PackageRevision => {
|
||||
const alias = identifier(context.identifier());
|
||||
const genericExports: GenericPackageExport[] = [];
|
||||
const queries: QueryDeclaration[] = [];
|
||||
const exports = context.packageExport().flatMap((exportContext): PackageExport[] => {
|
||||
const query = exportContext.packageQuery();
|
||||
if (query) {
|
||||
const close = (ctx: import("./generated/QuixosCapabilityParser.js").InterfaceTypeContext) =>
|
||||
new TypeSubstitution(state.types.environment()).application(state.types.interface(ctx));
|
||||
const declaration: QueryDeclaration = {
|
||||
id: stringValue(query.stringLiteral(0)),
|
||||
displayName: identifier(query.identifier()),
|
||||
root: close(query.interfaceType()),
|
||||
document: stringValue(query.stringLiteral(1)),
|
||||
operation: stringValue(query.stringLiteral(2)),
|
||||
fragments: [],
|
||||
views: [],
|
||||
allowances: [],
|
||||
budgets: { ...defaultQueryBudgets },
|
||||
watch: false,
|
||||
};
|
||||
const budgetNames: Record<string, keyof QueryBudgets> = {
|
||||
rows: "rows",
|
||||
depth: "depth",
|
||||
"result-bytes": "resultBytes",
|
||||
candidates: "candidates",
|
||||
"rpc-calls": "rpcCalls",
|
||||
concurrency: "concurrency",
|
||||
"deadline-ms": "deadlineMs",
|
||||
};
|
||||
const assigned = new Set<string>();
|
||||
for (const clause of query.queryClause()) {
|
||||
if (clause.FRAGMENTS()) declaration.fragments.push(stringValue(clause.stringLiteral()!));
|
||||
else if (clause.VIEW()) {
|
||||
const name = identifier(clause.identifier(0));
|
||||
const atomId = requireSymbol(state, state.atoms, name, clause, "atom");
|
||||
if (atomId) declaration.views.push({ atomId, interfaceRevisionId: close(clause.interfaceType()!) });
|
||||
} else if (clause.MAX()) {
|
||||
const name = identifier(clause.identifier(0));
|
||||
const key = budgetNames[name],
|
||||
n = Number(clause.INTEGER()!.getText());
|
||||
if (!key || assigned.has(name) || !Number.isSafeInteger(n) || n < 1 || n > defaultQueryBudgets[key])
|
||||
loweringIssue(
|
||||
state,
|
||||
clause,
|
||||
"invalid-query-budget",
|
||||
`Invalid, duplicate, or excessive query budget ${name}`,
|
||||
);
|
||||
else {
|
||||
declaration.budgets[key] = n;
|
||||
assigned.add(name);
|
||||
}
|
||||
} else if (clause.ALLOW()) {
|
||||
const interfaceRevisionId = close(clause.interfaceType()!);
|
||||
const contract = [...state.types.interfaces.values(), ...state.types.applications.values()].find(
|
||||
(entry) => entry.revisionId === interfaceRevisionId,
|
||||
);
|
||||
const member = contract?.members.find((entry) => entry.displayName === identifier(clause.identifier(0)));
|
||||
const use = identifier(clause.identifier(1));
|
||||
const reason = stringValue(clause.stringLiteral()!);
|
||||
if (!member || !["select", "predicate", "order"].includes(use) || !reason.trim())
|
||||
loweringIssue(
|
||||
state,
|
||||
clause,
|
||||
"invalid-query-allowance",
|
||||
"Query allowances name an exact member, use (select/predicate/order), and nonempty reason",
|
||||
);
|
||||
else
|
||||
declaration.allowances.push({ interfaceRevisionId, memberId: member.id, uses: [use as QueryUse], reason });
|
||||
} else if (clause.WATCH()) declaration.watch = true;
|
||||
else if (clause.POLL()) {
|
||||
const intervalMs = Number(clause.INTEGER()!.getText()),
|
||||
reason = stringValue(clause.stringLiteral()!);
|
||||
if (declaration.polling || !Number.isSafeInteger(intervalMs) || intervalMs < 1000 || !reason.trim())
|
||||
loweringIssue(
|
||||
state,
|
||||
clause,
|
||||
"invalid-query-polling",
|
||||
"Polling needs one interval of at least 1000ms and a reason",
|
||||
);
|
||||
else declaration.polling = { intervalMs, reason };
|
||||
}
|
||||
}
|
||||
if (queries.some((entry) => entry.id === declaration.id || entry.displayName === declaration.displayName))
|
||||
loweringIssue(state, query, "duplicate-query", "Duplicate query name or ID");
|
||||
queries.push(declaration);
|
||||
return [];
|
||||
}
|
||||
const operation = exportContext.packageOperationExport();
|
||||
const generic = operation ?? exportContext.packageFunctionExport();
|
||||
if (generic?.typeParameters()) {
|
||||
@@ -1162,6 +1275,7 @@ const lowerPackage = (
|
||||
displayName: alias,
|
||||
source,
|
||||
exports,
|
||||
...(queries.length ? { queries } : {}),
|
||||
...(genericExports.length ? { genericExports } : {}),
|
||||
};
|
||||
};
|
||||
@@ -1568,6 +1682,7 @@ const lowerConformance = (
|
||||
? [
|
||||
{
|
||||
operationId,
|
||||
...(bindingContext.stringLiteral() ? { queryReason: stringValue(bindingContext.stringLiteral()!) } : {}),
|
||||
binding: {
|
||||
kind: "package" as const,
|
||||
packageRevisionId: packageSymbol.revisionId,
|
||||
|
||||
@@ -4,13 +4,20 @@ import { parseQx, validateQxImportPath, walkSyntax } from "./source.js";
|
||||
|
||||
export const readQxSource = async (root: string, name: string) => {
|
||||
validateQxImportPath(name);
|
||||
return readRepositorySource(root, name);
|
||||
};
|
||||
|
||||
/** Refuse symlinks at every component, including the final source file. */
|
||||
export const readRepositorySource = async (root: string, name: string) => {
|
||||
if (!/^(?:[A-Za-z0-9_-][A-Za-z0-9_.-]*\/)*[A-Za-z0-9_-][A-Za-z0-9_.-]*$/.test(name))
|
||||
throw new Error(`Invalid repository-relative source path: ${name}`);
|
||||
let current = path.resolve(root);
|
||||
const segments = name.split("/");
|
||||
for (const [index, segment] of segments.entries()) {
|
||||
current = path.join(current, segment);
|
||||
const stat = await lstat(current);
|
||||
if (stat.isSymbolicLink() || (index === segments.length - 1 ? !stat.isFile() : !stat.isDirectory()))
|
||||
throw new Error(`QX imports must be ordinary files beneath ordinary directories: ${name}`);
|
||||
throw new Error(`Sources must be ordinary files beneath ordinary directories: ${name}`);
|
||||
}
|
||||
return readFile(current, "utf8");
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user