Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pkgs/configs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
},
"dependencies": {
"@eslint/js": "^9.34.0",
"@stylistic/eslint-plugin": "^5.2.3",
"@stylistic/eslint-plugin": "^5.3.1",
"eslint-plugin-de-morgan": "^1.3.1",
"eslint-plugin-function": "^0.0.24",
"eslint-plugin-jsdoc": "^54.1.1",
Expand Down
29 changes: 16 additions & 13 deletions .pkgs/eslint-plugin-local/dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import * as _typescript_eslint_utils_ts_eslint from '@typescript-eslint/utils/ts-eslint';
import "@typescript-eslint/utils/eslint-utils";
import * as _typescript_eslint_utils_ts_eslint0 from "@typescript-eslint/utils/ts-eslint";

//#region src/rules/prefer-eqeq-nullish-comparison.d.ts
type MessageID = "unexpectedComparison" | "useLooseComparisonSuggestion";

//#endregion
//#region src/index.d.ts
declare const _default: {
readonly meta: {
readonly name: string;
readonly version: string;
};
readonly rules: {
readonly "avoid-multiline-template-expression": _typescript_eslint_utils_ts_eslint.RuleModule<"avoidMultilineTemplateExpression", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
readonly "no-shadow-underscore": _typescript_eslint_utils_ts_eslint.RuleModule<"noShadowUnderscore", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
readonly "prefer-eqeq-nullish-comparison": _typescript_eslint_utils_ts_eslint.RuleModule<MessageID, [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
};
readonly meta: {
readonly name: string;
readonly version: string;
};
readonly rules: {
readonly "avoid-multiline-template-expression": _typescript_eslint_utils_ts_eslint0.RuleModule<"avoidMultilineTemplateExpression", [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener>;
readonly "no-shadow-underscore": _typescript_eslint_utils_ts_eslint0.RuleModule<"noShadowUnderscore", [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener>;
readonly "prefer-eqeq-nullish-comparison": _typescript_eslint_utils_ts_eslint0.RuleModule<MessageID, [], unknown, _typescript_eslint_utils_ts_eslint0.RuleListener>;
};
};

export { _default as default };
//#endregion
export { _default as default };
328 changes: 151 additions & 177 deletions .pkgs/eslint-plugin-local/dist/index.js
Original file line number Diff line number Diff line change
@@ -1,199 +1,173 @@
import * as AST from '@eslint-react/ast';
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
import { unit } from '@eslint-react/eff';
import { findVariable } from '@eslint-react/var';
import { AST_NODE_TYPES as AST_NODE_TYPES$1 } from '@typescript-eslint/types';
import { nullThrows, NullThrowsReasons } from '@typescript-eslint/utils/eslint-utils';
import * as AST from "@eslint-react/ast";
import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
import { unit } from "@eslint-react/eff";
import { findVariable } from "@eslint-react/var";
import { AST_NODE_TYPES as AST_NODE_TYPES$1 } from "@typescript-eslint/types";
import { NullThrowsReasons, nullThrows } from "@typescript-eslint/utils/eslint-utils";

// package.json
//#region package.json
var name = "@local/eslint-plugin-local";
var version = "0.0.0";

//#endregion
//#region src/utils/create-rule.ts
function getDocsUrl() {
return "TODO: add docs for local ESLint rules";
return "TODO: add docs for local ESLint rules";
}
var createRule = ESLintUtils.RuleCreator(getDocsUrl);
function isInitializedFromSource(name2, source, initialScope) {
const latestDef = findVariable(name2, initialScope)?.defs.at(-1);
if (latestDef == null) return false;
const { node, parent } = latestDef;
if (node.type === AST_NODE_TYPES$1.VariableDeclarator && node.init != null) {
const { init } = node;
if (init.type === AST_NODE_TYPES$1.MemberExpression && init.object.type === AST_NODE_TYPES$1.Identifier) {
return isInitializedFromSource(init.object.name, source, initialScope);
}
if (init.type === AST_NODE_TYPES$1.Identifier) {
return isInitializedFromSource(init.name, source, initialScope);
}
const args = getRequireExpressionArguments(init);
const arg0 = args?.[0];
if (arg0 == null || !AST.isLiteral(arg0, "string")) {
return false;
}
return arg0.value === source || arg0.value.startsWith(`${source}/`);
}
return parent?.type === AST_NODE_TYPES$1.ImportDeclaration && parent.source.value === source;
const createRule = ESLintUtils.RuleCreator(getDocsUrl);

//#endregion
//#region src/utils/is-initialized-from-source.ts
/**
* Check if an identifier is initialized from the given source
* @param name The top-level identifier's name
* @param source The import source to check against
* @param initialScope Initial scope to search for the identifier
* @returns Whether the identifier is initialized from the given source
*/
function isInitializedFromSource(name$1, source, initialScope) {
const latestDef = findVariable(name$1, initialScope)?.defs.at(-1);
if (latestDef == null) return false;
const { node, parent } = latestDef;
if (node.type === AST_NODE_TYPES$1.VariableDeclarator && node.init != null) {
const { init } = node;
if (init.type === AST_NODE_TYPES$1.MemberExpression && init.object.type === AST_NODE_TYPES$1.Identifier) return isInitializedFromSource(init.object.name, source, initialScope);
if (init.type === AST_NODE_TYPES$1.Identifier) return isInitializedFromSource(init.name, source, initialScope);
const args = getRequireExpressionArguments(init);
const arg0 = args?.[0];
if (arg0 == null || !AST.isLiteral(arg0, "string")) return false;
return arg0.value === source || arg0.value.startsWith(`${source}/`);
}
return parent?.type === AST_NODE_TYPES$1.ImportDeclaration && parent.source.value === source;
}
function getRequireExpressionArguments(node) {
switch (true) {
// require('source')
case (node.type === AST_NODE_TYPES$1.CallExpression && node.callee.type === AST_NODE_TYPES$1.Identifier && node.callee.name === "require"): {
return node.arguments;
}
// require('source').variable
case node.type === AST_NODE_TYPES$1.MemberExpression: {
return getRequireExpressionArguments(node.object);
}
}
return unit;
switch (true) {
case node.type === AST_NODE_TYPES$1.CallExpression && node.callee.type === AST_NODE_TYPES$1.Identifier && node.callee.name === "require": return node.arguments;
case node.type === AST_NODE_TYPES$1.MemberExpression: return getRequireExpressionArguments(node.object);
}
return unit;
}

// src/rules/avoid-multiline-template-expression.ts
var RULE_NAME = "avoid-multiline-template-expression";
var RULE_FEATURES = [];
//#endregion
//#region src/rules/avoid-multiline-template-expression.ts
const RULE_NAME$2 = "avoid-multiline-template-expression";
const RULE_FEATURES$1 = [];
var avoid_multiline_template_expression_default = createRule({
meta: {
type: "problem",
docs: {
description: "disallow multiline template expressions",
[Symbol.for("rule_features")]: RULE_FEATURES
},
messages: {
avoidMultilineTemplateExpression: "Avoid multiline template expressions."
},
schema: []
},
name: RULE_NAME,
create,
defaultOptions: []
meta: {
type: "problem",
docs: {
description: "disallow multiline template expressions",
[Symbol.for("rule_features")]: RULE_FEATURES$1
},
messages: { avoidMultilineTemplateExpression: "Avoid multiline template expressions." },
schema: []
},
name: RULE_NAME$2,
create: create$2,
defaultOptions: []
});
function create(context) {
return {
TemplateLiteral: (node) => {
if (AST.isMultiLine(node)) {
context.report({
messageId: "avoidMultilineTemplateExpression",
node
});
}
}
};
function create$2(context) {
return { TemplateLiteral: (node) => {
if (AST.isMultiLine(node)) context.report({
messageId: "avoidMultilineTemplateExpression",
node
});
} };
}

// src/rules/no-shadow-underscore.ts
var RULE_NAME2 = "no-shadow-underscore";
var RULE_FEATURES2 = [];
//#endregion
//#region src/rules/no-shadow-underscore.ts
const RULE_NAME$1 = "no-shadow-underscore";
const RULE_FEATURES = [];
var no_shadow_underscore_default = createRule({
meta: {
type: "problem",
docs: {
description: "disallow shadowing of the underscore identifier",
[Symbol.for("rule_features")]: RULE_FEATURES2
},
messages: {
noShadowUnderscore: "In this codebase, '_' is used to represent the undefined. Avoid shadowing it."
},
schema: []
},
name: RULE_NAME2,
create: create2,
defaultOptions: []
meta: {
type: "problem",
docs: {
description: "disallow shadowing of the underscore identifier",
[Symbol.for("rule_features")]: RULE_FEATURES
},
messages: { noShadowUnderscore: "In this codebase, '_' is used to represent the undefined. Avoid shadowing it." },
schema: []
},
name: RULE_NAME$1,
create: create$1,
defaultOptions: []
});
function create2(context) {
return {
"Identifier[name='_']"(node) {
const initialScope = context.sourceCode.getScope(node);
const isFromImport = isInitializedFromSource("_", "@eslint-react/eff", initialScope);
if (!isFromImport) {
context.report({
messageId: "noShadowUnderscore",
node
});
}
}
};
function create$1(context) {
return { "Identifier[name='_']"(node) {
const initialScope = context.sourceCode.getScope(node);
const isFromImport = isInitializedFromSource("_", "@eslint-react/eff", initialScope);
if (!isFromImport) context.report({
messageId: "noShadowUnderscore",
node
});
} };
}
var RULE_NAME3 = "prefer-eqeq-nullish-comparison";

//#endregion
//#region src/rules/prefer-eqeq-nullish-comparison.ts
const RULE_NAME = "prefer-eqeq-nullish-comparison";
var prefer_eqeq_nullish_comparison_default = createRule({
meta: {
type: "suggestion",
docs: {
description: "Enforces eqeqeq preferences around nullish comparisons."
},
fixable: "code",
hasSuggestions: true,
messages: {
unexpectedComparison: "Unexpected strict comparison (`{{strictOperator}}`) with `{{nullishKind}}`. In this codebase, we prefer to use loose equality as a general-purpose nullish check when possible.",
useLooseComparisonSuggestion: "Use loose comparison (`{{looseOperator}} null`) instead, to check both nullish values."
},
schema: []
},
name: RULE_NAME3,
create: create3,
defaultOptions: []
meta: {
type: "suggestion",
docs: { description: "Enforces eqeqeq preferences around nullish comparisons." },
fixable: "code",
hasSuggestions: true,
messages: {
unexpectedComparison: "Unexpected strict comparison (`{{strictOperator}}`) with `{{nullishKind}}`. In this codebase, we prefer to use loose equality as a general-purpose nullish check when possible.",
useLooseComparisonSuggestion: "Use loose comparison (`{{looseOperator}} null`) instead, to check both nullish values."
},
schema: []
},
name: RULE_NAME,
create,
defaultOptions: []
});
function create3(context) {
return {
BinaryExpression(node) {
if (node.operator === "===" || node.operator === "!==") {
const offendingChild = [node.left, node.right].find(
(child) => child.type === AST_NODE_TYPES.Identifier && child.name === "undefined" || child.type === AST_NODE_TYPES.Literal && child.raw === "null"
);
if (offendingChild == null) {
return;
}
const operatorToken = nullThrows(
context.sourceCode.getFirstTokenBetween(
node.left,
node.right,
(token) => token.value === node.operator
),
NullThrowsReasons.MissingToken(node.operator, "binary expression")
);
const wasLeft = node.left === offendingChild;
const nullishKind = offendingChild.type === AST_NODE_TYPES.Identifier ? "undefined" : "null";
const looseOperator = node.operator === "===" ? "==" : "!=";
context.report({
messageId: "unexpectedComparison",
data: {
nullishKind,
strictOperator: node.operator
},
loc: wasLeft ? {
end: operatorToken.loc.end,
start: node.left.loc.start
} : {
end: node.right.loc.end,
start: operatorToken.loc.start
},
suggest: [
{
messageId: "useLooseComparisonSuggestion",
data: {
looseOperator
},
fix: (fixer) => [
fixer.replaceText(offendingChild, "null"),
fixer.replaceText(operatorToken, looseOperator)
]
}
]
});
}
}
};
function create(context) {
return { BinaryExpression(node) {
if (node.operator === "===" || node.operator === "!==") {
const offendingChild = [node.left, node.right].find((child) => child.type === AST_NODE_TYPES.Identifier && child.name === "undefined" || child.type === AST_NODE_TYPES.Literal && child.raw === "null");
if (offendingChild == null) return;
const operatorToken = nullThrows(context.sourceCode.getFirstTokenBetween(node.left, node.right, (token) => token.value === node.operator), NullThrowsReasons.MissingToken(node.operator, "binary expression"));
const wasLeft = node.left === offendingChild;
const nullishKind = offendingChild.type === AST_NODE_TYPES.Identifier ? "undefined" : "null";
const looseOperator = node.operator === "===" ? "==" : "!=";
context.report({
messageId: "unexpectedComparison",
data: {
nullishKind,
strictOperator: node.operator
},
loc: wasLeft ? {
end: operatorToken.loc.end,
start: node.left.loc.start
} : {
end: node.right.loc.end,
start: operatorToken.loc.start
},
suggest: [{
messageId: "useLooseComparisonSuggestion",
data: { looseOperator },
fix: (fixer) => [fixer.replaceText(offendingChild, "null"), fixer.replaceText(operatorToken, looseOperator)]
}]
});
}
} };
}

// src/index.ts
var index_default = {
meta: {
name,
version
},
rules: {
"avoid-multiline-template-expression": avoid_multiline_template_expression_default,
"no-shadow-underscore": no_shadow_underscore_default,
"prefer-eqeq-nullish-comparison": prefer_eqeq_nullish_comparison_default
}
//#endregion
//#region src/index.ts
var src_default = {
meta: {
name,
version
},
rules: {
"avoid-multiline-template-expression": avoid_multiline_template_expression_default,
"no-shadow-underscore": no_shadow_underscore_default,
"prefer-eqeq-nullish-comparison": prefer_eqeq_nullish_comparison_default
}
};

export { index_default as default };
//#endregion
export { src_default as default };
Loading