@dsivd/prestations-ng 19.0.5-beta.4 → 19.0.5

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/UPGRADING_V19.md CHANGED
@@ -1092,7 +1092,7 @@ import rxjs from '@smarttools/eslint-plugin-rxjs';
1092
1092
  import simpleImportSort from 'eslint-plugin-simple-import-sort';
1093
1093
  import prettier from 'eslint-config-prettier';
1094
1094
  import importX from 'eslint-plugin-import-x';
1095
- TODO LHE: publish beta + test + UPDATE EXAMPLE !!!
1095
+ import prestationsNgEslint from '@dsivd/prestations-ng/eslint';
1096
1096
 
1097
1097
  export default tseslint.config(
1098
1098
  {
@@ -1123,6 +1123,7 @@ export default tseslint.config(
1123
1123
  rxjs,
1124
1124
  'simple-import-sort': simpleImportSort,
1125
1125
  'import-x': importX,
1126
+ '@dsivd/prestations-ng': prestationsNgEslint,
1126
1127
  },
1127
1128
  processor: angular.processInlineTemplates,
1128
1129
  rules: {
@@ -1229,6 +1230,9 @@ export default tseslint.config(
1229
1230
  // ── simple-import-sort ───────────────────────────────────────────
1230
1231
  'simple-import-sort/imports': 'error',
1231
1232
  'simple-import-sort/exports': 'error',
1233
+
1234
+ // ── prestations-ng ──────────────────────────────────────────────
1235
+ '@dsivd/prestations-ng/no-direct-signal-mutation': 'error',
1232
1236
  },
1233
1237
  },
1234
1238
 
Binary file
@@ -0,0 +1,7 @@
1
+ import { noDirectSignalMutation } from './rules/index.mjs';
2
+
3
+ export default {
4
+ rules: {
5
+ 'no-direct-signal-mutation': noDirectSignalMutation,
6
+ },
7
+ };
@@ -0,0 +1,98 @@
1
+ import { describe, it } from 'vitest';
2
+ import { RuleTester } from 'eslint';
3
+ import rule from '../no-direct-signal-mutation.mjs';
4
+
5
+ describe('no-direct-signal-mutation', () => {
6
+ const ruleTester = new RuleTester({
7
+ languageOptions: {
8
+ ecmaVersion: 2020,
9
+ sourceType: 'module',
10
+ },
11
+ });
12
+
13
+ it('should validate signal mutation rule', () => {
14
+ ruleTester.run('no-direct-signal-mutation', rule, {
15
+ valid: [
16
+ // Using .update()
17
+ 'model.update((current) => ({ ...current, property: value }))',
18
+ 'this.model.update((current) => ({ ...current, property: value }))',
19
+ 'getSignal().update((current) => ({ ...current, property: value }))',
20
+
21
+ // Using .set()
22
+ 'model.set({ property: value })',
23
+ 'this.model.set({ property: value })',
24
+ 'getSignal().set({ property: value })',
25
+
26
+ // Regular property assignments
27
+ 'this.property = value',
28
+ 'obj.property = value',
29
+ 'this.obj.property = value',
30
+
31
+ // Reading from function calls (no assignment)
32
+ 'model().property',
33
+ 'this.model().property',
34
+ 'getSignal().property',
35
+
36
+ // Method calls on function results
37
+ 'model().someMethod()',
38
+ 'this.model().someMethod()',
39
+ 'getSignal().doSomething()',
40
+
41
+ // Assignments to non-function results
42
+ 'let x = value',
43
+ 'const obj = { prop: value }',
44
+ 'array[0] = value',
45
+
46
+ // Method chaining without assignment
47
+ 'model().update((v) => v).subscribe()',
48
+
49
+ // One-way bindings are OK
50
+ '[model]="model().property"',
51
+ '[ngModel]="model().comment"',
52
+ ],
53
+
54
+ invalid: [
55
+ {
56
+ code: "model().property = value",
57
+ errors: [{ messageId: 'directMutation' }],
58
+ },
59
+ {
60
+ code: "this.model().property = value",
61
+ errors: [{ messageId: 'directMutation' }],
62
+ },
63
+ {
64
+ code: "getSignal().property = value",
65
+ errors: [{ messageId: 'directMutation' }],
66
+ },
67
+ {
68
+ code: "model().nested.property = value",
69
+ errors: [{ messageId: 'directMutation' }],
70
+ },
71
+ {
72
+ code: "this.model().deeply.nested.property = value",
73
+ errors: [{ messageId: 'directMutation' }],
74
+ },
75
+ {
76
+ code: "obj.getter().property = value",
77
+ errors: [{ messageId: 'directMutation' }],
78
+ },
79
+ {
80
+ code: "model().property += value",
81
+ errors: [{ messageId: 'directMutation' }],
82
+ },
83
+ {
84
+ code: "model().property -= value",
85
+ errors: [{ messageId: 'directMutation' }],
86
+ },
87
+ {
88
+ code: "model().property *= value",
89
+ errors: [{ messageId: 'directMutation' }],
90
+ },
91
+ {
92
+ code: "model().array[0] = value",
93
+ errors: [{ messageId: 'directMutation' }],
94
+ },
95
+ ],
96
+ });
97
+ });
98
+ });
@@ -0,0 +1 @@
1
+ export { default as noDirectSignalMutation } from './no-direct-signal-mutation.mjs';
@@ -0,0 +1,52 @@
1
+ /**
2
+ * ESLint rule to detect direct mutations of signal/getter results.
3
+ * Warns against patterns like: model().property = value
4
+ * Suggests using .update() or .set() instead.
5
+ */
6
+ export default {
7
+ meta: {
8
+ type: "problem",
9
+ docs: {
10
+ description:
11
+ "Warn on direct property mutations of function call results (signals, getters, etc.)",
12
+ category: "Best Practices",
13
+ recommended: true,
14
+ },
15
+ messages: {
16
+ directMutation:
17
+ "Direct mutation of function call result detected. Use .update() or .set() instead of direct assignment.",
18
+ },
19
+ },
20
+
21
+ create(context) {
22
+ return {
23
+ AssignmentExpression(node) {
24
+ // Check if left side is a member expression with a call expression
25
+ if (
26
+ node.left.type === "MemberExpression" &&
27
+ isCallExpression(node.left.object)
28
+ ) {
29
+ context.report({
30
+ node,
31
+ messageId: "directMutation",
32
+ });
33
+ }
34
+ },
35
+ };
36
+
37
+ /**
38
+ * Recursively check if a node is a call expression.
39
+ * Handles: func().prop, obj.func().prop, this.func().prop, etc.
40
+ */
41
+ function isCallExpression(node) {
42
+ if (!node) return false;
43
+ if (node.type === "CallExpression") {
44
+ return true;
45
+ }
46
+ if (node.type === "MemberExpression") {
47
+ return isCallExpression(node.object);
48
+ }
49
+ return false;
50
+ }
51
+ },
52
+ };
package/package.json CHANGED
@@ -40,7 +40,7 @@
40
40
  "ng-update": {
41
41
  "migrations": "./schematics/migration-collection.json"
42
42
  },
43
- "version": "19.0.5-beta.4",
43
+ "version": "19.0.5",
44
44
  "module": "fesm2022/dsivd-prestations-ng.mjs",
45
45
  "typings": "types/dsivd-prestations-ng.d.ts",
46
46
  "exports": {
@@ -50,6 +50,10 @@
50
50
  ".": {
51
51
  "types": "./types/dsivd-prestations-ng.d.ts",
52
52
  "default": "./fesm2022/dsivd-prestations-ng.mjs"
53
+ },
54
+ "./eslint": {
55
+ "import": "./eslint/index.mjs",
56
+ "require": "./eslint/index.mjs"
53
57
  }
54
58
  },
55
59
  "sideEffects": false,