@motifx/compiler 1.0.1 → 1.2.0-rc.0

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/index.cjs CHANGED
@@ -15,6 +15,7 @@ var htmlTags = require('html-tags');
15
15
  var svgTags = require('svg-tags');
16
16
  var generatorNs = require('@babel/generator');
17
17
  var path = require('node:path');
18
+ var node_fs = require('node:fs');
18
19
  var ts = require('typescript');
19
20
  var pPath = require('path');
20
21
 
@@ -510,12 +511,6 @@ const makeHtmlAttr = (prop, name, value, path) => {
510
511
  return t__namespace.objectProperty(t__namespace.stringLiteral(name), value || t__namespace.booleanLiteral(true));
511
512
  }
512
513
  else if (t__namespace.isArrowFunctionExpression(value) && value !== null) {
513
- if (t__namespace.isBlockStatement(value.body)) {
514
- t__namespace.functionExpression(null, value.params, value.body);
515
- }
516
- else {
517
- t__namespace.functionExpression(null, value.params, t__namespace.blockStatement([t__namespace.returnStatement(value.body)]));
518
- }
519
514
  return t__namespace.objectProperty(t__namespace.stringLiteral(name), value);
520
515
  }
521
516
  else if (t__namespace.isFunctionExpression(value)) {
@@ -740,33 +735,9 @@ const mergeHtmlAttributes = (htmlAttrlist) => {
740
735
  };
741
736
  const makeHtmlEvents = (prop, name, value, path) => {
742
737
  if (!t__namespace.isStringLiteral(value) && !t__namespace.isBooleanLiteral(value) && value !== null) {
743
- if (t__namespace.isArrowFunctionExpression(value)) {
744
- var el;
745
- if (t__namespace.isBlockStatement(value.body)) {
746
- el = t__namespace.arrowFunctionExpression(value.params, value.body);
747
- }
748
- else {
749
- el = t__namespace.arrowFunctionExpression(value.params, t__namespace.blockStatement([t__namespace.returnStatement(value.body)]));
750
- }
751
- var evName = name.toLowerCase().replace("on", '').replace('doubleclick', 'dblclick');
752
- return t__namespace.callExpression(t__namespace.identifier("sender.motif.on"), [t__namespace.stringLiteral(evName), el]);
753
- }
754
- else if (t__namespace.isFunctionExpression(value)) {
755
- var el;
756
- if (t__namespace.isBlockStatement(value.body)) {
757
- el = t__namespace.functionExpression(null, value.params, value.body);
758
- }
759
- else {
760
- el = t__namespace.functionExpression(null, value.params, t__namespace.blockStatement([t__namespace.returnStatement(value.body)]));
761
- }
738
+ if (t__namespace.isExpression(value)) {
762
739
  var evName = name.toLowerCase().replace("on", '').replace('doubleclick', 'dblclick');
763
- return t__namespace.callExpression(t__namespace.identifier("sender.motif.on"), [t__namespace.stringLiteral(evName), el]);
764
- }
765
- else {
766
- if (t__namespace.isExpression(value)) {
767
- var evName = name.toLowerCase().replace("on", '').replace('doubleclick', 'dblclick');
768
- return t__namespace.callExpression(t__namespace.identifier("sender.motif.on"), [t__namespace.stringLiteral(evName), value]);
769
- }
740
+ return t__namespace.callExpression(t__namespace.identifier("sender.motif.on"), [t__namespace.stringLiteral(evName), value]);
770
741
  }
771
742
  }
772
743
  else {
@@ -823,7 +794,10 @@ const ParentIfStatement = (path, state) => {
823
794
  else ;
824
795
  return state;
825
796
  };
826
- const returnIfStatement = (value, enableDefaultreturn = true, defaultLiteral = t__namespace.booleanLiteral(false)) => {
797
+ const returnIfStatement = (value, enableDefaultreturn = true, defaultLiteral = t__namespace.booleanLiteral(false), callFunctions = false) => {
798
+ if (callFunctions && t__namespace.isFunctionExpression(value)) {
799
+ return value;
800
+ }
827
801
  var ifStatement = findIfStatements(value);
828
802
  var mx = t__namespace.binaryExpression('===', t__namespace.unaryExpression('typeof', value), t__namespace.stringLiteral('function'));
829
803
  var rtrn;
@@ -837,13 +811,15 @@ const returnIfStatement = (value, enableDefaultreturn = true, defaultLiteral = t
837
811
  }
838
812
  }
839
813
  else if (t__namespace.isMemberExpression(value) || t__namespace.isIdentifier(value)) {
840
- rtrn = t__namespace.returnStatement(value);
814
+ rtrn = t__namespace.returnStatement(callFunctions
815
+ ? t__namespace.conditionalExpression(t__namespace.binaryExpression('===', t__namespace.unaryExpression('typeof', value), t__namespace.stringLiteral('function')), t__namespace.callExpression(value, []), value)
816
+ : value);
841
817
  var rtrns = t__namespace.ifStatement(ifStatement, t__namespace.blockStatement([rtrn]));
842
818
  if (enableDefaultreturn) {
843
- return t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns, t__namespace.returnStatement(defaultLiteral)]));
819
+ return cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns, t__namespace.returnStatement(defaultLiteral)])), [value]);
844
820
  }
845
821
  else {
846
- return t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns]));
822
+ return cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns])), [value]);
847
823
  }
848
824
  }
849
825
  else if (t__namespace.isFunctionExpression(value)) {
@@ -862,20 +838,20 @@ const returnIfStatement = (value, enableDefaultreturn = true, defaultLiteral = t
862
838
  var le = t__namespace.logicalExpression('&&', ifStatementA, ifStatementB);
863
839
  rtrn = t__namespace.returnStatement(value);
864
840
  if (enableDefaultreturn) {
865
- return t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([t__namespace.ifStatement(le, t__namespace.blockStatement([rtrn])), t__namespace.returnStatement(defaultLiteral)]));
841
+ return cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([t__namespace.ifStatement(le, t__namespace.blockStatement([rtrn])), t__namespace.returnStatement(defaultLiteral)])), [value.left, value.right]);
866
842
  }
867
843
  else {
868
- return t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([t__namespace.ifStatement(le, t__namespace.blockStatement([rtrn]))]));
844
+ return cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([t__namespace.ifStatement(le, t__namespace.blockStatement([rtrn]))])), [value.left, value.right]);
869
845
  }
870
846
  }
871
847
  else if (t__namespace.isCallExpression(value)) {
872
848
  rtrn = t__namespace.returnStatement(t__namespace.conditionalExpression(mx, t__namespace.callExpression(value, []), value));
873
849
  var rtrns = t__namespace.ifStatement(ifStatement, t__namespace.blockStatement([rtrn]));
874
850
  if (enableDefaultreturn) {
875
- return t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns, t__namespace.returnStatement(defaultLiteral)]));
851
+ return cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns, t__namespace.returnStatement(defaultLiteral)])), [value]);
876
852
  }
