Skip to content
5 changes: 5 additions & 0 deletions .changeset/few-ducks-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'eslint-plugin-php': minor
---

Add `disallow-references` rule
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ export default defineConfig([

💡 - Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).

| Rule ID | Description | 🔧 | 💡 |
| ------------------------ | --------------------------------------------------- | --- | --- |
| `php/eqeqeq` | Require the use of `===` and `!==` | | |
| `php/no-array-keyword` | Disallow the use of the array keyword | 🔧 | |
| `php/require-visibility` | Require visibility for class methods and properties | | 💡 |
| Rule ID | Description | 🔧 | 💡 |
| ------------------------- | --------------------------------------------------- | --- | --- |
| `php/disallow-references` | Disallow the use of references | | 💡 |
| `php/eqeqeq` | Require the use of `===` and `!==` | | |
| `php/no-array-keyword` | Disallow the use of the array keyword | 🔧 | |
| `php/require-visibility` | Require visibility for class methods and properties | | 💡 |
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ESLint } from 'eslint';
import { PHPLanguage } from './language/php-language';

import { disallowReferences } from './rules/disallow-references';
import { eqeqeq } from './rules/eqeqeq';
import { noArrayKeyword } from './rules/no-array-keyword';
import { requireVisibility } from './rules/require-visibility';
Expand All @@ -14,6 +15,7 @@ const plugin = {
php: new PHPLanguage(),
},
rules: {
'disallow-references': disallowReferences,
eqeqeq,
'no-array-keyword': noArrayKeyword,
'require-visibility': requireVisibility,
Expand Down
97 changes: 97 additions & 0 deletions src/rules/__tests__/disallow-references.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { RuleTester, type Rule } from 'eslint';
import php from '../../index';
import { disallowReferences } from '../disallow-references';

const ruleTester = new RuleTester({
plugins: {
php,
},
language: 'php/php',
});

// TODO: Fix the types.
ruleTester.run(
'disallow-references',
disallowReferences as unknown as Rule.RuleModule,
{
valid: [
'<?php $a = [1, 2, 3]; $my_var = $a;',
'<?php function myFunc($var) { return []; }',
'<?php $used = function() use($var) {};',
],
invalid: [
{
code: '<?php $a = [1, 2, 3]; $my_var = &$a;',
errors: [
{
messageId: 'disallowReferences',
line: 1,
column: 33,
endLine: 1,
endColumn: 36,
suggestions: [
{
messageId: 'removeAmp',
output: '<?php $a = [1, 2, 3]; $my_var = $a;',
},
],
},
],
},
{
code: '<?php function myFunc(&$var) { return []; }',
errors: [
{
messageId: 'disallowReferences',
line: 1,
column: 23,
endLine: 1,
endColumn: 28,
suggestions: [
{
messageId: 'removeAmp',
output: '<?php function myFunc($var) { return []; }',
},
],
},
],
},
{
code: '<?php function &myFunc($var) { return []; }',
errors: [
{
messageId: 'disallowReferences',
line: 1,
column: 16,
endLine: 1,
endColumn: 23,
suggestions: [
{
messageId: 'removeAmp',
output: '<?php function myFunc($var) { return []; }',
},
],
},
],
},
{
code: '<?php $used = function() use(&$var) {};',
errors: [
{
messageId: 'disallowReferences',
line: 1,
column: 30,
endLine: 1,
endColumn: 35,
suggestions: [
{
messageId: 'removeAmp',
output: '<?php $used = function() use($var) {};',
},
],
},
],
},
],
},
);
57 changes: 57 additions & 0 deletions src/rules/disallow-references.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { createRule } from '../utils/create-rule';

type MessageIds = 'disallowReferences' | 'removeAmp';
type Options = [];

export const disallowReferences = createRule<MessageIds, Options>({
meta: {
type: 'suggestion',
fixable: 'code',
hasSuggestions: true,
docs: {
description: 'Disallow the use of references',
},
messages: {
disallowReferences: 'Do not use references (&).',
removeAmp: 'Remove the reference operator (&).',
},
schema: [],
},

create(context) {
return {
'assignref > .right, parameter[byref="true"], function[byref="true"] > .name, variable[byref="true"]'(
node,
) {
const ampKeyWord = context.sourceCode.findClosestKeyword(
node,
'&',
);

if (!ampKeyWord) {
return;
}

context.report({
node,
loc: {
start: ampKeyWord.start,
end: context.sourceCode.getLoc(node).end,
},
messageId: 'disallowReferences',
suggest: [
{
messageId: 'removeAmp',
fix(fixer) {
return fixer.removeRange([
ampKeyWord.start.offset,
ampKeyWord.end.offset,
]);
},
},
],
});
},
};
},
});