File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -6,6 +6,7 @@ export const recommended: Linter.Config = {
66 'php/disallow-references' : 'error' ,
77 'php/eqeqeq' : 'error' ,
88 'php/no-array-keyword' : 'error' ,
9+ 'php/no-final' : 'error' ,
910 'php/require-type-annotations' : 'error' ,
1011 'php/require-visibility' : 'error' ,
1112 } ,
Original file line number Diff line number Diff line change @@ -5,6 +5,7 @@ import { type ESLint } from 'eslint';
55import { disallowReferences } from './rules/disallow-references' ;
66import { eqeqeq } from './rules/eqeqeq' ;
77import { noArrayKeyword } from './rules/no-array-keyword' ;
8+ import { noFinal } from './rules/no-final' ;
89import { requireTypeAnnotations } from './rules/require-type-annotations' ;
910import { requireVisibility } from './rules/require-visibility' ;
1011
@@ -26,6 +27,7 @@ const plugin = {
2627 'disallow-references' : disallowReferences ,
2728 eqeqeq,
2829 'no-array-keyword' : noArrayKeyword ,
30+ 'no-final' : noFinal ,
2931 'require-type-annotations' : requireTypeAnnotations ,
3032 'require-visibility' : requireVisibility ,
3133 } ,
Original file line number Diff line number Diff line change 1+ import { RuleTester } from 'eslint' ;
2+
3+ import php from '../../index' ;
4+ import { noFinal } from '../no-final' ;
5+
6+ const ruleTester = new RuleTester ( {
7+ plugins : { php } ,
8+ language : 'php/php' ,
9+ } ) ;
10+
11+ ruleTester . run ( 'no-final' , noFinal , {
12+ valid : [
13+ {
14+ name : 'methods' ,
15+ code : `
16+ <?php
17+ class Test {
18+ public function method1() {}
19+ protected function method2() {}
20+ private function method3() {}
21+ }
22+ ` ,
23+ } ,
24+
25+ {
26+ name : 'properties' ,
27+ code : `
28+ <?php
29+ class Test {
30+ public $property1;
31+ protected $property2;
32+ private $property3;
33+ }
34+ ` ,
35+ } ,
36+ ] ,
37+ invalid : [
38+ {
39+ name : 'final class' ,
40+ code : '<?php final class Test {}' ,
41+ errors : [
42+ {
43+ messageId : 'noFinal' ,
44+ line : 1 ,
45+ column : 19 ,
46+ endLine : 1 ,
47+ endColumn : 23 ,
48+ } ,
49+ ] ,
50+ } ,
51+
52+ {
53+ name : 'final class constant' ,
54+ code : `
55+ <?php
56+ class Test {
57+ final const CONSTANT = 'value';
58+ }
59+ ` ,
60+ errors : [
61+ {
62+ messageId : 'noFinal' ,
63+ line : 4 ,
64+ column : 6 ,
65+ endLine : 4 ,
66+ endColumn : 36 ,
67+ suggestions : [
68+ {
69+ messageId : 'removeFinal' ,
70+ output : `
71+ <?php
72+ class Test {
73+ const CONSTANT = 'value';
74+ }
75+ ` ,
76+ } ,
77+ ] ,
78+ } ,
79+ ] ,
80+ } ,
81+
82+ {
83+ name : 'final class property' ,
84+ code : `
85+ <?php
86+ class Test {
87+ final public $property = 'value',
88+ $property2 = 'value-1';
89+ }
90+ ` ,
91+ errors : [
92+ {
93+ messageId : 'noFinal' ,
94+ line : 4 ,
95+ column : 6 ,
96+ endLine : 5 ,
97+ endColumn : 29 ,
98+ suggestions : [
99+ {
100+ messageId : 'removeFinal' ,
101+ output : `
102+ <?php
103+ class Test {
104+ public $property = 'value',
105+ $property2 = 'value-1';
106+ }
107+ ` ,
108+ } ,
109+ ] ,
110+ } ,
111+ ] ,
112+ } ,
113+
114+ {
115+ name : 'final class method' ,
116+ code : `
117+ <?php
118+ class Test {
119+ final public function method() {
120+ // Code
121+ }
122+ }
123+ ` ,
124+ errors : [
125+ {
126+ messageId : 'noFinal' ,
127+ line : 4 ,
128+ column : 28 ,
129+ endLine : 4 ,
130+ endColumn : 34 ,
131+ } ,
132+ ] ,
133+ } ,
134+ ] ,
135+ } ) ;
Original file line number Diff line number Diff line change 1+ import type { ClassConstant , Identifier , PropertyStatement } from 'php-parser' ;
2+
3+ import { createRule } from '../utils/create-rule' ;
4+
5+ type MessageIds = 'noFinal' | 'removeFinal' ;
6+ type Options = [ ] ;
7+
8+ export const noFinal = createRule < MessageIds , Options > ( {
9+ meta : {
10+ hasSuggestions : true ,
11+ type : 'suggestion' ,
12+ docs : {
13+ description : 'Disallow using the `final` keyword' ,
14+ } ,
15+ messages : {
16+ noFinal : 'The `final` keyword is not allowed.' ,
17+ removeFinal : 'Remove the `final` keyword`.' ,
18+ } ,
19+ schema : [ ] ,
20+ } ,
21+
22+ create ( context ) {
23+ return {
24+ 'class[isFinal=true] > .name, method[isFinal=true] > .name' (
25+ node : Identifier ,
26+ ) {
27+ context . report ( {
28+ node,
29+ messageId : 'noFinal' ,
30+ } ) ;
31+ } ,
32+
33+ 'classconstant, propertystatement' (
34+ node : ClassConstant | PropertyStatement ,
35+ ) {
36+ const finalKeyword = context . sourceCode . findClosestKeyword (
37+ node ,
38+ 'final' ,
39+ ) ;
40+
41+ if ( ! finalKeyword ) {
42+ return ;
43+ }
44+
45+ context . report ( {
46+ node,
47+ loc : {
48+ start : finalKeyword . start ,
49+ end : context . sourceCode . getLoc ( node ) . end ,
50+ } ,
51+ messageId : 'noFinal' ,
52+ suggest : [
53+ {
54+ messageId : 'removeFinal' ,
55+ fix ( fixer ) {
56+ return fixer . removeRange ( [
57+ finalKeyword . start . offset ,
58+ finalKeyword . end . offset ,
59+ ] ) ;
60+ } ,
61+ } ,
62+ ] ,
63+ } ) ;
64+ } ,
65+ } ;
66+ } ,
67+ } ) ;
You can’t perform that action at this time.
0 commit comments