877
853
  else {
878
- return t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns]));
854
+ return cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns])), [value]);
879
855
  }
880
856
  }
881
857
  else {
@@ -945,6 +921,95 @@ const findIfStatements = (value) => {
945
921
  }
946
922
  return ifStatement;
947
923
  };
924
+ const isEffectNode = (node) => t__namespace.isCallExpression(node) || t__namespace.isOptionalCallExpression(node) || t__namespace.isNewExpression(node) ||
925
+ t__namespace.isTaggedTemplateExpression(node) || t__namespace.isUpdateExpression(node) || t__namespace.isAssignmentExpression(node) ||
926
+ t__namespace.isAwaitExpression(node) || t__namespace.isYieldExpression(node);
927
+ const hasEffect = (node) => {
928
+ if (!node || t__namespace.isFunction(node) || t__namespace.isClass(node))
929
+ return false;
930
+ if (isEffectNode(node))
931
+ return true;
932
+ for (const key of t__namespace.VISITOR_KEYS[node.type] ?? []) {
933
+ const child = node[key];
934
+ if (Array.isArray(child) ? child.some(c => hasEffect(c)) : hasEffect(child))
935
+ return true;
936
+ }
937
+ return false;
938
+ };
939
+ const guardCallLinks = (root, found) => {
940
+ if (!t__namespace.isExpression(root) || t__namespace.isFunction(root))
941
+ return;
942
+ if (!t__namespace.isIdentifier(root) && !t__namespace.isMemberExpression(root) && !t__namespace.isThisExpression(root) && !t__namespace.isLiteral(root) && hasEffect(root)) {
943
+ found.add(root);
944
+ }
945
+ if (t__namespace.isMemberExpression(root))
946
+ guardCallLinks(root.object, found);
947
+ else if (t__namespace.isCallExpression(root) && t__namespace.isExpression(root.callee))
948
+ guardCallLinks(root.callee, found);
949
+ };
950
+ const collectNames = (node, names) => {
951
+ if (!node)
952
+ return;
953
+ if (t__namespace.isIdentifier(node))
954
+ names.add(node.name);
955
+ for (const key of t__namespace.VISITOR_KEYS[node.type] ?? []) {
956
+ const child = node[key];
957
+ if (Array.isArray(child))
958
+ child.forEach(c => collectNames(c, names));
959
+ else
960
+ collectNames(child, names);
961
+ }
962
+ };
963
+ const cacheGuardCalls = (fn, roots) => {
964
+ if (!t__namespace.isBlockStatement(fn.body))
965
+ return fn;
966
+ const links = new Set();
967
+ roots.forEach(r => guardCallLinks(r, links));
968
+ if (links.size === 0)
969
+ return fn;
970
+ const used = new Set();
971
+ collectNames(fn, used);
972
+ const assigned = new Map();
973
+ let counter = 0;
974
+ const nextName = () => {
975
+ let name;
976
+ do {
977
+ name = `__r${++counter}`;
978
+ } while (used.has(name));
979
+ return name;
980
+ };
981
+ const rewrite = (node) => {
982
+ if (!node || typeof node !== 'object' || !node.type)
983
+ return node;
984
+ if (links.has(node)) {
985
+ const known = assigned.get(node);
986
+ if (known)
987
+ return t__namespace.identifier(known);
988
+ const name = nextName();
989
+ assigned.set(node, name);
990
+ return t__namespace.assignmentExpression('=', t__namespace.identifier(name), rewriteChildren(node));
991
+ }
992
+ if (t__namespace.isFunction(node) || t__namespace.isClass(node))
993
+ return node;
994
+ return rewriteChildren(node);
995
+ };
996
+ const rewriteChildren = (node) => {
997
+ const copy = t__namespace.cloneNode(node, false);
998
+ for (const key of t__namespace.VISITOR_KEYS[node.type] ?? []) {
999
+ const child = node[key];
1000
+ copy[key] = Array.isArray(child) ? child.map(rewrite) : rewrite(child);
1001
+ }
1002
+ return copy;
1003
+ };
1004
+ const body = rewriteChildren(fn.body);
1005
+ if (assigned.size === 0)
1006
+ return fn;
1007
+ const declaration = t__namespace.variableDeclaration('let', [...assigned.values()].map(name => t__namespace.variableDeclarator(t__namespace.identifier(name))));
1008
+ body.body.unshift(declaration);
1009
+ const result = t__namespace.cloneNode(fn, false);
1010
+ result.body = body;
1011
+ return result;
1012
+ };
948
1013
  const makeDirectives = (prop, name, value, path, state) => {
949
1014
  var result = null;
950
1015
  if (value != null) {
@@ -983,7 +1048,7 @@ const makeDirectives = (prop, name, value, path, state) => {
983
1048
  }
984
1049
  else {
985
1050
  if (t__namespace.isExpression(value)) {
986
- result = t__namespace.expressionStatement(t__namespace.callExpression(t__namespace.identifier(callerName), [returnIfStatement(value, false)]));
1051
+ result = t__namespace.expressionStatement(t__namespace.callExpression(t__namespace.identifier(callerName), [returnIfStatement(value, false, t__namespace.booleanLiteral(false), true)]));
987
1052
  }
988
1053
  }
989
1054
  }
@@ -1065,7 +1130,7 @@ const makePreDirectives = (prop, name, value, path) => {
1065
1130
  fail('MJX012', `Directive "${name}" does not accept an object literal.`, prop);
1066
1131
  }
1067
1132
  else if (t__namespace.isExpression(value)) {
1068
- result = t__namespace.expressionStatement(t__namespace.callExpression(t__namespace.identifier(callerName), [returnIfStatement(value, true, t__namespace.booleanLiteral(true))]));
1133
+ result = t__namespace.expressionStatement(t__namespace.callExpression(t__namespace.identifier(callerName), [returnIfStatement(value, true, t__namespace.booleanLiteral(true), true)]));
1069
1134
  }
1070
1135
  }
