@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.
@@ -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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dusted/anqst",
3
- "version": "0.1.3",
3
+ "version": "1.0.1",
4
4
  "description": "Opinionated backend generator for webapps.",
5
5
  "keywords": [
6
6
  "nodejs",