eslint-plugin-absolute 0.4.0 → 0.6.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.
Files changed (2) hide show
  1. package/dist/index.js +373 -56
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -194,7 +194,9 @@ var PURE_GLOBAL_IDENTIFIERS = new Set([
194
194
  "Boolean",
195
195
  "Date",
196
196
  "Function",
197
+ "JSON",
197
198
  "Map",
199
+ "Math",
198
200
  "Number",
199
201
  "Object",
200
202
  "Promise",
@@ -203,16 +205,145 @@ var PURE_GLOBAL_IDENTIFIERS = new Set([
203
205
  "String",
204
206
  "Symbol",
205
207
  "URL",
208
+ "globalThis",
206
209
  "undefined"
207
210
  ]);
208
- var PURE_GLOBAL_FUNCTIONS = new Set(["Boolean", "Number", "String"]);
211
+ var PURE_GLOBAL_FUNCTIONS = new Set([
212
+ "Boolean",
213
+ "Number",
214
+ "String",
215
+ "decodeURI",
216
+ "decodeURIComponent",
217
+ "encodeURI",
218
+ "encodeURIComponent",
219
+ "isFinite",
220
+ "isNaN",
221
+ "parseFloat",
222
+ "parseInt"
223
+ ]);
209
224
  var PURE_MEMBER_METHODS = new Set([
225
+ "toString",
226
+ "valueOf",
227
+ "at",
228
+ "charAt",
229
+ "charCodeAt",
230
+ "codePointAt",
231
+ "endsWith",
232
+ "includes",
233
+ "indexOf",
234
+ "lastIndexOf",
235
+ "match",
236
+ "matchAll",
237
+ "normalize",
238
+ "padEnd",
239
+ "padStart",
240
+ "repeat",
241
+ "replace",
242
+ "replaceAll",
243
+ "search",
244
+ "slice",
245
+ "split",
246
+ "startsWith",
247
+ "substr",
248
+ "substring",
249
+ "toLocaleLowerCase",
250
+ "toLocaleUpperCase",
251
+ "toLowerCase",
252
+ "toUpperCase",
253
+ "trim",
254
+ "trimEnd",
255
+ "trimStart",
256
+ "exec",
257
+ "test",
258
+ "toExponential",
259
+ "toFixed",
260
+ "toPrecision",
261
+ "isInteger",
262
+ "isSafeInteger",
263
+ "getDate",
210
264
  "getDay",
265
+ "getFullYear",
211
266
  "getHours",
212
267
  "getMilliseconds",
213
268
  "getMinutes",
269
+ "getMonth",
214
270
  "getSeconds",
215
- "padStart"
271
+ "getTime",
272
+ "getTimezoneOffset",
273
+ "getUTCDate",
274
+ "getUTCDay",
275
+ "getUTCFullYear",
276
+ "getUTCHours",
277
+ "getUTCMilliseconds",
278
+ "getUTCMinutes",
279
+ "getUTCMonth",
280
+ "getUTCSeconds",
281
+ "toDateString",
282
+ "toISOString",
283
+ "toJSON",
284
+ "toLocaleDateString",
285
+ "toLocaleString",
286
+ "toLocaleTimeString",
287
+ "toTimeString",
288
+ "toUTCString",
289
+ "abs",
290
+ "acos",
291
+ "acosh",
292
+ "asin",
293
+ "asinh",
294
+ "atan",
295
+ "atan2",
296
+ "atanh",
297
+ "cbrt",
298
+ "ceil",
299
+ "clz32",
300
+ "cos",
301
+ "cosh",
302
+ "exp",
303
+ "expm1",
304
+ "floor",
305
+ "fround",
306
+ "hypot",
307
+ "log",
308
+ "log10",
309
+ "log1p",
310
+ "log2",
311
+ "max",
312
+ "min",
313
+ "pow",
314
+ "round",
315
+ "sign",
316
+ "sin",
317
+ "sinh",
318
+ "sqrt",
319
+ "tan",
320
+ "tanh",
321
+ "trunc",
322
+ "entries",
323
+ "fromEntries",
324
+ "getOwnPropertyNames",
325
+ "getOwnPropertySymbols",
326
+ "getPrototypeOf",
327
+ "hasOwn",
328
+ "isArray",
329
+ "keys",
330
+ "values",
331
+ "concat",
332
+ "join",
333
+ "every",
334
+ "filter",
335
+ "find",
336
+ "findIndex",
337
+ "findLast",
338
+ "findLastIndex",
339
+ "flatMap",
340
+ "map",
341
+ "reduce",
342
+ "reduceRight",
343
+ "some",
344
+ "sort",
345
+ "parse",
346
+ "stringify"
216
347
  ]);
217
348
  var hasDuplicateNames = (names) => {
218
349
  const seen = new Set;
@@ -316,21 +447,27 @@ var sortKeysFixable = {
316
447
  });
317
448
  };
318
449
  const addTopLevelBindings = (statement) => {
319
- if (statement.type === "ImportDeclaration") {
320
- addImportBindings(statement);
450
+ let inner = statement;
451
+ if (inner.type === "ExportNamedDeclaration" && inner.declaration) {
452
+ inner = inner.declaration;
453
+ } else if (inner.type === "ExportDefaultDeclaration" && (inner.declaration.type === "FunctionDeclaration" || inner.declaration.type === "ClassDeclaration")) {
454
+ inner = inner.declaration;
455
+ }
456
+ if (inner.type === "ImportDeclaration") {
457
+ addImportBindings(inner);
321
458
  return;
322
459
  }
323
- if (statement.type === "FunctionDeclaration" && statement.id) {
324
- topLevelBindings.set(statement.id.name, {
460
+ if (inner.type === "FunctionDeclaration" && inner.id) {
461
+ topLevelBindings.set(inner.id.name, {
325
462
  kind: "function",
326
- node: statement
463
+ node: inner
327
464
  });
328
465
  return;
329
466
  }
330
- if (statement.type !== "VariableDeclaration" || statement.kind !== "const") {
467
+ if (inner.type !== "VariableDeclaration" || inner.kind !== "const") {
331
468
  return;
332
469
  }
333
- for (const declaration of statement.declarations) {
470
+ for (const declaration of inner.declarations) {
334
471
  addVariableBinding(declaration);
335
472
  }
336
473
  };
@@ -373,10 +510,14 @@ var sortKeysFixable = {
373
510
  };
374
511
  const addAncestorConstBindings = (ancestor, node, stableLocals) => {
375
512
  const addDeclarationBindings = (statement) => {
376
- if (statement.type !== "VariableDeclaration") {
513
+ let inner = statement;
514
+ if (inner.type === "ExportNamedDeclaration" && inner.declaration) {
515
+ inner = inner.declaration;
516
+ }
517
+ if (inner.type !== "VariableDeclaration") {
377
518
  return;
378
519
  }
379
- for (const declaration of statement.declarations) {
520
+ for (const declaration of inner.declarations) {
380
521
  addBoundIdentifiers(declaration.id, stableLocals);
381
522
  }
382
523
  };
@@ -399,11 +540,33 @@ var sortKeysFixable = {
399
540
  }
400
541
  addFunctionParamBindings(ancestor, stableLocals);
401
542
  };
543
+ const addForStatementBindings = (ancestor, stableLocals) => {
544
+ if (ancestor.type !== "ForOfStatement" && ancestor.type !== "ForInStatement" && ancestor.type !== "ForStatement") {
545
+ return;
546
+ }
547
+ const left = ancestor.type === "ForStatement" ? ancestor.init : ancestor.left;
548
+ if (!left)
549
+ return;
550
+ if (left.type === "VariableDeclaration") {
551
+ for (const declaration of left.declarations) {
552
+ addBoundIdentifiers(declaration.id, stableLocals);
553
+ }
554
+ } else {
555
+ addBoundIdentifiers(left, stableLocals);
556
+ }
557
+ };
558
+ const addCatchClauseBindings = (ancestor, stableLocals) => {
559
+ if (ancestor.type !== "CatchClause" || !ancestor.param)
560
+ return;
561
+ addBoundIdentifiers(ancestor.param, stableLocals);
562
+ };
402
563
  const getStableLocalsForNode = (node) => {
403
564
  const stableLocals = new Set;
404
565
  const ancestors = sourceCode.getAncestors(node);
405
566
  for (const ancestor of ancestors) {
406
567
  addFunctionBindingsForAncestor(ancestor, stableLocals);
568
+ addForStatementBindings(ancestor, stableLocals);
569
+ addCatchClauseBindings(ancestor, stableLocals);
407
570
  }
408
571
  for (const ancestor of ancestors) {
409
572
  addAncestorBindingsForNode(ancestor, node, stableLocals);
@@ -439,34 +602,60 @@ var sortKeysFixable = {
439
602
  }
440
603
  return false;
441
604
  };
442
- const isPureConstStatement = (statement, stableLocals, checkExpression) => {
443
- if (statement.kind !== "const") {
444
- return false;
445
- }
605
+ const isPureLocalVariableStatement = (statement, stableLocals) => {
446
606
  for (const declaration of statement.declarations) {
447
- if (declaration.id.type !== "Identifier" || !declaration.init) {
448
- return false;
449
- }
450
- if (!checkExpression(declaration.init)) {
451
- return false;
607
+ if (declaration.init) {
608
+ if (!isPureRuntimeExpression(declaration.init, stableLocals)) {
609
+ return false;
610
+ }
452
611
  }
453
- stableLocals.add(declaration.id.name);
612
+ addBoundIdentifiers(declaration.id, stableLocals);
454
613
  }
455
614
  return true;
456
615
  };
457
- const isPureFunctionStatement = (statement, stableLocals, checkExpression) => {
616
+ const isPureLocalAssignment = (expression, stableLocals) => {
617
+ if (expression.type !== "AssignmentExpression")
618
+ return false;
619
+ if (expression.operator !== "=") {}
620
+ if (expression.left.type !== "Identifier")
621
+ return false;
622
+ if (!stableLocals.has(expression.left.name))
623
+ return false;
624
+ return isPureRuntimeExpression(expression.right, stableLocals);
625
+ };
626
+ const isPureFunctionStatement = (statement, stableLocals) => {
458
627
  if (statement.type === "ReturnStatement") {
459
- return !statement.argument || checkExpression(statement.argument);
628
+ return !statement.argument || isPureRuntimeExpression(statement.argument, stableLocals);
460
629
  }
461
630
  if (statement.type === "VariableDeclaration") {
462
- return isPureConstStatement(statement, stableLocals, checkExpression);
631
+ return isPureLocalVariableStatement(statement, stableLocals);
632
+ }
633
+ if (statement.type === "ExpressionStatement") {
634
+ return isPureLocalAssignment(statement.expression, stableLocals);
635
+ }
636
+ if (statement.type === "IfStatement") {
637
+ if (!isPureRuntimeExpression(statement.test, stableLocals)) {
638
+ return false;
639
+ }
640
+ if (!isPureFunctionBranch(statement.consequent, new Set(stableLocals))) {
641
+ return false;
642
+ }
643
+ return !statement.alternate || isPureFunctionBranch(statement.alternate, new Set(stableLocals));
644
+ }
645
+ if (statement.type === "BlockStatement") {
646
+ return isPureFunctionBody(statement, new Set(stableLocals));
463
647
  }
464
648
  return false;
465
649
  };
466
- const isPureFunctionBody = (body, stableLocals, checkExpression) => {
650
+ const isPureFunctionBranch = (statement, stableLocals) => {
651
+ if (statement.type === "BlockStatement") {
652
+ return isPureFunctionBody(statement, stableLocals);
653
+ }
654
+ return isPureFunctionStatement(statement, stableLocals);
655
+ };
656
+ const isPureFunctionBody = (body, stableLocals) => {
467
657
  for (const statement of body.body) {
468
- const statementIsPure = isPureFunctionStatement(statement, stableLocals, checkExpression);
469
- if (!statementIsPure) {
658
+ if (!isPureFunctionStatement(statement, stableLocals)) {
470
659
  return false;
471
660
  }
472
661
  }
@@ -483,8 +672,7 @@ var sortKeysFixable = {
483
672
  pureFunctionInProgress.add(functionNode);
484
673
  const stableLocals = new Set;
485
674
  addFunctionParamBindings(functionNode, stableLocals);
486
- const checkExpression = (expression) => isPureRuntimeExpression(expression, stableLocals);
487
- const isPure = functionNode.body.type === "BlockStatement" ? isPureFunctionBody(functionNode.body, stableLocals, checkExpression) : checkExpression(functionNode.body);
675
+ const isPure = functionNode.body.type === "BlockStatement" ? isPureFunctionBody(functionNode.body, stableLocals) : isPureRuntimeExpression(functionNode.body, stableLocals);
488
676
  pureFunctionInProgress.delete(functionNode);
489
677
  pureFunctionCache.set(functionNode, isPure);
490
678
  return isPure;
@@ -585,35 +773,69 @@ var sortKeysFixable = {
585
773
  if (ts.isVariableDeclaration(declaration) && declaration.initializer && declaration.parent && ts.isVariableDeclarationList(declaration.parent) && declaration.parent.flags & ts.NodeFlags.Const) {
586
774
  return isPureTsExpression(declaration.initializer, new Set);
587
775
  }
588
- if (ts.isFunctionDeclaration(declaration) || ts.isClassDeclaration(declaration)) {
776
+ if (ts.isVariableDeclaration(declaration) || ts.isFunctionDeclaration(declaration) || ts.isClassDeclaration(declaration) || ts.isParameter(declaration) || ts.isBindingElement(declaration)) {
589
777
  return true;
590
778
  }
591
779
  return false;
592
780
  };
593
- const isPureTsBlock = (block, stableLocals) => {
594
- for (const statement of block.statements) {
595
- if (ts.isReturnStatement(statement)) {
596
- if (statement.expression && !isPureTsExpression(statement.expression, stableLocals)) {
597
- return false;
598
- }
599
- continue;
600
- }
601
- if (ts.isVariableStatement(statement)) {
602
- if (!(statement.declarationList.flags & ts.NodeFlags.Const)) {
603
- return false;
604
- }
605
- for (const declaration of statement.declarationList.declarations) {
606
- if (!ts.isIdentifier(declaration.name) || !declaration.initializer) {
607
- return false;
608
- }
781
+ const isPureTsLocalAssignment = (expression, stableLocals) => {
782
+ if (!ts.isBinaryExpression(expression))
783
+ return false;
784
+ if (!ASSIGNMENT_OPERATOR_KINDS.has(expression.operatorToken.kind))
785
+ return false;
786
+ if (!ts.isIdentifier(expression.left))
787
+ return false;
788
+ if (!stableLocals.has(expression.left.text))
789
+ return false;
790
+ return isPureTsExpression(expression.right, stableLocals);
791
+ };
792
+ const isPureTsStatement = (statement, stableLocals) => {
793
+ if (ts.isReturnStatement(statement)) {
794
+ return !statement.expression || isPureTsExpression(statement.expression, stableLocals);
795
+ }
796
+ if (ts.isVariableStatement(statement)) {
797
+ for (const declaration of statement.declarationList.declarations) {
798
+ if (declaration.initializer) {
609
799
  if (!isPureTsExpression(declaration.initializer, stableLocals)) {
610
800
  return false;
611
801
  }
612
- stableLocals.add(declaration.name.text);
613
802
  }
614
- continue;
803
+ addTsBoundIdentifiers(declaration.name, stableLocals);
804
+ }
805
+ return true;
806
+ }
807
+ if (ts.isExpressionStatement(statement)) {
808
+ return isPureTsLocalAssignment(statement.expression, stableLocals);
809
+ }
810
+ if (ts.isIfStatement(statement)) {
811
+ if (!isPureTsExpression(statement.expression, stableLocals)) {
812
+ return false;
813
+ }
814
+ const branchScope = new Set(stableLocals);
815
+ if (!isPureTsStatementOrBlock(statement.thenStatement, branchScope)) {
816
+ return false;
817
+ }
818
+ if (statement.elseStatement && !isPureTsStatementOrBlock(statement.elseStatement, new Set(stableLocals))) {
819
+ return false;
820
+ }
821
+ return true;
822
+ }
823
+ if (ts.isBlock(statement)) {
824
+ return isPureTsBlock(statement, new Set(stableLocals));
825
+ }
826
+ return false;
827
+ };
828
+ const isPureTsStatementOrBlock = (statement, stableLocals) => {
829
+ if (ts.isBlock(statement)) {
830
+ return isPureTsBlock(statement, stableLocals);
831
+ }
832
+ return isPureTsStatement(statement, stableLocals);
833
+ };
834
+ const isPureTsBlock = (block, stableLocals) => {
835
+ for (const statement of block.statements) {
836
+ if (!isPureTsStatement(statement, stableLocals)) {
837
+ return false;
615
838
  }
616
- return false;
617
839
  }
618
840
  return true;
619
841
  };
@@ -641,7 +863,7 @@ var sortKeysFixable = {
641
863
  const isPureTsCallExpression = (node, stableLocals) => {
642
864
  const argsArePure = node.arguments.every((argument) => {
643
865
  if (ts.isSpreadElement(argument)) {
644
- return false;
866
+ return isPureTsExpression(argument.expression, stableLocals);
645
867
  }
646
868
  return isPureTsExpression(argument, stableLocals);
647
869
  });
@@ -652,6 +874,12 @@ var sortKeysFixable = {
652
874
  if (calleePath !== null && pureImports.has(calleePath)) {
653
875
  return true;
654
876
  }
877
+ if (ts.isPropertyAccessExpression(node.expression)) {
878
+ const memberName = node.expression.name.text;
879
+ if (PURE_MEMBER_METHODS.has(memberName)) {
880
+ return isPureTsExpression(node.expression.expression, stableLocals);
881
+ }
882
+ }
655
883
  const calleeId = getCalleeIdentifier(node.expression);
656
884
  if (!calleeId) {
657
885
  return false;
@@ -705,6 +933,9 @@ var sortKeysFixable = {
705
933
  if (ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) {
706
934
  return isPureTsExpression(node.operand, stableLocals);
707
935
  }
936
+ if (ts.isTypeOfExpression(node) || ts.isVoidExpression(node)) {
937
+ return isPureTsExpression(node.expression, stableLocals);
938
+ }
708
939
  if (ts.isBinaryExpression(node)) {
709
940
  if (ASSIGNMENT_OPERATOR_KINDS.has(node.operatorToken.kind) || node.operatorToken.kind === ts.SyntaxKind.CommaToken) {
710
941
  return false;
@@ -717,7 +948,7 @@ var sortKeysFixable = {
717
948
  if (ts.isArrayLiteralExpression(node)) {
718
949
  return node.elements.every((element) => {
719
950
  if (ts.isSpreadElement(element)) {
720
- return false;
951
+ return isPureTsExpression(element.expression, stableLocals);
721
952
  }
722
953
  if (element.kind === ts.SyntaxKind.OmittedExpression) {
723
954
  return false;
@@ -828,6 +1059,73 @@ var sortKeysFixable = {
828
1059
  }
829
1060
  return isPureImportedCallExpression(callExpression);
830
1061
  };
1062
+ const getCallReturnTypeSymbol = (node) => {
1063
+ if (!tsChecker || !esTreeNodeToTSNodeMap)
1064
+ return;
1065
+ const tsNode = esTreeNodeToTSNodeMap.get(node);
1066
+ if (!tsNode)
1067
+ return;
1068
+ const type = tsChecker.getTypeAtLocation(tsNode);
1069
+ return type.symbol ?? type.aliasSymbol;
1070
+ };
1071
+ const isObjectLikeType = (type) => {
1072
+ if (type.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.Void)) {
1073
+ return false;
1074
+ }
1075
+ if (type.flags & ts.TypeFlags.Union) {
1076
+ return type.types.every((member) => {
1077
+ if (member.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined | ts.TypeFlags.Void)) {
1078
+ return true;
1079
+ }
1080
+ return isObjectLikeType(member);
1081
+ });
1082
+ }
1083
+ return Boolean(type.flags & (ts.TypeFlags.Object | ts.TypeFlags.Intersection));
1084
+ };
1085
+ const callReturnsNominalInstance = (node) => {
1086
+ if (!tsChecker || !esTreeNodeToTSNodeMap)
1087
+ return false;
1088
+ const tsNode = esTreeNodeToTSNodeMap.get(node);
1089
+ if (!tsNode)
1090
+ return false;
1091
+ const type = tsChecker.getTypeAtLocation(tsNode);
1092
+ return isObjectLikeType(type);
1093
+ };
1094
+ const isEncapsulatedFreshExpression = (node, stableLocals) => {
1095
+ if (!node)
1096
+ return false;
1097
+ if (node.type === "TSAsExpression" || node.type === "TSTypeAssertion" || node.type === "TSNonNullExpression" || node.type === "TSSatisfiesExpression" || node.type === "TSInstantiationExpression") {
1098
+ return isEncapsulatedFreshExpression(node.expression, stableLocals);
1099
+ }
1100
+ if (node.type === "ObjectExpression" || node.type === "ArrayExpression") {
1101
+ return isPureRuntimeExpression(node, stableLocals);
1102
+ }
1103
+ if (node.type === "NewExpression") {
1104
+ return node.arguments.every((argument) => {
1105
+ if (argument.type === "SpreadElement") {
1106
+ return isPureRuntimeExpression(argument.argument, stableLocals);
1107
+ }
1108
+ return isPureRuntimeExpression(argument, stableLocals);
1109
+ });
1110
+ }
1111
+ if (node.type === "CallExpression") {
1112
+ const argsArePure = node.arguments.every((argument) => {
1113
+ if (argument.type === "SpreadElement") {
1114
+ return isPureRuntimeExpression(argument.argument, stableLocals);
1115
+ }
1116
+ return isPureRuntimeExpression(argument, stableLocals);
1117
+ });
1118
+ if (!argsArePure)
1119
+ return false;
1120
+ if (node.callee.type === "MemberExpression") {
1121
+ return isEncapsulatedFreshExpression(node.callee.object, stableLocals);
1122
+ }
1123
+ if (node.callee.type === "Identifier") {
1124
+ return callReturnsNominalInstance(node);
1125
+ }
1126
+ }
1127
+ return false;
1128
+ };
831
1129
  const isPureRuntimeExpression = (node, stableLocals) => {
832
1130
  if (!node || node.type === "PrivateIdentifier") {
833
1131
  return false;
@@ -858,9 +1156,12 @@ var sortKeysFixable = {
858
1156
  return isPureRuntimeExpression(node.test, stableLocals) && isPureRuntimeExpression(node.consequent, stableLocals) && isPureRuntimeExpression(node.alternate, stableLocals);
859
1157
  case "ArrayExpression":
860
1158
  return node.elements.every((element) => {
861
- if (!element || element.type === "SpreadElement") {
1159
+ if (!element) {
862
1160
  return false;
863
1161
  }
1162
+ if (element.type === "SpreadElement") {
1163
+ return isPureRuntimeExpression(element.argument, stableLocals);
1164
+ }
864
1165
  return isPureRuntimeExpression(element, stableLocals);
865
1166
  });
866
1167
  case "ObjectExpression":
@@ -878,13 +1179,20 @@ var sortKeysFixable = {
878
1179
  });
879
1180
  case "MemberExpression":
880
1181
  return isPureRuntimeExpression(node.object, stableLocals) && (!node.computed || isPureRuntimeExpression(node.property, stableLocals));
881
- case "NewExpression":
882
- return node.callee.type === "Identifier" && PURE_CONSTRUCTORS.has(node.callee.name) && node.arguments.every((argument) => {
1182
+ case "NewExpression": {
1183
+ const argsArePure = node.arguments.every((argument) => {
883
1184
  if (argument.type === "SpreadElement") {
884
- return false;
1185
+ return isPureRuntimeExpression(argument.argument, stableLocals);
885
1186
  }
886
1187
  return isPureRuntimeExpression(argument, stableLocals);
887
1188
  });
1189
+ if (!argsArePure)
1190
+ return false;
1191
+ if (node.callee.type === "Identifier" && PURE_CONSTRUCTORS.has(node.callee.name)) {
1192
+ return true;
1193
+ }
1194
+ return true;
1195
+ }
888
1196
  case "CallExpression": {
889
1197
  const argsArePure = node.arguments.every((argument) => {
890
1198
  if (argument.type === "SpreadElement") {
@@ -900,7 +1208,10 @@ var sortKeysFixable = {
900
1208
  return true;
901
1209
  }
902
1210
  if (node.callee.type === "Identifier") {
903
- return isPureIdentifierCall(node);
1211
+ if (isPureIdentifierCall(node)) {
1212
+ return true;
1213
+ }
1214
+ return callReturnsNominalInstance(node);
904
1215
  }
905
1216
  if (node.callee.type !== "MemberExpression") {
906
1217
  return false;
@@ -909,6 +1220,12 @@ var sortKeysFixable = {
909
1220
  if (memberName && PURE_MEMBER_METHODS.has(memberName)) {
910
1221
  return isPureRuntimeExpression(node.callee.object, stableLocals);
911
1222
  }
1223
+ if (isEncapsulatedFreshExpression(node.callee.object, stableLocals)) {
1224
+ return true;
1225
+ }
1226
+ if (isPureRuntimeExpression(node.callee.object, stableLocals) && callReturnsNominalInstance(node)) {
1227
+ return true;
1228
+ }
912
1229
  return isPureImportedCallExpression(node);
913
1230
  }
914
1231
  default:
package/package.json CHANGED
@@ -40,5 +40,5 @@
40
40
  "typecheck": "bun run tsc --noEmit"
41
41
  },
42
42
  "type": "module",
43
- "version": "0.4.0"
43
+ "version": "0.6.0"
44
44
  }