@@ -226,8 +226,9 @@ ruleTester.run('no-get', rule, {
226226 } ,
227227 {
228228 // useOptionalChaining = false
229+ // We can safely autofix nested paths when the result of get() is chained,
229230 code : "foo1.foo2.get('bar.bar').baz;" ,
230- output : null ,
231+ output : 'foo1.foo2.bar.bar.baz;' ,
231232 options : [ { catchUnsafeObjects : true , useOptionalChaining : false } ] ,
232233 errors : [ { message : ERROR_MESSAGE_GET , type : 'CallExpression' } ] ,
233234 } ,
@@ -618,6 +619,18 @@ ruleTester.run('no-get', rule, {
618619 } ,
619620 ] ,
620621 } ,
622+ {
623+ // We can safely autofix nested paths when the result of get() is chained,
624+ code : "this.get('foo.0.bar')[123];" ,
625+ output : 'this.foo[0].bar[123];' ,
626+ options : [ { useOptionalChaining : true } ] ,
627+ errors : [
628+ {
629+ message : ERROR_MESSAGE_GET ,
630+ type : 'CallExpression' ,
631+ } ,
632+ ] ,
633+ } ,
621634 {
622635 // Handle array element access (left side of an assignment, entire string).
623636 code : "this.get('0')[123] = 'hello world';" ,
@@ -643,6 +656,194 @@ ruleTester.run('no-get', rule, {
643656 ] ,
644657 } ,
645658
659+ {
660+ code : `
661+ import { get } from '@ember/object';
662+ import { somethingElse } from '@ember/object';
663+ import { random } from 'random';
664+ get(this, 'foo.firstObject.bar');
665+ ` ,
666+ output : `
667+ import { get } from '@ember/object';
668+ import { somethingElse } from '@ember/object';
669+ import { random } from 'random';
670+ this.foo?.[0]?.bar;
671+ ` ,
672+ options : [ { useOptionalChaining : true } ] ,
673+ errors : [ { message : ERROR_MESSAGE_GET , type : 'CallExpression' } ] ,
674+ } ,
675+ {
676+ code : `
677+ import { get as g } from '@ember/object';
678+ import { somethingElse } from '@ember/object';
679+ import { random } from 'random';
680+ g(obj.baz.qux, 'foo.firstObject.bar');
681+ ` ,
682+ output : `
683+ import { get as g } from '@ember/object';
684+ import { somethingElse } from '@ember/object';
685+ import { random } from 'random';
686+ obj.baz.qux.foo?.[0]?.bar;
687+ ` ,
688+ options : [ { useOptionalChaining : true } ] ,
689+ errors : [ { message : ERROR_MESSAGE_GET , type : 'CallExpression' } ] ,
690+ } ,
691+ {
692+ // `firstObject` used in the middle of a path.
693+ // And the result of get() is chained (getResultIsChained=true).
694+ code : "this.get('foo.firstObject.bar')[123];" ,
695+ output : 'this.foo[0].bar[123];' ,
696+ options : [ { useOptionalChaining : true } ] ,
697+ errors : [
698+ {
699+ message : ERROR_MESSAGE_GET ,
700+ type : 'CallExpression' ,
701+ } ,
702+ ] ,
703+ } ,
704+ {
705+ // `firstObject` used in the middle of a path.
706+ // And the resolved path of `get` is NOT chained (getResultIsChained=false).
707+ code : "this.get('foo.firstObject.bar');" ,
708+ output : 'this.foo?.[0]?.bar;' ,
709+ options : [ { useOptionalChaining : true } ] ,
710+ errors : [
711+ {
712+ message : ERROR_MESSAGE_GET ,
713+ type : 'CallExpression' ,
714+ } ,
715+ ] ,
716+ } ,
717+ {
718+ // `firstObject` used at the beginning of a path.
719+ // And the resolved path of `get` is NOT chained (getResultIsChained=false).
720+ code : "this.get('firstObject.bar');" ,
721+ output : 'this[0]?.bar;' ,
722+ options : [ { useOptionalChaining : true } ] ,
723+ errors : [
724+ {
725+ message : ERROR_MESSAGE_GET ,
726+ type : 'CallExpression' ,
727+ } ,
728+ ] ,
729+ } ,
730+ {
731+ // `firstObject` used as the entire path.
732+ // And the result of get() is chained (getResultIsChained=true).
733+ code : "this.get('firstObject')[123];" ,
734+ output : 'this[0][123];' ,
735+ options : [ { useOptionalChaining : true } ] ,
736+ errors : [
737+ {
738+ message : ERROR_MESSAGE_GET ,
739+ type : 'CallExpression' ,
740+ } ,
741+ ] ,
742+ } ,
743+ {
744+ // `firstObject` used in the middle of a path.
745+ // And `get` is used in a left side of an assignment (isInLeftSideOfAssignmentExpression=true).
746+ code : "this.get('foo.firstObject.bar')[123] = 'hello world';" ,
747+ output : "this.foo[0].bar[123] = 'hello world';" ,
748+ options : [ { useOptionalChaining : true } ] ,
749+ errors : [
750+ {
751+ message : ERROR_MESSAGE_GET ,
752+ type : 'CallExpression' ,
753+ } ,
754+ ] ,
755+ } ,
756+ {
757+ // `lastObject` used in the middle of a path.
758+ // And the result of get() is chained (getResultIsChained=true).
759+ code : "this.get('foo.lastObject.bar')[123];" ,
760+ output : 'this.foo[this.foo.length - 1].bar[123];' ,
761+ options : [ { useOptionalChaining : true } ] ,
762+ errors : [
763+ {
764+ message : ERROR_MESSAGE_GET ,
765+ type : 'CallExpression' ,
766+ } ,
767+ ] ,
768+ } ,
769+ {
770+ // `lastObject` used at the beginning of a path.
771+ // And the result of get() is chained (getResultIsChained=true).
772+ code : "this.get('lastObject.bar')[123];" ,
773+ output : 'this[this.length - 1].bar[123];' ,
774+ options : [ { useOptionalChaining : true } ] ,
775+ errors : [
776+ {
777+ message : ERROR_MESSAGE_GET ,
778+ type : 'CallExpression' ,
779+ } ,
780+ ] ,
781+ } ,
782+ {
783+ // `lastObject` used as the entire path.
784+ // And the result of get() is chained (getResultIsChained=true).
785+ code : "this.get('lastObject')[123];" ,
786+ output : 'this[this.length - 1][123];' ,
787+ options : [ { useOptionalChaining : true } ] ,
788+ errors : [
789+ {
790+ message : ERROR_MESSAGE_GET ,
791+ type : 'CallExpression' ,
792+ } ,
793+ ] ,
794+ } ,
795+ {
796+ // `lastObject` used in the middle of a path.
797+ // And the resolved path of `get` is NOT chained (getResultIsChained=false).
798+ code : "this.get('foo.lastObject.bar');" ,
799+ output : 'this.foo?.[this.foo.length - 1]?.bar;' ,
800+ options : [ { useOptionalChaining : true } ] ,
801+ errors : [
802+ {
803+ message : ERROR_MESSAGE_GET ,
804+ type : 'CallExpression' ,
805+ } ,
806+ ] ,
807+ } ,
808+ {
809+ // `lastObject` used at the beginning of a path.
810+ // And the resolved path of `get` is NOT chained (getResultIsChained=false).
811+ code : "this.get('lastObject.bar');" ,
812+ output : 'this[this.length - 1]?.bar;' ,
813+ options : [ { useOptionalChaining : true } ] ,
814+ errors : [
815+ {
816+ message : ERROR_MESSAGE_GET ,
817+ type : 'CallExpression' ,
818+ } ,
819+ ] ,
820+ } ,
821+ {
822+ // `lastObject` used in the middle of a path.
823+ // When multiple `lastObject` are chained, it won't auto-fix.
824+ code : "this.get('foo.lastObject.bar.lastObject')[123];" ,
825+ output : null ,
826+ options : [ { useOptionalChaining : true } ] ,
827+ errors : [
828+ {
829+ message : ERROR_MESSAGE_GET ,
830+ type : 'CallExpression' ,
831+ } ,
832+ ] ,
833+ } ,
834+ {
835+ // `lastObject` used at the beginning of a path.
836+ // And the result of get() is chained (getResultIsChained=true).
837+ code : "this.get('lastObject.bar.lastObject')[123];" ,
838+ output : null ,
839+ options : [ { useOptionalChaining : true } ] ,
840+ errors : [
841+ {
842+ message : ERROR_MESSAGE_GET ,
843+ type : 'CallExpression' ,
844+ } ,
845+ ] ,
846+ } ,
646847 {
647848 // Reports violation after (classic) proxy class.
648849 code : `
0 commit comments