@lexical/eslint-plugin 0.44.1-nightly.20260519.0 → 0.45.0

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.
@@ -25,7 +25,7 @@ function getDefaultExportFromCjs (x) {
25
25
  }
26
26
 
27
27
  var name = "@lexical/eslint-plugin";
28
- var version = "0.44.1-nightly.20260519.0";
28
+ var version = "0.45.0";
29
29
  var require$$0 = {
30
30
  name: name,
31
31
  version: version};
@@ -23,7 +23,7 @@ function getDefaultExportFromCjs (x) {
23
23
  }
24
24
 
25
25
  var name = "@lexical/eslint-plugin";
26
- var version = "0.44.1-nightly.20260519.0";
26
+ var version = "0.45.0";
27
27
  var require$$0 = {
28
28
  name: name,
29
29
  version: version};
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ "use strict";function e(e,n){for(var t=0;t<n.length;t++){var r=n[t];if("string"!=typeof r&&!Array.isArray(r))for(var i in r)"default"===i||i in e||(e[i]=r[i])}return e}function n(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var t,r,i={name:"@lexical/eslint-plugin",version:"0.45.0"},o={},s={},a={};function l(){return t||(t=1,a.getParentAssignmentName=function(e){const n=e.parent;if(null!=n)return"VariableDeclarator"===n.type&&n.init===e?n.id:"AssignmentExpression"===n.type&&n.right===e&&"="===n.operator?n.left:void 0}),a}function c(){if(r)return s;r=1;const{getParentAssignmentName:e}=l();return s.getFunctionName=function(n){return"FunctionDeclaration"===n.type||"FunctionExpression"===n.type&&n.id?n.id:"FunctionExpression"===n.type||"ArrowFunctionExpression"===n.type?e(n):void 0},s}var u,f,p,d,g={};function x(){if(u)return g;function e(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}return u=1,g.buildMatcher=function(...n){const t=[],r=[];for(const i of n.flat(1))i&&("string"==typeof i?r.push(/^[(^]/.test(i)?i:`^${e(i)}$`):i&&i instanceof RegExp?i.flags?t.push(e=>i.test(e)):r.push(i.source):"function"==typeof i&&t.push(i));const i=r.map(e=>`(?:${e})`).join("|");if(i){const e=new RegExp(i);t.push(n=>e.test(n))}return e=>{if(e){if("Identifier"!==e.type)throw new Error(`Expecting Identifier, not ${e.type}`);for(const n of t)if(n(e.name,e))return!0}return!1}},g}function m(){if(f)return o;f=1;const{getFunctionName:e}=c(),{getParentAssignmentName:n}=l(),{buildMatcher:t}=x();const r={isDollarFunction:[/^\$[a-z_]/],isIgnoredFunction:[],isLexicalProvider:["parseEditorState","read","registerCommand","registerNodeTransform","update"],isSafeDollarFunction:[/^\$is[A-Z_]/]};function i(e){if(e)return"Identifier"===e.type?e:"MemberExpression"!==e.type||e.computed?void 0:i(e.property)}function s(e,n){const t=Array.isArray(e.options)?e.options[0]:void 0;return t&&n in t?t[n]:void 0}const a={oneOf:[{type:"string"},{contains:{type:"string"},type:"array"}]};return o.rulesOfLexical={create(o){const a=function(e){return e.sourceCode?e.sourceCode:e.getSourceCode()}(o),l=function(e){const n={};for(const i in r){const o=i;n[o]=t(r[o],s(e,o))}return n}(o),c=new Set,u=new Set,f=[],p=e=>c.add(e),d=e=>c.delete(e),g=t=>{const r=i(function(t){const r=e(t);if(r)return r;const o=t.parent;if(null!=o&&"CallExpression"===o.type&&o.arguments[0]===t&&function(e){return e&&"Identifier"===e.type&&/^use([A-Z]|$)/.test(e.name)}(i(o.callee)))return n(o)}(t));f.push({name:r,node:t}),(l.isDollarFunction(r)||l.isIgnoredFunction(r)||l.isLexicalProvider(r))&&p(t)},x=e=>{f.pop(),d(e)};return{ArrowFunctionExpression:g,"ArrowFunctionExpression:exit":x,CallExpression:e=>{if((()=>{if(c.size>0)return!0;const e=f[f.length-1];return e&&null!=e.node.parent&&"Property"===e.node.parent.type})())return;const n=i(e.callee);if(l.isLexicalProvider(n)||l.isSafeDollarFunction(n))return void p(e);if(!l.isDollarFunction(n))return;const t=(()=>{const e=f[f.length-1];return e?e.name:void 0})();if(!t||u.has(t))return;u.add(t);const r=function(e,n){const t=e.scopeManager;for(let e=n;e;e=e.parent){const r=t.getDeclaredVariables(e).find(e=>e.identifiers.includes(n));if(r)return r;const i=t.acquire(e);if(i)return i.set.get(n.name)||(i.upper?i.upper.set.get(n.name):void 0)}}(a,t),s=function(e,n){const t=function(e){return/^[a-z]/.test(e)?"$"+e:/^[A-Z][a-z]/.test(e)?"$"+e.slice(0,1).toLowerCase()+e.slice(1):`$_${e}`}(e.name);if(n)for(let e=n.scope;e;e=e.upper)if(e.set.has(t))return t+"_";return t}(t,r),d=function(e){if(e&&1===e.defs.length){const n=e.defs[0].node.parent;if(null!=n&&"ExportNamedDeclaration"===n.type)return n;if(null!=n&&"VariableDeclaration"===n.type&&null!=n.parent&&"ExportNamedDeclaration"===n.parent.type)return n.parent}}(r),g={callee:a.getText(e.callee),caller:a.getText(t),suggestName:s},x=e=>{const n=new Set,i=[],o=t=>{n.has(t)||(n.add(t),i.push(e.replaceText(t,s)))};if(o(t),d&&i.push(e.insertTextAfter(d,function({caller:e,suggestName:n}){return`\n/** @deprecated renamed to {@link ${n}} by @lexical/eslint-plugin rules-of-lexical */\nexport const ${e} = ${n};`}(g))),r)for(const e of r.references)o(e.identifier);return i};o.report({data:g,fix:x,messageId:"rulesOfLexicalReport",node:t,suggest:[{data:g,fix:x,messageId:"rulesOfLexicalSuggestion"}]})},"CallExpression:exit":d,ClassBody:p,"ClassBody:exit":d,FunctionDeclaration:g,"FunctionDeclaration:exit":x,FunctionExpression:g,"FunctionExpression:exit":x}},meta:{docs:{description:"enforces the Rules of Lexical",recommended:!0,url:"https://lexical.dev/docs/packages/lexical-eslint-plugin"},fixable:"code",hasSuggestions:!0,messages:{rulesOfLexicalReport:"{{ callee }} called from {{ caller }}, without $ prefix or read/update context",rulesOfLexicalSuggestion:"Rename {{ caller }} to {{ suggestName }}"},schema:[{additionalProperties:!1,properties:{isDollarFunction:a,isIgnoredFunction:a,isLexicalProvider:a,isSafeDollarFunction:a},type:"object"}],type:"suggestion"}},o}function y(){if(d)return p;d=1;const{name:e,version:n}=i,{rulesOfLexical:t}=m(),r={plugins:["@lexical"],rules:{"@lexical/rules-of-lexical":"warn"}},o={configs:{all:r,"flat/all":null,"flat/recommended":null,"legacy-all":r,"legacy-recommended":r,recommended:r},meta:{name:e,version:n},rules:{"rules-of-lexical":t}},s={plugins:{"@lexical":o},rules:{"@lexical/rules-of-lexical":"warn"}};return o.configs["flat/all"]=s,o.configs["flat/recommended"]=s,p=o}var h=y();const v=e({__proto__:null,default:n(h)},[h]);module.exports=v;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ function e(e,n){for(var t=0;t<n.length;t++){var r=n[t];if("string"!=typeof r&&!Array.isArray(r))for(var i in r)"default"===i||i in e||(e[i]=r[i])}return e}function n(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var t,r,i={name:"@lexical/eslint-plugin",version:"0.45.0"},o={},s={},a={};function l(){return t||(t=1,a.getParentAssignmentName=function(e){const n=e.parent;if(null!=n)return"VariableDeclarator"===n.type&&n.init===e?n.id:"AssignmentExpression"===n.type&&n.right===e&&"="===n.operator?n.left:void 0}),a}function c(){if(r)return s;r=1;const{getParentAssignmentName:e}=l();return s.getFunctionName=function(n){return"FunctionDeclaration"===n.type||"FunctionExpression"===n.type&&n.id?n.id:"FunctionExpression"===n.type||"ArrowFunctionExpression"===n.type?e(n):void 0},s}var u,f,p,d,g={};function x(){if(u)return g;function e(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}return u=1,g.buildMatcher=function(...n){const t=[],r=[];for(const i of n.flat(1))i&&("string"==typeof i?r.push(/^[(^]/.test(i)?i:`^${e(i)}$`):i&&i instanceof RegExp?i.flags?t.push(e=>i.test(e)):r.push(i.source):"function"==typeof i&&t.push(i));const i=r.map(e=>`(?:${e})`).join("|");if(i){const e=new RegExp(i);t.push(n=>e.test(n))}return e=>{if(e){if("Identifier"!==e.type)throw new Error(`Expecting Identifier, not ${e.type}`);for(const n of t)if(n(e.name,e))return!0}return!1}},g}function m(){if(f)return o;f=1;const{getFunctionName:e}=c(),{getParentAssignmentName:n}=l(),{buildMatcher:t}=x();const r={isDollarFunction:[/^\$[a-z_]/],isIgnoredFunction:[],isLexicalProvider:["parseEditorState","read","registerCommand","registerNodeTransform","update"],isSafeDollarFunction:[/^\$is[A-Z_]/]};function i(e){if(e)return"Identifier"===e.type?e:"MemberExpression"!==e.type||e.computed?void 0:i(e.property)}function s(e,n){const t=Array.isArray(e.options)?e.options[0]:void 0;return t&&n in t?t[n]:void 0}const a={oneOf:[{type:"string"},{contains:{type:"string"},type:"array"}]};return o.rulesOfLexical={create(o){const a=function(e){return e.sourceCode?e.sourceCode:e.getSourceCode()}(o),l=function(e){const n={};for(const i in r){const o=i;n[o]=t(r[o],s(e,o))}return n}(o),c=new Set,u=new Set,f=[],p=e=>c.add(e),d=e=>c.delete(e),g=t=>{const r=i(function(t){const r=e(t);if(r)return r;const o=t.parent;if(null!=o&&"CallExpression"===o.type&&o.arguments[0]===t&&function(e){return e&&"Identifier"===e.type&&/^use([A-Z]|$)/.test(e.name)}(i(o.callee)))return n(o)}(t));f.push({name:r,node:t}),(l.isDollarFunction(r)||l.isIgnoredFunction(r)||l.isLexicalProvider(r))&&p(t)},x=e=>{f.pop(),d(e)};return{ArrowFunctionExpression:g,"ArrowFunctionExpression:exit":x,CallExpression:e=>{if((()=>{if(c.size>0)return!0;const e=f[f.length-1];return e&&null!=e.node.parent&&"Property"===e.node.parent.type})())return;const n=i(e.callee);if(l.isLexicalProvider(n)||l.isSafeDollarFunction(n))return void p(e);if(!l.isDollarFunction(n))return;const t=(()=>{const e=f[f.length-1];return e?e.name:void 0})();if(!t||u.has(t))return;u.add(t);const r=function(e,n){const t=e.scopeManager;for(let e=n;e;e=e.parent){const r=t.getDeclaredVariables(e).find(e=>e.identifiers.includes(n));if(r)return r;const i=t.acquire(e);if(i)return i.set.get(n.name)||(i.upper?i.upper.set.get(n.name):void 0)}}(a,t),s=function(e,n){const t=function(e){return/^[a-z]/.test(e)?"$"+e:/^[A-Z][a-z]/.test(e)?"$"+e.slice(0,1).toLowerCase()+e.slice(1):`$_${e}`}(e.name);if(n)for(let e=n.scope;e;e=e.upper)if(e.set.has(t))return t+"_";return t}(t,r),d=function(e){if(e&&1===e.defs.length){const n=e.defs[0].node.parent;if(null!=n&&"ExportNamedDeclaration"===n.type)return n;if(null!=n&&"VariableDeclaration"===n.type&&null!=n.parent&&"ExportNamedDeclaration"===n.parent.type)return n.parent}}(r),g={callee:a.getText(e.callee),caller:a.getText(t),suggestName:s},x=e=>{const n=new Set,i=[],o=t=>{n.has(t)||(n.add(t),i.push(e.replaceText(t,s)))};if(o(t),d&&i.push(e.insertTextAfter(d,function({caller:e,suggestName:n}){return`\n/** @deprecated renamed to {@link ${n}} by @lexical/eslint-plugin rules-of-lexical */\nexport const ${e} = ${n};`}(g))),r)for(const e of r.references)o(e.identifier);return i};o.report({data:g,fix:x,messageId:"rulesOfLexicalReport",node:t,suggest:[{data:g,fix:x,messageId:"rulesOfLexicalSuggestion"}]})},"CallExpression:exit":d,ClassBody:p,"ClassBody:exit":d,FunctionDeclaration:g,"FunctionDeclaration:exit":x,FunctionExpression:g,"FunctionExpression:exit":x}},meta:{docs:{description:"enforces the Rules of Lexical",recommended:!0,url:"https://lexical.dev/docs/packages/lexical-eslint-plugin"},fixable:"code",hasSuggestions:!0,messages:{rulesOfLexicalReport:"{{ callee }} called from {{ caller }}, without $ prefix or read/update context",rulesOfLexicalSuggestion:"Rename {{ caller }} to {{ suggestName }}"},schema:[{additionalProperties:!1,properties:{isDollarFunction:a,isIgnoredFunction:a,isLexicalProvider:a,isSafeDollarFunction:a},type:"object"}],type:"suggestion"}},o}function y(){if(d)return p;d=1;const{name:e,version:n}=i,{rulesOfLexical:t}=m(),r={plugins:["@lexical"],rules:{"@lexical/rules-of-lexical":"warn"}},o={configs:{all:r,"flat/all":null,"flat/recommended":null,"legacy-all":r,"legacy-recommended":r,recommended:r},meta:{name:e,version:n},rules:{"rules-of-lexical":t}},s={plugins:{"@lexical":o},rules:{"@lexical/rules-of-lexical":"warn"}};return o.configs["flat/all"]=s,o.configs["flat/recommended"]=s,p=o}var h=y();const v=e({__proto__:null,default:n(h)},[h]);export{v as default};
package/package.json CHANGED
@@ -8,15 +8,15 @@
8
8
  "lexical",
9
9
  "editor"
10
10
  ],
11
- "version": "0.44.1-nightly.20260519.0",
11
+ "version": "0.45.0",
12
12
  "license": "MIT",
13
13
  "repository": {
14
14
  "type": "git",
15
15
  "url": "git+https://github.com/facebook/lexical.git",
16
16
  "directory": "packages/lexical-eslint-plugin"
17
17
  },
18
- "main": "LexicalEslintPlugin.js",
19
- "types": "index.d.ts",
18
+ "main": "./dist/LexicalEslintPlugin.js",
19
+ "types": "./dist/index.d.ts",
20
20
  "bugs": {
21
21
  "url": "https://github.com/facebook/lexical/issues"
22
22
  },
@@ -27,18 +27,19 @@
27
27
  },
28
28
  "exports": {
29
29
  ".": {
30
+ "source": "./src/index.ts",
30
31
  "import": {
31
- "types": "./index.d.ts",
32
- "development": "./LexicalEslintPlugin.dev.mjs",
33
- "production": "./LexicalEslintPlugin.prod.mjs",
34
- "node": "./LexicalEslintPlugin.node.mjs",
35
- "default": "./LexicalEslintPlugin.mjs"
32
+ "types": "./dist/index.d.ts",
33
+ "development": "./dist/LexicalEslintPlugin.dev.mjs",
34
+ "production": "./dist/LexicalEslintPlugin.prod.mjs",
35
+ "node": "./dist/LexicalEslintPlugin.node.mjs",
36
+ "default": "./dist/LexicalEslintPlugin.mjs"
36
37
  },
37
38
  "require": {
38
- "types": "./index.d.ts",
39
- "development": "./LexicalEslintPlugin.dev.js",
40
- "production": "./LexicalEslintPlugin.prod.js",
41
- "default": "./LexicalEslintPlugin.js"
39
+ "types": "./dist/index.d.ts",
40
+ "development": "./dist/LexicalEslintPlugin.dev.js",
41
+ "production": "./dist/LexicalEslintPlugin.prod.js",
42
+ "default": "./dist/LexicalEslintPlugin.js"
42
43
  }
43
44
  }
44
45
  },
@@ -46,5 +47,18 @@
46
47
  "@types/eslint": "^9.6.1",
47
48
  "@types/estree": "^1.0.6"
48
49
  },
49
- "module": "LexicalEslintPlugin.mjs"
50
+ "module": "./dist/LexicalEslintPlugin.mjs",
51
+ "files": [
52
+ "dist",
53
+ "src",
54
+ "!src/__tests__",
55
+ "!src/__bench__",
56
+ "!src/__mocks__",
57
+ "!src/**/*.test.ts",
58
+ "!src/**/*.test.tsx",
59
+ "!src/**/*.bench.ts",
60
+ "!src/**/*.bench.tsx",
61
+ "README.md",
62
+ "LICENSE"
63
+ ]
50
64
  }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ // @ts-check
