@dsivd/prestations-ng 19.0.5-beta.3 → 19.0.5-beta.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/ANGULAR_SIGNALS.md +0 -3
- package/UPGRADING_V19.md +5 -0
- package/dsivd-prestations-ng-19.0.5-beta.5.tgz +0 -0
- package/eslint/index.mjs +7 -0
- package/eslint/rules/__tests__/no-direct-signal-mutation.test.mjs +98 -0
- package/eslint/rules/index.mjs +1 -0
- package/eslint/rules/no-direct-signal-mutation.mjs +52 -0
- package/fesm2022/dsivd-prestations-ng.mjs +0 -10
- package/fesm2022/dsivd-prestations-ng.mjs.map +1 -1
- package/package.json +5 -1
- package/src/eslint/index.mjs +7 -0
- package/src/eslint/rules/__tests__/no-direct-signal-mutation.test.mjs +98 -0
- package/src/eslint/rules/index.mjs +1 -0
- package/src/eslint/rules/no-direct-signal-mutation.mjs +52 -0
- package/types/dsivd-prestations-ng.d.ts +0 -1
- package/dsivd-prestations-ng-19.0.5-beta.3.tgz +0 -0
package/ANGULAR_SIGNALS.md
CHANGED
package/UPGRADING_V19.md
CHANGED
|
@@ -1092,6 +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
|
+
import prestationsNgEslint from '@dsivd/prestations-ng/eslint';
|
|
1095
1096
|
|
|
1096
1097
|
export default tseslint.config(
|
|
1097
1098
|
{
|
|
@@ -1122,6 +1123,7 @@ export default tseslint.config(
|
|
|
1122
1123
|
rxjs,
|
|
1123
1124
|
'simple-import-sort': simpleImportSort,
|
|
1124
1125
|
'import-x': importX,
|
|
1126
|
+
'@dsivd/prestations-ng': prestationsNgEslint,
|
|
1125
1127
|
},
|
|
1126
1128
|
processor: angular.processInlineTemplates,
|
|
1127
1129
|
rules: {
|
|
@@ -1228,6 +1230,9 @@ export default tseslint.config(
|
|
|
1228
1230
|
// ── simple-import-sort ───────────────────────────────────────────
|
|
1229
1231
|
'simple-import-sort/imports': 'error',
|
|
1230
1232
|
'simple-import-sort/exports': 'error',
|
|
1233
|
+
|
|
1234
|
+
// ── prestations-ng ──────────────────────────────────────────────
|
|
1235
|
+
'@dsivd/prestations-ng/no-direct-signal-mutation': 'error',
|
|
1231
1236
|
},
|
|
1232
1237
|
},
|
|
1233
1238
|
|
|
Binary file
|
package/eslint/index.mjs
ADDED
|
@@ -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
|
+
};
|
|
@@ -793,16 +793,6 @@ class FoehnInputComponent {
|
|
|
793
793
|
this.modelEffect = effect(() => {
|
|
794
794
|
this.onModelChange(this.model());
|
|
795
795
|
}, ...(ngDevMode ? [{ debugName: "modelEffect" }] : /* istanbul ignore next */ []));
|
|
796
|
-
this.patchModel = (patch) => {
|
|
797
|
-
this.model.update((current) => {
|
|
798
|
-
if (current &&
|
|
799
|
-
typeof current === 'object' &&
|
|
800
|
-
!Array.isArray(current)) {
|
|
801
|
-
return { ...current, ...patch };
|
|
802
|
-
}
|
|
803
|
-
throw new Error('patchModel can only be used with object models.');
|
|
804
|
-
});
|
|
805
|
-
};
|
|
806
796
|
}
|
|
807
797
|
get errors() {
|
|
808
798
|
return this._errors?.sort((a, b) => ObjectHelper.stripHtml(a.message).localeCompare(ObjectHelper.stripHtml(b.message)));
|