@dusted/anqst 0.1.3 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/app.js +102 -77
- package/dist/src/build-stamp.js +1 -1
- package/dist/src/emit.js +231 -6
- package/dist/src/parser.js +53 -5
- package/package.json +1 -1
- package/spec/AnQst-Spec-DSL.d.ts +328 -249
package/dist/src/parser.js
CHANGED
|
@@ -55,7 +55,7 @@ function parseMemberKindFromAnQstType(typeNode) {
|
|
|
55
55
|
if (!typeName.startsWith("AnQst."))
|
|
56
56
|
return null;
|
|
57
57
|
const kind = typeName.slice("AnQst.".length);
|
|
58
|
-
if (!["Call", "Slot", "Emitter", "Output", "Input"].includes(kind))
|
|
58
|
+
if (!["Call", "Slot", "Emitter", "Output", "Input", "DropTarget", "HoverTarget"].includes(kind))
|
|
59
59
|
return null;
|
|
60
60
|
if (kind === "Emitter")
|
|
61
61
|
return { kind, payload: null };
|
|
@@ -71,7 +71,7 @@ function parseMemberKindWithConfig(typeNode) {
|
|
|
71
71
|
if (!typeName.startsWith("AnQst."))
|
|
72
72
|
return null;
|
|
73
73
|
const kind = typeName.slice("AnQst.".length);
|
|
74
|
-
if (!["Call", "Slot", "Emitter", "Output", "Input"].includes(kind))
|
|
74
|
+
if (!["Call", "Slot", "Emitter", "Output", "Input", "DropTarget", "HoverTarget"].includes(kind))
|
|
75
75
|
return null;
|
|
76
76
|
const typeArgs = typeNode.typeArguments ?? [];
|
|
77
77
|
if (kind === "Emitter") {
|
|
@@ -84,7 +84,7 @@ function parseMemberKindWithConfig(typeNode) {
|
|
|
84
84
|
return {
|
|
85
85
|
kind,
|
|
86
86
|
payload: typeArgs[0] ? typeArgs[0].getText() : null,
|
|
87
|
-
configTypeNode: kind === "Call" ? (typeArgs[1] ?? null) : null
|
|
87
|
+
configTypeNode: (kind === "Call" || kind === "HoverTarget") ? (typeArgs[1] ?? null) : null
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
function parseNumericLiteralType(node) {
|
|
@@ -156,6 +156,51 @@ function resolveMemberTimeoutMs(source, serviceName, memberName, kind, configTyp
|
|
|
156
156
|
}
|
|
157
157
|
return effectiveMs;
|
|
158
158
|
}
|
|
159
|
+
const DEFAULT_HOVER_RATE_HZ = 60;
|
|
160
|
+
const DEFAULT_HOVER_THROTTLE_MS = Math.round(1000 / DEFAULT_HOVER_RATE_HZ);
|
|
161
|
+
function resolveHoverThrottleMs(source, serviceName, memberName, kind, configTypeNode, warnings, memberLoc) {
|
|
162
|
+
if (kind !== "HoverTarget")
|
|
163
|
+
return 0;
|
|
164
|
+
if (!configTypeNode)
|
|
165
|
+
return DEFAULT_HOVER_THROTTLE_MS;
|
|
166
|
+
if (!typescript_1.default.isTypeLiteralNode(configTypeNode)) {
|
|
167
|
+
throw new errors_1.VerifyError(`HoverTarget config for '${memberName}' must be an inline object literal type.`, locFromNode(source, configTypeNode));
|
|
168
|
+
}
|
|
169
|
+
let maxRateHz = null;
|
|
170
|
+
const memberPath = `${serviceName}.${memberName}`;
|
|
171
|
+
for (const prop of configTypeNode.members) {
|
|
172
|
+
if (!typescript_1.default.isPropertySignature(prop) || !prop.name) {
|
|
173
|
+
throw new errors_1.VerifyError(`HoverTarget config for '${memberName}' only supports named properties.`, locFromNode(source, prop));
|
|
174
|
+
}
|
|
175
|
+
if (!typescript_1.default.isIdentifier(prop.name)) {
|
|
176
|
+
throw new errors_1.VerifyError(`HoverTarget config for '${memberName}' only supports identifier keys.`, locFromNode(source, prop.name));
|
|
177
|
+
}
|
|
178
|
+
const key = prop.name.text;
|
|
179
|
+
if (!prop.type) {
|
|
180
|
+
throw new errors_1.VerifyError(`HoverTarget config key '${key}' in '${memberName}' must declare a numeric literal value.`, locFromNode(source, prop));
|
|
181
|
+
}
|
|
182
|
+
if (key !== "maxRateHz") {
|
|
183
|
+
warnings.push({
|
|
184
|
+
severity: "warn",
|
|
185
|
+
message: `Unknown HoverTarget config key '${key}' ignored for '${memberPath}'.`,
|
|
186
|
+
loc: locFromNode(source, prop.name),
|
|
187
|
+
memberPath
|
|
188
|
+
});
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const numericValue = parseNumericLiteralType(prop.type);
|
|
192
|
+
if (numericValue === null || !Number.isFinite(numericValue)) {
|
|
193
|
+
throw new errors_1.VerifyError(`HoverTarget config key '${key}' in '${memberName}' must be a numeric literal >= 0.`, locFromNode(source, prop.type));
|
|
194
|
+
}
|
|
195
|
+
if (numericValue < 0) {
|
|
196
|
+
throw new errors_1.VerifyError(`HoverTarget config key '${key}' in '${memberName}' must be >= 0.`, locFromNode(source, prop.type));
|
|
197
|
+
}
|
|
198
|
+
maxRateHz = numericValue;
|
|
199
|
+
}
|
|
200
|
+
if (maxRateHz === null)
|
|
201
|
+
return DEFAULT_HOVER_THROTTLE_MS;
|
|
202
|
+
return maxRateHz === 0 ? 0 : Math.round(1000 / maxRateHz);
|
|
203
|
+
}
|
|
159
204
|
function parseServiceMember(source, serviceName, member, warnings) {
|
|
160
205
|
if (typescript_1.default.isMethodSignature(member)) {
|
|
161
206
|
if (member.questionToken)
|
|
@@ -166,7 +211,7 @@ function parseServiceMember(source, serviceName, member, warnings) {
|
|
|
166
211
|
const parsed = parseMemberKindWithConfig(returnType);
|
|
167
212
|
if (!parsed)
|
|
168
213
|
throw new errors_1.VerifyError(`Unsupported service method return type '${returnType.getText()}'.`, locFromNode(source, member));
|
|
169
|
-
if (parsed.kind === "Input" || parsed.kind === "Output") {
|
|
214
|
+
if (parsed.kind === "Input" || parsed.kind === "Output" || parsed.kind === "DropTarget" || parsed.kind === "HoverTarget") {
|
|
170
215
|
throw new errors_1.VerifyError(`${parsed.kind} must be declared as property, not method.`, locFromNode(source, member));
|
|
171
216
|
}
|
|
172
217
|
if (parsed.kind === "Emitter" && parsed.configTypeNode !== null) {
|
|
@@ -191,6 +236,7 @@ function parseServiceMember(source, serviceName, member, warnings) {
|
|
|
191
236
|
payloadTypeText: parsed.payload,
|
|
192
237
|
parameters,
|
|
193
238
|
timeoutMs,
|
|
239
|
+
hoverThrottleMs: 0,
|
|
194
240
|
loc: locFromNode(source, member)
|
|
195
241
|
};
|
|
196
242
|
}
|
|
@@ -202,19 +248,21 @@ function parseServiceMember(source, serviceName, member, warnings) {
|
|
|
202
248
|
const parsed = parseMemberKindWithConfig(member.type);
|
|
203
249
|
if (!parsed)
|
|
204
250
|
throw new errors_1.VerifyError(`Unsupported service property type '${member.type.getText()}'.`, locFromNode(source, member));
|
|
205
|
-
if (parsed.kind !== "Input" && parsed.kind !== "Output") {
|
|
251
|
+
if (parsed.kind !== "Input" && parsed.kind !== "Output" && parsed.kind !== "DropTarget" && parsed.kind !== "HoverTarget") {
|
|
206
252
|
throw new errors_1.VerifyError(`${parsed.kind} must be declared as method, not property.`, locFromNode(source, member));
|
|
207
253
|
}
|
|
208
254
|
if (!member.name || !typescript_1.default.isIdentifier(member.name)) {
|
|
209
255
|
throw new errors_1.VerifyError("Only identifier service property names are supported.", locFromNode(source, member));
|
|
210
256
|
}
|
|
211
257
|
const timeoutMs = resolveMemberTimeoutMs(source, serviceName, member.name.text, parsed.kind, parsed.configTypeNode, warnings, locFromNode(source, member));
|
|
258
|
+
const hoverThrottleMs = resolveHoverThrottleMs(source, serviceName, member.name.text, parsed.kind, parsed.configTypeNode, warnings, locFromNode(source, member));
|
|
212
259
|
return {
|
|
213
260
|
kind: parsed.kind,
|
|
214
261
|
name: member.name.text,
|
|
215
262
|
payloadTypeText: parsed.payload,
|
|
216
263
|
parameters: [],
|
|
217
264
|
timeoutMs,
|
|
265
|
+
hoverThrottleMs,
|
|
218
266
|
loc: locFromNode(source, member)
|
|
219
267
|
};
|
|
220
268
|
}
|