@markw65/monkeyc-optimizer 1.0.6 → 1.0.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/build/api.cjs CHANGED
@@ -40,12 +40,12 @@ __webpack_require__.r(__webpack_exports__);
40
40
 
41
41
  // EXPORTS
42
42
  __webpack_require__.d(__webpack_exports__, {
43
- "LiteralIntegerRe": () => (/* binding */ LiteralIntegerRe),
44
- "collectNamespaces": () => (/* binding */ collectNamespaces),
43
+ "LiteralIntegerRe": () => (/* binding */ api_LiteralIntegerRe),
44
+ "collectNamespaces": () => (/* binding */ api_collectNamespaces),
45
45
  "formatAst": () => (/* binding */ formatAst),
46
- "getApiMapping": () => (/* binding */ getApiMapping),
47
- "hasProperty": () => (/* binding */ hasProperty),
48
- "traverseAst": () => (/* binding */ traverseAst)
46
+ "getApiMapping": () => (/* binding */ api_getApiMapping),
47
+ "hasProperty": () => (/* binding */ api_hasProperty),
48
+ "traverseAst": () => (/* binding */ api_traverseAst)
49
49
  });
50
50
 
51
51
  ;// CONCATENATED MODULE: external "@markw65/prettier-plugin-monkeyc"
@@ -112,6 +112,663 @@ const negativeFixups = [
112
112
  "Toybox.WatchUi.LAYOUT_HALIGN_LEFT",
113
113
  ];
114
114
 
