Skip to content

Commit

Permalink
BREAKING CHANGE: prevents the usage of Intl.NumberFormat for performa…
Browse files Browse the repository at this point in the history
…nce purposes
  • Loading branch information
fannytavart committed Aug 28, 2024
1 parent 3f5064a commit 8147b29
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// This code should trigger the ESLint rule `avoidIntlNumberFormatRule`

const number = 1234567.89;

// Incorrect usage: This will be flagged by the ESLint rule
const formatter = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
});

const formattedNumber = formatter.format(number);

// eslint-disable-next-line no-console
console.log(formattedNumber); // Outputs: $1,234,567.89
13 changes: 7 additions & 6 deletions packages/eslint-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,13 @@ This plugin exports some custom rules that you can optionally use in your projec
🧪 Set in the `tests` configuration.\
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).

| Name                              | Description | 💼 | 🔧 |
| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | :--------------------- | :-- |
| [await-user-event](https://github.com/bamlab/react-native-project-config/blob/main/packages/eslint-plugin/docs/rules/await-user-event.md) | Enforces awaiting userEvent calls | 🧪 | 🔧 |
| [no-animated-without-native-driver](https://github.com/bamlab/react-native-project-config/blob/main/packages/eslint-plugin/docs/rules/no-animated-without-native-driver.md) | Disallow the use of `Animated` with `useNativeDriver: false` | ![badge-performance][] | 🔧 |
| [prefer-user-event](https://github.com/bamlab/react-native-project-config/blob/main/packages/eslint-plugin/docs/rules/prefer-user-event.md) | Enforces usage of userEvent over fireEvent in tests. | | 🔧 |
| [require-named-effect](https://github.com/bamlab/react-native-project-config/blob/main/packages/eslint-plugin/docs/rules/require-named-effect.md) | Enforces the use of named functions inside a useEffect | | |
| Name                              | Description | 💼 | 🔧 |
| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- | :--------------------- | :-- |
| [avoid-intl-number-format](https://github.com/bamlab/react-native-project-config/blob/main/packages/eslint-plugin/docs/rules/avoid-intl-number-format.md) | Disallow the use of `Intl.NumberFormat` due to potential performance issues. | ![badge-performance][] | 🔧 |
| [await-user-event](https://github.com/bamlab/react-native-project-config/blob/main/packages/eslint-plugin/docs/rules/await-user-event.md) | Enforces awaiting userEvent calls | 🧪 | 🔧 |
| [no-animated-without-native-driver](https://github.com/bamlab/react-native-project-config/blob/main/packages/eslint-plugin/docs/rules/no-animated-without-native-driver.md) | Disallow the use of `Animated` with `useNativeDriver: false` | ![badge-performance][] | 🔧 |
| [prefer-user-event](https://github.com/bamlab/react-native-project-config/blob/main/packages/eslint-plugin/docs/rules/prefer-user-event.md) | Enforces usage of userEvent over fireEvent in tests. | | 🔧 |
| [require-named-effect](https://github.com/bamlab/react-native-project-config/blob/main/packages/eslint-plugin/docs/rules/require-named-effect.md) | Enforces the use of named functions inside a useEffect | | |

<!-- end auto-generated rules list -->

Expand Down
9 changes: 9 additions & 0 deletions packages/eslint-plugin/docs/rules/avoid-intl-number-format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Disallow the use of `Intl.NumberFormat` due to potential performance issues (`@bam.tech/avoid-intl-number-format`)

💼 This rule is enabled in the `performance` config.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

<!-- end auto-generated rule header -->

Prevents from the using `Intl.NumberFormat` to improve performance.
1 change: 1 addition & 0 deletions packages/eslint-plugin/lib/configs/performance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const performanceConfig = defineConfig({
},
],
"@bam.tech/no-animated-without-native-driver": "error",
"@bam.tech/avoid-intl-number-format": "error",
},
overrides: [
{
Expand Down
40 changes: 40 additions & 0 deletions packages/eslint-plugin/lib/rules/avoid-intl-number-format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { Rule } from "eslint";

// Custom Rule: No Intl.NumberFormat Usage
export const avoidIntlNumberFormatRule: Rule.RuleModule = {
meta: {
type: "problem",
docs: {
description:
"Disallow the use of `Intl.NumberFormat` due to potential performance issues.",
category: "Possible Errors",
recommended: true,
url: "https://github.com/your-repo/eslint-plugin/docs/rules/no-intl-numberformat.md", // Update with your actual URL
},
messages: {
noIntlNumberFormat:
"Avoid using `Intl.NumberFormat` as it can lead to performance issues. Consider using a lightweight formatting alternative or memoizing the formatter instance.",
},
schema: [],
fixable: "code",
},

create(context) {
return {
NewExpression(node) {
if (
node.callee.type === "MemberExpression" &&
node.callee.object.type === "Identifier" &&
node.callee.object.name === "Intl" &&
node.callee.property.type === "Identifier" &&
node.callee.property.name === "NumberFormat"
) {
context.report({
node,
messageId: "noIntlNumberFormat",
});
}
},
};
},
};
2 changes: 2 additions & 0 deletions packages/eslint-plugin/lib/rules/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { avoidIntlNumberFormatRule } from "./avoid-intl-number-format";
import { awaitUserEventRule } from "./await-user-event";
import { noAnimatedWithoutNativeDriverRule } from "./no-animated-without-native-driver";
import { preferUserEventRule } from "./prefer-user-event";
Expand All @@ -8,4 +9,5 @@ export default {
"prefer-user-event": preferUserEventRule,
"require-named-effect": requireNamedEffectRule,
"no-animated-without-native-driver": noAnimatedWithoutNativeDriverRule,
"avoid-intl-number-format": avoidIntlNumberFormatRule,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Save without formatting: [⌘ + K] > [S]

// This should trigger an error breaking eslint-plugin-bam-custom-rules:
// bam-custom-rules/avoid-intl-number-format

import { avoidIntlNumberFormatRule } from "../../../lib/rules/avoid-intl-number-format";
import { RuleTester } from "eslint";

const ruleTester = new RuleTester({
parser: require.resolve("@typescript-eslint/parser"),
});

const valid = [
` const formatCurrency = (number: number) => {
return numeral(number).format('$0,0.00');
};
const number = 1234567.89;
console.log(formatCurrency(number));`,
];

const invalid = [
` const number = 1234567.89;
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
});
const formattedNumber = formatter.format(number);
console.log(formattedNumber);`,
];

ruleTester.run("no-animated-without-native-driver", avoidIntlNumberFormatRule, {
valid,
invalid: invalid.map((code) => ({
code,
errors: [
"Avoid using `Intl.NumberFormat` as it can lead to performance issues. Consider using a lightweight formatting alternative or memoizing the formatter instance.",
],
})),
});

0 comments on commit 8147b29

Please sign in to comment.