1071
1136
  else {
@@ -1606,7 +1671,7 @@ const getProps = (props, path, state) => {
1606
1671
  refEntries.push({ prop, lowered: t__namespace.arrowFunctionExpression([t__namespace.identifier('sender')], t__namespace.blockStatement(body)) });
1607
1672
  }
1608
1673
  else if (t__namespace.isFunctionExpression(value) || t__namespace.isArrowFunctionExpression(value)) {
1609
- refEntries.push({ prop, lowered: t__namespace.arrowFunctionExpression(value.params, value.body) });
1674
+ refEntries.push({ prop, lowered: t__namespace.arrowFunctionExpression(value.params, value.body, value.async) });
1610
1675
  }
1611
1676
  else if (t__namespace.isExpression(value)) {
1612
1677
  var cx = t__namespace.expressionStatement(value);
@@ -2239,7 +2304,7 @@ const mkText = (exp) => {
2239
2304
  var mx = t__namespace.binaryExpression('===', t__namespace.unaryExpression('typeof', exp), t__namespace.stringLiteral('function'));
2240
2305
  var rtrn = t__namespace.returnStatement(t__namespace.conditionalExpression(mx, t__namespace.callExpression(exp, []), t__namespace.arrowFunctionExpression([], exp)));
2241
2306
  var rtrns = t__namespace.ifStatement(ifStatement, t__namespace.blockStatement([rtrn]));
2242
- var kx = t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns]));
2307
+ var kx = cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns])), [exp]);
2243
2308
  a1 = t__namespace.callExpression(id('sender.bindings.add'), [t__namespace.stringLiteral("textContent"), kx]);
2244
2309
  }
2245
2310
  }
@@ -2305,7 +2370,7 @@ const mkText = (exp) => {
2305
2370
  // var a1 = t.callExpression(id('sender.bind.logic'), [kx, exp.right]);
2306
2371
  var rtrns = t__namespace.ifStatement(ifStatement, t__namespace.blockStatement([t__namespace.returnStatement(exp.left)]));
2307
2372
  var tryStatement = t__namespace.tryStatement(t__namespace.blockStatement([rtrns]), t__namespace.catchClause(null, t__namespace.blockStatement([t__namespace.returnStatement(t__namespace.nullLiteral())])), null);
2308
- var kx = t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([tryStatement]));
2373
+ var kx = cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([tryStatement])), [exp.left]);
2309
2374
  if (!t__namespace.isFunctionDeclaration(exp.right) && !t__namespace.isArrowFunctionExpression(exp.right)) {
2310
2375
  t__namespace.ifStatement(t__namespace.identifier('__v'), t__namespace.blockStatement([t__namespace.returnStatement(exp.right)]), t__namespace.blockStatement([t__namespace.returnStatement(t__namespace.callExpression(t__namespace.identifier(motifComponent()), [t__namespace.objectExpression([])]))]));
2311
2376
  exp.right = t__namespace.arrowFunctionExpression([t__namespace.identifier("__v")], t__namespace.blockStatement([t__namespace.returnStatement(exp.right)]));
@@ -2325,7 +2390,7 @@ const mkText = (exp) => {
2325
2390
  var mx = t__namespace.binaryExpression('===', t__namespace.unaryExpression('typeof', exp), t__namespace.stringLiteral('function'));
2326
2391
  var rtrn = t__namespace.returnStatement(t__namespace.conditionalExpression(mx, t__namespace.callExpression(exp, []), t__namespace.arrowFunctionExpression([], exp)));
2327
2392
  var rtrns = t__namespace.ifStatement(ifStatement, t__namespace.blockStatement([rtrn]));
2328
- var kx = t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns]));
2393
+ var kx = cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns])), [exp]);
2329
2394
  a1 = t__namespace.callExpression(id('sender.bindings.add'), [t__namespace.stringLiteral("textContent"), kx]);
2330
2395
  }
2331
2396
  else {
@@ -2333,7 +2398,7 @@ const mkText = (exp) => {
2333
2398
  var mx = t__namespace.binaryExpression('===', t__namespace.unaryExpression('typeof', exp), t__namespace.stringLiteral('function'));
2334
2399
  var rtrn = t__namespace.returnStatement(t__namespace.conditionalExpression(mx, t__namespace.callExpression(exp, []), t__namespace.arrowFunctionExpression([], exp)));
2335
2400
  var rtrns = t__namespace.ifStatement(ifStatement, t__namespace.blockStatement([rtrn]));
2336
- var kx = t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns]));
2401
+ var kx = cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([rtrns])), [exp]);
2337
2402
  a1 = t__namespace.callExpression(id('sender.bindings.add'), [t__namespace.stringLiteral("textContent"), kx]);
2338
2403
  }
2339
2404
  var arrayBody = t__namespace.arrowFunctionExpression([id('sender')], t__namespace.blockStatement([t__namespace.expressionStatement(a1)]));