115
+ ;// CONCATENATED MODULE: external "./api.cjs"
116
+ const external_api_cjs_namespaceObject = require("./api.cjs");
117
+ ;// CONCATENATED MODULE: ./src/mc-rewrite.js
118
+
119
+
120
+
121
+
122
+
123
+ function processImports(allImports, lookup) {
124
+ allImports.forEach(({ node, stack }) => {
125
+ const [name, module] = lookup(node.id, node.as && node.as.name, stack);
126
+ if (name && module) {
127
+ const [parent] = stack.slice(-1);
128
+ if (!parent.decls) parent.decls = {};
129
+ if (!hasProperty(parent.decls, name)) parent.decls[name] = [];
130
+ module.forEach((m) => {
131
+ if (m.type == "ModuleDeclaration") {
132
+ pushUnique(parent.decls[name], m);
133
+ }
134
+ });
135
+ }
136
+ });
137
+ }
138
+
139
+ function collectClassInfo(state) {
140
+ state.allClasses.forEach((elm) => {
141
+ if (elm.node.superClass) {
142
+ const [, classes] = state.lookup(elm.node.superClass, null, elm.stack);
143
+ if (classes) {
144
+ elm.superClass = classes.filter((c) => c.type == "ClassDeclaration");
145
+ }
146
+ // set it "true" if there is a superClass, but we can't find it.
147
+ if (!elm.superClass || !elm.superClass.length) elm.superClass = true;
148
+ }
149
+ });
150
+
151
+ const markOverrides = (cls, scls) => {
152
+ if (scls === true) return;
153
+ scls.forEach((c) => {
154
+ c.decls &&
155
+ Object.values(c.decls).forEach((f) => {
156
+ if (f.type == "FunctionDeclaration") {
157
+ if (hasProperty(cls.decls, f.name)) {
158
+ f.hasOverride = true;
159
+ }
160
+ }
161
+ });
162
+ if (c.superClass) markOverrides(cls, c.superClass);
163
+ });
164
+ };
165
+
166
+ state.allClasses.forEach((elm) => {
167
+ if (elm.superClass) markOverrides(elm, elm.superClass);
168
+ });
169
+ }
170
+
171
+ async function analyze(fileNames, buildConfig) {
172
+ const excludeAnnotations =
173
+ buildConfig && buildConfig.excludeAnnotations
174
+ ? Object.fromEntries(buildConfig.excludeAnnotations.map((a) => [a, true]))
175
+ : {};
176
+
177
+ const allImports = [];
178
+ const state = {
179
+ allFunctions: [],
180
+ allClasses: [],
181
+ shouldExclude(node) {
182
+ if (node.attrs && node.attrs.attrs) {
183
+ if (
184
+ node.attrs.attrs.filter((attr) => {
185
+ if (attr.type != "UnaryExpression") return false;
186
+ if (attr.argument.type != "Identifier") return false;
187
+ return hasProperty(excludeAnnotations, attr.argument.name);
188
+ }).length
189
+ ) {
190
+ return true;
191
+ }
192
+ }
193
+ },
194
+ post(node) {
195
+ switch (node.type) {
196
+ case "FunctionDeclaration":
197
+ case "ClassDeclaration": {
198
+ const [scope] = state.stack.slice(-1);
199
+ const stack = state.stack.slice(0, -1);
200
+ scope.stack = stack;
201
+ (node.type == "FunctionDeclaration"
202
+ ? state.allFunctions
203
+ : state.allClasses
204
+ ).push(scope);
205
+ return;
206
+ }
207
+ case "Using":
208
+ case "ImportModule":
209
+ allImports.push({ node, stack: state.stack.slice() });
210
+ return;
211
+ }
212
+ },
213
+ };
214
+
215
+ await getApiMapping(state);
216
+
217
+ // Mark all functions from api.mir as "special" by
218
+ // setting their bodies to null. In api.mir, they're
219
+ // all empty, which makes it look like they're
220
+ // do-nothing functions.
221
+ const markApi = (node) => {
222
+ if (node.type == "FunctionDeclaration") {
223
+ node.node.body = null;
224
+ }
225
+ if (node.decls) {
226
+ Object.values(node.decls).forEach(markApi);
227
+ }
228
+ };
229
+ markApi(state.stack[0]);
230
+
231
+ const files = await Promise.all(
232
+ fileNames.map(async (name) => ({
233
+ name,
234
+ monkeyCSource: (await fs.readFile(name))
235
+ .toString()
236
+ .replace(/\r\n/g, "\n"),
237
+ }))
238
+ );
239
+
240
+ files.forEach((f) => {
241
+ f.ast = MonkeyC.parsers.monkeyc.parse(f.monkeyCSource, {
242
+ grammarSource: f.name,
243
+ });
244
+ f.ast.source = f.name;
245
+ f.ast.monkeyCSource = f.monkeyCSource;
246
+ delete f.monkeyCSource;
247
+ collectNamespaces(f.ast, state);
248
+ });
249
+
250
+ delete state.shouldExclude;
251
+ delete state.post;
252
+
253
+ processImports(allImports, state.lookup);
254
+ collectClassInfo(state);
255
+
256
+ return { files, state };
257
+ }
258
+
259
+ function getLiteralNode(node) {
260
+ if (Array.isArray(node)) {
261
+ if (!node.length) return null;
262
+ if (node.length === 1) return getLiteralNode(node[0]);
263
+ let result;
264
+ if (
265
+ node.every((n) => {
266
+ const lit = getLiteralNode(n);
267
+ if (!lit) return false;
268
+ if (!result) {
269
+ result = lit;
270
+ } else {
271
+ if (lit.value !== result.value) return false;
272
+ }
273
+ return true;
274
+ })
275
+ ) {
276
+ return result;
277
+ }
278
+ return null;
279
+ }
280
+ if (node.type == "Literal") return node;
281
+ if (node.type == "BinaryExpression" && node.operator == "as") {
282
+ return getLiteralNode(node.left) && node;
283
+ }
284
+ if (node.type == "UnaryExpression") {
285
+ if (node.argument.type != "Literal") return null;
286
+ switch (node.operator) {
287
+ case "-":
288
+ if (typeof node.argument.value == "number") {
289
+ return {
290
+ ...node.argument,
291
+ value: -node.argument.value,
292
+ raw: "-" + node.argument.value,
293
+ enumType: node.enumType,
294
+ };
295
+ }
296
+ }
297
+ }
298
+ }
299
+
300
+ function getNodeValue(node) {
301
+ if (
302
+ node.type == "BinaryExpression" &&
303
+ node.operator == "as" &&
304
+ node.right.type == "TypeSpecList" &&
305
+ node.right.ts.length == 1 &&
306
+ typeof node.right.ts[0] == "string"
307
+ ) {
308
+ // this is a cast we inserted to retain the type of an enum
309
+ // any arithmetic on it will revert to "Number", or "Long",
310
+ // so just ignore it.
311
+ return getNodeValue(node.left);
312
+ }
313
+ if (node.type != "Literal") {
314
+ return [null, null];
315
+ }
316
+ let type = node.value === null ? "Null" : typeof node.value;
317
+ if (type === "number") {
318
+ const match = LiteralIntegerRe.exec(node.raw);
319
+ if (match) {
320
+ type = match[2] == "l" ? "Long" : "Number";
321
+ } else if (node.raw.endsWith("d")) {
322
+ type = "Double";
323
+ } else {
324
+ type = "Float";
325
+ }
326
+ } else if (type === "string") {
327
+ type = "String";
328
+ } else if (type === "boolean") {
329
+ type = "Boolean";
330
+ } else {
331
+ type = "Unknown";
332
+ }
333
+ return [node, type];
334
+ }
335
+
336
+ function optimizeNode(node) {
337
+ switch (node.type) {
338
+ case "UnaryExpression": {
339
+ const [arg, type] = getNodeValue(node.argument);
340
+ if (arg === null) break;
341
+ switch (node.operator) {
342
+ case "+":
343
+ if (type === "Number" || type === "Long") {
344
+ return arg;
345
+ }
346
+ break;
347
+ case "-":
348
+ if (type === "Number" || type === "Long") {
349
+ return {
350
+ ...arg,
351
+ value: -arg.value,
352
+ raw: (-arg.value).toString() + (type === "Long" ? "l" : ""),
353
+ };
354
+ }
355
+ break;
356
+ case "!":
357
+ case "~":
358
+ {
359
+ let value;
360
+ if (type === "Number" || type === "Long") {
361
+ value = -arg.value - 1;
362
+ } else if (type === "Boolean" && node.operator == "!") {
363
+ value = !arg.value;
364
+ }
365
+ if (value !== undefined) {
366
+ return {
367
+ ...arg,
368
+ value,
369
+ raw: value.toString() + (type === "Long" ? "l" : ""),
370
+ };
371
+ }
372
+ }
373
+ break;
374
+ }
375
+ break;
376
+ }
377
+ case "BinaryExpression": {
378
+ const operators = {
379
+ "+": (left, right) => left + right,
380
+ "-": (left, right) => left - right,
381
+ "*": (left, right) => left * right,
382
+ "/": (left, right) => Math.trunc(left / right),
383
+ "%": (left, right) => left % right,
384
+ "&": (left, right, type) => (type === "Number" ? left & right : null),
385
+ "|": (left, right, type) => (type === "Number" ? left | right : null),
386
+ "<<": (left, right, type) => (type === "Number" ? left << right : null),
387
+ ">>": (left, right, type) => (type === "Number" ? left >> right : null),
388
+ };
389
+ const op = operators[node.operator];
390
+ if (op) {
391
+ const [left, left_type] = getNodeValue(node.left);
392
+ const [right, right_type] = getNodeValue(node.right);
393
+ if (!left || !right) break;
394
+ if (
395
+ left_type != right_type ||
396
+ (left_type != "Number" && left_type != "Long")
397
+ ) {
398
+ break;
399
+ }
400
+ const value = op(left.value, right.value, left_type);
401
+ if (value === null) break;
402
+ return {
403
+ ...left,
404
+ value,
405
+ raw: value.toString() + (left_type === "Long" ? "l" : ""),
406
+ };
407
+ }
408
+ break;
409
+ }
410
+ case "FunctionDeclaration":
411
+ if (node.body && evaluateFunction(node, null) !== false) {
412
+ node.optimizable = true;
413
+ }
414
+ break;
415
+ }
416
+ }
417
+
418
+ function evaluateFunction(func, args) {
419
+ if (args && args.length != func.params.length) {
420
+ return false;
421
+ }
422
+ const paramValues =
423
+ args && Object.fromEntries(func.params.map((p, i) => [p.name, args[i]]));
424
+ let ret = null;
425
+ const body = args ? JSON.parse(JSON.stringify(func.body)) : func.body;
426
+ try {
427
+ traverseAst(
428
+ body,
429
+ (node) => {
430
+ switch (node.type) {
431
+ case "BlockStatement":
432
+ case "ReturnStatement":
433
+ case "UnaryExpression":
434
+ case "BinaryExpression":
435
+ case "Literal":
436
+ case "Identifier":
437
+ return;
438
+ default:
439
+ throw new Error("Bad node type");
440
+ }
441
+ },
442
+ args &&
443
+ ((node) => {
444
+ switch (node.type) {
445
+ case "ReturnStatement":
446
+ ret = node.argument;
447
+ return;
448
+ case "BlockStatement":
449
+ case "Literal":
450
+ return;
451
+ case "Identifier":
452
+ if (hasProperty(paramValues, node.name)) {
453
+ return paramValues[node.name];
454
+ }
455
+ // fall through;
456
+ default: {
457
+ const repl = optimizeNode(node);
458
+ if (repl && repl.type === "Literal") return repl;
459
+ throw new Error("Didn't optimize");
460
+ }
461
+ }
462
+ })
463
+ );
464
+ return ret;
465
+ } catch (e) {
466
+ return false;
467
+ }
468
+ }
469
+
470
+ async function optimizeMonkeyC(fileNames, buildConfig) {
471
+ const { files, state } = await analyze(fileNames, buildConfig);
472
+ const replace = (node, obj) => {
473
+ for (const k of Object.keys(node)) {
474
+ delete node[k];
475
+ }
476
+ if (obj.enumType) {
477
+ obj = {
478
+ type: "BinaryExpression",
479
+ operator: "as",
480
+ left: obj,
481
+ right: { type: "TypeSpecList", ts: [obj.enumType] },
482
+ };
483
+ }
484
+ for (const [k, v] of Object.entries(obj)) {
485
+ node[k] = v;
486
+ }
487
+ };
488
+ const lookupAndReplace = (node) => {
489
+ const [, objects] = state.lookup(node);
490
+ if (!objects) {
491
+ return false;
492
+ }
493
+ const obj = getLiteralNode(objects);
494
+ if (!obj) {
495
+ return false;
496
+ }
497
+ replace(node, obj);
498
+ return true;
499
+ };
500
+
501
+ /*
502
+ * Might this function be called from somewhere, including
503
+ * callbacks from the api (eg getSettingsView, etc).
504
+ */
505
+ const maybeCalled = (func) => {
506
+ if (!func.body) {
507
+ // this is an api.mir function. It can be called
508
+ return true;
509
+ }
510
+ if (hasProperty(state.exposed, func.id.name)) return true;
511
+ if (hasProperty(state.calledFunctions, func.id.name)) {
512
+ return (
513
+ state.calledFunctions[func.id.name].find((f) => f === func) !== null
514
+ );
515
+ }
516
+ };
517
+ /*
518
+ * Does elm (a class) have a maybeCalled function called name,
519
+ * anywhere in its superClass chain.
520
+ */
521
+ const checkInherited = (elm, name) =>
522
+ elm.superClass === true ||
523
+ elm.superClass.some(
524
+ (sc) =>
525
+ (hasProperty(sc.decls, name) &&
526
+ sc.decls[name].some(
527
+ (f) => f.type == "FunctionDeclaration" && maybeCalled(f)
528
+ )) ||
529
+ (sc.superClass && checkInherited(sc, name))
530
+ );
531
+
532
+ state.exposed = {};
533
+ state.calledFunctions = {};
534
+ state.pre = (node) => {
535
+ switch (node.type) {
536
+ case "ConditionalExpression":
537
+ case "IfStatement":
538
+ case "DoWhileStatement":
539
+ case "WhileStatement":
540
+ state.traverse(node.test);
541
+ const [value, type] = getNodeValue(node.test);
542
+ if (value) {
543
+ let result = null;
544
+ if (type === "Null") {
545
+ result = false;
546
+ } else if (
547
+ type === "Boolean" ||
548
+ type === "Number" ||
549
+ type === "Long"
550
+ ) {
551
+ result = !!value.value;
552
+ }
553
+ if (result !== null) {
554
+ if (
555
+ node.type === "IfStatement" ||
556
+ node.type === "ConditionalExpression"
557
+ ) {
558
+ if (result === false) {
559
+ node.consequent = null;
560
+ } else {
561
+ node.alternate = null;
562
+ }
563
+ node.test = result;
564
+ } else if (node.type === "WhileStatement") {
565
+ if (result === false) {
566
+ node.body = null;
567
+ }
568
+ } else if (node.type === "DoWhileStatement") {
569
+ if (result === false) {
570
+ node.test = null;
571
+ }
572
+ } else {
573
+ throw new Error("Unexpected Node type");
574
+ }
575
+ }
576
+ }
577
+ return;
578
+
579
+ case "EnumDeclaration":
580
+ return false;
581
+ case "VariableDeclarator":
582
+ return ["init"];
583
+ case "UnaryExpression":
584
+ if (node.operator == ":") {
585
+ // If we produce a Symbol, for a given name,
586
+ // its possible that someone uses that symbol
587
+ // indirectly, so we can't remove any enums or
588
+ // constants with that name (we can still replace
589
+ // uses of those constants though).
590
+ state.exposed[node.argument.name] = true;
591
+ // In any case, we can't replace *this* use of the
592
+ // symbol with its value...
593
+ return false;
594
+ }
595
+ break;
596
+ case "Identifier": {
597
+ if (hasProperty(state.index, node.name)) {
598
+ if (!lookupAndReplace(node)) {
599
+ state.exposed[node.name] = true;
600
+ }
601
+ }
602
+ return false;
603
+ }
604
+ case "MemberExpression":
605
+ if (node.property.type === "Identifier" && !node.computed) {
606
+ if (hasProperty(state.index, node.property.name)) {
607
+ if (lookupAndReplace(node)) {
608
+ return false;
609
+ } else {
610
+ state.exposed[node.property.name] = true;
611
+ }
612
+ }
613
+ // Don't optimize the property.
614
+ return ["object"];
615
+ }
616
+ break;
617
+ case "FunctionDeclaration": {
618
+ const [parent] = state.stack.slice(-2);
619
+ if (parent.type == "ClassDeclaration" && !maybeCalled(node)) {
620
+ let used = false;
621
+ if (node.id.name == "initialize") {
622
+ used = true;
623
+ } else if (parent.superClass) {
624
+ used = checkInherited(parent, node.id.name);
625
+ }
626
+ if (used) {
627
+ if (!hasProperty(state.calledFunctions, node.id.name)) {
628
+ state.calledFunctions[node.id.name] = [];
629
+ }
630
+ state.calledFunctions[node.id.name].push(node);
631
+ }
632
+ }
633
+ }
634
+ }
635
+ };
636
+ state.post = (node) => {
637
+ const opt = optimizeNode(node);
638
+ if (opt) {
639
+ replace(node, opt);
640
+ return;
641
+ }
642
+ switch (node.type) {
643
+ case "ConditionalExpression":
644
+ case "IfStatement":
645
+ if (typeof node.test === "boolean") {
646
+ const rep = node.test ? node.consequent : node.alternate;
647
+ if (!rep) return false;
648
+ replace(node, rep);
649
+ }
650
+ break;
651
+ case "WhileStatement":
652
+ if (!node.body) return false;
653
+ break;
654
+ case "DoWhileStatement":
655
+ if (!node.test) return node.body;
656
+ break;
657
+
658
+ case "CallExpression": {
659
+ const [name, callees] = state.lookup(node.callee);
660
+ if (!callees || !callees.length) {
661
+ const n =
662
+ name ||
663
+ node.callee.name ||
664
+ (node.callee.property && node.callee.property.name);
665
+ if (n) {
666
+ state.exposed[n] = true;
667
+ } else {
668
+ // There are unnamed CallExpressions, such as new [size]
669
+ // So there's nothing to do here.
670
+ }
671
+ return;
672
+ }
673
+ if (callees.length == 1) {
674
+ const callee = callees[0].node;
675
+ if (
676
+ callee.optimizable &&
677
+ !callee.hasOverride &&
678
+ node.arguments.every((n) => getNodeValue(n)[0] !== null)
679
+ ) {
680
+ const ret = evaluateFunction(callee, node.arguments);
681
+ if (ret) {
682
+ replace(node, ret);
683
+ return;
684
+ }
685
+ }
686
+ }
687
+ if (!hasProperty(state.calledFunctions, name)) {
688
+ state.calledFunctions[name] = [];
689
+ }
690
+ callees.forEach((c) => state.calledFunctions[name].push(c.node));
691
+ break;
692
+ }
693
+ }
694
+ };
695
+ files.forEach((f) => {
696
+ collectNamespaces(f.ast, state);
697
+ });
698
+ files.forEach((f) => {
699
+ traverseAst(f.ast, null, (node) => {
700
+ switch (node.type) {
701
+ case "EnumStringBody":
702
+ if (
703
+ node.members.every((m) => {
704
+ const name = m.name || m.id.name;
705
+ return (
706
+ hasProperty(state.index, name) &&
707
+ !hasProperty(state.exposed, name)
708
+ );
709
+ })
710
+ ) {
711
+ node.enumType = [
712
+ ...new Set(
713
+ node.members.map((m) => {
714
+ if (!m.init) return "Number";
715
+ const [node, type] = getNodeValue(m.init);
716
+ if (!node) {
717
+ throw new Error("Failed to get type for eliminated enum");
718
+ }
719
+ return type;
720
+ })
721
+ ),
722
+ ].join(" or ");
723
+ node.members.splice(0);
724
+ }
725
+ break;
726
+ case "EnumDeclaration":
727
+ if (!node.body.members.length) {
728
+ if (!node.id) return false;
729
+ if (!node.body.enumType) {
730
+ throw new Error("Missing enumType on optimized enum");
731
+ }
732
+ replace(node, {
733
+ type: "TypedefDeclaration",
734
+ id: node.id,
735
+ ts: {
736
+ type: "UnaryExpression",
737
+ argument: { type: "TypeSpecList", ts: [node.body.enumType] },
738
+ prefix: true,
739
+ operator: " as",
740
+ },
741
+ });
742
+ }
743
+ break;
744
+ case "VariableDeclaration": {
745
+ node.declarations = node.declarations.filter(
746
+ (d) =>
747
+ !hasProperty(state.index, d.id.name) ||
748
+ hasProperty(state.exposed, d.id.name)
749
+ );
750
+ if (!node.declarations.length) {
751
+ return false;
752
+ }
753
+ break;
754
+ }
755
+ case "ClassElement":
756
+ if (!node.item) {
757
+ return false;
758
+ }
759
+ break;
760
+ case "FunctionDeclaration":
761
+ if (!maybeCalled(node)) {
762
+ return false;
763
+ }
764
+ break;
765
+ }
766
+ });
767
+ });
768
+
769
+ return files;
770
+ }
771
+
115
772
  ;// CONCATENATED MODULE: ./src/api.js
