@dsivd/prestations-ng 19.0.5-beta.2 → 19.0.5-beta.4
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 +1 -0
- package/dsivd-prestations-ng-19.0.5-beta.4.tgz +0 -0
- package/fesm2022/dsivd-prestations-ng.mjs +0 -10
- package/fesm2022/dsivd-prestations-ng.mjs.map +1 -1
- package/package.json +1 -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.2.tgz +0 -0
package/package.json
CHANGED
|
@@ -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
|
+
};
|
|
@@ -205,7 +205,6 @@ declare abstract class FoehnInputComponent<T> implements OnInit, AfterViewInit {
|
|
|
205
205
|
onModelChange(value: T): void;
|
|
206
206
|
handleChange(value: T): void;
|
|
207
207
|
updateNgModel(value: T): void;
|
|
208
|
-
patchModel(patch: T extends object ? Partial<T> : never): void;
|
|
209
208
|
hasErrorsToDisplay(): boolean;
|
|
210
209
|
hasErrors(): boolean;
|
|
211
210
|
hasInheritErrorFromParent(): boolean;
|
|
Binary file
|