Skip to content

Commit 8710a7a

Browse files
Add isEmberSourceVersionAtLeast and gate no-tracked-built-ins on ember-source >= 6.8
Co-authored-by: NullVoxPopuli <[email protected]>
1 parent 21b8474 commit 8710a7a

4 files changed

Lines changed: 220 additions & 138 deletions

File tree

lib/rules/no-tracked-built-ins.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
const emberSourceVersion = require('../utils/ember-source-version');
4+
35
//------------------------------------------------------------------------------
46
// Mapping from tracked-built-ins exports to @ember/reactive/collections exports
57
//------------------------------------------------------------------------------
@@ -46,6 +48,11 @@ module.exports = {
4648
ERROR_MESSAGE_IMPORT,
4749

4850
create(context) {
51+
// Only report when ember-source >= 6.8 (which provides @ember/reactive/collections)
52+
if (!emberSourceVersion.isEmberSourceVersionAtLeast(6, 8)) {
53+
return {};
54+
}
55+
4956
// Track which imported identifiers map to tracked-built-ins classes
5057
// so we can fix `new TrackedArray(...)` → `trackedArray(...)`
5158
const trackedIdentifiers = new Map();

lib/utils/ember-source-version.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,21 @@ function isVersionAtLeast(version, major, minor) {
4545
return vMajor > major || (vMajor === major && vMinor >= minor);
4646
}
4747

48+
/**
49+
* Check if the installed ember-source version meets a minimum major.minor requirement.
50+
*
51+
* @param {number} major - Required minimum major version
52+
* @param {number} minor - Required minimum minor version
53+
* @param {string} [projectRoot] - Project root directory (defaults to process.cwd())
54+
* @returns {boolean} True if installed ember-source version >= major.minor
55+
*/
56+
function isEmberSourceVersionAtLeast(major, minor, projectRoot) {
57+
const version = getEmberSourceVersion(projectRoot);
58+
return isVersionAtLeast(version, major, minor);
59+
}
60+
4861
module.exports = {
4962
getEmberSourceVersion,
5063
isVersionAtLeast,
64+
isEmberSourceVersionAtLeast,
5165
};

tests/lib/rules/no-tracked-built-ins.js

Lines changed: 149 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// Requirements
55
//------------------------------------------------------------------------------
66

7+
const emberSourceVersionUtil = require('../../../lib/utils/ember-source-version');
78
const rule = require('../../../lib/rules/no-tracked-built-ins');
89
const RuleTester = require('eslint').RuleTester;
910

@@ -15,154 +16,164 @@ const { ERROR_MESSAGE_IMPORT } = rule;
1516
// Tests
1617
//------------------------------------------------------------------------------
1718

18-
const ruleTester = new RuleTester({
19-
parserOptions,
20-
parser: require.resolve('@babel/eslint-parser'),
21-
});
22-
23-
ruleTester.run('no-tracked-built-ins', rule, {
24-
valid: [
25-
// Already using @ember/reactive/collections
26-
"import { trackedArray } from '@ember/reactive/collections';",
27-
"import { trackedObject, trackedMap } from '@ember/reactive/collections';",
28-
29-
// Not tracked-built-ins
30-
"import { something } from 'other-package';",
31-
"import { TrackedArray } from 'some-other-package';",
32-
33-
// No import at all
34-
'const arr = [];',
35-
],
36-
37-
invalid: [
38-
// Single named import
39-
{
40-
code: "import { TrackedArray } from 'tracked-built-ins';",
41-
output: "import { trackedArray } from '@ember/reactive/collections';",
42-
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
43-
},
44-
45-
// Multiple named imports
46-
{
47-
code: "import { TrackedArray, TrackedObject } from 'tracked-built-ins';",
48-
output: "import { trackedArray, trackedObject } from '@ember/reactive/collections';",
49-
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
50-
},
51-
52-
// All tracked imports
53-
{
54-
code: "import { TrackedArray, TrackedObject, TrackedMap, TrackedSet, TrackedWeakMap, TrackedWeakSet } from 'tracked-built-ins';",
55-
output:
56-
"import { trackedArray, trackedObject, trackedMap, trackedSet, trackedWeakMap, trackedWeakSet } from '@ember/reactive/collections';",
57-
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
58-
},
59-
60-
// Aliased import
61-
{
62-
code: "import { TrackedArray as TA } from 'tracked-built-ins';",
63-
output: "import { trackedArray as TA } from '@ember/reactive/collections';",
64-
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
65-
},
66-
67-
// Default import (no autofix)
68-
{
69-
code: "import TrackedBuiltins from 'tracked-built-ins';",
70-
output: null,
71-
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
72-
},
73-
74-
// Default import with named imports (no autofix)
75-
{
76-
code: "import TrackedBuiltins, { TrackedArray } from 'tracked-built-ins';",
77-
output: null,
78-
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
79-
},
80-
81-
// new TrackedArray() with import
82-
{
83-
code: `import { TrackedArray } from 'tracked-built-ins';
19+
describe('no-tracked-built-ins', () => {
20+
beforeAll(() => {
21+
vi.spyOn(emberSourceVersionUtil, 'isEmberSourceVersionAtLeast').mockReturnValue(true);
22+
});
23+
24+
afterAll(() => {
25+
vi.restoreAllMocks();
26+
});
27+
28+
const ruleTester = new RuleTester({
29+
parserOptions,
30+
parser: require.resolve('@babel/eslint-parser'),
31+
});
32+
33+
ruleTester.run('no-tracked-built-ins', rule, {
34+
valid: [
35+
// Already using @ember/reactive/collections
36+
"import { trackedArray } from '@ember/reactive/collections';",
37+
"import { trackedObject, trackedMap } from '@ember/reactive/collections';",
38+
39+
// Not tracked-built-ins
40+
"import { something } from 'other-package';",
41+
"import { TrackedArray } from 'some-other-package';",
42+
43+
// No import at all
44+
'const arr = [];',
45+
],
46+
47+
invalid: [
48+
// Single named import
49+
{
50+
code: "import { TrackedArray } from 'tracked-built-ins';",
51+
output: "import { trackedArray } from '@ember/reactive/collections';",
52+
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
53+
},
54+
55+
// Multiple named imports
56+
{
57+
code: "import { TrackedArray, TrackedObject } from 'tracked-built-ins';",
58+
output: "import { trackedArray, trackedObject } from '@ember/reactive/collections';",
59+
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
60+
},
61+
62+
// All tracked imports
63+
{
64+
code: "import { TrackedArray, TrackedObject, TrackedMap, TrackedSet, TrackedWeakMap, TrackedWeakSet } from 'tracked-built-ins';",
65+
output:
66+
"import { trackedArray, trackedObject, trackedMap, trackedSet, trackedWeakMap, trackedWeakSet } from '@ember/reactive/collections';",
67+
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
68+
},
69+
70+
// Aliased import
71+
{
72+
code: "import { TrackedArray as TA } from 'tracked-built-ins';",
73+
output: "import { trackedArray as TA } from '@ember/reactive/collections';",
74+
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
75+
},
76+
77+
// Default import (no autofix)
78+
{
79+
code: "import TrackedBuiltins from 'tracked-built-ins';",
80+
output: null,
81+
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
82+
},
83+
84+
// Default import with named imports (no autofix)
85+
{
86+
code: "import TrackedBuiltins, { TrackedArray } from 'tracked-built-ins';",
87+
output: null,
88+
errors: [{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' }],
89+
},
90+
91+
// new TrackedArray() with import
92+
{
93+
code: `import { TrackedArray } from 'tracked-built-ins';
8494
const arr = new TrackedArray([1, 2, 3]);`,
85-
output: `import { trackedArray } from '@ember/reactive/collections';
95+
output: `import { trackedArray } from '@ember/reactive/collections';
8696
const arr = trackedArray([1, 2, 3]);`,
87-
errors: [
88-
{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' },
89-
{
90-
message:
91-
'Use `trackedArray(...)` instead of `new TrackedArray(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
92-
type: 'NewExpression',
93-
},
94-
],
95-
},
96-
97-
// new TrackedObject() with import
98-
{
99-
code: `import { TrackedObject } from 'tracked-built-ins';
97+
errors: [
98+
{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' },
99+
{
100+
message:
101+
'Use `trackedArray(...)` instead of `new TrackedArray(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
102+
type: 'NewExpression',
103+
},
104+
],
105+
},
106+
107+
// new TrackedObject() with import
108+
{
109+
code: `import { TrackedObject } from 'tracked-built-ins';
100110
const obj = new TrackedObject({ a: 1 });`,
101-
output: `import { trackedObject } from '@ember/reactive/collections';
111+
output: `import { trackedObject } from '@ember/reactive/collections';
102112
const obj = trackedObject({ a: 1 });`,
103-
errors: [
104-
{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' },
105-
{
106-
message:
107-
'Use `trackedObject(...)` instead of `new TrackedObject(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
108-
type: 'NewExpression',
109-
},
110-
],
111-
},
112-
113-
// new TrackedMap() with import
114-
{
115-
code: `import { TrackedMap } from 'tracked-built-ins';
113+
errors: [
114+
{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' },
115+
{
116+
message:
117+
'Use `trackedObject(...)` instead of `new TrackedObject(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
118+
type: 'NewExpression',
119+
},
120+
],
121+
},
122+
123+
// new TrackedMap() with import
124+
{
125+
code: `import { TrackedMap } from 'tracked-built-ins';
116126
const map = new TrackedMap();`,
117-
output: `import { trackedMap } from '@ember/reactive/collections';
127+
output: `import { trackedMap } from '@ember/reactive/collections';
118128
const map = trackedMap();`,
119-
errors: [
120-
{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' },
121-
{
122-
message:
123-
'Use `trackedMap(...)` instead of `new TrackedMap(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
124-
type: 'NewExpression',
125-
},
126-
],
127-
},
128-
129-
// Aliased import with new expression
130-
{
131-
code: `import { TrackedArray as TA } from 'tracked-built-ins';
129+
errors: [
130+
{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' },
131+
{
132+
message:
133+
'Use `trackedMap(...)` instead of `new TrackedMap(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
134+
type: 'NewExpression',
135+
},
136+
],
137+
},
138+
139+
// Aliased import with new expression
140+
{
141+
code: `import { TrackedArray as TA } from 'tracked-built-ins';
132142
const arr = new TA([1, 2, 3]);`,
133-
output: `import { trackedArray as TA } from '@ember/reactive/collections';
143+
output: `import { trackedArray as TA } from '@ember/reactive/collections';
134144
const arr = TA([1, 2, 3]);`,
135-
errors: [
136-
{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' },
137-
{
138-
message:
139-
'Use `trackedArray(...)` instead of `new TA(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
140-
type: 'NewExpression',
141-
},
142-
],
143-
},
144-
145-
// Multiple new expressions
146-
{
147-
code: `import { TrackedArray, TrackedMap } from 'tracked-built-ins';
145+
errors: [
146+
{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' },
147+
{
148+
message:
149+
'Use `trackedArray(...)` instead of `new TA(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
150+
type: 'NewExpression',
151+
},
152+
],
153+
},
154+
155+
// Multiple new expressions
156+
{
157+
code: `import { TrackedArray, TrackedMap } from 'tracked-built-ins';
148158
const arr = new TrackedArray();
149159
const map = new TrackedMap();`,
150-
output: `import { trackedArray, trackedMap } from '@ember/reactive/collections';
160+
output: `import { trackedArray, trackedMap } from '@ember/reactive/collections';
151161
const arr = trackedArray();
152162
const map = trackedMap();`,
153-
errors: [
154-
{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' },
155-
{
156-
message:
157-
'Use `trackedArray(...)` instead of `new TrackedArray(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
158-
type: 'NewExpression',
159-
},
160-
{
161-
message:
162-
'Use `trackedMap(...)` instead of `new TrackedMap(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
163-
type: 'NewExpression',
164-
},
165-
],
166-
},
167-
],
163+
errors: [
164+
{ message: ERROR_MESSAGE_IMPORT, type: 'ImportDeclaration' },
165+
{
166+
message:
167+
'Use `trackedArray(...)` instead of `new TrackedArray(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
168+
type: 'NewExpression',
169+
},
170+
{
171+
message:
172+
'Use `trackedMap(...)` instead of `new TrackedMap(...)`. The `@ember/reactive/collections` utilities do not use `new`.',
173+
type: 'NewExpression',
174+
},
175+
],
176+
},
177+
],
178+
});
168179
});

0 commit comments

Comments
 (0)