Compile and dispatch authoritative acceptance hooks with target-specific package roots
This commit is contained in:
@@ -169,12 +169,16 @@ queryClause
|
|||||||
|
|
||||||
packageOperationExport
|
packageOperationExport
|
||||||
: OPERATION identifier typeParameters? ID stringLiteral COLON valueType ARROW valueType
|
: OPERATION identifier typeParameters? ID stringLiteral COLON valueType ARROW valueType
|
||||||
MODE operationMode executionClause? eventClause? RECEIVER receiverRequirement dependencyBlock? SEMI
|
MODE operationMode executionClause? eventClause? RECEIVER receiverRequirement dependencyBlock? acceptanceClause? SEMI
|
||||||
;
|
;
|
||||||
|
|
||||||
packageFunctionExport
|
packageFunctionExport
|
||||||
: FUNCTION identifier typeParameters? ID stringLiteral COLON valueType ARROW valueType
|
: FUNCTION identifier typeParameters? ID stringLiteral COLON valueType ARROW valueType
|
||||||
executionClause? dependencyBlock? SEMI
|
executionClause? dependencyBlock? acceptanceClause? SEMI
|
||||||
|
;
|
||||||
|
|
||||||
|
acceptanceClause
|
||||||
|
: ACCEPT USING identifier
|
||||||
;
|
;
|
||||||
|
|
||||||
executionClause
|
executionClause
|
||||||
@@ -332,7 +336,11 @@ operationProvider
|
|||||||
: STATE identifier DOT statePrimitive
|
: STATE identifier DOT statePrimitive
|
||||||
| EDGE identifier DOT identifier DOT edgePrimitive
|
| EDGE identifier DOT identifier DOT edgePrimitive
|
||||||
| INTERFACE identifier typeArguments? DOT memberOperationRef
|
| INTERFACE identifier typeArguments? DOT memberOperationRef
|
||||||
| PACKAGE identifier DOT identifier typeArguments? dependencyBindingBlock?
|
| PACKAGE identifier DOT identifier typeArguments? dependencyBindingBlock? acceptanceBinding?
|
||||||
|
;
|
||||||
|
|
||||||
|
acceptanceBinding
|
||||||
|
: ACCEPT dependencyBindingBlock
|
||||||
;
|
;
|
||||||
|
|
||||||
statePrimitive
|
statePrimitive
|
||||||
@@ -528,6 +536,7 @@ EDGE: 'edge';
|
|||||||
PROJECTION: 'projection';
|
PROJECTION: 'projection';
|
||||||
WITH: 'with';
|
WITH: 'with';
|
||||||
USING: 'using';
|
USING: 'using';
|
||||||
|
ACCEPT: 'accept';
|
||||||
VIA: 'via';
|
VIA: 'via';
|
||||||
MATERIALIZE: 'materialize';
|
MATERIALIZE: 'materialize';
|
||||||
IF: 'if';
|
IF: 'if';
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -58,92 +58,93 @@ EDGE=57
|
|||||||
PROJECTION=58
|
PROJECTION=58
|
||||||
WITH=59
|
WITH=59
|
||||||
USING=60
|
USING=60
|
||||||
VIA=61
|
ACCEPT=61
|
||||||
MATERIALIZE=62
|
VIA=62
|
||||||
IF=63
|
MATERIALIZE=63
|
||||||
ABSENT=64
|
IF=64
|
||||||
ON=65
|
ABSENT=65
|
||||||
POLICY=66
|
ON=66
|
||||||
DEFAULT=67
|
POLICY=67
|
||||||
SOURCE=68
|
DEFAULT=68
|
||||||
REPOSITORY=69
|
SOURCE=69
|
||||||
COMMIT=70
|
REPOSITORY=70
|
||||||
REVISION=71
|
COMMIT=71
|
||||||
SEMANTIC_MAJOR=72
|
REVISION=72
|
||||||
ON_DELETE=73
|
SEMANTIC_MAJOR=73
|
||||||
RETAIN_OTHER=74
|
ON_DELETE=74
|
||||||
KEYED=75
|
RETAIN_OTHER=75
|
||||||
PUBLIC_TRAVERSAL=76
|
KEYED=76
|
||||||
ID=77
|
PUBLIC_TRAVERSAL=77
|
||||||
DOC=78
|
ID=78
|
||||||
MODE=79
|
DOC=79
|
||||||
EMITS=80
|
MODE=80
|
||||||
RECEIVER=81
|
EMITS=81
|
||||||
REQUIRES=82
|
RECEIVER=82
|
||||||
ANY=83
|
REQUIRES=83
|
||||||
GET=84
|
ANY=84
|
||||||
SET=85
|
GET=85
|
||||||
WATCH=86
|
SET=86
|
||||||
START=87
|
WATCH=87
|
||||||
STOP=88
|
START=88
|
||||||
READ=89
|
STOP=89
|
||||||
WRITE=90
|
READ=90
|
||||||
RESOLVE=91
|
WRITE=91
|
||||||
CONNECT=92
|
RESOLVE=92
|
||||||
DISCONNECT=93
|
CONNECT=93
|
||||||
CALL=94
|
DISCONNECT=94
|
||||||
WATCH_START=95
|
CALL=95
|
||||||
WATCH_STOP=96
|
WATCH_START=96
|
||||||
SUBSCRIBE=97
|
WATCH_STOP=97
|
||||||
UNSUBSCRIBE=98
|
SUBSCRIBE=98
|
||||||
REGISTER=99
|
UNSUBSCRIBE=99
|
||||||
CRDT=100
|
REGISTER=100
|
||||||
OPTIONAL_ONE=101
|
CRDT=101
|
||||||
EXACTLY_ONE=102
|
OPTIONAL_ONE=102
|
||||||
MANY_UNIQUE=103
|
EXACTLY_ONE=103
|
||||||
MANY=104
|
MANY_UNIQUE=104
|
||||||
ORDERED=105
|
MANY=105
|
||||||
UNIT=106
|
ORDERED=106
|
||||||
WATCH_HANDLE=107
|
UNIT=107
|
||||||
MESSAGE=108
|
WATCH_HANDLE=108
|
||||||
ATOM_REF=109
|
MESSAGE=109
|
||||||
INTERFACE_REF=110
|
ATOM_REF=110
|
||||||
OPTIONAL=111
|
INTERFACE_REF=111
|
||||||
LIST=112
|
OPTIONAL=112
|
||||||
RECORD=113
|
LIST=113
|
||||||
BOOL=114
|
RECORD=114
|
||||||
BYTES=115
|
BOOL=115
|
||||||
DOUBLE=116
|
BYTES=116
|
||||||
INT32=117
|
DOUBLE=117
|
||||||
INT64=118
|
INT32=118
|
||||||
STRING=119
|
INT64=119
|
||||||
UINT32=120
|
STRING=120
|
||||||
UINT64=121
|
UINT32=121
|
||||||
TRUE=122
|
UINT64=122
|
||||||
FALSE=123
|
TRUE=123
|
||||||
NULL=124
|
FALSE=124
|
||||||
ARROW=125
|
NULL=125
|
||||||
COLON=126
|
ARROW=126
|
||||||
SEMI=127
|
COLON=127
|
||||||
COMMA=128
|
SEMI=128
|
||||||
DOT=129
|
COMMA=129
|
||||||
LBRACE=130
|
DOT=130
|
||||||
RBRACE=131
|
LBRACE=131
|
||||||
LBRACK=132
|
RBRACE=132
|
||||||
RBRACK=133
|
LBRACK=133
|
||||||
LPAREN=134
|
RBRACK=134
|
||||||
RPAREN=135
|
LPAREN=135
|
||||||
LT=136
|
RPAREN=136
|
||||||
GT=137
|
LT=137
|
||||||
AMP=138
|
GT=138
|
||||||
EQUAL=139
|
AMP=139
|
||||||
INTEGER=140
|
EQUAL=140
|
||||||
JSON_NUMBER=141
|
INTEGER=141
|
||||||
IDENTIFIER=142
|
JSON_NUMBER=142
|
||||||
STRING_LITERAL=143
|
IDENTIFIER=143
|
||||||
LINE_COMMENT=144
|
STRING_LITERAL=144
|
||||||
BLOCK_COMMENT=145
|
LINE_COMMENT=145
|
||||||
WS=146
|
BLOCK_COMMENT=146
|
||||||
|
WS=147
|
||||||
'edit'=1
|
'edit'=1
|
||||||
'creation'=2
|
'creation'=2
|
||||||
'initialize'=3
|
'initialize'=3
|
||||||
@@ -204,82 +205,83 @@ WS=146
|
|||||||
'projection'=58
|
'projection'=58
|
||||||
'with'=59
|
'with'=59
|
||||||
'using'=60
|
'using'=60
|
||||||
'via'=61
|
'accept'=61
|
||||||
'materialize'=62
|
'via'=62
|
||||||
'if'=63
|
'materialize'=63
|
||||||
'absent'=64
|
'if'=64
|
||||||
'on'=65
|
'absent'=65
|
||||||
'policy'=66
|
'on'=66
|
||||||
'default'=67
|
'policy'=67
|
||||||
'source'=68
|
'default'=68
|
||||||
'repository'=69
|
'source'=69
|
||||||
'commit'=70
|
'repository'=70
|
||||||
'revision'=71
|
'commit'=71
|
||||||
'semantic-major'=72
|
'revision'=72
|
||||||
'on-delete'=73
|
'semantic-major'=73
|
||||||
'retain-other'=74
|
'on-delete'=74
|
||||||
'keyed'=75
|
'retain-other'=75
|
||||||
'public-traversal'=76
|
'keyed'=76
|
||||||
'id'=77
|
'public-traversal'=77
|
||||||
'doc'=78
|
'id'=78
|
||||||
'mode'=79
|
'doc'=79
|
||||||
'emits'=80
|
'mode'=80
|
||||||
'receiver'=81
|
'emits'=81
|
||||||
'requires'=82
|
'receiver'=82
|
||||||
'any'=83
|
'requires'=83
|
||||||
'get'=84
|
'any'=84
|
||||||
'set'=85
|
'get'=85
|
||||||
'watch'=86
|
'set'=86
|
||||||
'start'=87
|
'watch'=87
|
||||||
'stop'=88
|
'start'=88
|
||||||
'read'=89
|
'stop'=89
|
||||||
'write'=90
|
'read'=90
|
||||||
'resolve'=91
|
'write'=91
|
||||||
'connect'=92
|
'resolve'=92
|
||||||
'disconnect'=93
|
'connect'=93
|
||||||
'call'=94
|
'disconnect'=94
|
||||||
'watch-start'=95
|
'call'=95
|
||||||
'watch-stop'=96
|
'watch-start'=96
|
||||||
'subscribe'=97
|
'watch-stop'=97
|
||||||
'unsubscribe'=98
|
'subscribe'=98
|
||||||
'register'=99
|
'unsubscribe'=99
|
||||||
'crdt'=100
|
'register'=100
|
||||||
'optional-one'=101
|
'crdt'=101
|
||||||
'exactly-one'=102
|
'optional-one'=102
|
||||||
'many-unique'=103
|
'exactly-one'=103
|
||||||
'many'=104
|
'many-unique'=104
|
||||||
'ordered'=105
|
'many'=105
|
||||||
'unit'=106
|
'ordered'=106
|
||||||
'watch-handle'=107
|
'unit'=107
|
||||||
'message'=108
|
'watch-handle'=108
|
||||||
'atom-ref'=109
|
'message'=109
|
||||||
'interface-ref'=110
|
'atom-ref'=110
|
||||||
'optional'=111
|
'interface-ref'=111
|
||||||
'list'=112
|
'optional'=112
|
||||||
'record'=113
|
'list'=113
|
||||||
'bool'=114
|
'record'=114
|
||||||
'bytes'=115
|
'bool'=115
|
||||||
'double'=116
|
'bytes'=116
|
||||||
'int32'=117
|
'double'=117
|
||||||
'int64'=118
|
'int32'=118
|
||||||
'string'=119
|
'int64'=119
|
||||||
'uint32'=120
|
'string'=120
|
||||||
'uint64'=121
|
'uint32'=121
|
||||||
'true'=122
|
'uint64'=122
|
||||||
'false'=123
|
'true'=123
|
||||||
'null'=124
|
'false'=124
|
||||||
'->'=125
|
'null'=125
|
||||||
':'=126
|
'->'=126
|
||||||
';'=127
|
':'=127
|
||||||
','=128
|
';'=128
|
||||||
'.'=129
|
','=129
|
||||||
'{'=130
|
'.'=130
|
||||||
'}'=131
|
'{'=131
|
||||||
'['=132
|
'}'=132
|
||||||
']'=133
|
'['=133
|
||||||
'('=134
|
']'=134
|
||||||
')'=135
|
'('=135
|
||||||
'<'=136
|
')'=136
|
||||||
'>'=137
|
'<'=137
|
||||||
'&'=138
|
'>'=138
|
||||||
'='=139
|
'&'=139
|
||||||
|
'='=140
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -58,92 +58,93 @@ EDGE=57
|
|||||||
PROJECTION=58
|
PROJECTION=58
|
||||||
WITH=59
|
WITH=59
|
||||||
USING=60
|
USING=60
|
||||||
VIA=61
|
ACCEPT=61
|
||||||
MATERIALIZE=62
|
VIA=62
|
||||||
IF=63
|
MATERIALIZE=63
|
||||||
ABSENT=64
|
IF=64
|
||||||
ON=65
|
ABSENT=65
|
||||||
POLICY=66
|
ON=66
|
||||||
DEFAULT=67
|
POLICY=67
|
||||||
SOURCE=68
|
DEFAULT=68
|
||||||
REPOSITORY=69
|
SOURCE=69
|
||||||
COMMIT=70
|
REPOSITORY=70
|
||||||
REVISION=71
|
COMMIT=71
|
||||||
SEMANTIC_MAJOR=72
|
REVISION=72
|
||||||
ON_DELETE=73
|
SEMANTIC_MAJOR=73
|
||||||
RETAIN_OTHER=74
|
ON_DELETE=74
|
||||||
KEYED=75
|
RETAIN_OTHER=75
|
||||||
PUBLIC_TRAVERSAL=76
|
KEYED=76
|
||||||
ID=77
|
PUBLIC_TRAVERSAL=77
|
||||||
DOC=78
|
ID=78
|
||||||
MODE=79
|
DOC=79
|
||||||
EMITS=80
|
MODE=80
|
||||||
RECEIVER=81
|
EMITS=81
|
||||||
REQUIRES=82
|
RECEIVER=82
|
||||||
ANY=83
|
REQUIRES=83
|
||||||
GET=84
|
ANY=84
|
||||||
SET=85
|
GET=85
|
||||||
WATCH=86
|
SET=86
|
||||||
START=87
|
WATCH=87
|
||||||
STOP=88
|
START=88
|
||||||
READ=89
|
STOP=89
|
||||||
WRITE=90
|
READ=90
|
||||||
RESOLVE=91
|
WRITE=91
|
||||||
CONNECT=92
|
RESOLVE=92
|
||||||
DISCONNECT=93
|
CONNECT=93
|
||||||
CALL=94
|
DISCONNECT=94
|
||||||
WATCH_START=95
|
CALL=95
|
||||||
WATCH_STOP=96
|
WATCH_START=96
|
||||||
SUBSCRIBE=97
|
WATCH_STOP=97
|
||||||
UNSUBSCRIBE=98
|
SUBSCRIBE=98
|
||||||
REGISTER=99
|
UNSUBSCRIBE=99
|
||||||
CRDT=100
|
REGISTER=100
|
||||||
OPTIONAL_ONE=101
|
CRDT=101
|
||||||
EXACTLY_ONE=102
|
OPTIONAL_ONE=102
|
||||||
MANY_UNIQUE=103
|
EXACTLY_ONE=103
|
||||||
MANY=104
|
MANY_UNIQUE=104
|
||||||
ORDERED=105
|
MANY=105
|
||||||
UNIT=106
|
ORDERED=106
|
||||||
WATCH_HANDLE=107
|
UNIT=107
|
||||||
MESSAGE=108
|
WATCH_HANDLE=108
|
||||||
ATOM_REF=109
|
MESSAGE=109
|
||||||
INTERFACE_REF=110
|
ATOM_REF=110
|
||||||
OPTIONAL=111
|
INTERFACE_REF=111
|
||||||
LIST=112
|
OPTIONAL=112
|
||||||
RECORD=113
|
LIST=113
|
||||||
BOOL=114
|
RECORD=114
|
||||||
BYTES=115
|
BOOL=115
|
||||||
DOUBLE=116
|
BYTES=116
|
||||||
INT32=117
|
DOUBLE=117
|
||||||
INT64=118
|
INT32=118
|
||||||
STRING=119
|
INT64=119
|
||||||
UINT32=120
|
STRING=120
|
||||||
UINT64=121
|
UINT32=121
|
||||||
TRUE=122
|
UINT64=122
|
||||||
FALSE=123
|
TRUE=123
|
||||||
NULL=124
|
FALSE=124
|
||||||
ARROW=125
|
NULL=125
|
||||||
COLON=126
|
ARROW=126
|
||||||
SEMI=127
|
COLON=127
|
||||||
COMMA=128
|
SEMI=128
|
||||||
DOT=129
|
COMMA=129
|
||||||
LBRACE=130
|
DOT=130
|
||||||
RBRACE=131
|
LBRACE=131
|
||||||
LBRACK=132
|
RBRACE=132
|
||||||
RBRACK=133
|
LBRACK=133
|
||||||
LPAREN=134
|
RBRACK=134
|
||||||
RPAREN=135
|
LPAREN=135
|
||||||
LT=136
|
RPAREN=136
|
||||||
GT=137
|
LT=137
|
||||||
AMP=138
|
GT=138
|
||||||
EQUAL=139
|
AMP=139
|
||||||
INTEGER=140
|
EQUAL=140
|
||||||
JSON_NUMBER=141
|
INTEGER=141
|
||||||
IDENTIFIER=142
|
JSON_NUMBER=142
|
||||||
STRING_LITERAL=143
|
IDENTIFIER=143
|
||||||
LINE_COMMENT=144
|
STRING_LITERAL=144
|
||||||
BLOCK_COMMENT=145
|
LINE_COMMENT=145
|
||||||
WS=146
|
BLOCK_COMMENT=146
|
||||||
|
WS=147
|
||||||
'edit'=1
|
'edit'=1
|
||||||
'creation'=2
|
'creation'=2
|
||||||
'initialize'=3
|
'initialize'=3
|
||||||
@@ -204,82 +205,83 @@ WS=146
|
|||||||
'projection'=58
|
'projection'=58
|
||||||
'with'=59
|
'with'=59
|
||||||
'using'=60
|
'using'=60
|
||||||
'via'=61
|
'accept'=61
|
||||||
'materialize'=62
|
'via'=62
|
||||||
'if'=63
|
'materialize'=63
|
||||||
'absent'=64
|
'if'=64
|
||||||
'on'=65
|
'absent'=65
|
||||||
'policy'=66
|
'on'=66
|
||||||
'default'=67
|
'policy'=67
|
||||||
'source'=68
|
'default'=68
|
||||||
'repository'=69
|
'source'=69
|
||||||
'commit'=70
|
'repository'=70
|
||||||
'revision'=71
|
'commit'=71
|
||||||
'semantic-major'=72
|
'revision'=72
|
||||||
'on-delete'=73
|
'semantic-major'=73
|
||||||
'retain-other'=74
|
'on-delete'=74
|
||||||
'keyed'=75
|
'retain-other'=75
|
||||||
'public-traversal'=76
|
'keyed'=76
|
||||||
'id'=77
|
'public-traversal'=77
|
||||||
'doc'=78
|
'id'=78
|
||||||
'mode'=79
|
'doc'=79
|
||||||
'emits'=80
|
'mode'=80
|
||||||
'receiver'=81
|
'emits'=81
|
||||||
'requires'=82
|
'receiver'=82
|
||||||
'any'=83
|
'requires'=83
|
||||||
'get'=84
|
'any'=84
|
||||||
'set'=85
|
'get'=85
|
||||||
'watch'=86
|
'set'=86
|
||||||
'start'=87
|
'watch'=87
|
||||||
'stop'=88
|
'start'=88
|
||||||
'read'=89
|
'stop'=89
|
||||||
'write'=90
|
'read'=90
|
||||||
'resolve'=91
|
'write'=91
|
||||||
'connect'=92
|
'resolve'=92
|
||||||
'disconnect'=93
|
'connect'=93
|
||||||
'call'=94
|
'disconnect'=94
|
||||||
'watch-start'=95
|
'call'=95
|
||||||
'watch-stop'=96
|
'watch-start'=96
|
||||||
'subscribe'=97
|
'watch-stop'=97
|
||||||
'unsubscribe'=98
|
'subscribe'=98
|
||||||
'register'=99
|
'unsubscribe'=99
|
||||||
'crdt'=100
|
'register'=100
|
||||||
'optional-one'=101
|
'crdt'=101
|
||||||
'exactly-one'=102
|
'optional-one'=102
|
||||||
'many-unique'=103
|
'exactly-one'=103
|
||||||
'many'=104
|
'many-unique'=104
|
||||||
'ordered'=105
|
'many'=105
|
||||||
'unit'=106
|
'ordered'=106
|
||||||
'watch-handle'=107
|
'unit'=107
|
||||||
'message'=108
|
'watch-handle'=108
|
||||||
'atom-ref'=109
|
'message'=109
|
||||||
'interface-ref'=110
|
'atom-ref'=110
|
||||||
'optional'=111
|
'interface-ref'=111
|
||||||
'list'=112
|
'optional'=112
|
||||||
'record'=113
|
'list'=113
|
||||||
'bool'=114
|
'record'=114
|
||||||
'bytes'=115
|
'bool'=115
|
||||||
'double'=116
|
'bytes'=116
|
||||||
'int32'=117
|
'double'=117
|
||||||
'int64'=118
|
'int32'=118
|
||||||
'string'=119
|
'int64'=119
|
||||||
'uint32'=120
|
'string'=120
|
||||||
'uint64'=121
|
'uint32'=121
|
||||||
'true'=122
|
'uint64'=122
|
||||||
'false'=123
|
'true'=123
|
||||||
'null'=124
|
'false'=124
|
||||||
'->'=125
|
'null'=125
|
||||||
':'=126
|
'->'=126
|
||||||
';'=127
|
':'=127
|
||||||
','=128
|
';'=128
|
||||||
'.'=129
|
','=129
|
||||||
'{'=130
|
'.'=130
|
||||||
'}'=131
|
'{'=131
|
||||||
'['=132
|
'}'=132
|
||||||
']'=133
|
'['=133
|
||||||
'('=134
|
']'=134
|
||||||
')'=135
|
'('=135
|
||||||
'<'=136
|
')'=136
|
||||||
'>'=137
|
'<'=137
|
||||||
'&'=138
|
'>'=138
|
||||||
'='=139
|
'&'=139
|
||||||
|
'='=140
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,7 @@ import { PackageQuerySpecializationContext } from "./QuixosCapabilityParser.js";
|
|||||||
import { QueryClauseContext } from "./QuixosCapabilityParser.js";
|
import { QueryClauseContext } from "./QuixosCapabilityParser.js";
|
||||||
import { PackageOperationExportContext } from "./QuixosCapabilityParser.js";
|
import { PackageOperationExportContext } from "./QuixosCapabilityParser.js";
|
||||||
import { PackageFunctionExportContext } from "./QuixosCapabilityParser.js";
|
import { PackageFunctionExportContext } from "./QuixosCapabilityParser.js";
|
||||||
|
import { AcceptanceClauseContext } from "./QuixosCapabilityParser.js";
|
||||||
import { ExecutionClauseContext } from "./QuixosCapabilityParser.js";
|
import { ExecutionClauseContext } from "./QuixosCapabilityParser.js";
|
||||||
import { SelectedOperationsContext } from "./QuixosCapabilityParser.js";
|
import { SelectedOperationsContext } from "./QuixosCapabilityParser.js";
|
||||||
import { PackageConstructorExportContext } from "./QuixosCapabilityParser.js";
|
import { PackageConstructorExportContext } from "./QuixosCapabilityParser.js";
|
||||||
@@ -62,6 +63,7 @@ import { OperationBindingDeclContext } from "./QuixosCapabilityParser.js";
|
|||||||
import { MemberOperationRefContext } from "./QuixosCapabilityParser.js";
|
import { MemberOperationRefContext } from "./QuixosCapabilityParser.js";
|
||||||
import { OperationNameContext } from "./QuixosCapabilityParser.js";
|
import { OperationNameContext } from "./QuixosCapabilityParser.js";
|
||||||
import { OperationProviderContext } from "./QuixosCapabilityParser.js";
|
import { OperationProviderContext } from "./QuixosCapabilityParser.js";
|
||||||
|
import { AcceptanceBindingContext } from "./QuixosCapabilityParser.js";
|
||||||
import { StatePrimitiveContext } from "./QuixosCapabilityParser.js";
|
import { StatePrimitiveContext } from "./QuixosCapabilityParser.js";
|
||||||
import { EdgePrimitiveContext } from "./QuixosCapabilityParser.js";
|
import { EdgePrimitiveContext } from "./QuixosCapabilityParser.js";
|
||||||
import { DependencyBindingBlockContext } from "./QuixosCapabilityParser.js";
|
import { DependencyBindingBlockContext } from "./QuixosCapabilityParser.js";
|
||||||
@@ -279,6 +281,12 @@ export class QuixosCapabilityVisitor<Result> extends AbstractParseTreeVisitor<Re
|
|||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitPackageFunctionExport?: (ctx: PackageFunctionExportContext) => Result;
|
visitPackageFunctionExport?: (ctx: PackageFunctionExportContext) => Result;
|
||||||
|
/**
|
||||||
|
* Visit a parse tree produced by `QuixosCapabilityParser.acceptanceClause`.
|
||||||
|
* @param ctx the parse tree
|
||||||
|
* @return the visitor result
|
||||||
|
*/
|
||||||
|
visitAcceptanceClause?: (ctx: AcceptanceClauseContext) => Result;
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `QuixosCapabilityParser.executionClause`.
|
* Visit a parse tree produced by `QuixosCapabilityParser.executionClause`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
@@ -447,6 +455,12 @@ export class QuixosCapabilityVisitor<Result> extends AbstractParseTreeVisitor<Re
|
|||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
visitOperationProvider?: (ctx: OperationProviderContext) => Result;
|
visitOperationProvider?: (ctx: OperationProviderContext) => Result;
|
||||||
|
/**
|
||||||
|
* Visit a parse tree produced by `QuixosCapabilityParser.acceptanceBinding`.
|
||||||
|
* @param ctx the parse tree
|
||||||
|
* @return the visitor result
|
||||||
|
*/
|
||||||
|
visitAcceptanceBinding?: (ctx: AcceptanceBindingContext) => Result;
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by `QuixosCapabilityParser.statePrimitive`.
|
* Visit a parse tree produced by `QuixosCapabilityParser.statePrimitive`.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
|
|||||||
@@ -1514,6 +1514,13 @@ const lowerPackage = (
|
|||||||
const operation = exportContext.packageOperationExport();
|
const operation = exportContext.packageOperationExport();
|
||||||
const generic = operation ?? exportContext.packageFunctionExport();
|
const generic = operation ?? exportContext.packageFunctionExport();
|
||||||
if (generic?.typeParameters()) {
|
if (generic?.typeParameters()) {
|
||||||
|
if (generic.acceptanceClause())
|
||||||
|
loweringIssue(
|
||||||
|
state,
|
||||||
|
generic,
|
||||||
|
"unsupported-generic-acceptance",
|
||||||
|
"Acceptance hooks currently require a closed export",
|
||||||
|
);
|
||||||
genericExports.push(atGenericSource(generic, () => lowerGenericPackageExport(state, generic)));
|
genericExports.push(atGenericSource(generic, () => lowerGenericPackageExport(state, generic)));
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -1535,6 +1542,22 @@ const lowerPackage = (
|
|||||||
state.types.self = previousSelf;
|
state.types.self = previousSelf;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Resolve after all exports have been declared, so checks can follow bodies.
|
||||||
|
for (const source of context.packageExport()) {
|
||||||
|
const declaration = source.packageOperationExport() ?? source.packageFunctionExport();
|
||||||
|
const clause = declaration?.acceptanceClause();
|
||||||
|
if (!declaration || !clause || declaration.typeParameters()) continue;
|
||||||
|
const entry = exports.find((entry) => entry.displayName === identifier(declaration.identifier()));
|
||||||
|
const check = exports.find((entry) => entry.displayName === identifier(clause.identifier()));
|
||||||
|
if (!check)
|
||||||
|
loweringIssue(
|
||||||
|
state,
|
||||||
|
clause,
|
||||||
|
"unknown-acceptance-export",
|
||||||
|
"Acceptance hook must name a closed export in this package",
|
||||||
|
);
|
||||||
|
else if (entry) entry.acceptanceExportId = check.id;
|
||||||
|
}
|
||||||
for (const entry of context.packageExport()) {
|
for (const entry of context.packageExport()) {
|
||||||
const specialized = entry.packageQuerySpecialization();
|
const specialized = entry.packageQuerySpecialization();
|
||||||
if (!specialized) continue;
|
if (!specialized) continue;
|
||||||
@@ -2047,6 +2070,22 @@ const lowerConformance = (
|
|||||||
} else if (provider.typeArguments()) {
|
} else if (provider.typeArguments()) {
|
||||||
throw new GenericTypeError("type-arity", exportName, "Non-generic export takes no type arguments");
|
throw new GenericTypeError("type-arity", exportName, "Non-generic export takes no type arguments");
|
||||||
}
|
}
|
||||||
|
const packageExport = packageSymbol?.definition?.exports.find((entry) => entry.id === exportSymbol?.exportId);
|
||||||
|
const check = packageSymbol?.definition?.exports.find((entry) => entry.id === packageExport?.acceptanceExportId);
|
||||||
|
const acceptanceBlock = provider.acceptanceBinding()?.dependencyBindingBlock();
|
||||||
|
if (acceptanceBlock && !check)
|
||||||
|
loweringIssue(
|
||||||
|
state,
|
||||||
|
acceptanceBlock,
|
||||||
|
"unexpected-acceptance-binding",
|
||||||
|
"Export does not declare an acceptance hook",
|
||||||
|
);
|
||||||
|
const acceptanceDependencies = check
|
||||||
|
? lowerBoundDependencies(state, acceptanceBlock ?? undefined, {
|
||||||
|
exportId: check.id,
|
||||||
|
ports: new Map(check.dependencyPorts.map((port) => [port.displayName, port.id])),
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
return packageSymbol && exportSymbol
|
return packageSymbol && exportSymbol
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
@@ -2056,6 +2095,7 @@ const lowerConformance = (
|
|||||||
kind: "package" as const,
|
kind: "package" as const,
|
||||||
packageRevisionId: packageSymbol.revisionId,
|
packageRevisionId: packageSymbol.revisionId,
|
||||||
exportId: exportSymbol.exportId,
|
exportId: exportSymbol.exportId,
|
||||||
|
...(acceptanceDependencies ? { acceptanceDependencies } : {}),
|
||||||
dependencies: lowerBoundDependencies(
|
dependencies: lowerBoundDependencies(
|
||||||
state,
|
state,
|
||||||
provider.dependencyBindingBlock() ?? undefined,
|
provider.dependencyBindingBlock() ?? undefined,
|
||||||
|
|||||||
@@ -257,6 +257,8 @@ export interface DependencyPort {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface PackageExportBase {
|
interface PackageExportBase {
|
||||||
|
/** Required authoritative snapshot export in this package. */
|
||||||
|
acceptanceExportId?: PackageExportId;
|
||||||
execution?: ExecutionContract;
|
execution?: ExecutionContract;
|
||||||
id: PackageExportId;
|
id: PackageExportId;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
@@ -375,6 +377,7 @@ export type Binding =
|
|||||||
packageRevisionId: PackageRevisionId;
|
packageRevisionId: PackageRevisionId;
|
||||||
exportId: PackageExportId;
|
exportId: PackageExportId;
|
||||||
dependencies: BoundDependency[];
|
dependencies: BoundDependency[];
|
||||||
|
acceptanceDependencies?: BoundDependency[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface OperationBinding {
|
export interface OperationBinding {
|
||||||
|
|||||||
@@ -961,6 +961,32 @@ const validatePackages = (
|
|||||||
const exportPath = `${path}.exports[${exportIndex}]`;
|
const exportPath = `${path}.exports[${exportIndex}]`;
|
||||||
validateValueType(issues, entry.inputType, `${exportPath}.inputType`, indexes);
|
validateValueType(issues, entry.inputType, `${exportPath}.inputType`, indexes);
|
||||||
validateValueType(issues, entry.outputType, `${exportPath}.outputType`, indexes);
|
validateValueType(issues, entry.outputType, `${exportPath}.outputType`, indexes);
|
||||||
|
if (entry.acceptanceExportId !== undefined) {
|
||||||
|
const check = revision.exports.find((candidate) => candidate.id === entry.acceptanceExportId);
|
||||||
|
if (
|
||||||
|
entry.execution?.kind !== "transaction" ||
|
||||||
|
!entry.execution.targets.includes("server") ||
|
||||||
|
!check ||
|
||||||
|
check.execution?.kind !== "snapshot" ||
|
||||||
|
check.execution.targets.length !== 1 ||
|
||||||
|
check.execution.targets[0] !== "server" ||
|
||||||
|
check.acceptanceExportId !== undefined ||
|
||||||
|
entry.kind !== check.kind ||
|
||||||
|
entry.kind === "constructor" ||
|
||||||
|
!valueTypesEqual(entry.inputType, check.inputType) ||
|
||||||
|
!valueTypesEqual(check.outputType, valueType.unit) ||
|
||||||
|
(entry.kind === "operation" &&
|
||||||
|
(check.kind !== "operation" ||
|
||||||
|
check.mode !== "call" ||
|
||||||
|
!isDeepStrictEqual(entry.receiverRequirement, check.receiverRequirement)))
|
||||||
|
)
|
||||||
|
issue(
|
||||||
|
issues,
|
||||||
|
"invalid-operation",
|
||||||
|
`${exportPath}.acceptanceExportId`,
|
||||||
|
"Acceptance requires a server snapshot export with matching kind, receiver and input, unit output, and no further acceptance hook",
|
||||||
|
);
|
||||||
|
}
|
||||||
if (entry.kind === "operation") {
|
if (entry.kind === "operation") {
|
||||||
validateOperationEventShape(issues, entry, exportPath);
|
validateOperationEventShape(issues, entry, exportPath);
|
||||||
if (entry.eventType) {
|
if (entry.eventType) {
|
||||||
@@ -1862,6 +1888,20 @@ const validateConformances = (
|
|||||||
requirementGraph,
|
requirementGraph,
|
||||||
graphSourceKey: key,
|
graphSourceKey: key,
|
||||||
});
|
});
|
||||||
|
const check = packageEntry.exports.get(packageExport.acceptanceExportId!);
|
||||||
|
if (check) {
|
||||||
|
validateBoundDependencies(issues, {
|
||||||
|
dependencies: binding.acceptanceDependencies ?? [],
|
||||||
|
dependencyPorts: check.dependencyPorts,
|
||||||
|
atomId: conformance.atomId,
|
||||||
|
conformance,
|
||||||
|
path: `${bindingPath}.binding.acceptance`,
|
||||||
|
indexes,
|
||||||
|
requirementGraph,
|
||||||
|
graphSourceKey: key,
|
||||||
|
});
|
||||||
|
} else if (binding.acceptanceDependencies !== undefined)
|
||||||
|
issue(issues, "invalid-package-binding", bindingPath, "Acceptance ports require a declared acceptance export");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const member of interfaceEntry.revision.members) {
|
for (const member of interfaceEntry.revision.members) {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import type {
|
|||||||
InitializationField,
|
InitializationField,
|
||||||
PersistentAttachment,
|
PersistentAttachment,
|
||||||
DependencyBinding,
|
DependencyBinding,
|
||||||
|
BoundDependency,
|
||||||
|
PackageExport,
|
||||||
} from "../capability-model/types.js";
|
} from "../capability-model/types.js";
|
||||||
import { type ExecutionPlan, ExecutionPlanError, hexDigest } from "./plan.js";
|
import { type ExecutionPlan, ExecutionPlanError, hexDigest } from "./plan.js";
|
||||||
import { portableValueSchema } from "../bindings/portable.js";
|
import { portableValueSchema } from "../bindings/portable.js";
|
||||||
@@ -107,57 +109,70 @@ export function compileKernelProgram(plan: ExecutionPlan): unknown {
|
|||||||
else {
|
else {
|
||||||
const pkg = workspace.packageImports.find((p) => p.revisionId === binding.packageRevisionId)!;
|
const pkg = workspace.packageImports.find((p) => p.revisionId === binding.packageRevisionId)!;
|
||||||
const entry = pkg.exports.find((e) => e.id === binding.exportId)!;
|
const entry = pkg.exports.find((e) => e.id === binding.exportId)!;
|
||||||
const ports = binding.dependencies.map((dependency) => {
|
const compilePorts = (entry: PackageExport, dependencies: BoundDependency[]) =>
|
||||||
const requirement = entry.dependencyPorts.find((p) => p.id === dependency.portId)!.requirement;
|
dependencies.map((dependency) => {
|
||||||
const bound = dependency.binding;
|
const requirement = entry.dependencyPorts.find((p) => p.id === dependency.portId)!.requirement;
|
||||||
const common = { id: dependency.portId, ...via(bound) };
|
const bound = dependency.binding;
|
||||||
if (bound.kind === "state" && requirement.kind === "state")
|
const common = { id: dependency.portId, ...via(bound) };
|
||||||
return {
|
if (bound.kind === "state" && requirement.kind === "state")
|
||||||
...common,
|
return {
|
||||||
kind: "state",
|
...common,
|
||||||
owner: slotOwner(bound.slotId),
|
kind: "state",
|
||||||
slot: bound.slotId,
|
owner: slotOwner(bound.slotId),
|
||||||
primitives: requirement.primitives,
|
slot: bound.slotId,
|
||||||
};
|
primitives: requirement.primitives,
|
||||||
if (bound.kind === "edge" && requirement.kind === "edge")
|
};
|
||||||
return {
|
if (bound.kind === "edge" && requirement.kind === "edge")
|
||||||
...common,
|
return {
|
||||||
kind: "edge",
|
...common,
|
||||||
edge: bound.edgeTypeId,
|
kind: "edge",
|
||||||
projection: bound.projectionId,
|
edge: bound.edgeTypeId,
|
||||||
primitives: requirement.primitives,
|
projection: bound.projectionId,
|
||||||
};
|
primitives: requirement.primitives,
|
||||||
if (bound.kind === "interface" && requirement.kind === "interface") {
|
};
|
||||||
const iface = workspace.interfaceImports.find((i) => i.revisionId === bound.interfaceRevisionId)!;
|
if (bound.kind === "interface" && requirement.kind === "interface") {
|
||||||
return {
|
const iface = workspace.interfaceImports.find((i) => i.revisionId === bound.interfaceRevisionId)!;
|
||||||
...common,
|
return {
|
||||||
kind: "interface",
|
...common,
|
||||||
interface: bound.interfaceRevisionId,
|
kind: "interface",
|
||||||
operations: requirement.operations ?? iface.members.flatMap((m) => m.operations.map((o) => o.id)),
|
interface: bound.interfaceRevisionId,
|
||||||
};
|
operations: requirement.operations ?? iface.members.flatMap((m) => m.operations.map((o) => o.id)),
|
||||||
}
|
};
|
||||||
if (bound.kind === "creation" && requirement.kind === "creation")
|
}
|
||||||
return {
|
if (bound.kind === "creation" && requirement.kind === "creation")
|
||||||
...common,
|
return {
|
||||||
kind: "creation",
|
...common,
|
||||||
atom: bound.atomId,
|
kind: "creation",
|
||||||
schema: portableValueSchema(requirement.inputType),
|
atom: bound.atomId,
|
||||||
recipe: hexDigest({ plan: plan.digest, operation: operation.key, port: dependency.portId }),
|
schema: portableValueSchema(requirement.inputType),
|
||||||
owners: bound.owners.map((seed) => {
|
recipe: hexDigest({ plan: plan.digest, operation: operation.key, port: dependency.portId }),
|
||||||
const owner = owners.find((o) => o.atom === bound.atomId && o.interface === seed.interfaceRevisionId);
|
owners: bound.owners.map((seed) => {
|
||||||
if (!owner)
|
const owner = owners.find((o) => o.atom === bound.atomId && o.interface === seed.interfaceRevisionId);
|
||||||
throw new ExecutionPlanError(
|
if (!owner)
|
||||||
"MISSING_STORAGE_OWNER",
|
throw new ExecutionPlanError(
|
||||||
dependency.portId,
|
"MISSING_STORAGE_OWNER",
|
||||||
"Creation has no initialization owner",
|
dependency.portId,
|
||||||
);
|
"Creation has no initialization owner",
|
||||||
return { owner: owner.id, inputPath: seed.inputPath };
|
);
|
||||||
}),
|
return { owner: owner.id, inputPath: seed.inputPath };
|
||||||
};
|
}),
|
||||||
unsupported = `UNSUPPORTED_EXECUTION_PORT:${bound.kind}`;
|
};
|
||||||
return { ...common, kind: "unavailable" };
|
unsupported = `UNSUPPORTED_EXECUTION_PORT:${bound.kind}`;
|
||||||
});
|
return { ...common, kind: "unavailable" };
|
||||||
target = { kind: "package", package: binding.packageRevisionId, export: binding.exportId, ports };
|
});
|
||||||
|
const ports = compilePorts(entry, binding.dependencies);
|
||||||
|
const check = entry.acceptanceExportId
|
||||||
|
? pkg.exports.find((candidate) => candidate.id === entry.acceptanceExportId)!
|
||||||
|
: undefined;
|
||||||
|
target = {
|
||||||
|
kind: "package",
|
||||||
|
package: binding.packageRevisionId,
|
||||||
|
export: binding.exportId,
|
||||||
|
ports,
|
||||||
|
...(check
|
||||||
|
? { acceptance: { export: check.id, ports: compilePorts(check, binding.acceptanceDependencies ?? []) } }
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
const input = schema(operation.input),
|
const input = schema(operation.input),
|
||||||
output = schema(operation.output);
|
output = schema(operation.output);
|
||||||
@@ -179,6 +194,7 @@ export function compileKernelProgram(plan: ExecutionPlan): unknown {
|
|||||||
revision: pkg.revisionId,
|
revision: pkg.revisionId,
|
||||||
exports: pkg.exports.map((entry) => ({
|
exports: pkg.exports.map((entry) => ({
|
||||||
id: entry.id,
|
id: entry.id,
|
||||||
|
...(entry.acceptanceExportId ? { acceptance: entry.acceptanceExportId } : {}),
|
||||||
effect: entry.execution?.kind ?? "remote",
|
effect: entry.execution?.kind ?? "remote",
|
||||||
targets: entry.execution && entry.execution.kind !== "remote" ? entry.execution.targets : [],
|
targets: entry.execution && entry.execution.kind !== "remote" ? entry.execution.targets : [],
|
||||||
receiver:
|
receiver:
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/parser.js";
|
||||||
|
const contract = `interface Limit id "limit" revision "limit@1" {
|
||||||
|
operation change id "change" : int32 -> unit {
|
||||||
|
call id "change:call" execution transaction targets [browser, server];
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
export const runtime = `external atom Item id "item";
|
||||||
|
package Runtime id "runtime" revision "runtime@1" {
|
||||||
|
operation change id "runtime:change" : int32 -> unit mode call execution transaction targets [browser, server]
|
||||||
|
receiver atom Item requires { state level id "write:value" : int32 [write]; } accept using check;
|
||||||
|
operation check id "runtime:check" : int32 -> unit mode call execution snapshot targets [server]
|
||||||
|
receiver atom Item requires {
|
||||||
|
state level id "read:value" : int32 [read];
|
||||||
|
state ceiling id "read:ceiling" : int32 [read];
|
||||||
|
};
|
||||||
|
}`;
|
||||||
|
export const workspace = `workspace LimitTest id "workspace:limit" revision "workspace:limit@1" commit "${"a".repeat(40)}" {
|
||||||
|
import interface Limit;
|
||||||
|
import package Runtime;
|
||||||
|
atom Item id "item";
|
||||||
|
conform Item as Limit id "item:limit" {
|
||||||
|
private state Value id "value" on Item : int32 policy register default 0;
|
||||||
|
private state Ceiling id "ceiling" on Item : int32 policy register default 100;
|
||||||
|
bind change.call to package Runtime.change with { level to state Value; }
|
||||||
|
accept with { level to state Value; ceiling to state Ceiling; };
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
export function compile(packageSource = runtime, workspaceSource = workspace) {
|
||||||
|
const source = { repository: "https://example.test/limit.git", commit: "a".repeat(40) };
|
||||||
|
const iface = compileCapabilityResourceSource(contract, { source });
|
||||||
|
assert.ok(iface.ok && iface.resource.kind === "interface", JSON.stringify(iface.diagnostics));
|
||||||
|
const pkg = compileCapabilityResourceSource(packageSource, { source });
|
||||||
|
if (!pkg.ok) return pkg;
|
||||||
|
assert.equal(pkg.resource.kind, "package");
|
||||||
|
if (pkg.resource.kind !== "package") throw Error("Expected package");
|
||||||
|
return compileCapabilitySource(workspaceSource, "workspace.qx", {
|
||||||
|
interfaces: new Map([["Limit", iface.resource.revision]]),
|
||||||
|
packages: new Map([["Runtime", pkg.resource.revision]]),
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { test } from "node:test";
|
||||||
|
import { compileCapabilityResourceSource } from "../src/capability-language/parser.js";
|
||||||
|
import { formatQx } from "../src/capability-language/source.js";
|
||||||
|
import { compileExecutionPlan, compileKernelProgram, checkExecutionWorld } from "../src/execution-world/index.js";
|
||||||
|
import { generatePortableTypeScriptBindings } from "../src/bindings/portable.js";
|
||||||
|
import { buildArtifactFixture } from "./artifact-fixture.js";
|
||||||
|
import { compile, runtime, workspace } from "./acceptance-fixture.js";
|
||||||
|
test("acceptance syntax retains separate final-state ports through formatting, planning, adapters and artifacts", async () => {
|
||||||
|
const result = compile();
|
||||||
|
assert.ok(result.ok, JSON.stringify(result.diagnostics));
|
||||||
|
const formatted = compile(formatQx(runtime), formatQx(workspace));
|
||||||
|
assert.ok(formatted.ok, JSON.stringify(formatted.diagnostics));
|
||||||
|
const plan = compileExecutionPlan(result.workspace);
|
||||||
|
assert.equal(compileExecutionPlan(formatted.workspace).digest, plan.digest);
|
||||||
|
const kernel = compileKernelProgram(plan) as {
|
||||||
|
operations: { binding: { ports: { id: string }[]; acceptance: { export: string; ports: { id: string }[] } } }[];
|
||||||
|
packages: { exports: { id: string; acceptance?: string }[] }[];
|
||||||
|
};
|
||||||
|
assert.deepEqual(
|
||||||
|
kernel.operations[0]!.binding.ports.map((p) => p.id),
|
||||||
|
["write:value"],
|
||||||
|
);
|
||||||
|
assert.equal(kernel.operations[0]!.binding.acceptance.export, "runtime:check");
|
||||||
|
assert.deepEqual(kernel.operations[0]!.binding.acceptance.ports.map((p) => p.id).sort(), [
|
||||||
|
"read:ceiling",
|
||||||
|
"read:value",
|
||||||
|
]);
|
||||||
|
assert.equal(kernel.packages[0]!.exports.find((e) => e.id === "runtime:change")!.acceptance, "runtime:check");
|
||||||
|
assert.ok(
|
||||||
|
!generatePortableTypeScriptBindings(plan.definition.bindingSchema, "runtime@1", { target: "browser" }).includes(
|
||||||
|
'"runtime:check"',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
generatePortableTypeScriptBindings(plan.definition.bindingSchema, "runtime@1", { target: "server" }).includes(
|
||||||
|
'"runtime:check"',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const artifacts = buildArtifactFixture(plan, "runtime@1");
|
||||||
|
await checkExecutionWorld(plan, [artifacts.manifest], artifacts.read);
|
||||||
|
});
|
||||||
|
test("acceptance declarations reject wrong effects/signatures and missing or mutable ports", () => {
|
||||||
|
for (const [pkg, ws] of [
|
||||||
|
[runtime.replace("snapshot targets [server]", "transaction targets [server]"), workspace],
|
||||||
|
[runtime.replace("snapshot targets [server]", "snapshot targets [browser, server]"), workspace],
|
||||||
|
[
|
||||||
|
runtime.replace('check id "runtime:check" : int32 -> unit', 'check id "runtime:check" : string -> unit'),
|
||||||
|
workspace,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
runtime.replace('check id "runtime:check" : int32 -> unit', 'check id "runtime:check" : int32 -> int32'),
|
||||||
|
workspace,
|
||||||
|
],
|
||||||
|
[runtime.replace('id "read:ceiling" : int32 [read]', 'id "read:ceiling" : int32 [write]'), workspace],
|
||||||
|
[runtime, workspace.replace("ceiling to state Ceiling;", "")],
|
||||||
|
[runtime.replace(" accept using check", ""), workspace],
|
||||||
|
])
|
||||||
|
assert.equal(compile(pkg, ws).ok, false, `${pkg}\n${ws}`);
|
||||||
|
});
|
||||||
|
test("generic acceptance syntax rejects explicitly until specialization is supported", () => {
|
||||||
|
const result = compileCapabilityResourceSource(
|
||||||
|
runtime.replace("operation change id", "operation change<value T> id"),
|
||||||
|
{
|
||||||
|
source: { repository: "https://example.test/limit.git", commit: "a".repeat(40) },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert.equal(result.ok, false);
|
||||||
|
assert.ok(result.diagnostics.some((d) => d.code === "unsupported-generic-acceptance"));
|
||||||
|
});
|
||||||
@@ -21,7 +21,9 @@ export const buildArtifactFixture = (plan: ExecutionPlan, revision = plan.defini
|
|||||||
path,
|
path,
|
||||||
ports: "quixos-transaction-ports-v1" as const,
|
ports: "quixos-transaction-ports-v1" as const,
|
||||||
...(compatibility === "quixos-js-module-v1" ? { registryExport: "handlers" } : {}),
|
...(compatibility === "quixos-js-module-v1" ? { registryExport: "handlers" } : {}),
|
||||||
exports: expected.exports.map((e) => e.id),
|
exports: expected.exports
|
||||||
|
.filter((e) => target === "server" || (e.execution.kind !== "remote" && e.execution.targets.includes(target)))
|
||||||
|
.map((e) => e.id),
|
||||||
files: [
|
files: [
|
||||||
{
|
{
|
||||||
path,
|
path,
|
||||||
|
|||||||
@@ -89,6 +89,13 @@ void negative;
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { asyncObjectPlan } = await import("./async-fixture.js");
|
const { asyncObjectPlan } = await import("./async-fixture.js");
|
||||||
|
const { compile: compileAcceptance } = await import("./acceptance-fixture.js");
|
||||||
|
const acceptance = compileAcceptance();
|
||||||
|
if (!acceptance.ok) throw Error(JSON.stringify(acceptance.diagnostics));
|
||||||
|
const acceptancePlan = compileExecutionPlan(acceptance.workspace);
|
||||||
|
await mkdir("dist/portable-reader/acceptance", { recursive: true });
|
||||||
|
await writeFile("dist/portable-reader/acceptance/plan.json", JSON.stringify(acceptancePlan));
|
||||||
|
await writeFile("dist/portable-reader/acceptance/kernel.json", JSON.stringify(compileKernelProgram(acceptancePlan)));
|
||||||
const { recurringTaskPlan } = await import("./recurring-fixture.js");
|
const { recurringTaskPlan } = await import("./recurring-fixture.js");
|
||||||
const recurringPlan = await recurringTaskPlan();
|
const recurringPlan = await recurringTaskPlan();
|
||||||
await mkdir("dist/portable-reader/recurring", { recursive: true });
|
await mkdir("dist/portable-reader/recurring", { recursive: true });
|
||||||
|
|||||||
Reference in New Issue
Block a user