@typecad/cuttlefish 1.0.0-alpha.3 → 1.0.0-alpha.7
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/README.md +4 -4
- package/dist/api/shared/display-adapter.d.ts +2 -1
- package/dist/api/shared/display-adapter.js +8 -1
- package/dist/api/shared/display-adapters/sdl.js +9 -2
- package/dist/api/shared/display-profile.d.ts +20 -3
- package/dist/api/shared/display-profile.js +21 -6
- package/dist/api/shared/framework-manifest-registry.d.ts +9 -0
- package/dist/api/shared/framework-manifest-registry.js +25 -0
- package/dist/api/shared/framework-manifest.d.ts +462 -0
- package/dist/api/shared/framework-manifest.js +149 -0
- package/dist/api/shared/glcdfont.d.ts +12 -0
- package/dist/api/shared/glcdfont.js +124 -0
- package/dist/api/shared/graphics-strategy.d.ts +28 -0
- package/dist/api/shared/hal-op-ir.d.ts +427 -1
- package/dist/api/shared/hal-op-ir.js +95 -1
- package/dist/api/shared/index.d.ts +11 -1
- package/dist/api/shared/index.js +14 -0
- package/dist/api/shared/native-display-op-resolver.d.ts +10 -0
- package/dist/api/shared/native-display-op-resolver.js +64 -0
- package/dist/api/shared/platform-strategy.d.ts +9 -0
- package/dist/api/shared/promise-runtime.js +78 -0
- package/dist/api/shared/types.d.ts +8 -0
- package/dist/api/shared/validate-framework-manifest.d.ts +28 -0
- package/dist/api/shared/validate-framework-manifest.js +417 -0
- package/dist/cli-utils.d.ts +1 -0
- package/dist/cli-utils.js +3 -1
- package/dist/cli.js +175 -4
- package/dist/config-loader.js +20 -1
- package/dist/config-schema.d.ts +36 -36
- package/dist/create/board-spec.d.ts +4 -4
- package/dist/create/index.d.ts +1 -1
- package/dist/create/index.js +1 -1
- package/dist/create/init-scaffold.d.ts +3 -0
- package/dist/create/init-scaffold.js +74 -2
- package/dist/create/init-templates.d.ts +4 -0
- package/dist/create/init-templates.js +217 -17
- package/dist/create/init-wizard.js +20 -1
- package/dist/emit/cpp-emitter.js +4 -3
- package/dist/emit/emitters/emitter-context.d.ts +5 -0
- package/dist/emit/emitters/function-emitter-impl.js +69 -59
- package/dist/emit/emitters/output-finalizer.d.ts +6 -0
- package/dist/emit/emitters/output-finalizer.js +21 -11
- package/dist/emit/emitters/setup.js +155 -0
- package/dist/emit/emitters/top-level-prep.js +2 -0
- package/dist/emit/emitters/ui-emitter.js +23 -8
- package/dist/emit/expression-renderer.js +10 -1
- package/dist/emit/snprintf-helpers.js +8 -0
- package/dist/emit/statement-renderer.js +13 -0
- package/dist/emit/utils/async-state-machine.js +185 -116
- package/dist/emit/utils/hal-op-cpp-type.d.ts +6 -0
- package/dist/emit/utils/hal-op-cpp-type.js +40 -0
- package/dist/ir/adc-range-validation.js +26 -25
- package/dist/ir/build-ir.js +5 -1
- package/dist/ir/expression-to-ir.js +57 -6
- package/dist/ir/feature-registry.js +7 -25
- package/dist/ir/hal/hal-emitter.d.ts +5 -2
- package/dist/ir/hal/hal-emitter.js +40 -12
- package/dist/ir/hal/hal-parser.d.ts +6 -0
- package/dist/ir/hal/hal-parser.js +74 -0
- package/dist/ir/hal/hal-plugins.js +571 -0
- package/dist/ir/identifier-collector.js +18 -0
- package/dist/ir/interrupt-analysis.js +8 -3
- package/dist/ir/memory-budget-validation.js +1 -0
- package/dist/ir/network-validation.d.ts +4 -0
- package/dist/ir/network-validation.js +184 -0
- package/dist/ir/ownership-analysis.js +33 -1
- package/dist/ir/peripheral-ownership.js +5 -0
- package/dist/ir/peripheral-validation.d.ts +1 -1
- package/dist/ir/peripheral-validation.js +6 -3
- package/dist/ir/pin-alias-conflict.d.ts +1 -1
- package/dist/ir/pin-alias-conflict.js +2 -1
- package/dist/ir/pin-capability-validation.js +34 -32
- package/dist/ir/pin-mode-validation.js +5 -0
- package/dist/ir/pin-safety.d.ts +1 -1
- package/dist/ir/pin-safety.js +2 -1
- package/dist/ir/program-analysis.d.ts +39 -0
- package/dist/ir/program-analysis.js +192 -0
- package/dist/ir/pulldown-validation.d.ts +1 -1
- package/dist/ir/pulldown-validation.js +2 -1
- package/dist/ir/pwm-timer-sharing.d.ts +1 -1
- package/dist/ir/pwm-timer-sharing.js +2 -1
- package/dist/ir/resource-analysis.js +2 -0
- package/dist/ir/timer0-pwm-timing-conflict.d.ts +1 -1
- package/dist/ir/timer0-pwm-timing-conflict.js +2 -1
- package/dist/ir/timing-validation.d.ts +6 -1
- package/dist/ir/timing-validation.js +51 -12
- package/dist/ir/transformers/expressions.js +58 -0
- package/dist/ir/transformers/hal-emit-helpers.js +1 -1
- package/dist/ir/transformers/variables.js +86 -19
- package/dist/ir/try-catch-validation.js +2 -0
- package/dist/ir/type-resolution.js +2 -2
- package/dist/ir/unit-suspicion-validation.js +9 -7
- package/dist/ir/validation-orchestrator.js +9 -7
- package/dist/libdef/c-to-decl.d.ts +27 -0
- package/dist/libdef/c-to-decl.js +397 -0
- package/dist/libdef/component-decls.d.ts +2 -0
- package/dist/libdef/component-decls.js +6 -0
- package/dist/libdef/component-discovery.d.ts +43 -0
- package/dist/libdef/component-discovery.js +83 -0
- package/dist/libdef/cpp-to-decl.d.ts +9 -0
- package/dist/libdef/cpp-to-decl.js +72 -0
- package/dist/libdef/idf-discovery.d.ts +7 -0
- package/dist/libdef/idf-discovery.js +59 -0
- package/dist/libdef/registry.js +5 -2
- package/dist/licenses.d.ts +185 -0
- package/dist/licenses.js +963 -0
- package/dist/lint-cache.d.ts +59 -0
- package/dist/lint-cache.js +257 -0
- package/dist/orchestrator/graph-builder.js +6 -2
- package/dist/stores/display-profile-store.d.ts +1 -0
- package/dist/stores/display-profile-store.js +1 -0
- package/dist/testing.d.ts +4 -2
- package/dist/testing.js +4 -2
- package/dist/transpile.d.ts +3 -0
- package/dist/transpile.js +78 -32
- package/dist/types.d.ts +5 -1
- package/dist/ui-hook.d.ts +17 -1
- package/dist/utils/cli.js +71 -1
- package/dist/utils/fs.d.ts +13 -0
- package/dist/utils/fs.js +50 -0
- package/package.json +9 -4
- package/dist/ir/heap-array-validation.d.ts +0 -24
- package/dist/ir/heap-array-validation.js +0 -29
|
@@ -105,6 +105,44 @@ function resolveNumericOrExpression(args, idx, instance, paramNames, callArgText
|
|
|
105
105
|
return num;
|
|
106
106
|
return resolveSemanticArg(args, idx, instance, paramNames, callArgTexts, paramDefaults);
|
|
107
107
|
}
|
|
108
|
+
/** Normalize an optional resolved arg: an omitted optional parameter with no
|
|
109
|
+
* default resolves to the literal text "undefined" (see resolveExpressionText);
|
|
110
|
+
* map that to null so op builders can omit the field entirely. */
|
|
111
|
+
function dropUndefined(value) {
|
|
112
|
+
return value === "undefined" ? null : value;
|
|
113
|
+
}
|
|
114
|
+
/** Quote a resolved string value unless it is already a quoted literal or a
|
|
115
|
+
* plain identifier / member-access expression (i.e. a runtime variable). */
|
|
116
|
+
function quoteNonIdentifier(value) {
|
|
117
|
+
const t = value.trim();
|
|
118
|
+
if (/^".*"$/.test(t))
|
|
119
|
+
return t;
|
|
120
|
+
if (/^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/.test(t))
|
|
121
|
+
return t;
|
|
122
|
+
return JSON.stringify(t);
|
|
123
|
+
}
|
|
124
|
+
/** Resolve a BlePerm expression to its numeric bitmask.
|
|
125
|
+
* Handles: plain numbers (3), "BlePerm.Read", "BlePerm.Read | BlePerm.Notify". */
|
|
126
|
+
const BLE_PERM_VALUES = {
|
|
127
|
+
Read: 1, Write: 2, Notify: 4,
|
|
128
|
+
};
|
|
129
|
+
function resolveBlePermExpr(raw) {
|
|
130
|
+
if (raw === null)
|
|
131
|
+
return 0;
|
|
132
|
+
const s = String(raw).trim();
|
|
133
|
+
if (/^\d+$/.test(s))
|
|
134
|
+
return Number(s);
|
|
135
|
+
// Extract all BlePerm.X member names and sum their values.
|
|
136
|
+
let sum = 0;
|
|
137
|
+
const re = /BlePerm\.(\w+)/g;
|
|
138
|
+
let m;
|
|
139
|
+
let matched = false;
|
|
140
|
+
while ((m = re.exec(s)) !== null) {
|
|
141
|
+
matched = true;
|
|
142
|
+
sum += BLE_PERM_VALUES[m[1]] ?? 0;
|
|
143
|
+
}
|
|
144
|
+
return matched ? sum : 0;
|
|
145
|
+
}
|
|
108
146
|
/** Extract the MCU port name from the current HAL instance, if available. */
|
|
109
147
|
export function portFromInstance(instance) {
|
|
110
148
|
const port = instance.fieldValues.get('_port');
|
|
@@ -312,6 +350,101 @@ export function tryResolveSemanticCall(fnName, args, instance, paramNames, callA
|
|
|
312
350
|
return null;
|
|
313
351
|
return { operation: "pwm.write", port, pin, duty };
|
|
314
352
|
}
|
|
353
|
+
// ── RMT ──
|
|
354
|
+
// rmtTxInit/rmtRxInit are POSITIONAL semantic primitives (the ergonomic
|
|
355
|
+
// opts-object form lives in hal/rmt.ts's RmtChannel class, which
|
|
356
|
+
// destructures opts and forwards positionally). The resolver dispatches on
|
|
357
|
+
// the literal callee name, so rmt.ts must call these by their real names
|
|
358
|
+
// (no `as _rmtTxInit` aliasing — that breaks the switch).
|
|
359
|
+
// rmtTxInit(pin, resolutionHz, bit0Hi, bit0Lo, bit1Hi, bit1Lo, msbFirst, queueDepth)
|
|
360
|
+
case "rmtTxInit": {
|
|
361
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
362
|
+
const resolutionHz = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
363
|
+
const bit0Hi = resolveNumericOrExpression(args, 2, instance, paramNames, callArgTexts, paramDefaults);
|
|
364
|
+
const bit0Lo = resolveNumericOrExpression(args, 3, instance, paramNames, callArgTexts, paramDefaults);
|
|
365
|
+
const bit1Hi = resolveNumericOrExpression(args, 4, instance, paramNames, callArgTexts, paramDefaults);
|
|
366
|
+
const bit1Lo = resolveNumericOrExpression(args, 5, instance, paramNames, callArgTexts, paramDefaults);
|
|
367
|
+
const msbFirst = resolveSemanticArg(args, 6, instance, paramNames, callArgTexts, paramDefaults);
|
|
368
|
+
const queueDepth = resolveNumericOrExpression(args, 7, instance, paramNames, callArgTexts, paramDefaults);
|
|
369
|
+
if (pin === null || resolutionHz === null)
|
|
370
|
+
return null;
|
|
371
|
+
const op = { operation: "rmt.tx_init", port, pin, resolutionHz, bit0Hi, bit0Lo, bit1Hi, bit1Lo };
|
|
372
|
+
if (queueDepth !== null)
|
|
373
|
+
op.queueDepth = queueDepth;
|
|
374
|
+
if (msbFirst !== null)
|
|
375
|
+
op.msbFirst = msbFirst;
|
|
376
|
+
return op;
|
|
377
|
+
}
|
|
378
|
+
case "rmtTxWriteBytes": {
|
|
379
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
380
|
+
// bytes is an array literal — resolveSemanticArg renders it positionally as "1, 2, 3".
|
|
381
|
+
const bytes = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
382
|
+
if (pin === null || bytes === null)
|
|
383
|
+
return null;
|
|
384
|
+
return { operation: "rmt.tx_write_bytes", port, pin, bytes };
|
|
385
|
+
}
|
|
386
|
+
case "rmtTxWriteSymbols": {
|
|
387
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
388
|
+
const symbols = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
389
|
+
if (pin === null || symbols === null)
|
|
390
|
+
return null;
|
|
391
|
+
return { operation: "rmt.tx_write_symbols", port, pin, symbols };
|
|
392
|
+
}
|
|
393
|
+
case "rmtTxWaitDone": {
|
|
394
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
395
|
+
const timeoutMs = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
396
|
+
if (pin === null)
|
|
397
|
+
return null;
|
|
398
|
+
const op = { operation: "rmt.tx_wait_done", port, pin };
|
|
399
|
+
if (timeoutMs !== null)
|
|
400
|
+
op.timeoutMs = timeoutMs;
|
|
401
|
+
return op;
|
|
402
|
+
}
|
|
403
|
+
case "rmtTxDeinit": {
|
|
404
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
405
|
+
if (pin === null)
|
|
406
|
+
return null;
|
|
407
|
+
return { operation: "rmt.tx_deinit", port, pin };
|
|
408
|
+
}
|
|
409
|
+
case "rmtRxInit": {
|
|
410
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
411
|
+
const resolutionHz = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
412
|
+
if (pin === null || resolutionHz === null)
|
|
413
|
+
return null;
|
|
414
|
+
return { operation: "rmt.rx_init", port, pin, resolutionHz };
|
|
415
|
+
}
|
|
416
|
+
case "rmtRxOnReceived": {
|
|
417
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
418
|
+
const handler = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
419
|
+
if (pin === null || handler === null)
|
|
420
|
+
return null;
|
|
421
|
+
return { operation: "rmt.rx_on_received", port, pin, handler };
|
|
422
|
+
}
|
|
423
|
+
case "rmtRxStart": {
|
|
424
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
425
|
+
if (pin === null)
|
|
426
|
+
return null;
|
|
427
|
+
return { operation: "rmt.rx_start", port, pin };
|
|
428
|
+
}
|
|
429
|
+
case "rmtRxStop": {
|
|
430
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
431
|
+
if (pin === null)
|
|
432
|
+
return null;
|
|
433
|
+
return { operation: "rmt.rx_stop", port, pin };
|
|
434
|
+
}
|
|
435
|
+
case "rmtRxRead": {
|
|
436
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
437
|
+
const maxCount = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
438
|
+
if (pin === null || maxCount === null)
|
|
439
|
+
return null;
|
|
440
|
+
return { operation: "rmt.rx_read", port, pin, maxCount };
|
|
441
|
+
}
|
|
442
|
+
case "rmtRxDeinit": {
|
|
443
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
444
|
+
if (pin === null)
|
|
445
|
+
return null;
|
|
446
|
+
return { operation: "rmt.rx_deinit", port, pin };
|
|
447
|
+
}
|
|
315
448
|
// ── ADC ──
|
|
316
449
|
case "adcRead": {
|
|
317
450
|
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
@@ -383,6 +516,434 @@ export function tryResolveSemanticCall(fnName, args, instance, paramNames, callA
|
|
|
383
516
|
return null;
|
|
384
517
|
return { operation: "power.set_cpu_frequency", mhz };
|
|
385
518
|
}
|
|
519
|
+
case "powerDeepSleepPin": {
|
|
520
|
+
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
521
|
+
const level = resolveNumericArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
522
|
+
if (pin === null || level === null)
|
|
523
|
+
return null;
|
|
524
|
+
return { operation: "power.deep_sleep_pin", pin, level };
|
|
525
|
+
}
|
|
526
|
+
// ── WiFi ──
|
|
527
|
+
// Optional string args (password, dns) resolve to the text "undefined"
|
|
528
|
+
// when omitted at the call site (no default in the HAL signature). Treat
|
|
529
|
+
// that as absent so the backend emits its own default ("").
|
|
530
|
+
case "wifiConnect": {
|
|
531
|
+
const ssid = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
532
|
+
const password = dropUndefined(resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults));
|
|
533
|
+
const timeoutMs = resolveSemanticArg(args, 2, instance, paramNames, callArgTexts, paramDefaults) ?? 15000;
|
|
534
|
+
if (ssid === null)
|
|
535
|
+
return null;
|
|
536
|
+
return {
|
|
537
|
+
operation: "wifi.connect",
|
|
538
|
+
ssid,
|
|
539
|
+
...(password !== null ? { password } : {}),
|
|
540
|
+
timeoutMs,
|
|
541
|
+
blocking: true,
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
case "wifiConnectStart": {
|
|
545
|
+
const ssid = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
546
|
+
const password = dropUndefined(resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults));
|
|
547
|
+
if (ssid === null)
|
|
548
|
+
return null;
|
|
549
|
+
return { operation: "wifi.connect_start", ssid, ...(password !== null ? { password } : {}) };
|
|
550
|
+
}
|
|
551
|
+
case "wifiDisconnect":
|
|
552
|
+
return { operation: "wifi.disconnect" };
|
|
553
|
+
case "wifiStatus":
|
|
554
|
+
return { operation: "wifi.status" };
|
|
555
|
+
case "wifiIsConnected":
|
|
556
|
+
return { operation: "wifi.is_connected" };
|
|
557
|
+
case "wifiLocalIp":
|
|
558
|
+
return { operation: "wifi.local_ip" };
|
|
559
|
+
case "wifiRssi":
|
|
560
|
+
return { operation: "wifi.rssi" };
|
|
561
|
+
case "wifiMac":
|
|
562
|
+
return { operation: "wifi.mac" };
|
|
563
|
+
case "wifiSetHostname": {
|
|
564
|
+
const name = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
565
|
+
if (name === null)
|
|
566
|
+
return null;
|
|
567
|
+
return { operation: "wifi.set_hostname", name };
|
|
568
|
+
}
|
|
569
|
+
case "wifiSetStaticIp": {
|
|
570
|
+
const ip = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
571
|
+
const gateway = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
572
|
+
const subnet = resolveSemanticArg(args, 2, instance, paramNames, callArgTexts, paramDefaults);
|
|
573
|
+
const dns = dropUndefined(resolveSemanticArg(args, 3, instance, paramNames, callArgTexts, paramDefaults));
|
|
574
|
+
if (ip === null || gateway === null || subnet === null)
|
|
575
|
+
return null;
|
|
576
|
+
return { operation: "wifi.set_static_ip", ip, gateway, subnet, ...(dns !== null ? { dns } : {}) };
|
|
577
|
+
}
|
|
578
|
+
case "wifiSetAutoReconnect": {
|
|
579
|
+
const enabled = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
580
|
+
if (enabled === null)
|
|
581
|
+
return null;
|
|
582
|
+
return { operation: "wifi.set_auto_reconnect", enabled: enabled === "true" };
|
|
583
|
+
}
|
|
584
|
+
case "wifiSetPowerSave": {
|
|
585
|
+
const mode = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
586
|
+
if (mode === null)
|
|
587
|
+
return null;
|
|
588
|
+
return { operation: "wifi.set_power_save", mode };
|
|
589
|
+
}
|
|
590
|
+
case "wifiSetTxPower": {
|
|
591
|
+
const dbm = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
592
|
+
if (dbm === null)
|
|
593
|
+
return null;
|
|
594
|
+
return { operation: "wifi.set_tx_power", dbm };
|
|
595
|
+
}
|
|
596
|
+
case "wifiOnEvent": {
|
|
597
|
+
const event = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
598
|
+
const handler = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
599
|
+
if (event === null || handler === null)
|
|
600
|
+
return null;
|
|
601
|
+
return { operation: "wifi.on_event", event: String(event).replace(/^["']|["']$/g, ""), handler };
|
|
602
|
+
}
|
|
603
|
+
case "wifiApStart": {
|
|
604
|
+
const ssid = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
605
|
+
const password = dropUndefined(resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults));
|
|
606
|
+
const channel = dropUndefined(resolveSemanticArg(args, 2, instance, paramNames, callArgTexts, paramDefaults));
|
|
607
|
+
const hidden = dropUndefined(resolveSemanticArg(args, 3, instance, paramNames, callArgTexts, paramDefaults));
|
|
608
|
+
const maxClients = dropUndefined(resolveSemanticArg(args, 4, instance, paramNames, callArgTexts, paramDefaults));
|
|
609
|
+
if (ssid === null)
|
|
610
|
+
return null;
|
|
611
|
+
return {
|
|
612
|
+
operation: "wifi.ap_start",
|
|
613
|
+
ssid,
|
|
614
|
+
...(password !== null ? { password } : {}),
|
|
615
|
+
...(channel !== null ? { channel } : {}),
|
|
616
|
+
...(hidden !== null ? { hidden } : {}),
|
|
617
|
+
...(maxClients !== null ? { maxClients } : {}),
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
case "wifiApStop":
|
|
621
|
+
return { operation: "wifi.ap_stop" };
|
|
622
|
+
case "wifiApClientCount":
|
|
623
|
+
return { operation: "wifi.ap_client_count" };
|
|
624
|
+
case "wifiApIp":
|
|
625
|
+
return { operation: "wifi.ap_ip" };
|
|
626
|
+
case "wifiApSetChannel": {
|
|
627
|
+
const channel = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
628
|
+
if (channel === null)
|
|
629
|
+
return null;
|
|
630
|
+
return { operation: "wifi.ap_set_channel", channel };
|
|
631
|
+
}
|
|
632
|
+
case "wifiApSetHidden": {
|
|
633
|
+
const hidden = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
634
|
+
if (hidden === null)
|
|
635
|
+
return null;
|
|
636
|
+
return { operation: "wifi.ap_set_hidden", hidden };
|
|
637
|
+
}
|
|
638
|
+
case "wifiApSetMaxClients": {
|
|
639
|
+
const maxClients = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
640
|
+
if (maxClients === null)
|
|
641
|
+
return null;
|
|
642
|
+
return { operation: "wifi.ap_set_max_clients", maxClients };
|
|
643
|
+
}
|
|
644
|
+
case "wifiScan":
|
|
645
|
+
return { operation: "wifi.scan" };
|
|
646
|
+
case "wifiScanStart":
|
|
647
|
+
return { operation: "wifi.scan_start" };
|
|
648
|
+
case "wifiScanCount":
|
|
649
|
+
return { operation: "wifi.scan_count" };
|
|
650
|
+
case "wifiScanSsid": {
|
|
651
|
+
const index = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
652
|
+
if (index === null)
|
|
653
|
+
return null;
|
|
654
|
+
return { operation: "wifi.scan_ssid", index };
|
|
655
|
+
}
|
|
656
|
+
case "wifiScanRssi": {
|
|
657
|
+
const index = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
658
|
+
if (index === null)
|
|
659
|
+
return null;
|
|
660
|
+
return { operation: "wifi.scan_rssi", index };
|
|
661
|
+
}
|
|
662
|
+
case "wifiScanEncryption": {
|
|
663
|
+
const index = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
664
|
+
if (index === null)
|
|
665
|
+
return null;
|
|
666
|
+
return { operation: "wifi.scan_encryption", index };
|
|
667
|
+
}
|
|
668
|
+
case "wifiScanChannel": {
|
|
669
|
+
const index = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
670
|
+
if (index === null)
|
|
671
|
+
return null;
|
|
672
|
+
return { operation: "wifi.scan_channel", index };
|
|
673
|
+
}
|
|
674
|
+
case "wifiSaveCredentials": {
|
|
675
|
+
const ssid = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
676
|
+
const password = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
677
|
+
if (ssid === null || password === null)
|
|
678
|
+
return null;
|
|
679
|
+
return { operation: "wifi.save_credentials", ssid, password };
|
|
680
|
+
}
|
|
681
|
+
case "wifiConnectSaved": {
|
|
682
|
+
const timeoutMs = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults) ?? 15000;
|
|
683
|
+
return { operation: "wifi.connect_saved", timeoutMs };
|
|
684
|
+
}
|
|
685
|
+
case "wifiClearCredentials":
|
|
686
|
+
return { operation: "wifi.clear_credentials" };
|
|
687
|
+
case "wifiWaitConnected": {
|
|
688
|
+
const timeoutMs = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults) ?? 15000;
|
|
689
|
+
return { operation: "wifi.wait_connected", timeoutMs };
|
|
690
|
+
}
|
|
691
|
+
case "wifiWaitDisconnected":
|
|
692
|
+
return { operation: "wifi.wait_disconnected" };
|
|
693
|
+
// ── HTTP ──
|
|
694
|
+
case "httpBegin": {
|
|
695
|
+
const method = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
696
|
+
const url = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
697
|
+
if (method === null || url === null)
|
|
698
|
+
return null;
|
|
699
|
+
// this._url resolved through `new HttpRequest(...)` ctor fields stores
|
|
700
|
+
// string literals without quotes; re-quote anything that isn't already
|
|
701
|
+
// a quoted literal or a plain identifier/member expression so the
|
|
702
|
+
// lowering emits valid C++.
|
|
703
|
+
return { operation: "http.begin", method, url: quoteNonIdentifier(url) };
|
|
704
|
+
}
|
|
705
|
+
case "httpReset":
|
|
706
|
+
return { operation: "http.reset" };
|
|
707
|
+
case "httpSetHeader": {
|
|
708
|
+
const name = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
709
|
+
const value = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
710
|
+
if (name === null || value === null)
|
|
711
|
+
return null;
|
|
712
|
+
return { operation: "http.set_header", name, value };
|
|
713
|
+
}
|
|
714
|
+
case "httpSetTimeout": {
|
|
715
|
+
const ms = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
716
|
+
if (ms === null)
|
|
717
|
+
return null;
|
|
718
|
+
return { operation: "http.set_timeout", ms };
|
|
719
|
+
}
|
|
720
|
+
case "httpSetMaxBody": {
|
|
721
|
+
const bytes = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
722
|
+
if (bytes === null)
|
|
723
|
+
return null;
|
|
724
|
+
return { operation: "http.set_max_body", bytes };
|
|
725
|
+
}
|
|
726
|
+
case "httpSetBody": {
|
|
727
|
+
const data = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
728
|
+
const json = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
729
|
+
if (data === null)
|
|
730
|
+
return null;
|
|
731
|
+
return { operation: "http.set_body", data, json: json === "true" };
|
|
732
|
+
}
|
|
733
|
+
case "httpSetInsecure":
|
|
734
|
+
return { operation: "http.set_insecure" };
|
|
735
|
+
case "httpSetCaCert": {
|
|
736
|
+
const pem = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
737
|
+
if (pem === null)
|
|
738
|
+
return null;
|
|
739
|
+
return { operation: "http.set_ca_cert", pem };
|
|
740
|
+
}
|
|
741
|
+
case "httpSend":
|
|
742
|
+
return { operation: "http.send", blocking: true };
|
|
743
|
+
case "httpSendStart":
|
|
744
|
+
return { operation: "http.send_start" };
|
|
745
|
+
case "httpStatus":
|
|
746
|
+
return { operation: "http.status" };
|
|
747
|
+
case "httpOk":
|
|
748
|
+
return { operation: "http.ok" };
|
|
749
|
+
case "httpBody":
|
|
750
|
+
return { operation: "http.body" };
|
|
751
|
+
case "httpContentLength":
|
|
752
|
+
return { operation: "http.content_length" };
|
|
753
|
+
case "httpResponseHeader": {
|
|
754
|
+
const name = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
755
|
+
if (name === null)
|
|
756
|
+
return null;
|
|
757
|
+
return { operation: "http.response_header", name };
|
|
758
|
+
}
|
|
759
|
+
// ── BLE (NimBLE GATT peripheral) ──
|
|
760
|
+
case "bleServerBegin": {
|
|
761
|
+
const name = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
762
|
+
if (name === null)
|
|
763
|
+
return null;
|
|
764
|
+
return { operation: "ble.server_begin", name: quoteNonIdentifier(name) };
|
|
765
|
+
}
|
|
766
|
+
case "bleAdvertiseStart":
|
|
767
|
+
return { operation: "ble.advertise_start" };
|
|
768
|
+
case "bleAdvertiseStop":
|
|
769
|
+
return { operation: "ble.advertise_stop" };
|
|
770
|
+
case "bleAddService": {
|
|
771
|
+
const uuid = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
772
|
+
if (uuid === null)
|
|
773
|
+
return null;
|
|
774
|
+
return { operation: "ble.add_service", uuid: quoteNonIdentifier(uuid) };
|
|
775
|
+
}
|
|
776
|
+
case "bleAddChar": {
|
|
777
|
+
const index = resolveNumericOrExpression(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
778
|
+
const uuid = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
779
|
+
const type = resolveSemanticArg(args, 2, instance, paramNames, callArgTexts, paramDefaults);
|
|
780
|
+
const perms = resolveNumericOrExpression(args, 3, instance, paramNames, callArgTexts, paramDefaults);
|
|
781
|
+
const svcIndex = resolveNumericOrExpression(args, 4, instance, paramNames, callArgTexts, paramDefaults);
|
|
782
|
+
if (uuid === null || type === null)
|
|
783
|
+
return null;
|
|
784
|
+
// Resolve BleValueType.X → the enum's string value (e.g. Int16 → 'int16').
|
|
785
|
+
const resolvedType = type.startsWith("BleValueType.")
|
|
786
|
+
? JSON.stringify(type.replace(/^BleValueType\./, "").toLowerCase())
|
|
787
|
+
: quoteNonIdentifier(type);
|
|
788
|
+
// Resolve BlePerm.X | BlePerm.Y → numeric bitmask.
|
|
789
|
+
// The | expression renders as "BlePerm.Read | BlePerm.Notify" via the
|
|
790
|
+
// binary-expression handler in resolveExpressionText, which keeps the
|
|
791
|
+
// raw text. Evaluate it by extracting member names and mapping to values.
|
|
792
|
+
const resolvedPerms = resolveBlePermExpr(perms);
|
|
793
|
+
return {
|
|
794
|
+
operation: "ble.add_char",
|
|
795
|
+
index: index ?? 0,
|
|
796
|
+
uuid: quoteNonIdentifier(uuid),
|
|
797
|
+
type: resolvedType,
|
|
798
|
+
perms: resolvedPerms,
|
|
799
|
+
svcIndex: svcIndex ?? 0,
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
case "bleOnRead": {
|
|
803
|
+
const index = resolveNumericOrExpression(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
804
|
+
const handler = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
805
|
+
if (handler === null)
|
|
806
|
+
return null;
|
|
807
|
+
return { operation: "ble.on_read", index: index ?? 0, handler };
|
|
808
|
+
}
|
|
809
|
+
case "bleOnWrite": {
|
|
810
|
+
const index = resolveNumericOrExpression(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
811
|
+
const handler = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
812
|
+
if (handler === null)
|
|
813
|
+
return null;
|
|
814
|
+
return { operation: "ble.on_write", index: index ?? 0, handler };
|
|
815
|
+
}
|
|
816
|
+
case "bleOnConnect": {
|
|
817
|
+
const handler = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
818
|
+
if (handler === null)
|
|
819
|
+
return null;
|
|
820
|
+
return { operation: "ble.on_connect", handler };
|
|
821
|
+
}
|
|
822
|
+
case "bleOnDisconnect": {
|
|
823
|
+
const handler = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
824
|
+
if (handler === null)
|
|
825
|
+
return null;
|
|
826
|
+
return { operation: "ble.on_disconnect", handler };
|
|
827
|
+
}
|
|
828
|
+
case "bleNotify": {
|
|
829
|
+
const index = resolveNumericOrExpression(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
830
|
+
const value = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
831
|
+
if (value === null)
|
|
832
|
+
return null;
|
|
833
|
+
return { operation: "ble.notify", index: index ?? 0, value };
|
|
834
|
+
}
|
|
835
|
+
case "bleIsConnected":
|
|
836
|
+
return { operation: "ble.is_connected" };
|
|
837
|
+
case "bleClientCount":
|
|
838
|
+
return { operation: "ble.client_count" };
|
|
839
|
+
case "bleStatus":
|
|
840
|
+
return { operation: "ble.status" };
|
|
841
|
+
case "bleSetName": {
|
|
842
|
+
const name = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
843
|
+
if (name === null)
|
|
844
|
+
return null;
|
|
845
|
+
return { operation: "ble.set_name", name: quoteNonIdentifier(name) };
|
|
846
|
+
}
|
|
847
|
+
case "bleUntilConnected": {
|
|
848
|
+
const timeoutMs = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults) ?? 0;
|
|
849
|
+
return { operation: "ble.until_connected", timeoutMs, blocking: true };
|
|
850
|
+
}
|
|
851
|
+
case "bleUntilConnectedStart":
|
|
852
|
+
return { operation: "ble.until_connected_start" };
|
|
853
|
+
case "bleSetTxPower": {
|
|
854
|
+
const dbm = resolveNumericOrExpression(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
855
|
+
if (dbm === null)
|
|
856
|
+
return null;
|
|
857
|
+
return { operation: "ble.set_tx_power", dbm };
|
|
858
|
+
}
|
|
859
|
+
// ── Preferences (NVS key/value store) ──
|
|
860
|
+
case "preferencesBegin": {
|
|
861
|
+
const ns = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
862
|
+
const ro = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
863
|
+
if (ns === null)
|
|
864
|
+
return null;
|
|
865
|
+
return { operation: "preferences.begin", namespace: quoteNonIdentifier(ns), readOnly: ro === "true" };
|
|
866
|
+
}
|
|
867
|
+
case "preferencesEnd":
|
|
868
|
+
return { operation: "preferences.end" };
|
|
869
|
+
case "preferencesClear":
|
|
870
|
+
return { operation: "preferences.clear" };
|
|
871
|
+
case "preferencesRemove": {
|
|
872
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
873
|
+
if (key === null)
|
|
874
|
+
return null;
|
|
875
|
+
return { operation: "preferences.remove", key: quoteNonIdentifier(key) };
|
|
876
|
+
}
|
|
877
|
+
case "preferencesPutInt": {
|
|
878
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
879
|
+
const value = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
880
|
+
if (key === null || value === null)
|
|
881
|
+
return null;
|
|
882
|
+
return { operation: "preferences.put_int", key: quoteNonIdentifier(key), value };
|
|
883
|
+
}
|
|
884
|
+
case "preferencesGetInt": {
|
|
885
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
886
|
+
const def = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults) ?? 0;
|
|
887
|
+
if (key === null)
|
|
888
|
+
return null;
|
|
889
|
+
return { operation: "preferences.get_int", key: quoteNonIdentifier(key), defaultValue: def };
|
|
890
|
+
}
|
|
891
|
+
case "preferencesPutUInt": {
|
|
892
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
893
|
+
const value = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
894
|
+
if (key === null || value === null)
|
|
895
|
+
return null;
|
|
896
|
+
return { operation: "preferences.put_uint", key: quoteNonIdentifier(key), value };
|
|
897
|
+
}
|
|
898
|
+
case "preferencesGetUInt": {
|
|
899
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
900
|
+
const def = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults) ?? 0;
|
|
901
|
+
if (key === null)
|
|
902
|
+
return null;
|
|
903
|
+
return { operation: "preferences.get_uint", key: quoteNonIdentifier(key), defaultValue: def };
|
|
904
|
+
}
|
|
905
|
+
case "preferencesPutBool": {
|
|
906
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
907
|
+
const value = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
908
|
+
if (key === null || value === null)
|
|
909
|
+
return null;
|
|
910
|
+
return { operation: "preferences.put_bool", key: quoteNonIdentifier(key), value: value === "true" };
|
|
911
|
+
}
|
|
912
|
+
case "preferencesGetBool": {
|
|
913
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
914
|
+
const def = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
915
|
+
if (key === null)
|
|
916
|
+
return null;
|
|
917
|
+
return { operation: "preferences.get_bool", key: quoteNonIdentifier(key), defaultValue: def === "true" };
|
|
918
|
+
}
|
|
919
|
+
case "preferencesPutFloat": {
|
|
920
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
921
|
+
const value = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
922
|
+
if (key === null || value === null)
|
|
923
|
+
return null;
|
|
924
|
+
return { operation: "preferences.put_float", key: quoteNonIdentifier(key), value };
|
|
925
|
+
}
|
|
926
|
+
case "preferencesGetFloat": {
|
|
927
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
928
|
+
const def = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults) ?? 0;
|
|
929
|
+
if (key === null)
|
|
930
|
+
return null;
|
|
931
|
+
return { operation: "preferences.get_float", key: quoteNonIdentifier(key), defaultValue: def };
|
|
932
|
+
}
|
|
933
|
+
case "preferencesPutString": {
|
|
934
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
935
|
+
const value = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
936
|
+
if (key === null || value === null)
|
|
937
|
+
return null;
|
|
938
|
+
return { operation: "preferences.put_string", key: quoteNonIdentifier(key), value: quoteNonIdentifier(value) };
|
|
939
|
+
}
|
|
940
|
+
case "preferencesGetString": {
|
|
941
|
+
const key = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
942
|
+
const def = resolveSemanticArg(args, 1, instance, paramNames, callArgTexts, paramDefaults) ?? '""';
|
|
943
|
+
if (key === null)
|
|
944
|
+
return null;
|
|
945
|
+
return { operation: "preferences.get_string", key: quoteNonIdentifier(key), defaultValue: quoteNonIdentifier(def) };
|
|
946
|
+
}
|
|
386
947
|
// ── Interrupts ──
|
|
387
948
|
case "interruptAttach": {
|
|
388
949
|
const pin = resolveNumericArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
@@ -580,6 +1141,16 @@ export function tryResolveSemanticCall(fnName, args, instance, paramNames, callA
|
|
|
580
1141
|
return null;
|
|
581
1142
|
return { operation: "spi.set_bit_order", bus, order };
|
|
582
1143
|
}
|
|
1144
|
+
case "spiReadBuffer": {
|
|
1145
|
+
const bus = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
1146
|
+
const count = resolveNumericOrExpression(args, 1, instance, paramNames, callArgTexts, paramDefaults);
|
|
1147
|
+
if (bus === null || count === null)
|
|
1148
|
+
return null;
|
|
1149
|
+
// The buffer arg (args[2]) is only a placeholder for type resolution;
|
|
1150
|
+
// the real target is the caller's variable, rewritten from
|
|
1151
|
+
// __HAL_READ_BUF__ by replaceHalReadBufferPlaceholder.
|
|
1152
|
+
return { operation: "spi.read_buffer", bus, count, buffer: "__HAL_READ_BUF__" };
|
|
1153
|
+
}
|
|
583
1154
|
// ── UART ──
|
|
584
1155
|
case "uartBegin": {
|
|
585
1156
|
const port = resolveSemanticArg(args, 0, instance, paramNames, callArgTexts, paramDefaults);
|
|
@@ -435,5 +435,23 @@ function collectHALOpIdentifiers(op) {
|
|
|
435
435
|
}
|
|
436
436
|
// Other HAL ops have only numeric/literal fields — no identifier references
|
|
437
437
|
}
|
|
438
|
+
// wifi.* / http.* ops carry resolved C++ expression texts in their string
|
|
439
|
+
// fields (e.g. wifi.connect ssid: `WIFI_SSID` — a top-level const, or a
|
|
440
|
+
// quoted literal). Scan every string field for identifiers so referenced
|
|
441
|
+
// globals survive tree-shaking; quoted literals are skipped.
|
|
442
|
+
if (op.operation.startsWith("wifi.") || op.operation.startsWith("http.")) {
|
|
443
|
+
for (const value of Object.values(op)) {
|
|
444
|
+
if (typeof value !== "string" || value === op.operation)
|
|
445
|
+
continue;
|
|
446
|
+
if (/^".*"$/.test(value.trim()))
|
|
447
|
+
continue;
|
|
448
|
+
const matches = value.match(/[A-Za-z_][A-Za-z0-9_]*/g);
|
|
449
|
+
if (matches) {
|
|
450
|
+
for (const match of matches) {
|
|
451
|
+
identifiers.add(match);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
438
456
|
return identifiers;
|
|
439
457
|
}
|