@ethlete/eslint-plugin 0.1.0-next.4 → 0.1.0-next.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/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.0-next.7
4
+
5
+ ### Patch Changes
6
+
7
+ - [`7e8ac6b`](https://github.com/ethlete-io/ethdk/commit/7e8ac6bf18f580289c7c7966c6c33a2a7f077299) Thanks [@TomTomB](https://github.com/TomTomB)! - Fix false positives in pipes
8
+
9
+ ## 0.1.0-next.6
10
+
11
+ ### Patch Changes
12
+
13
+ - [`b73a127`](https://github.com/ethlete-io/ethdk/commit/b73a127002a06e3aa0c4e7e977b1ad1f3e04e7e6) Thanks [@TomTomB](https://github.com/TomTomB)! - Bump yet again, final one for sure, pinky promise
14
+
15
+ ## 0.1.0-beta.5
16
+
17
+ ### Patch Changes
18
+
19
+ - [`ddb5d09`](https://github.com/ethlete-io/ethdk/commit/ddb5d09e4bc56e18cc8c228aa78a200441e7a766) Thanks [@TomTomB](https://github.com/TomTomB)! - Bump to beta
20
+
3
21
  ## 0.1.0-next.4
4
22
 
5
23
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ethlete/eslint-plugin",
3
- "version": "0.1.0-next.4",
3
+ "version": "0.1.0-next.7",
4
4
  "license": "MIT",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -3,6 +3,23 @@
3
3
 
4
4
  const SCREAMING_CASE_RE = /^[A-Z][A-Z0-9_]*$/;
5
5
 
6
+ /**
7
+ * @param {any} classNode
8
+ */
9
+ const hasPipeDecorator = (classNode) => {
10
+ const decorators = classNode.decorators ?? [];
11
+ return decorators.some((/** @type {any} */ dec) => {
12
+ const expr = dec.expression;
13
+ if (expr.type === 'CallExpression') {
14
+ return expr.callee.type === 'Identifier' && expr.callee.name === 'Pipe';
15
+ }
16
+ if (expr.type === 'Identifier') {
17
+ return expr.name === 'Pipe';
18
+ }
19
+ return false;
20
+ });
21
+ };
22
+
6
23
  const REACTIVE_APIS = new Set([
7
24
  'signal',
8
25
  'computed',
@@ -309,6 +326,10 @@ const classConstantProperty = {
309
326
  continue;
310
327
  }
311
328
 
329
+ if (memberName === 'transform' && hasPipeDecorator(node.parent)) {
330
+ continue;
331
+ }
332
+
312
333
  if (!member.readonly) {
313
334
  context.report({
314
335
  node: member,
@@ -232,14 +232,11 @@ const sortMembers = (members) => {
232
232
  const remainingMembers = [...members];
233
233
  /** @type {TMemberEntry[]} */
234
234
  const sortedMembers = [];
235
+ const remainingNames = new Set(remainingMembers.map((m) => m.name));
235
236
 
236
237
  while (remainingMembers.length > 0) {
237
238
  const readyMembers = remainingMembers
238
- .filter((member) =>
239
- [...member.dependencies].every(
240
- (dependencyName) => !remainingMembers.some((remainingMember) => remainingMember.name === dependencyName),
241
- ),
242
- )
239
+ .filter((member) => [...member.dependencies].every((dependencyName) => !remainingNames.has(dependencyName)))
243
240
  .sort((left, right) => {
244
241
  if (left.groupIndex !== right.groupIndex) {
245
242
  return left.groupIndex - right.groupIndex;
@@ -258,6 +255,7 @@ const sortMembers = (members) => {
258
255
 
259
256
  const nextMemberIndex = remainingMembers.indexOf(nextMember);
260
257
  remainingMembers.splice(nextMemberIndex, 1);
258
+ remainingNames.delete(nextMember.name);
261
259
  }
262
260
 
263
261
  return sortedMembers;
@@ -377,6 +375,21 @@ const classMemberOrder = {
377
375
  return;
378
376
  }
379
377
 
378
+ // Methods live on the prototype and are available regardless of declaration order,
379
+ // so this.method() calls in initializers don't create real ordering dependencies.
380
+ const methodNames = new Set(
381
+ members.filter((m) => m.group === 'method' || m.group === 'private-method').map((m) => m.name),
382
+ );
383
+ if (methodNames.size > 0) {
384
+ for (const member of members) {
385
+ for (const dep of member.dependencies) {
386
+ if (methodNames.has(dep)) {
387
+ member.dependencies.delete(dep);
388
+ }
389
+ }
390
+ }
391
+ }
392
+
380
393
  const fix = buildClassOrderFix(sourceCode, node, members);
381
394
  let hasAttachedFix = false;
382
395
 
@@ -88,6 +88,20 @@ const templateMemberAccessibility = {
88
88
  },
89
89
  create(context) {
90
90
  const sourceCode = context.sourceCode;
91
+ /** @type {WeakMap<any, Set<string>>} */
92
+ const contractMembersCache = new WeakMap();
93
+
94
+ /**
95
+ * @param {any} classNode
96
+ */
97
+ const getContractMembers = (classNode) => {
98
+ if (contractMembersCache.has(classNode)) {
99
+ return contractMembersCache.get(classNode);
100
+ }
101
+ const result = getImplementedContractMemberNames({ classNode, context });
102
+ contractMembersCache.set(classNode, result);
103
+ return result;
104
+ };
91
105
 
92
106
  /**
93
107
  * @param {any} node
@@ -103,7 +117,7 @@ const templateMemberAccessibility = {
103
117
  const memberName = getMemberName(node);
104
118
  if (!memberName) return;
105
119
 
106
- const implementedContractMembers = getImplementedContractMemberNames({ classNode, context });
120
+ const implementedContractMembers = getContractMembers(classNode);
107
121
  const implementsPublicContract = implementedContractMembers.has(memberName);
108
122
 
109
123
  if (implementsPublicContract) {
@@ -160,7 +174,7 @@ const templateMemberAccessibility = {
160
174
  const memberName = getMemberName(node);
161
175
  if (!memberName) return;
162
176
 
163
- const implementedContractMembers = getImplementedContractMemberNames({ classNode, context });
177
+ const implementedContractMembers = getContractMembers(classNode);
164
178
  if (implementedContractMembers.has(memberName)) return;
165
179
 
166
180
  if (isReferencedFromTemplateOrHost(classNode, memberName, context)) return;