@@ -2499,7 +2564,7 @@ function ParseComponent(path, state) {
2499
2564
  // var rtrn = t.returnStatement(t.conditionalExpression(mx, t.callExpression(cx.left, []), t.arrowFunctionExpression([], cx.left)));
2500
2565
  var rtrns = t__namespace.ifStatement(ifStatement, t__namespace.blockStatement([t__namespace.returnStatement(cx.left)]));
2501
2566
  var tryStatement = t__namespace.tryStatement(t__namespace.blockStatement([rtrns]), t__namespace.catchClause(null, t__namespace.blockStatement([t__namespace.returnStatement(t__namespace.nullLiteral())])), null);
2502
- var kx = t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([tryStatement]));
2567
+ var kx = cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([tryStatement])), [cx.left]);
2503
2568
  if (!t__namespace.isFunctionDeclaration(cx.right) && !t__namespace.isArrowFunctionExpression(cx.right)) {
2504
2569
  t__namespace.ifStatement(t__namespace.identifier('__v'), t__namespace.blockStatement([t__namespace.returnStatement(cx.right)]), t__namespace.blockStatement([t__namespace.returnStatement(t__namespace.callExpression(t__namespace.identifier(motifComponent()), [t__namespace.objectExpression([])]))]));
2505
2570
  cx.right = t__namespace.arrowFunctionExpression([t__namespace.identifier("__v")], t__namespace.blockStatement([t__namespace.returnStatement(cx.right)]));
@@ -2644,7 +2709,7 @@ function ParseFrament(path, state) {
2644
2709
  else {
2645
2710
  var rtrnsPlain = t__namespace.ifStatement(ifStatement, t__namespace.blockStatement([t__namespace.returnStatement(exp.left)]));
2646
2711
  var tryStatement = t__namespace.tryStatement(t__namespace.blockStatement([rtrnsPlain]), t__namespace.catchClause(null, t__namespace.blockStatement([t__namespace.returnStatement(t__namespace.nullLiteral())])), null);
2647
- condFn = t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([tryStatement]));
2712
+ condFn = cacheGuardCalls(t__namespace.arrowFunctionExpression([], t__namespace.blockStatement([tryStatement])), [exp.left]);
2648
2713
  }
2649
2714
  if (!t__namespace.isFunctionDeclaration(exp.right) && !t__namespace.isArrowFunctionExpression(exp.right)) {
2650
2715
  exp.right = t__namespace.arrowFunctionExpression([t__namespace.identifier("val")], t__namespace.blockStatement([t__namespace.returnStatement(exp.right)]));
@@ -3090,12 +3155,9 @@ class Compiler {
3090
3155
  },
3091
3156
  function devOnlyStrip() {
3092
3157
  let isDev = true;
3093
- try {
3094
- const flag = (0, eval)('typeof __MOTIF_DEV__ !== "undefined" ? __MOTIF_DEV__ : undefined');
3095
- if (typeof flag === 'boolean')
3096
- isDev = flag;
3097
- }
3098
- catch { /* ignore */ }
3158
+ const flag = globalThis.__MOTIF_DEV__;
3159
+ if (typeof flag === 'boolean')
3160
+ isDev = flag;
3099
3161
  if (typeof process !== 'undefined' && process?.env?.MOTIF_DEV === 'false')
3100
3162
  isDev = false;
3101
3163
  const consumed = new WeakSet();
@@ -3156,11 +3218,492 @@ class Compiler {
3156
3218
  }
3157
3219
  }
3158
3220
 
3221
+ const SUPER_METHODS = ['build', 'setState', 'reState', 'setText', 'style', 'dispose', 'disposeAsync', 'using', 'doWork', 'getService', '$', 'useModel'];
3222
+ const SUPER_ACCESSORS = ['context', 'siblings', 'serviceProvider', 'isWait'];
3223
+ const CORE_COMPONENT_CLASSES = ['Component', 'ComponentBase', 'ContentBlock', 'ContentBody', 'FragmentNode', 'Frame', 'RouterLink', 'RouterView', 'Transport', 'TransportTo', 'Virtualization'];
3224
+ const coreComponents = new Set(CORE_COMPONENT_CLASSES);
3225
+ const superNames = new Set([...SUPER_METHODS, ...SUPER_ACCESSORS]);
3226
+ const quickMember = new RegExp(`(?:^|[\\s;{}])(?:async\\s+|get\\s+|set\\s+|override\\s+|public\\s+|protected\\s+)*(?:${[...superNames].map(n => n.replace('$', '\\$')).join('|')})\\s*\\(`, 'm');
3227
+ function mayHaveSuperOverrides(code) {
3228
+ return /\bextends\b/.test(code) && quickMember.test(code);
3229
+ }
3230
+ function isCoreSource(source) {
3231
+ return source === '@motifx/core' || source.startsWith('@motifx/core/');
3232
+ }
3233
+ function isCoreComponent(name) {
3234
+ return coreComponents.has(name);
3235
+ }
3236
+ function parseModule(code, filename) {
3237
+ const isTs = /\.[mc]?tsx?$/.test(filename);
3238
+ const isTsx = /\.tsx$/.test(filename);
3239
+ const plugins = isTs ? ['typescript', 'decorators-legacy', 'classProperties'] : ['jsx', 'decorators-legacy', 'classProperties'];
3240
+ if (isTsx)
3241
+ plugins.push('jsx');
3242
+ try {
3243
+ const ast = babel__namespace.parseSync(code, {
3244
+ filename,
3245
+ babelrc: false,
3246
+ configFile: false,
3247
+ browserslistConfigFile: false,
3248
+ sourceType: 'unambiguous',
3249
+ parserOpts: { plugins, errorRecovery: true },
3250
+ });
3251
+ return ast ?? null;
3252
+ }
3253
+ catch {
3254
+ return null;
3255
+ }
3256
+ }
3257
+ function isSuperMember(node, name) {
3258
+ if (!node || !(t__namespace.isMemberExpression(node) || t__namespace.isOptionalMemberExpression(node)) || !t__namespace.isSuper(node.object))
3259
+ return false;
3260
+ if (!node.computed && t__namespace.isIdentifier(node.property))
3261
+ return node.property.name === name;
3262
+ return t__namespace.isStringLiteral(node.property) && node.property.value === name;
3263
+ }
3264
+ function directUse(node, name, use) {
3265
+ if (use === 'call' && (t__namespace.isCallExpression(node) || t__namespace.isOptionalCallExpression(node))) {
3266
+ const callee = node.callee;
3267
+ if (isSuperMember(callee, name))
3268
+ return true;
3269
+ if ((t__namespace.isMemberExpression(callee) || t__namespace.isOptionalMemberExpression(callee)) && isSuperMember(callee.object, name)
3270
+ && t__namespace.isIdentifier(callee.property) && (callee.property.name === 'call' || callee.property.name === 'apply'))
3271
+ return true;
3272
+ }
3273
+ if (use === 'get' && isSuperMember(node, name))
3274
+ return true;
3275
+ if (use === 'set' && t__namespace.isAssignmentExpression(node) && isSuperMember(node.left, name))
3276
+ return true;
3277
+ return false;
3278
+ }
3279
+ function definitely(node, name, use) {
3280
+ if (!node || typeof node !== 'object')
3281
+ return false;
3282
+ if (t__namespace.isFunction(node) || t__namespace.isClass(node))
3283
+ return false;
3284
+ if (directUse(node, name, use))
3285
+ return true;
3286
+ if (use === 'get' && t__namespace.isAssignmentExpression(node) && isSuperMember(node.left, name))
3287
+ return definitely(node.right, name, use);
3288
+ if (t__namespace.isLogicalExpression(node))
3289
+ return definitely(node.left, name, use);
3290
+ if (t__namespace.isConditionalExpression(node))
3291
+ return definitely(node.test, name, use) || (definitely(node.consequent, name, use) && definitely(node.alternate, name, use));
3292
+ if (t__namespace.isOptionalCallExpression(node) || t__namespace.isOptionalMemberExpression(node)) {
3293
+ const head = t__namespace.isOptionalCallExpression(node) ? node.callee : node.object;
3294
+ return definitely(head, name, use);
3295
+ }
3296
+ for (const key of t__namespace.VISITOR_KEYS[node.type] ?? []) {
3297
+ const child = node[key];
3298
+ if (Array.isArray(child) ? child.some(c => definitely(c, name, use)) : definitely(child, name, use))
3299
+ return true;
3300
+ }
3301
+ return false;
3302
+ }
3303
+ function mentions(node, name, use) {
3304
+ if (!node || typeof node !== 'object')
3305
+ return false;
3306
+ if (directUse(node, name, use))
3307
+ return true;
3308
+ if (t__namespace.isClass(node))
3309
+ return false;
3310
+ for (const key of t__namespace.VISITOR_KEYS[node.type] ?? []) {
3311
+ const child = node[key];
3312
+ if (Array.isArray(child) ? child.some(c => mentions(c, name, use)) : mentions(child, name, use))
3313
+ return true;
3314
+ }
3315
+ return false;
3316
+ }
3317
+ const join = (a, b) => a === null ? b : b === null ? a : a && b;
3318
+ const GUARDS = {
3319
+ build: ['isBuilt', 'isDisposed', 'isWait'],
3320
+ dispose: ['isDisposed'],
3321
+ disposeAsync: ['isDisposed'],
3322
+ };
3323
+ function isGuardTest(test, member) {
3324
+ const allowed = GUARDS[member];
3325
+ if (!allowed)
3326
+ return false;
3327
+ if (t__namespace.isLogicalExpression(test) && test.operator === '||')
3328
+ return isGuardTest(test.left, member) && isGuardTest(test.right, member);
3329
+ return t__namespace.isMemberExpression(test) && t__namespace.isThisExpression(test.object) && !test.computed && t__namespace.isIdentifier(test.property) && allowed.includes(test.property.name);
3330
+ }
3331
+ function isBareReturn(node) {
3332
+ if (t__namespace.isReturnStatement(node))
3333
+ return true;
3334
+ return t__namespace.isBlockStatement(node) && node.body.length === 1 && t__namespace.isReturnStatement(node.body[0]);
3335
+ }
3336
+ function flow(node, called, name, use, member) {
3337
+ const plain = (c) => ({ normal: c, returns: true, breaks: null, continues: null });
3338
+ if (!node)
3339
+ return plain(called);
3340
+ const d = (e) => called || definitely(e, name, use);
3341
+ if (t__namespace.isBlockStatement(node) || t__namespace.isProgram(node))
3342
+ return block(node.body, called, name, use, member);
3343
+ if (t__namespace.isExpressionStatement(node))
3344
+ return plain(d(node.expression));
3345
+ if (t__namespace.isVariableDeclaration(node))
3346
+ return plain(called || node.declarations.some(x => definitely(x.init, name, use)));
3347
+ if (t__namespace.isReturnStatement(node))
3348
+ return { normal: null, returns: d(node.argument), breaks: null, continues: null };
3349
+ if (t__namespace.isThrowStatement(node))
3350
+ return { normal: null, returns: true, breaks: null, continues: null };
3351
+ if (t__namespace.isBreakStatement(node))
3352
+ return { normal: null, returns: true, breaks: called, continues: null };
3353
+ if (t__namespace.isContinueStatement(node))
3354
+ return { normal: null, returns: true, breaks: null, continues: called };
3355
+ if (t__namespace.isIfStatement(node)) {
3356
+ const tc = d(node.test);
3357
+ if (!tc && isGuardTest(node.test, member) && isBareReturn(node.consequent)) {
3358
+ const alt = node.alternate ? flow(node.alternate, tc, name, use, member) : plain(tc);
3359
+ return { normal: alt.normal, returns: alt.returns, breaks: alt.breaks, continues: alt.continues };
3360
+ }
3361
+ const cons = flow(node.consequent, tc, name, use, member);
3362
+ const alt = node.alternate ? flow(node.alternate, tc, name, use, member) : plain(tc);
3363
+ return { normal: join(cons.normal, alt.normal), returns: cons.returns && alt.returns, breaks: join(cons.breaks, alt.breaks), continues: join(cons.continues, alt.continues) };
3364
+ }
3365
+ if (t__namespace.isWhileStatement(node) || t__namespace.isForStatement(node) || t__namespace.isForInStatement(node) || t__namespace.isForOfStatement(node)) {
3366
+ let tc = called;
3367
+ if (t__namespace.isForStatement(node))
3368
+ tc = called || definitely(node.init, name, use) || definitely(node.test, name, use);
3369
+ else if (t__namespace.isWhileStatement(node))
3370
+ tc = d(node.test);
3371
+ else
3372
+ tc = d(node.right);
3373
+ const body = flow(node.body, tc, name, use, member);
3374
+ return { normal: join(tc, body.breaks), returns: body.returns, breaks: null, continues: null };
3375
+ }
3376
+ if (t__namespace.isDoWhileStatement(node)) {
3377
+ const body = flow(node.body, called, name, use, member);
3378
+ const afterBody = join(body.normal, body.continues);
3379
+ const afterTest = afterBody === null ? null : afterBody || definitely(node.test, name, use);
3380
+ return { normal: join(afterTest, body.breaks), returns: body.returns, breaks: null, continues: null };
3381
+ }
3382
+ if (t__namespace.isSwitchStatement(node)) {
3383
+ const dc = d(node.discriminant);
3384
+ let fall = null;
3385
+ let returns = true;
3386
+ let breaks = null;
3387
+ let continues = null;
3388
+ let hasDefault = false;
3389
+ for (const c of node.cases) {
3390
+ if (!c.test)
3391
+ hasDefault = true;
3392
+ const entry = join(fall, dc || definitely(c.test, name, use));
3393
+ const out = entry === null ? null : block(c.consequent, entry, name, use, member);
3394
+ if (out) {
3395
+ returns = returns && out.returns;
3396
+ breaks = join(breaks, out.breaks);
3397
+ continues = join(continues, out.continues);
3398
+ fall = out.normal;
3399
+ }
3400
+ else {
3401
+ fall = null;
3402
+ }
3403
+ }
3404
+ let normal = join(fall, breaks);
3405
+ if (!hasDefault)
3406
+ normal = join(normal, dc);
3407
+ return { normal, returns, breaks: null, continues };
3408
+ }
3409
+ if (t__namespace.isTryStatement(node)) {
3410
+ const tryOut = flow(node.block, called, name, use, member);
3411
+ const catchOut = node.handler ? flow(node.handler.body, called, name, use, member) : null;
3412
+ let normal = catchOut ? join(tryOut.normal, catchOut.normal) : tryOut.normal;
3413
+ let returns = tryOut.returns && (catchOut ? catchOut.returns : true);
3414
+ let breaks = catchOut ? join(tryOut.breaks, catchOut.breaks) : tryOut.breaks;
3415
+ let continues = catchOut ? join(tryOut.continues, catchOut.continues) : tryOut.continues;
3416
+ if (node.finalizer) {
3417
+ const fin = flow(node.finalizer, false, name, use, member);
3418
+ if (fin.normal === true) {
3419
+ normal = normal === null ? null : true;
3420
+ returns = true;
3421
+ breaks = breaks === null ? null : true;
3422
+ continues = continues === null ? null : true;
3423
+ }
3424
+ else if (fin.normal === null) {
3425
+ return { normal: null, returns: returns && fin.returns, breaks: fin.breaks, continues: fin.continues };
3426
+ }
3427
+ returns = returns && fin.returns;
3428
+ }
3429
+ return { normal, returns, breaks, continues };
3430
+ }
3431
+ if (t__namespace.isLabeledStatement(node)) {
3432
+ const body = flow(node.body, called, name, use, member);
3433
+ return { normal: join(body.normal, body.breaks), returns: body.returns, breaks: null, continues: body.continues };
3434
+ }
3435
+ if (t__namespace.isFunctionDeclaration(node) || t__namespace.isClassDeclaration(node))
3436
+ return plain(called);
3437
+ let c = called;
3438
+ for (const key of t__namespace.VISITOR_KEYS[node.type] ?? []) {
3439
+ const child = node[key];
3440
+ if (Array.isArray(child) ? child.some(x => definitely(x, name, use)) : definitely(child, name, use)) {
3441
+ c = true;
3442
+ break;
3443
+ }
3444
+ }
3445
+ return plain(c);
3446
+ }
3447
+ function block(body, called, name, use, member) {
3448
+ let state = called;
3449
+ let returns = true;
3450
+ let breaks = null;
3451
+ let continues = null;
3452
+ for (const s of body) {
3453
+ if (state === null)
3454
+ break;
3455
+ const out = flow(s, state, name, use, member);
3456
+ returns = returns && out.returns;
3457
+ breaks = join(breaks, out.breaks);
3458
+ continues = join(continues, out.continues);
3459
+ state = out.normal;
3460
+ }
3461
+ return { normal: state, returns, breaks, continues };
3462
+ }
3463
+ function checkMemberBody(body, member, accessor) {
3464
+ const use = accessor === 'method' ? 'call' : accessor;
3465
+ if (!mentions(body, member, use))
3466
+ return 'never';
3467
+ const out = flow(body, false, member, use, member);
3468
+ return out.normal !== false && out.returns ? 'ok' : 'path';
3469
+ }
3470
+ function memberName(m) {
3471
+ const key = m.key;
3472
+ if (m.computed)
3473
+ return t__namespace.isStringLiteral(key) ? key.value : null;
3474
+ if (t__namespace.isIdentifier(key))
3475
+ return key.name;
3476
+ if (t__namespace.isStringLiteral(key))
3477
+ return key.value;
3478
+ return null;
3479
+ }
3480
+ function analyzeModule(ast) {
3481
+ const imports = new Map();
3482
+ const classes = new Map();
3483
+ const exportsMap = new Map();
3484
+ const starSources = [];
3485
+ const findings = [];
3486
+ const classNodes = [];
3487
+ const noteClass = (node, name) => {
3488
+ if (name)
3489
+ classes.set(name, node);
3490
+ classNodes.push({ node, name: name ?? 'An anonymous class' });
3491
+ };
3492
+ const walk = (node, parent) => {
3493
+ if (!node || typeof node !== 'object' || !node.type)
3494
+ return;
3495
+ if (t__namespace.isImportDeclaration(node)) {
3496
+ for (const s of node.specifiers) {
3497
+ if (t__namespace.isImportSpecifier(s))
3498
+ imports.set(s.local.name, { source: node.source.value, name: t__namespace.isIdentifier(s.imported) ? s.imported.name : s.imported.value });
3499
+ else if (t__namespace.isImportDefaultSpecifier(s))
3500
+ imports.set(s.local.name, { source: node.source.value, name: 'default' });
3501
+ else if (t__namespace.isImportNamespaceSpecifier(s))
3502
+ imports.set(s.local.name, { source: node.source.value, name: '*' });
3503
+ }
3504
+ }
3505
+ else if (t__namespace.isExportNamedDeclaration(node)) {
3506
+ if (node.source) {
3507
+ for (const s of node.specifiers) {
3508
+ if (t__namespace.isExportSpecifier(s)) {
3509
+ const exported = t__namespace.isIdentifier(s.exported) ? s.exported.name : s.exported.value;
3510
+ exportsMap.set(exported, { from: node.source.value, imported: s.local.name });
3511
+ }
3512
+ }
3513
+ }
3514
+ else {
3515
+ for (const s of node.specifiers) {
3516
+ if (t__namespace.isExportSpecifier(s)) {
3517
+ const exported = t__namespace.isIdentifier(s.exported) ? s.exported.name : s.exported.value;
3518
+ exportsMap.set(exported, { local: s.local.name });
3519
+ }
3520
+ }
3521
+ const decl = node.declaration;
3522
+ if (t__namespace.isClassDeclaration(decl) && decl.id)
3523
+ exportsMap.set(decl.id.name, { local: decl.id.name });
3524
+ if (t__namespace.isVariableDeclaration(decl)) {
3525
+ for (const v of decl.declarations)
3526
+ if (t__namespace.isIdentifier(v.id))
3527
+ exportsMap.set(v.id.name, { local: v.id.name });
3528
+ }
3529
+ }
3530
+ }
3531
+ else if (t__namespace.isExportDefaultDeclaration(node)) {
3532
+ const decl = node.declaration;
3533
+ if (t__namespace.isClassDeclaration(decl)) {
3534
+ const local = decl.id?.name ?? '*default*';
3535
+ if (!decl.id)
3536
+ classes.set(local, decl);
3537
+ exportsMap.set('default', { local });
3538
+ }
3539
+ else if (t__namespace.isIdentifier(decl)) {
3540
+ exportsMap.set('default', { local: decl.name });
3541
+ }
3542
+ }
3543
+ else if (t__namespace.isExportAllDeclaration(node)) {
3544
+ starSources.push(node.source.value);
3545
+ }
3546
+ if (t__namespace.isClassDeclaration(node)) {
3547
+ noteClass(node, node.id?.name ?? (t__namespace.isExportDefaultDeclaration(parent) ? '*default*' : null));
3548
+ }
3549
+ else if (t__namespace.isClassExpression(node)) {
3550
+ const name = node.id?.name ?? (t__namespace.isVariableDeclarator(parent) && t__namespace.isIdentifier(parent.id) ? parent.id.name : null);
3551
+ noteClass(node, name);
3552
+ }
3553
+ for (const key of t__namespace.VISITOR_KEYS[node.type] ?? []) {
3554
+ const child = node[key];
3555
+ if (Array.isArray(child))
3556
+ child.forEach(c => walk(c, node));
3557
+ else
3558
+ walk(child, node);
3559
+ }
3560
+ };
3561
+ walk(ast.program, null);
3562
+ const baseOf = (cls, seen) => {
3563
+ if (seen.has(cls))
3564
+ return { kind: 'unknown' };
3565
+ seen.add(cls);
3566
+ const sup = cls.superClass;
3567
+ if (t__namespace.isIdentifier(sup)) {
3568
+ const imp = imports.get(sup.name);
3569
+ if (imp && imp.name !== '*')
3570
+ return { kind: 'import', source: imp.source, name: imp.name };
3571
+ const local = classes.get(sup.name);
3572
+ if (local)
3573
+ return baseOf(local, seen);
3574
+ return { kind: 'unknown' };
3575
+ }
3576
+ if (t__namespace.isMemberExpression(sup) && t__namespace.isIdentifier(sup.object) && !sup.computed && t__namespace.isIdentifier(sup.property)) {
3577
+ const imp = imports.get(sup.object.name);
3578
+ if (imp && imp.name === '*')
3579
+ return { kind: 'import', source: imp.source, name: sup.property.name };
3580
+ }
3581
+ return { kind: 'unknown' };
3582
+ };
3583
+ for (const { node, name } of classNodes) {
3584
+ if (!node.superClass)
3585
+ continue;
3586
+ let base;
3587
+ for (const m of node.body.body) {
3588
+ if (!(t__namespace.isClassMethod(m) || t__namespace.isClassPrivateMethod(m)) || m.static || t__namespace.isClassPrivateMethod(m))
3589
+ continue;
3590
+ if (m.kind === 'constructor')
3591
+ continue;
3592
+ const member = memberName(m);
3593
+ if (!member || !superNames.has(member))
3594
+ continue;
3595
+ const accessor = m.kind === 'get' ? 'get' : m.kind === 'set' ? 'set' : 'method';
3596
+ if (accessor === 'method' && !SUPER_METHODS.includes(member))
3597
+ continue;
3598
+ if (accessor !== 'method' && !SUPER_ACCESSORS.includes(member))
3599
+ continue;
3600
+ const result = checkMemberBody(m.body, member, accessor);
3601
+ if (result === 'ok')
3602
+ continue;
3603
+ base ??= baseOf(node, new Set());
3604
+ findings.push({
3605
+ className: name === '*default*' ? 'The default-exported class' : name,
3606
+ member,
3607
+ accessor,
3608
+ kind: result,
3609
+ line: m.loc?.start.line ?? 0,
3610
+ column: m.loc?.start.column ?? 0,
3611
+ classLine: node.loc?.start.line ?? 0,
3612
+ base,
3613
+ });
3614
+ }
3615
+ }
3616
+ return {
3617
+ findings,
3618
+ classBase(exportedOrLocal) {
3619
+ const cls = classes.get(exportedOrLocal);
3620
+ return cls ? baseOf(cls, new Set()) : null;
3621
+ },
3622
+ exportOf(name) {
3623
+ return exportsMap.get(name) ?? null;
3624
+ },
3625
+ starSources,
3626
+ };
3627
+ }
3628
+ function superCallMessage(f) {
3629
+ const target = f.accessor === 'get' ? `read super.${f.member}` : f.accessor === 'set' ? `assign super.${f.member}` : `call super.${f.member}(…)`;
3630
+ return f.kind === 'never'
3631
+ ? `${f.className}.${f.member} overrides a ComponentBase member and does not ${target}; MotifJS relies on it. Rename the member, or ${target} on every path.`
3632
+ : `${f.className}.${f.member} can finish without reaching super.${f.member} (a return, a branch, a loop or a catch skips it); MotifJS relies on it. ${target[0].toUpperCase() + target.slice(1)} on every path.`;
3633
+ }
3634
+ function createComponentResolver(resolve, read) {
3635
+ const cache = new Map();
3636
+ const shapes = new Map();
3637
+ const shapeOf = (file) => {
3638
+ let p = shapes.get(file);
3639
+ if (!p) {
3640
+ p = (async () => {
3641
+ const code = await read(file);
3642
+ if (code == null || code.length > 2_000_000)
3643
+ return null;
3644
+ const ast = parseModule(code, file);
3645
+ return ast ? analyzeModule(ast) : null;
3646
+ })();
3647
+ shapes.set(file, p);
3648
+ }
3649
+ return p;
3650
+ };
3651
+ const isComponentExport = (file, name, depth) => {
3652
+ const key = `${file}#${name}`;
3653
+ let p = cache.get(key);
3654
+ if (!p) {
3655
+ cache.set(key, Promise.resolve(false));
3656
+ p = (async () => {
3657
+ if (depth > 12)
3658
+ return false;
3659
+ const shape = await shapeOf(file);
3660
+ if (!shape)
3661
+ return false;
3662
+ const exp = shape.exportOf(name);
3663
+ if (exp?.from)
3664
+ return isComponentBase({ kind: 'import', source: exp.from, name: exp.imported ?? name }, file, depth + 1);
3665
+ const local = exp?.local ?? (name === 'default' ? '*default*' : null);
3666
+ if (local) {
3667
+ const base = shape.classBase(local);
3668
+ if (base)
3669
+ return isComponentBase(base, file, depth + 1);
3670
+ return false;
3671
+ }
3672
+ for (const star of shape.starSources) {
3673
+ if (await isComponentBase({ kind: 'import', source: star, name }, file, depth + 1))
3674
+ return true;
3675
+ }
3676
+ return false;
3677
+ })();
3678
+ cache.set(key, p);
3679
+ }
3680
+ return p;
3681
+ };
3682
+ const isComponentBase = async (base, importer, depth = 0) => {
3683
+ if (base.kind !== 'import')
3684
+ return false;
3685
+ if (isCoreSource(base.source))
3686
+ return isCoreComponent(base.name);
3687
+ let file = null;
3688
+ try {
3689
+ file = await resolve(base.source, importer);
3690
+ }
3691
+ catch {
3692
+ file = null;
3693
+ }
3694
+ if (!file)
3695
+ return false;
3696
+ return isComponentExport(file, base.name, depth);
3697
+ };
3698
+ return isComponentBase;
3699
+ }
3700
+
3159
3701
  const fileRegex = /\.(jsx|tsx|aio|mjsx|mtsx)$/;
3160
3702
  const decoratorFileRegex = /\.(ts|mts|cts|js|mjs|cjs)$/;
3161
3703
  const declarationFileRegex = /\.d\.[mc]?ts$/;
3162
3704
  const decoratorSyntaxRegex = /(?:^|[\s(,;{}])@[A-Za-z_$]/;
3163
3705
  const assetQueryRegex = /(?:^|&)(?:raw|url|worker|sharedworker|inline)(?:[&=]|$)/;
3706
+ const analyzableFileRegex = /\.(jsx|tsx|mjsx|mtsx|ts|mts|cts|js|mjs|cjs)$/;
3164
3707
  function sourceFile(id) {
3165
3708
  if (id.charCodeAt(0) === 0)
3166
3709
  return null;
@@ -3181,6 +3724,41 @@ function shouldLowerDecorators(id, src) {
3181
3724
  return false;
3182
3725
  return decoratorSyntaxRegex.test(src);
3183
3726
  }
3727
+ function shouldCheckSuperCalls(id, src) {
3728
+ const file = sourceFile(id);
3729
+ if (file === null || !analyzableFileRegex.test(file) || declarationFileRegex.test(file))
3730
+ return false;
3731
+ if (file.replace(/\\/g, '/').includes('/node_modules/'))
3732
+ return false;
3733
+ return mayHaveSuperOverrides(src);
3734
+ }
3735
+ function lineFrame(src, line, column) {
3736
+ const lines = src.split(/\r?\n/);
3737
+ if (line < 1 || line > lines.length)
3738
+ return undefined;
3739
+ const from = Math.max(1, line - 1);
3740
+ const to = Math.min(lines.length, line + 1);
3741
+ const width = String(to).length;
3742
+ const out = [];
3743
+ for (let i = from; i <= to; i++) {
3744
+ out.push(`${i === line ? '>' : ' '} ${String(i).padStart(width)} | ${lines[i - 1]}`);
3745
+ if (i === line)
3746
+ out.push(` ${' '.repeat(width)} | ${' '.repeat(column)}^`);
3747
+ }
3748
+ return out.join('\n');
3749
+ }
3750
+ async function checkSuperCalls(src, file, isComponentBase) {
3751
+ const ast = parseModule(src, file);
3752
+ if (!ast)
3753
+ return [];
3754
+ const out = [];
3755
+ for (const f of analyzeModule(ast).findings) {
3756
+ if (!(await isComponentBase(f.base, file)))
3757
+ continue;
3758
+ out.push({ code: 'MJX015', message: superCallMessage(f), file, line: f.line, frame: lineFrame(src, f.line, f.column) });
3759
+ }
3760
+ return out;
3761
+ }
3184
3762
  function legacyDecoratorsChecker() {
3185
3763
  const byConfig = new Map();
3186
3764
  return (file) => {
@@ -3208,10 +3786,45 @@ function explainMatches(opt, id) {
3208
3786
  function vitePlugin(options = {}) {
3209
3787
  const showDiagnostics = options.diagnostics !== false;
3210
3788
  const usesLegacyDecorators = legacyDecoratorsChecker();
3789
+ let context = null;
3790
+ const makeResolver = () => createComponentResolver(async (source, importer) => {
3791
+ if (!context?.resolve)
3792
+ return null;
3793
+ const r = await context.resolve(source, importer, { skipSelf: true });
3794
+ if (!r || r.external)
3795
+ return null;
3796
+ return sourceFile(r.id);
3797
+ }, async (file) => {
3798
+ try {
3799
+ return await node_fs.promises.readFile(file, 'utf8');
3800
+ }
3801
+ catch {
3802
+ return null;
3803
+ }
3804
+ });
3805
+ let isComponentBase = makeResolver();
3806
+ const pending = new Set();
3211
3807
  return {
3212
3808
  name: 'transform-file-motif-jsx',
3213
3809
  enforce: 'pre',
3810
+ watchChange() {
3811
+ isComponentBase = makeResolver();
3812
+ },
3813
+ handleHotUpdate() {
3814
+ isComponentBase = makeResolver();
3815
+ },
3816
+ async buildEnd() {
3817
+ await Promise.all([...pending]);
3818
+ },
3214
3819
  transform(src, id) {
3820
+ if (showDiagnostics && shouldCheckSuperCalls(id, src)) {
3821
+ context = this;
3822
+ const check = checkSuperCalls(src, sourceFile(id), isComponentBase)
3823
+ .then(found => { if (found.length > 0)
3824
+ printDiagnostics(found); }, () => { })
3825
+ .finally(() => { pending.delete(check); });
3826
+ pending.add(check);
3827
+ }
3215
3828
  if (shouldLowerDecorators(id, src)) {
3216
3829
  if (usesLegacyDecorators(sourceFile(id)))
3217
3830
  return;
@@ -3314,6 +3927,7 @@ function lintProgram(program, files) {
3314
3927
  continue;
3315
3928
  if (wanted && !wanted.has(normalize(sf.fileName)))
3316
3929
  continue;
3930
+ out.push(...superCallFindings(sf, checker));
3317
3931
  if (!/\.(tsx|jsx|mtsx|mjsx)$/.test(sf.fileName))
3318
3932
  continue;
3319
3933
  const visit = (node) => {
@@ -3369,6 +3983,60 @@ function lintProgram(program, files) {
3369
3983
  }
3370
3984
  return out;
3371
3985
  }
3986
+ const coreDeclarationFile = /[\\/](?:@motifx[\\/]core|motifjs[\\/](?:dist|src))[\\/]/;
3987
+ function derivesFromComponentBase(node, checker) {
3988
+ try {
3989
+ let type = checker.getTypeAtLocation(node);
3990
+ const seen = new Set();
3991
+ const queue = type ? [type] : [];
3992
+ while (queue.length > 0) {
3993
+ type = queue.shift();
3994
+ const target = (type.target ?? type);
3995
+ if (seen.has(target))
3996
+ continue;
3997
+ seen.add(target);
3998
+ const sym = target.getSymbol();
3999
+ if (sym && sym.getName() === 'ComponentBase' && sym.declarations?.some(d => coreDeclarationFile.test(d.getSourceFile().fileName)))
4000
+ return true;
4001
+ if (!(target.objectFlags & (ts__namespace.ObjectFlags.Class | ts__namespace.ObjectFlags.Interface)))
4002
+ continue;
4003
+ for (const b of checker.getBaseTypes(target) ?? [])
4004
+ queue.push(b);
4005
+ }
4006
+ }
4007
+ catch { }
4008
+ return false;
4009
+ }
4010
+ function superCallFindings(sf, checker) {
4011
+ if (!mayHaveSuperOverrides(sf.text))
4012
+ return [];
4013
+ const ast = parseModule(sf.text, sf.fileName);
4014
+ if (!ast)
4015
+ return [];
4016
+ const findings = analyzeModule(ast).findings;
4017
+ if (findings.length === 0)
4018
+ return [];
4019
+ const membersByLine = new Map();
4020
+ const collect = (n) => {
4021
+ if ((ts__namespace.isMethodDeclaration(n) || ts__namespace.isGetAccessorDeclaration(n) || ts__namespace.isSetAccessorDeclaration(n)) && (ts__namespace.isClassDeclaration(n.parent) || ts__namespace.isClassExpression(n.parent))) {
4022
+ const name = n.name && (ts__namespace.isIdentifier(n.name) || ts__namespace.isStringLiteral(n.name)) ? n.name.text : '';
4023
+ const lines = [n.getStart(sf), n.name.getStart(sf)].map(p => sf.getLineAndCharacterOfPosition(p).line + 1);
4024
+ for (const l of lines)
4025
+ membersByLine.set(`${l}:${name}`, n);
4026
+ }
4027
+ ts__namespace.forEachChild(n, collect);
4028
+ };
4029
+ collect(sf);
4030
+ const out = [];
4031
+ for (const f of findings) {
4032
+ const member = membersByLine.get(`${f.line}:${f.member}`);
4033
+ const cls = member?.parent;
4034
+ if (!member || !cls || !derivesFromComponentBase(cls, checker))
4035
+ continue;
4036
+ out.push({ code: 'MJX015', file: sf.fileName, line: f.line, message: superCallMessage(f), frame: codeFrame(sf, member) });
4037
+ }
4038
+ return out;
4039
+ }
3372
4040
  /** tsconfig'den program kurup denetler. CLI bunu kullanır. */
3373
4041
  function lintProject(options = {}) {
3374
4042
  const projectPath = options.project ?? 'tsconfig.json';