10
+
11
+ const {name, version} = require('../package.json');
12
+ const {rulesOfLexical} = require('./rules/rules-of-lexical.js');
13
+
14
+ // Legacy config format (ESLint 7-8)
15
+ const legacyAll = {
16
+ plugins: ['@lexical'],
17
+ rules: {
18
+ '@lexical/rules-of-lexical': /** @type {'warn'|'error'|'off'}*/ ('warn'),
19
+ },
20
+ };
21
+
22
+ const plugin = {
23
+ configs: {
24
+ // Legacy configs (ESLint 7-8) - available under multiple names for compatibility
25
+ all: legacyAll,
26
+ // Flat configs (ESLint 9-10+) - placeholders, will be set below
27
+ 'flat/all': /** @type {any} */ (null),
28
+ 'flat/recommended': /** @type {any} */ (null),
29
+ 'legacy-all': legacyAll,
30
+ 'legacy-recommended': legacyAll,
31
+ recommended: legacyAll,
32
+ },
33
+ meta: {name, version},
34
+ rules: {
35
+ 'rules-of-lexical': rulesOfLexical,
36
+ },
37
+ };
38
+
39
+ // Flat config format (ESLint 9-10+)
40
+ // Must be created after plugin is defined to avoid circular reference
41
+ const flatAll = {
42
+ plugins: {
43
+ '@lexical': plugin,
44
+ },
45
+ rules: {
46
+ '@lexical/rules-of-lexical': 'warn' /** @type {'warn'|'error'|'off'}*/,
47
+ },
48
+ };
49
+
50
+ plugin.configs['flat/all'] = flatAll;
51
+ plugin.configs['flat/recommended'] = flatAll;
52
+
53
+ module.exports = plugin;
package/src/index.ts ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ /**
10
+ * For bootstrapping reasons, this module is written in CJS JavaScript so no
11
+ * compilation is necessary
12
+ */
13
+
14
+ import type {Rule} from 'eslint';
15
+
16
+ import * as jsPlugin from './LexicalEslintPlugin.js';
17
+
18
+ export type {RulesOfLexicalOptions} from './rules/rules-of-lexical.js';
19
+
20
+ // Legacy config format (ESLint 7-8)
21
+ export interface LegacyConfig {
22
+ plugins: string[];
23
+ rules: {
24
+ '@lexical/rules-of-lexical': 'warn' | 'error' | 'off';
25
+ };
26
+ }
27
+
28
+ // Flat config format (ESLint 9-10+)
29
+ export interface FlatConfig {
30
+ plugins: {
31
+ '@lexical': Plugin;
32
+ };
33
+ rules: {
34
+ '@lexical/rules-of-lexical': 'warn' | 'error' | 'off';
35
+ };
36
+ }
37
+
38
+ export interface Plugin {
39
+ meta: {
40
+ name: string;
41
+ version: string;
42
+ };
43
+ rules: {
44
+ 'rules-of-lexical': Rule.RuleModule;
45
+ };
46
+ configs: {
47
+ // Legacy configs (ESLint 7-8) - available under multiple names
48
+ all: LegacyConfig;
49
+ 'legacy-all': LegacyConfig;
50
+ 'legacy-recommended': LegacyConfig;
51
+ recommended: LegacyConfig;
52
+ // Flat configs (ESLint 9-10+)
53
+ 'flat/all': FlatConfig;
54
+ 'flat/recommended': FlatConfig;
55
+ };
56
+ }
57
+
58
+ const plugin: Plugin = jsPlugin;
59
+
60
+ // eslint-disable-next-line no-restricted-exports
61
+ export default plugin;
@@ -0,0 +1,431 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ // @ts-check
9
+
10
+ const {getFunctionName} = require('../util/getFunctionName.js');
11
+ const {getParentAssignmentName} = require('../util/getParentAssignmentName.js');
12
+ const {buildMatcher} = require('../util/buildMatcher.js');
13
+
14
+ /**
15
+ * @typedef {import('eslint').Rule.NodeParentExtension} NodeParentExtension
16
+ * @typedef {import('estree').CallExpression & NodeParentExtension} CallExpression
17
+ * @typedef {import('estree').Identifier & NodeParentExtension} Identifier
18
+ * @typedef {import('eslint').Rule.RuleContext} RuleContext
19
+ * @typedef {import('eslint').Rule.Fix} Fix
20
+ * @typedef {import('eslint').Rule.Node} Node
21
+ * @typedef {import('eslint').Rule.RuleModule} RuleModule
22
+ * @typedef {import('eslint').Rule.ReportFixer} ReportFixer
23
+ * @typedef {import('eslint').SourceCode} SourceCode
24
+ * @typedef {import('eslint').Scope.Variable} Variable
25
+ * @typedef {import('eslint').Scope.Scope} Scope
26
+ */
27
+
28
+ /**
29
+ * Find the variable associated with the given Identifier
30
+ *
31
+ * @param {SourceCode} sourceCode
32
+ * @param {Identifier} identifier
33
+ */
34
+ function getIdentifierVariable(sourceCode, identifier) {
35
+ const scopeManager = sourceCode.scopeManager;
36
+ for (
37
+ let node = /** @type {Node | null} */ (identifier);
38
+ node;
39
+ node = /** @type {Node | null}*/ (node.parent)
40
+ ) {
41
+ const variable = scopeManager
42
+ .getDeclaredVariables(node)
43
+ .find(v => v.identifiers.includes(identifier));
44
+ if (variable) {
45
+ return variable;
46
+ }
47
+ const scope = scopeManager.acquire(node);
48
+ if (scope) {
49
+ return (
50
+ scope.set.get(identifier.name) ||
51
+ (scope.upper ? scope.upper.set.get(identifier.name) : undefined)
52
+ );
53
+ }
54
+ }
55
+ return undefined;
56
+ }
57
+
58
+ /**
59
+ * @typedef {import('../util/buildMatcher.js').ToMatcher} ToMatcher
60
+ * @typedef {import('../util/buildMatcher.js').IdentifierMatcher} IdentifierMatcher
61
+ */
62
+
63
+ /**
64
+ * @template T
65
+ * @typedef {Object} BaseMatchers<T>
66
+ * @property {T} isDollarFunction Catch all identifiers that begin with '$' or 'INTERNAL_$' followed by a lowercase Latin character or underscore
67
+ * @property {T} isIgnoredFunction These functions may call any $functions even though they do not have the isDollarFunction naming convention
68
+ * @property {T} isLexicalProvider Certain calls through the editor or editorState allow for implicit access to call $functions: read, registerCommand, registerNodeTransform, update.
69
+ * @property {T} isSafeDollarFunction It's usually safe to call $isNode functions, so any '$is' or 'INTERNAL_$is' function may be called in any context.
70
+ */
71
+
72
+ /** @type {BaseMatchers<Exclude<ToMatcher, undefined>[]>} */
73
+ const BaseMatchers = {
74
+ isDollarFunction: [/^\$[a-z_]/],
75
+ isIgnoredFunction: [],
76
+ isLexicalProvider: [
77
+ 'parseEditorState',
78
+ 'read',
79
+ 'registerCommand',
80
+ 'registerNodeTransform',
81
+ 'update',
82
+ ],
83
+ isSafeDollarFunction: [/^\$is[A-Z_]/],
84
+ };
85
+
86
+ /**
87
+ * @typedef {Partial<BaseMatchers<ToMatcher | ToMatcher[]>>} RulesOfLexicalOptions
88
+ * @typedef {BaseMatchers<IdentifierMatcher>} Matchers
89
+ */
90
+
91
+ /**
92
+ * @param {RuleContext} context
93
+ * @returns {Matchers}
94
+ */
95
+ function compileMatchers(context) {
96
+ const rval = /** @type {Matchers} */ ({});
97
+ for (const k_ in BaseMatchers) {
98
+ const k = /** @type {keyof Matchers} */ (k_);
99
+ rval[k] = buildMatcher(BaseMatchers[k], parseMatcherOption(context, k));
100
+ }
101
+ return rval;
102
+ }
103
+
104
+ /**
105
+ * Hook functions start with use followed by a capital latin letter.
106
+ *
107
+ * @param {Node | undefined} node
108
+ */
109
+ function isHookFunctionIdentifier(node) {
110
+ return node && node.type === 'Identifier' && /^use([A-Z]|$)/.test(node.name);
111
+ }
112
+
113
+ /**
114
+ * Return this node if is an Identifier, otherwise if it is a MemberExpression such as
115
+ * `editor.read` return the Identifier of its property ('read' in this case).
116
+ *
117
+ * @param {Node | undefined} node
118
+ * @returns {Identifier | undefined}
119
+ */
120
+ function getFunctionNameIdentifier(node) {
121
+ if (!node) {
122
+ return;
123
+ } else if (node.type === 'Identifier') {
124
+ return node;
125
+ } else if (node.type === 'MemberExpression' && !node.computed) {
126
+ return getFunctionNameIdentifier(/** @type {Node} */ (node.property));
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Get the function's name, or if it is defined with a hook
132
+ * (e.g. useMemo, useCallback), then get the name of the variable the result
133
+ * is assigned to.
134
+ *
135
+ * @param {Node} node
136
+ */
137
+ function getLexicalFunctionName(node) {
138
+ const name = getFunctionName(node);
139
+ if (name) {
140
+ return name;
141
+ }
142
+ const nodeParent = node.parent;
143
+ if (
144
+ nodeParent != null &&
145
+ nodeParent.type === 'CallExpression' &&
146
+ nodeParent.arguments[0] === node
147
+ ) {
148
+ const parentName = getFunctionNameIdentifier(
149
+ /** @type {Node} */ (nodeParent.callee),
150
+ );
151
+ if (isHookFunctionIdentifier(parentName)) {
152
+ return getParentAssignmentName(/** @type {Node} */ (nodeParent));
153
+ }
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Return a name suitable for a suggestion.
159
+ * isDollarFunction(getFirstSuggestion(name)) should
160
+ * be true for any given name.
161
+ *
162
+ * @param {string} name
163
+ * @returns {string}
164
+ */
165
+ function getFirstSuggestion(name) {
166
+ if (/^[a-z]/.test(name)) {
167
+ return '$' + name;
168
+ } else if (/^[A-Z][a-z]/.test(name)) {
169
+ return '$' + name.slice(0, 1).toLowerCase() + name.slice(1);
170
+ } else {
171
+ return `$_${name}`;
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Get the suggested name for a variable and add an underscore if it shadows
177
+ * or conflicts with an existing variable.
178
+ *
179
+ * @param {Identifier} nameIdentifier
180
+ * @param {Variable | undefined} variable
181
+ */
182
+ function getSuggestName(nameIdentifier, variable) {
183
+ const suggestName = getFirstSuggestion(nameIdentifier.name);
184
+ // Add an underscore if this would shadow an existing name
185
+ if (variable) {
186
+ for (
187
+ let scope = /** @type {Scope | null} */ (variable.scope);
188
+ scope;
189
+ scope = scope.upper
190
+ ) {
191
+ if (scope.set.has(suggestName)) {
192
+ return suggestName + '_';
193
+ }
194
+ }
195
+ }
196
+ return suggestName;
197
+ }
198
+
199
+ /**
200
+ * Get the export declaration for a variable, if it has one.
201
+ *
202
+ * @param {Variable | undefined} variable
203
+ */
204
+ function getExportDeclaration(variable) {
205
+ if (variable && variable.defs.length === 1) {
206
+ const defNode = /** @type {Node} */ (variable.defs[0].node);
207
+ const defParent = defNode.parent;
208
+ if (defParent != null && defParent.type === 'ExportNamedDeclaration') {
209
+ // export function foo();
210
+ return defParent;
211
+ } else if (
212
+ defParent != null &&
213
+ defParent.type === 'VariableDeclaration' &&
214
+ defParent.parent != null &&
215
+ defParent.parent.type === 'ExportNamedDeclaration'
216
+ ) {
217
+ // export const foo = () => {};
218
+ return defParent.parent;
219
+ }
220
+ }
221
+ }
222
+
223
+ /**
224
+ * The comment we insert when an export is renamed.
225
+ *
226
+ * @param {Record<'caller'|'suggestName', string>} data
227
+ */
228
+ function renameExportText({caller, suggestName}) {
229
+ return `\n/** @deprecated renamed to {@link ${suggestName}} by @lexical/eslint-plugin rules-of-lexical */\nexport const ${caller} = ${suggestName};`;
230
+ }
231
+
232
+ /**
233
+ * @param {RuleContext} context
234
+ * @param {string} optionName
235
+ * @returns {ToMatcher}
236
+ */
237
+ function parseMatcherOption(context, optionName) {
238
+ const options = Array.isArray(context.options)
239
+ ? context.options[0]
240
+ : undefined;
241
+ return options && optionName in options ? options[optionName] : undefined;
242
+ }
243
+
244
+ /** @param {RuleContext} context */
245
+ function getSourceCode(context) {
246
+ if (context.sourceCode) {
247
+ return context.sourceCode;
248
+ }
249
+ // @ts-expect-error -- getSourceCode() removed from types in ESLint 10, kept for ESLint 8 compat
250
+ return context.getSourceCode();
251
+ }
252
+
253
+ const matcherSchema = {
254
+ oneOf: [{type: 'string'}, {contains: {type: 'string'}, type: 'array'}],
255
+ };
256
+
257
+ /** @type {RuleModule} */
258
+ module.exports.rulesOfLexical = {
259
+ create(context) {
260
+ const sourceCode = getSourceCode(context);
261
+ const matchers = compileMatchers(context);
262
+
263
+ /**
264
+ * When this set is non-empty it means that we are visiting a node
265
+ * that should not be analyzed.
266
+ *
267
+ * @type {Set<Node>}
268
+ */
269
+ const ignoreSet = new Set();
270
+ /**
271
+ * The set of Identifier nodes that have been reported, we do not
272
+ * want to report the same node more than once (a function making several
273
+ * calls to $functions only needs to be renamed once!)
274
+ *
275
+ * @type {Set<Identifier>}
276
+ */
277
+ const reportedSet = new Set();
278
+ /**
279
+ * The current stack of functions
280
+ *
281
+ * @type {{ name?: Identifier, node: Node }[]} funStack
282
+ */
283
+ const funStack = [];
284
+ const shouldIgnore = () => {
285
+ if (ignoreSet.size > 0) {
286
+ return true;
287
+ }
288
+ // Ignore property assignments
289
+ const lastFunction = funStack[funStack.length - 1];
290
+ return (
291
+ lastFunction &&
292
+ lastFunction.node.parent != null &&
293
+ lastFunction.node.parent.type === 'Property'
294
+ );
295
+ };
296
+ const pushIgnoredNode = (/** @type {Node} */ node) => ignoreSet.add(node);
297
+ const popIgnoredNode = (/** @type {Node} */ node) => ignoreSet.delete(node);
298
+ const pushFunction = (/** @type {Node} */ node) => {
299
+ const name = getFunctionNameIdentifier(
300
+ /** @type {Node | undefined} */ (getLexicalFunctionName(node)),
301
+ );
302
+ funStack.push({name, node});
303
+ if (
304
+ matchers.isDollarFunction(name) ||
305
+ matchers.isIgnoredFunction(name) ||
306
+ matchers.isLexicalProvider(name)
307
+ ) {
308
+ pushIgnoredNode(node);
309
+ }
310
+ };
311
+ const popFunction = (/** @type {Node} */ node) => {
312
+ funStack.pop();
313
+ popIgnoredNode(node);
314
+ };
315
+ const getParentLexicalFunctionNameIdentifier = (
316
+ /** @type {Node} */ _node,
317
+ ) => {
318
+ const pair = funStack[funStack.length - 1];
319
+ return pair ? pair.name : undefined;
320
+ };
321
+ // Find all $function calls that are not inside a class or inside a $function
322
+ // by visiting all function definitions and calls
323
+ return {
324
+ ArrowFunctionExpression: pushFunction,
325
+ 'ArrowFunctionExpression:exit': popFunction,
326
+ CallExpression: node => {
327
+ if (shouldIgnore()) {
328
+ return;
329
+ }
330
+ const calleeName = getFunctionNameIdentifier(
331
+ /** @type {Node} */ (node.callee),
332
+ );
333
+ if (
334
+ matchers.isLexicalProvider(calleeName) ||
335
+ matchers.isSafeDollarFunction(calleeName)
336
+ ) {
337
+ pushIgnoredNode(node);
338
+ return;
339
+ }
340
+ if (!matchers.isDollarFunction(calleeName)) {
341
+ return;
342
+ }
343
+ const nameIdentifier = getParentLexicalFunctionNameIdentifier(node);
344
+ if (!nameIdentifier || reportedSet.has(nameIdentifier)) {
345
+ return;
346
+ }
347
+ reportedSet.add(nameIdentifier);
348
+ const variable = getIdentifierVariable(sourceCode, nameIdentifier);
349
+ const suggestName = getSuggestName(nameIdentifier, variable);
350
+ const exportDeclaration = getExportDeclaration(variable);
351
+ const data = {
352
+ callee: sourceCode.getText(node.callee),
353
+ caller: sourceCode.getText(nameIdentifier),
354
+ suggestName,
355
+ };
356
+ /** @type {ReportFixer} */
357
+ const fix = fixer => {
358
+ /** @type {Set<Identifier>} */
359
+ const replaced = new Set();
360
+ /** @type {Fix[]} */
361
+ const fixes = [];
362
+ const renameIdentifier = (/** @type {Identifier} */ identifier) => {
363
+ if (!replaced.has(identifier)) {
364
+ replaced.add(identifier);
365
+ fixes.push(fixer.replaceText(identifier, suggestName));
366
+ }
367
+ };
368
+ renameIdentifier(nameIdentifier);
369
+ if (exportDeclaration) {
370
+ fixes.push(
371
+ fixer.insertTextAfter(exportDeclaration, renameExportText(data)),
372
+ );
373
+ }
374
+ if (variable) {
375
+ for (const ref of variable.references) {
376
+ renameIdentifier(/** @type {Identifier} */ (ref.identifier));
377
+ }
378
+ }
379
+ return fixes;
380
+ };
381
+ context.report({
382
+ data,
383
+ fix,
384
+ messageId: 'rulesOfLexicalReport',
385
+ node: nameIdentifier,
386
+ suggest: [
387
+ {
388
+ data,
389
+ fix,
390
+ messageId: 'rulesOfLexicalSuggestion',
391
+ },
392
+ ],
393
+ });
394
+ },
395
+ 'CallExpression:exit': popIgnoredNode,
396
+ ClassBody: pushIgnoredNode,
397
+ 'ClassBody:exit': popIgnoredNode,
398
+ FunctionDeclaration: pushFunction,
399
+ 'FunctionDeclaration:exit': popFunction,
400
+ FunctionExpression: pushFunction,
401
+ 'FunctionExpression:exit': popFunction,
402
+ };
403
+ },
404
+ meta: {
405
+ docs: {
406
+ description: 'enforces the Rules of Lexical',
407
+ recommended: true,
408
+ url: 'https://lexical.dev/docs/packages/lexical-eslint-plugin',
409
+ },
410
+ fixable: 'code',
411
+ hasSuggestions: true,
412
+ messages: {
413
+ rulesOfLexicalReport:
414
+ '{{ callee }} called from {{ caller }}, without $ prefix or read/update context',
415
+ rulesOfLexicalSuggestion: 'Rename {{ caller }} to {{ suggestName }}',
416
+ },
417
+ schema: [
418
+ {
419
+ additionalProperties: false,
420
+ properties: {
421
+ isDollarFunction: matcherSchema,
422
+ isIgnoredFunction: matcherSchema,
423
+ isLexicalProvider: matcherSchema,
424
+ isSafeDollarFunction: matcherSchema,
425
+ },
426
+ type: 'object',
427
+ },
428
+ ],
429
+ type: 'suggestion',
430
+ },
431
+ };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ /**
10
+ * @typedef {import('estree').Node} Node
11
+ * @typedef {import('estree').Identifier} Identifier
12
+ * @typedef {(name: string, node: Identifier) => boolean} NameIdentifierMatcher
13
+ * @typedef {NameIdentifierMatcher | string | RegExp | undefined} ToMatcher
14
+ * @typedef {(node: Identifier | undefined) => boolean} IdentifierMatcher
15
+ */
16
+
17
+ /**
18
+ * Escape a string for exact match in a RegExp
19
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#escaping
20
+ *
21
+ * @param {string} string
22
+ * @returns {string}
23
+ */
24
+ function escapeRegExp(string) {
25
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
26
+ }
27
+
28
+ /**
29
+ * Build an Identifier Node Matcher from the given ToMatcher arguments.
30
+ * The Matcher is roughly equivalent to building RegExp from all of the
31
+ * sources and or-ing them together. String arguments are treated as
32
+ * RegExp sources and will be escaped with an implicit '^...$' wrapper
33
+ * unless it starts with a '(' or '^'
34
+ *
35
+ * @param {(ToMatcher | ToMatcher[])[]} args
36
+ * @returns {IdentifierMatcher}
37
+ */
38
+ module.exports.buildMatcher = function buildMatcher(...toMatchers) {
39
+ /** @type {Matcher[]} */
40
+ const matchFuns = [];
41
+ /** @type {string[]} */
42
+ const regExpSources = [];
43
+ for (const arg of toMatchers.flat(1)) {
44
+ if (!arg) {
45
+ continue;
46
+ } else if (typeof arg === 'string') {
47
+ regExpSources.push(/^[(^]/.test(arg) ? arg : `^${escapeRegExp(arg)}$`);
48
+ } else if (arg && arg instanceof RegExp) {
49
+ if (arg.flags) {
50
+ matchFuns.push(s => arg.test(s));
51
+ } else {
52
+ regExpSources.push(arg.source);
53
+ }
54
+ } else if (typeof arg === 'function') {
55
+ matchFuns.push(arg);
56
+ }
57
+ }
58
+ const pattern = regExpSources.map(s => `(?:${s})`).join('|');
59
+ if (pattern) {
60
+ const re = new RegExp(pattern);
61
+ matchFuns.push(s => re.test(s));
62
+ }
63
+ return node => {
64
+ if (node) {
65
+ if (node.type !== 'Identifier') {
66
+ // Runtime type invariant check
67
+ throw new Error(`Expecting Identifier, not ${node.type}`);
68
+ }
69
+ for (const matcher of matchFuns) {
70
+ if (matcher(node.name, node)) {
71
+ return true;
72
+ }
73
+ }
74
+ }
75
+ return false;
76
+ };
77
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ // @ts-check
9
+
10
+ const {getParentAssignmentName} = require('./getParentAssignmentName');
11
+
12
+ /**
13
+ * Gets the static name of a function AST node. For function declarations it is
14
+ * easy. For anonymous function expressions it is much harder. If you search for
15
+ * `IsAnonymousFunctionDefinition()` in the ECMAScript spec you'll find places
16
+ * where JS gives anonymous function expressions names. We roughly detect the
17
+ * same AST nodes with some exceptions to better fit our use case.
18
+ *
19
+ * @param {import('eslint').Rule.Node} node
20
+ */
21
+ module.exports.getFunctionName = function getFunctionName(node) {
22
+ if (
23
+ node.type === 'FunctionDeclaration' ||
24
+ (node.type === 'FunctionExpression' && node.id)
25
+ ) {
26
+ // function $function() {}
27
+ // const whatever = function $function() {};
28
+ //
29
+ // Function declaration or function expression names win over any
30
+ // assignment statements or other renames.
31
+ return node.id;
32
+ } else if (
33
+ node.type === 'FunctionExpression' ||
34
+ node.type === 'ArrowFunctionExpression'
35
+ ) {
36
+ // This checks for assignments such as
37
+ // const $function = function () {};
38
+ // const $function = () => {};
39
+ return getParentAssignmentName(node);
40
+ } else {
41
+ return undefined;
42
+ }
43
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ // @ts-check
9
+ 'use strict';
10
+
11
+ /**
12
+ * Gets the static name of an AST node's parent, used to determine the name of an
13
+ * anonymous function declaration, possibly through a higher order function call.
14
+ * This was extracted from the body of getFunctionName so it could also be used
15
+ * in the context of `useCallback` or `useMemo`, e.g.
16
+ * `const $fun = useCallback(() => {}, [])` where the name is not the direct
17
+ * parent of the anonymous function.
18
+ *
19
+ * @param {import('eslint').Rule.Node} node
20
+ */
21
+ module.exports.getParentAssignmentName = function getParentAssignmentName(
22
+ node,
23
+ ) {
24
+ // Unlike React's rules of hooks, this does not check property assignment.
25
+ // The rules of lexical $function convention only applies to functions,
26
+ // not methods or properties.
27
+ const parentNode = node.parent;
28
+ if (parentNode == null) {
29
+ return undefined;
30
+ }
31
+ if (parentNode.type === 'VariableDeclarator' && parentNode.init === node) {
32
+ // const $function = () => {};
33
+ return parentNode.id;
34
+ } else if (
35
+ parentNode.type === 'AssignmentExpression' &&
36
+ parentNode.right === node &&
37
+ parentNode.operator === '='
38
+ ) {
39
+ // $function = () => {};
40
+ return parentNode.left;
41
+ } else {
42
+ return undefined;
43
+ }
44
+ };
@@ -1,9 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- */
8
-
9
- "use strict";function e(e,n){for(var t=0;t<n.length;t++){var r=n[t];if("string"!=typeof r&&!Array.isArray(r))for(var i in r)"default"===i||i in e||(e[i]=r[i])}return e}function n(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var t,r,i={name:"@lexical/eslint-plugin",version:"0.44.1-nightly.20260519.0"},o={},s={},a={};function l(){return t||(t=1,a.getParentAssignmentName=function(e){const n=e.parent;if(null!=n)return"VariableDeclarator"===n.type&&n.init===e?n.id:"AssignmentExpression"===n.type&&n.right===e&&"="===n.operator?n.left:void 0}),a}function c(){if(r)return s;r=1;const{getParentAssignmentName:e}=l();return s.getFunctionName=function(n){return"FunctionDeclaration"===n.type||"FunctionExpression"===n.type&&n.id?n.id:"FunctionExpression"===n.type||"ArrowFunctionExpression"===n.type?e(n):void 0},s}var u,f,p,d,g={};function x(){if(u)return g;function e(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}return u=1,g.buildMatcher=function(...n){const t=[],r=[];for(const i of n.flat(1))i&&("string"==typeof i?r.push(/^[(^]/.test(i)?i:`^${e(i)}$`):i&&i instanceof RegExp?i.flags?t.push(e=>i.test(e)):r.push(i.source):"function"==typeof i&&t.push(i));const i=r.map(e=>`(?:${e})`).join("|");if(i){const e=new RegExp(i);t.push(n=>e.test(n))}return e=>{if(e){if("Identifier"!==e.type)throw new Error(`Expecting Identifier, not ${e.type}`);for(const n of t)if(n(e.name,e))return!0}return!1}},g}function m(){if(f)return o;f=1;const{getFunctionName:e}=c(),{getParentAssignmentName:n}=l(),{buildMatcher:t}=x();const r={isDollarFunction:[/^\$[a-z_]/],isIgnoredFunction:[],isLexicalProvider:["parseEditorState","read","registerCommand","registerNodeTransform","update"],isSafeDollarFunction:[/^\$is[A-Z_]/]};function i(e){if(e)return"Identifier"===e.type?e:"MemberExpression"!==e.type||e.computed?void 0:i(e.property)}function s(e,n){const t=Array.isArray(e.options)?e.options[0]:void 0;return t&&n in t?t[n]:void 0}const a={oneOf:[{type:"string"},{contains:{type:"string"},type:"array"}]};return o.rulesOfLexical={create(o){const a=function(e){return e.sourceCode?e.sourceCode:e.getSourceCode()}(o),l=function(e){const n={};for(const i in r){const o=i;n[o]=t(r[o],s(e,o))}return n}(o),c=new Set,u=new Set,f=[],p=e=>c.add(e),d=e=>c.delete(e),g=t=>{const r=i(function(t){const r=e(t);if(r)return r;const o=t.parent;if(null!=o&&"CallExpression"===o.type&&o.arguments[0]===t&&function(e){return e&&"Identifier"===e.type&&/^use([A-Z]|$)/.test(e.name)}(i(o.callee)))return n(o)}(t));f.push({name:r,node:t}),(l.isDollarFunction(r)||l.isIgnoredFunction(r)||l.isLexicalProvider(r))&&p(t)},x=e=>{f.pop(),d(e)};return{ArrowFunctionExpression:g,"ArrowFunctionExpression:exit":x,CallExpression:e=>{if((()=>{if(c.size>0)return!0;const e=f[f.length-1];return e&&null!=e.node.parent&&"Property"===e.node.parent.type})())return;const n=i(e.callee);if(l.isLexicalProvider(n)||l.isSafeDollarFunction(n))return void p(e);if(!l.isDollarFunction(n))return;const t=(()=>{const e=f[f.length-1];return e?e.name:void 0})();if(!t||u.has(t))return;u.add(t);const r=function(e,n){const t=e.scopeManager;for(let e=n;e;e=e.parent){const r=t.getDeclaredVariables(e).find(e=>e.identifiers.includes(n));if(r)return r;const i=t.acquire(e);if(i)return i.set.get(n.name)||(i.upper?i.upper.set.get(n.name):void 0)}}(a,t),s=function(e,n){const t=function(e){return/^[a-z]/.test(e)?"$"+e:/^[A-Z][a-z]/.test(e)?"$"+e.slice(0,1).toLowerCase()+e.slice(1):`$_${e}`}(e.name);if(n)for(let e=n.scope;e;e=e.upper)if(e.set.has(t))return t+"_";return t}(t,r),d=function(e){if(e&&1===e.defs.length){const n=e.defs[0].node.parent;if(null!=n&&"ExportNamedDeclaration"===n.type)return n;if(null!=n&&"VariableDeclaration"===n.type&&null!=n.parent&&"ExportNamedDeclaration"===n.parent.type)return n.parent}}(r),g={callee:a.getText(e.callee),caller:a.getText(t),suggestName:s},x=e=>{const n=new Set,i=[],o=t=>{n.has(t)||(n.add(t),i.push(e.replaceText(t,s)))};if(o(t),d&&i.push(e.insertTextAfter(d,function({caller:e,suggestName:n}){return`\n/** @deprecated renamed to {@link ${n}} by @lexical/eslint-plugin rules-of-lexical */\nexport const ${e} = ${n};`}(g))),r)for(const e of r.references)o(e.identifier);return i};o.report({data:g,fix:x,messageId:"rulesOfLexicalReport",node:t,suggest:[{data:g,fix:x,messageId:"rulesOfLexicalSuggestion"}]})},"CallExpression:exit":d,ClassBody:p,"ClassBody:exit":d,FunctionDeclaration:g,"FunctionDeclaration:exit":x,FunctionExpression:g,"FunctionExpression:exit":x}},meta:{docs:{description:"enforces the Rules of Lexical",recommended:!0,url:"https://lexical.dev/docs/packages/lexical-eslint-plugin"},fixable:"code",hasSuggestions:!0,messages:{rulesOfLexicalReport:"{{ callee }} called from {{ caller }}, without $ prefix or read/update context",rulesOfLexicalSuggestion:"Rename {{ caller }} to {{ suggestName }}"},schema:[{additionalProperties:!1,properties:{isDollarFunction:a,isIgnoredFunction:a,isLexicalProvider:a,isSafeDollarFunction:a},type:"object"}],type:"suggestion"}},o}function y(){if(d)return p;d=1;const{name:e,version:n}=i,{rulesOfLexical:t}=m(),r={plugins:["@lexical"],rules:{"@lexical/rules-of-lexical":"warn"}},o={configs:{all:r,"flat/all":null,"flat/recommended":null,"legacy-all":r,"legacy-recommended":r,recommended:r},meta:{name:e,version:n},rules:{"rules-of-lexical":t}},s={plugins:{"@lexical":o},rules:{"@lexical/rules-of-lexical":"warn"}};return o.configs["flat/all"]=s,o.configs["flat/recommended"]=s,p=o}var h=y();const v=e({__proto__:null,default:n(h)},[h]);module.exports=v;
@@ -1,9 +0,0 @@
1
- /**
2
- * Copyright (c) Meta Platforms, Inc. and affiliates.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- */
8
-
9
- function e(e,n){for(var t=0;t<n.length;t++){var r=n[t];if("string"!=typeof r&&!Array.isArray(r))for(var i in r)"default"===i||i in e||(e[i]=r[i])}return e}function n(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var t,r,i={name:"@lexical/eslint-plugin",version:"0.44.1-nightly.20260519.0"},o={},s={},a={};function l(){return t||(t=1,a.getParentAssignmentName=function(e){const n=e.parent;if(null!=n)return"VariableDeclarator"===n.type&&n.init===e?n.id:"AssignmentExpression"===n.type&&n.right===e&&"="===n.operator?n.left:void 0}),a}function c(){if(r)return s;r=1;const{getParentAssignmentName:e}=l();return s.getFunctionName=function(n){return"FunctionDeclaration"===n.type||"FunctionExpression"===n.type&&n.id?n.id:"FunctionExpression"===n.type||"ArrowFunctionExpression"===n.type?e(n):void 0},s}var u,f,p,d,g={};function x(){if(u)return g;function e(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}return u=1,g.buildMatcher=function(...n){const t=[],r=[];for(const i of n.flat(1))i&&("string"==typeof i?r.push(/^[(^]/.test(i)?i:`^${e(i)}$`):i&&i instanceof RegExp?i.flags?t.push(e=>i.test(e)):r.push(i.source):"function"==typeof i&&t.push(i));const i=r.map(e=>`(?:${e})`).join("|");if(i){const e=new RegExp(i);t.push(n=>e.test(n))}return e=>{if(e){if("Identifier"!==e.type)throw new Error(`Expecting Identifier, not ${e.type}`);for(const n of t)if(n(e.name,e))return!0}return!1}},g}function m(){if(f)return o;f=1;const{getFunctionName:e}=c(),{getParentAssignmentName:n}=l(),{buildMatcher:t}=x();const r={isDollarFunction:[/^\$[a-z_]/],isIgnoredFunction:[],isLexicalProvider:["parseEditorState","read","registerCommand","registerNodeTransform","update"],isSafeDollarFunction:[/^\$is[A-Z_]/]};function i(e){if(e)return"Identifier"===e.type?e:"MemberExpression"!==e.type||e.computed?void 0:i(e.property)}function s(e,n){const t=Array.isArray(e.options)?e.options[0]:void 0;return t&&n in t?t[n]:void 0}const a={oneOf:[{type:"string"},{contains:{type:"string"},type:"array"}]};return o.rulesOfLexical={create(o){const a=function(e){return e.sourceCode?e.sourceCode:e.getSourceCode()}(o),l=function(e){const n={};for(const i in r){const o=i;n[o]=t(r[o],s(e,o))}return n}(o),c=new Set,u=new Set,f=[],p=e=>c.add(e),d=e=>c.delete(e),g=t=>{const r=i(function(t){const r=e(t);if(r)return r;const o=t.parent;if(null!=o&&"CallExpression"===o.type&&o.arguments[0]===t&&function(e){return e&&"Identifier"===e.type&&/^use([A-Z]|$)/.test(e.name)}(i(o.callee)))return n(o)}(t));f.push({name:r,node:t}),(l.isDollarFunction(r)||l.isIgnoredFunction(r)||l.isLexicalProvider(r))&&p(t)},x=e=>{f.pop(),d(e)};return{ArrowFunctionExpression:g,"ArrowFunctionExpression:exit":x,CallExpression:e=>{if((()=>{if(c.size>0)return!0;const e=f[f.length-1];return e&&null!=e.node.parent&&"Property"===e.node.parent.type})())return;const n=i(e.callee);if(l.isLexicalProvider(n)||l.isSafeDollarFunction(n))return void p(e);if(!l.isDollarFunction(n))return;const t=(()=>{const e=f[f.length-1];return e?e.name:void 0})();if(!t||u.has(t))return;u.add(t);const r=function(e,n){const t=e.scopeManager;for(let e=n;e;e=e.parent){const r=t.getDeclaredVariables(e).find(e=>e.identifiers.includes(n));if(r)return r;const i=t.acquire(e);if(i)return i.set.get(n.name)||(i.upper?i.upper.set.get(n.name):void 0)}}(a,t),s=function(e,n){const t=function(e){return/^[a-z]/.test(e)?"$"+e:/^[A-Z][a-z]/.test(e)?"$"+e.slice(0,1).toLowerCase()+e.slice(1):`$_${e}`}(e.name);if(n)for(let e=n.scope;e;e=e.upper)if(e.set.has(t))return t+"_";return t}(t,r),d=function(e){if(e&&1===e.defs.length){const n=e.defs[0].node.parent;if(null!=n&&"ExportNamedDeclaration"===n.type)return n;if(null!=n&&"VariableDeclaration"===n.type&&null!=n.parent&&"ExportNamedDeclaration"===n.parent.type)return n.parent}}(r),g={callee:a.getText(e.callee),caller:a.getText(t),suggestName:s},x=e=>{const n=new Set,i=[],o=t=>{n.has(t)||(n.add(t),i.push(e.replaceText(t,s)))};if(o(t),d&&i.push(e.insertTextAfter(d,function({caller:e,suggestName:n}){return`\n/** @deprecated renamed to {@link ${n}} by @lexical/eslint-plugin rules-of-lexical */\nexport const ${e} = ${n};`}(g))),r)for(const e of r.references)o(e.identifier);return i};o.report({data:g,fix:x,messageId:"rulesOfLexicalReport",node:t,suggest:[{data:g,fix:x,messageId:"rulesOfLexicalSuggestion"}]})},"CallExpression:exit":d,ClassBody:p,"ClassBody:exit":d,FunctionDeclaration:g,"FunctionDeclaration:exit":x,FunctionExpression:g,"FunctionExpression:exit":x}},meta:{docs:{description:"enforces the Rules of Lexical",recommended:!0,url:"https://lexical.dev/docs/packages/lexical-eslint-plugin"},fixable:"code",hasSuggestions:!0,messages:{rulesOfLexicalReport:"{{ callee }} called from {{ caller }}, without $ prefix or read/update context",rulesOfLexicalSuggestion:"Rename {{ caller }} to {{ suggestName }}"},schema:[{additionalProperties:!1,properties:{isDollarFunction:a,isIgnoredFunction:a,isLexicalProvider:a,isSafeDollarFunction:a},type:"object"}],type:"suggestion"}},o}function y(){if(d)return p;d=1;const{name:e,version:n}=i,{rulesOfLexical:t}=m(),r={plugins:["@lexical"],rules:{"@lexical/rules-of-lexical":"warn"}},o={configs:{all:r,"flat/all":null,"flat/recommended":null,"legacy-all":r,"legacy-recommended":r,recommended:r},meta:{name:e,version:n},rules:{"rules-of-lexical":t}},s={plugins:{"@lexical":o},rules:{"@lexical/rules-of-lexical":"warn"}};return o.configs["flat/all"]=s,o.configs["flat/recommended"]=s,p=o}var h=y();const v=e({__proto__:null,default:n(h)},[h]);export{v as default};
File without changes
File without changes
File without changes
File without changes