Skip to content

Commit

Permalink
chore(lint): add lint plugin for using for loop instead of `for...o…
Browse files Browse the repository at this point in the history
…f` over array (#587)

* Add prefer for loop

* change plugin name

* Revert tsconfig

* Revert random comment

* Revert eslint config parser options

---------

Co-authored-by: Sojin Park <[email protected]>
  • Loading branch information
dayongkr and raon0211 committed Sep 24, 2024
1 parent 36b14be commit f38392c
Show file tree
Hide file tree
Showing 27 changed files with 165 additions and 66 deletions.
22 changes: 21 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import tseslint from 'typescript-eslint';
import jsdoc from 'eslint-plugin-jsdoc';
import prettier from 'eslint-config-prettier';
import pluginVue from 'eslint-plugin-vue';
import noForOfArrayPlugin from 'eslint-plugin-no-for-of-array';

export default [
{
Expand All @@ -27,7 +28,6 @@ export default [
...globals['shared-node-browser'],
...globals.es2015,
},

parserOptions: {
ecmaFeatures: {
jsx: true,
Expand All @@ -42,6 +42,26 @@ export default [
prettier,
jsdoc.configs['flat/recommended'],
...pluginVue.configs['flat/recommended'],
{
files: ['src/**/*.ts'],
ignores: ['**/*.spec.ts'],
languageOptions: {
parser: tseslint.parser,
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: import.meta.dirname,
ecmaFeatures: {
jsx: true,
},
},
},
plugins: {
'no-for-of-array': noForOfArrayPlugin,
},
rules: {
'no-for-of-array/no-for-of-array': 'error',
},
},
{
rules: {
'no-implicit-coercion': 'error',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
"eslint": "^9.9.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-jsdoc": "^50.2.2",
"eslint-plugin-no-for-of-array": "^0.0.1",
"eslint-plugin-vue": "^9.28.0",
"execa": "^9.3.0",
"globals": "^15.9.0",
Expand Down
3 changes: 2 additions & 1 deletion src/array/compact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ type NotFalsey<T> = Exclude<T, false | null | 0 | 0n | '' | undefined>;
export function compact<T>(arr: readonly T[]): Array<NotFalsey<T>> {
const result: Array<NotFalsey<T>> = [];

for (const item of arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
if (item) {
result.push(item as NotFalsey<T>);
}
Expand Down
3 changes: 2 additions & 1 deletion src/array/countBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
export function countBy<T, K extends PropertyKey>(arr: readonly T[], mapper: (item: T) => K): Record<K, number> {
const result = {} as Record<K, number>;

for (const item of arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
const key = mapper(item);

result[key] = (result[key] ?? 0) + 1;
Expand Down
3 changes: 2 additions & 1 deletion src/array/groupBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
export function groupBy<T, K extends PropertyKey>(arr: readonly T[], getKeyFromItem: (item: T) => K): Record<K, T[]> {
const result = Object.create(null) as Record<K, T[]>;

for (const item of arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
const key = getKeyFromItem(item);

if (result[key] == null) {
Expand Down
3 changes: 2 additions & 1 deletion src/array/keyBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
export function keyBy<T, K extends PropertyKey>(arr: readonly T[], getKeyFromItem: (item: T) => K): Record<K, T> {
const result = {} as Record<K, T>;

for (const item of arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
const key = getKeyFromItem(item);
result[key] = item;
}
Expand Down
3 changes: 2 additions & 1 deletion src/array/maxBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ export function maxBy<T>(items: readonly T[], getValue: (element: T) => number):
let maxElement = items[0];
let max = -Infinity;

for (const element of items) {
for (let i = 0; i < items.length; i++) {
const element = items[i];
const value = getValue(element);
if (value > max) {
max = value;
Expand Down
3 changes: 2 additions & 1 deletion src/array/minBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ export function minBy<T>(items: readonly T[], getValue: (element: T) => number):
let minElement = items[0];
let min = Infinity;

for (const element of items) {
for (let i = 0; i < items.length; i++) {
const element = items[i];
const value = getValue(element);
if (value < min) {
min = value;
Expand Down
3 changes: 2 additions & 1 deletion src/array/partition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export function partition<T>(arr: readonly T[], isInTruthy: (value: T) => boolea
const truthy: T[] = [];
const falsy: T[] = [];

for (const item of arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
if (isInTruthy(item)) {
truthy.push(item);
} else {
Expand Down
3 changes: 2 additions & 1 deletion src/array/takeWhile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
export function takeWhile<T>(arr: readonly T[], shouldContinueTaking: (element: T) => boolean): T[] {
const result: T[] = [];

for (const item of arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
if (!shouldContinueTaking(item)) {
break;
}
Expand Down
4 changes: 3 additions & 1 deletion src/array/unionBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
export function unionBy<T, U>(arr1: readonly T[], arr2: readonly T[], mapper: (item: T) => U): T[] {
const map = new Map<U, T>();

for (const item of [...arr1, ...arr2]) {
const items = [...arr1, ...arr2];
for (let i = 0; i < items.length; i++) {
const item = items[i];
const key = mapper(item);

if (!map.has(key)) {
Expand Down
3 changes: 2 additions & 1 deletion src/array/uniqBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
export function uniqBy<T, U>(arr: readonly T[], mapper: (item: T) => U): T[] {
const map = new Map<U, T>();

for (const item of arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
const key = mapper(item);

if (!map.has(key)) {
Expand Down
3 changes: 2 additions & 1 deletion src/array/uniqWith.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
export function uniqWith<T>(arr: readonly T[], areItemsEqual: (item1: T, item2: T) => boolean): T[] {
const result: T[] = [];

for (const item of arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
const isUniq = result.every(v => !areItemsEqual(v, item));

if (isUniq) {
Expand Down
16 changes: 10 additions & 6 deletions src/compat/function/debounce.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ describe('debounce', () => {
expect(callCount).toBe(2);
});

it('subsequent debounced calls return the last `func` result', async done => {
it('subsequent debounced calls return the last `func` result', async () => {
const debounced = debounce(identity, 32);
debounced('a');

Expand Down Expand Up @@ -383,7 +383,7 @@ describe('debounce', () => {
expect(callCount).toBe(2);
});

it('should support `maxWait` in a tight loop', async done => {
it('should support `maxWait` in a tight loop', async () => {
const limit = 1000;
let withCount = 0;
let withoutCount = 0;
Expand Down Expand Up @@ -460,10 +460,12 @@ describe('debounce', () => {
const object = {};

const debounced = debounce(
function (this: any, value: any) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function (this: any, _: any) {
actual = [this];
// eslint-disable-next-line prefer-rest-params
Array.prototype.push.apply(actual, arguments as any);
return ++callCount != 2;
return ++callCount !== 2;
},
32,
{ leading: true, maxWait: 64 }
Expand Down Expand Up @@ -505,7 +507,7 @@ describe('debounce', () => {
expect(callCount).toBe(isDebounce ? 1 : 2);
});

it(`\`_.${methodName}\` should invoke \`func\` with the correct \`this\` binding`, async done => {
it(`\`_.${methodName}\` should invoke \`func\` with the correct \`this\` binding`, async () => {
const actual: any[] = [];
const object = {
funced: func(function (this: any) {
Expand All @@ -526,8 +528,10 @@ describe('debounce', () => {
const expected = args.slice();
const queue: any[] = args.slice();

var funced = func(function (this: any, _: unknown) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const funced = func(function (this: any, _: unknown) {
const current = [this];
// eslint-disable-next-line prefer-rest-params
Array.prototype.push.apply(current, arguments as any);
actual.push(current);

Expand Down
11 changes: 6 additions & 5 deletions src/compat/function/throttle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ describe('throttle', () => {
expect(results2[0]).not.toStrictEqual(undefined);
});

it('should clear timeout when `func` is called', async done => {
it('should clear timeout when `func` is called', async () => {
let callCount = 0;
let dateCount = 0;

const throttled = throttle(() => {
callCount++;
Expand Down Expand Up @@ -81,7 +80,7 @@ describe('throttle', () => {
options
);

const start = +new Date();
const start = Number(new Date());
while (Date.now() - start < limit) {
throttled();
}
Expand Down Expand Up @@ -229,7 +228,7 @@ describe('throttle', () => {
expect(callCount).toBe(isDebounce ? 1 : 2);
});

it(`\`_.${methodName}\` should invoke \`func\` with the correct \`this\` binding`, async done => {
it(`\`_.${methodName}\` should invoke \`func\` with the correct \`this\` binding`, async () => {
const actual: any[] = [];
const object = {
funced: func(function (this: any) {
Expand All @@ -250,8 +249,10 @@ describe('throttle', () => {
const expected = args.slice();
const queue: any[] = args.slice();

var funced = func(function (this: any, _: unknown) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const funced = func(function (this: any, _: unknown) {
const current = [this];
// eslint-disable-next-line prefer-rest-params
Array.prototype.push.apply(current, arguments as any);
actual.push(current);

Expand Down
3 changes: 2 additions & 1 deletion src/compat/math/max.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export function max<T>(items: readonly T[] = []): T | undefined {
let maxElement = items[0];
let max: any = undefined;

for (const element of items) {
for (let i = 0; i < items.length; i++) {
const element = items[i];
if (max == null || element > max) {
max = element;
maxElement = element;
Expand Down
3 changes: 2 additions & 1 deletion src/compat/math/min.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export function min<T>(items: readonly T[] = []): T {
let minElement = items[0];
let min: any = undefined;

for (const element of items) {
for (let i = 0; i < items.length; i++) {
const element = items[i];
if (min == null || element < min) {
min = element;
minElement = element;
Expand Down
7 changes: 4 additions & 3 deletions src/compat/math/random.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ export function random(minimum: number, maximum: number, floating?: boolean): nu
* const result3 = random(5, 5); // If the minimum is equal to the maximum, an error is thrown.
*/
export function random(...args: any[]): number {
let minimum: number = 0;
let maximum: number = 1;
let floating: boolean = false;
let minimum = 0;
let maximum = 1;
let floating = false;

switch (args.length) {
case 1: {
Expand All @@ -91,6 +91,7 @@ export function random(...args: any[]): number {
maximum = args[1];
}
}
// eslint-disable-next-line no-fallthrough
case 3: {
if (typeof args[2] === 'object' && args[2] != null && args[2][args[1]] === args[0]) {
minimum = 0;
Expand Down
3 changes: 2 additions & 1 deletion src/compat/object/pick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ export function pick<

const result: any = {};

for (let keys of keysArr) {
for (let i = 0; i < keysArr.length; i++) {
let keys = keysArr[i];
switch (typeof keys) {
case 'object': {
if (!Array.isArray(keys)) {
Expand Down
4 changes: 3 additions & 1 deletion src/compat/predicate/conformsTo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ export function conformsTo(
return Object.keys(source).length === 0;
}

for (const key of Object.keys(source)) {
const keys = Object.keys(source);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const predicate = source[key];
const value = target[key];
if ((value === undefined && !(key in target)) || !predicate(value)) {
Expand Down
24 changes: 1 addition & 23 deletions src/function/debounce.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,3 @@
interface DebounceTimer {
/**
* Checks if the timer is active.
* @returns {boolean} True if the timer is active, otherwise false.
*/
isActive: () => boolean;

/**
* Triggers the debounce timer.
* This method resets the timer and schedules the execution of the debounced function
* after the specified delay. If the timer is already active, it clears the existing timeout
* before setting a new one.
*/
trigger: () => void;

/**
* Cancels any pending execution of the debounced function.
* This method clears the active timer, ensuring that the function will not be called
* at the end of the debounce period. It also resets any stored context or arguments.
*/
cancel: () => void;
}

interface DebounceOptions {
/**
* An optional AbortSignal to cancel the debounced function.
Expand Down Expand Up @@ -158,6 +135,7 @@ export function debounce<F extends (...args: any[]) => void>(
return;
}

// eslint-disable-next-line @typescript-eslint/no-this-alias
pendingThis = this;
pendingArgs = args;

Expand Down
3 changes: 2 additions & 1 deletion src/object/omit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
export function omit<T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]): Omit<T, K> {
const result = { ...obj };

for (const key of keys) {
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
delete result[key];
}

Expand Down
10 changes: 5 additions & 5 deletions src/object/omitBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ export function omitBy<T extends Record<string, any>>(
): Partial<T> {
const result: Partial<T> = {};

for (const [key, value] of Object.entries(obj)) {
if (shouldOmit(value, key)) {
continue;
const objEntries = Object.entries(obj);
for (let i = 0; i < objEntries.length; i++) {
const [key, value] = objEntries[i];
if (!shouldOmit(value, key)) {
(result as any)[key] = value;
}

(result as any)[key] = value;
}

return result;
Expand Down
3 changes: 2 additions & 1 deletion src/object/pick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
export function pick<T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]): Pick<T, K> {
const result = {} as Pick<T, K>;

for (const key of keys) {
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
result[key] = obj[key];
}

Expand Down
Loading

0 comments on commit f38392c

Please sign in to comment.