116
773
 
117
774
 
@@ -119,7 +776,8 @@ const negativeFixups = [
119
776
 
120
777
 
121
778
 
122
- const LiteralIntegerRe = /^(0x[0-9a-f]+|\d+)(l)?$/;
779
+
780
+ const api_LiteralIntegerRe = /^(0x[0-9a-f]+|\d+)(l)?$/;
123
781
  /*
124
782
  * This is an unfortunate hack. I want to be able to extract things
125
783
  * like the types of all of a Class's variables (in particular the type
@@ -131,7 +789,7 @@ const LiteralIntegerRe = /^(0x[0-9a-f]+|\d+)(l)?$/;
131
789
  */
132
790
 
133
791
  // Extract all enum values from api.mir
134
- async function getApiMapping(state) {
792
+ async function api_getApiMapping(state) {
135
793
  // get the path to the currently active sdk
136
794
  const parser = prettier_plugin_monkeyc_namespaceObject.parsers.monkeyc;
137
795
 
@@ -145,7 +803,7 @@ async function getApiMapping(state) {
145
803
  .replace(/^(\s*type)\s/gm, "$1def ");
146
804
 
147
805
  try {
148
- const result = collectNamespaces(parser.parse(api, {}), state);
806
+ const result = api_collectNamespaces(parser.parse(api, {}), state);
149
807
  negativeFixups.forEach((fixup) => {
150
808
  const value = fixup.split(".").reduce((state, part) => {
151
809
  const decls = state.decls[part];
@@ -170,18 +828,18 @@ async function getApiMapping(state) {
170
828
  }
171
829
  }
172
830
 
173
- function hasProperty(obj, prop) {
831
+ function api_hasProperty(obj, prop) {
174
832
  return obj && Object.prototype.hasOwnProperty.call(obj, prop);
175
833
  }
176
834
 
177
- function collectNamespaces(ast, state) {
835
+ function api_collectNamespaces(ast, state) {
178
836
  state = state || {};
179
837
  if (!state.index) state.index = {};
180
838
  if (!state.stack) {
181
839
  state.stack = [{ type: "Program", name: "$", fullName: "$" }];
182
840
  }
183
841
  const checkOne = (ns, name) => {
184
- if (hasProperty(ns.decls, name)) {
842
+ if (api_hasProperty(ns.decls, name)) {
185
843
  return ns.decls[name];
186
844
  }
187
845
  return null;
@@ -219,7 +877,7 @@ function collectNamespaces(ast, state) {
219
877
  };
220
878
 
221
879
  state.traverse = (root) =>
222
- traverseAst(
880
+ api_traverseAst(
223
881
  root,
224
882
  (node) => {
225
883
  try {
@@ -263,7 +921,7 @@ function collectNamespaces(ast, state) {
263
921
  .join(".");
264
922
  if (elm.name) {
265
923
  if (!parent.decls) parent.decls = {};
266
- if (hasProperty(parent.decls, elm.name)) {
924
+ if (api_hasProperty(parent.decls, elm.name)) {
267
925
  const what =
268
926
  node.type == "ModuleDeclaration" ? "type" : "node";
269
927
  const e = parent.decls[elm.name].find(
@@ -296,7 +954,7 @@ function collectNamespaces(ast, state) {
296
954
  case "TypedefDeclaration": {
297
955
  const [parent] = state.stack.slice(-1);
298
956
  if (!parent.decls) parent.decls = {};
299
- if (!hasProperty(parent.decls, node.id.name)) {
957
+ if (!api_hasProperty(parent.decls, node.id.name)) {
300
958
  parent.decls[node.id.name] = [];
301
959
  }
302
960
  (0,external_util_cjs_namespaceObject.pushUnique)(
@@ -309,12 +967,12 @@ function collectNamespaces(ast, state) {
309
967
  const [parent] = state.stack.slice(-1);
310
968
  if (!parent.decls) parent.decls = {};
311
969
  node.declarations.forEach((decl) => {
312
- if (!hasProperty(parent.decls, decl.id.name)) {
970
+ if (!api_hasProperty(parent.decls, decl.id.name)) {
313
971
  parent.decls[decl.id.name] = [];
314
972
  }
315
973
  if (node.kind == "const") {
316
974
  (0,external_util_cjs_namespaceObject.pushUnique)(parent.decls[decl.id.name], decl.init);
317
- if (!hasProperty(state.index, decl.id.name)) {
975
+ if (!api_hasProperty(state.index, decl.id.name)) {
318
976
  state.index[decl.id.name] = [];
319
977
  }
320
978
  (0,external_util_cjs_namespaceObject.pushUnique)(state.index[decl.id.name], parent);
@@ -335,10 +993,16 @@ function collectNamespaces(ast, state) {
335
993
  let name, init;
336
994
  if (m.type == "EnumStringMember") {
337
995
  name = m.id.name;
338
- init = m.init;
996
+ init = getLiteralNode(m.init);
997
+ if (!init) {
998
+ throw new Error("Unexpected enum initializer");
999
+ }
1000
+ if (init != m.init) {
1001
+ m.init = init;
1002
+ }
339
1003
  if (
340
1004
  init.type == "Literal" &&
341
- LiteralIntegerRe.test(init.raw)
1005
+ api_LiteralIntegerRe.test(init.raw)
342
1006
  ) {
343
1007
  prev = init.value;
344
1008
  }
@@ -359,11 +1023,11 @@ function collectNamespaces(ast, state) {
359
1023
  };
360
1024
  }
361
1025
  }
362
- if (!hasProperty(values, name)) {
1026
+ if (!api_hasProperty(values, name)) {
363
1027
  values[name] = [];
364
1028
  }
365
1029
  (0,external_util_cjs_namespaceObject.pushUnique)(values[name], init);
366
- if (!hasProperty(state.index, name)) {
1030
+ if (!api_hasProperty(state.index, name)) {
367
1031
  state.index[name] = [];
368
1032
  }
369
1033
  (0,external_util_cjs_namespaceObject.pushUnique)(state.index[name], parent);
@@ -413,7 +1077,7 @@ function collectNamespaces(ast, state) {
413
1077
  * - if post returns false, the node it was called on is
414
1078
  * removed.
415
1079
  */
416
- function traverseAst(node, pre, post) {
1080
+ function api_traverseAst(node, pre, post) {
417
1081
  const nodes = pre && pre(node);
418
1082
  if (nodes === false) return;
419
1083
  for (const key of nodes || Object.keys(node)) {
@@ -421,7 +1085,7 @@ function traverseAst(node, pre, post) {
421
1085
  if (!value) continue;
422
1086
  if (Array.isArray(value)) {
423
1087
  const deletions = value.reduce((state, obj, i) => {
424
- const repl = traverseAst(obj, pre, post);
1088
+ const repl = api_traverseAst(obj, pre, post);
425
1089
  if (repl === false) {
426
1090
  if (!state) state = {};
427
1091
  state[i] = true;
@@ -438,7 +1102,7 @@ function traverseAst(node, pre, post) {
438
1102
  );
439
1103
  }
440
1104
  } else if (typeof value == "object" && value.type) {
441
- const repl = traverseAst(value, pre, post);
1105
+ const repl = api_traverseAst(value, pre, post);
442
1106
  if (repl === false) {
443
1107
  delete node[key];
444
1108
  } else if (repl != null) {