feat(linter): improve no-accumulating-spread#5302
Conversation
|
This stack of pull requests is managed by Graphite. Learn more about stacking. |
cc648de to
b1ba16f
Compare
CodSpeed Performance ReportMerging #5302 will not alter performanceComparing Summary
|
|
I disagree with this change. These examples are still |
why would the fixed version of this code be O(n^2)? it would improve performance in the same way converting a spread in a reduce loop to a push would. |
|
i also think i've dona a bad job explaining this. so let me try again, and attempt to explain why this is a good thing to add to the lint rule. 🙂 lets take the following example, where let foo = [];
for (let i = 0; i < n; i++) {
foo = [...foo, i];
}The time complexity of this example
this leads to a total time complexity of If we rewrite this code as let foo = [];
for (let i = 0; i < n; i++) {
foo.push(i)
}The time complexity of this will be:
leading to a total time complexity of Furthermore, in the first example, it will make We can see the difference in performance brenchmarks import { bench, run } from 'mitata';
const Ns = [1, 10, 100, 1000, 10000, 100000, 1000000];
for (const N of Ns) {
bench(`slow (spread array) ${N}`, () => {
let foo = [];
for (let i = 0; i < N; i++) {
foo = [...foo, i];
}
});
bench(`fast (push into array) ${N}`, () => {
let foo = [];
for (let i = 0; i < N; i++) {
foo.push(i);
}
});
}
await run();yeilds the following results: ( represented a bit cleaner: as you can see. using @DonIsaac let me know your thoughts |
|
@camc314 i owe you an apology, I though this PR was allowing spreads in for-loops. This is a misunderstanding on my part. I'll re-open this PR. |
|
This is nice 👍 |
no worries, thanks for bearing with me! the description lacked a clear explanation |
b1ba16f to
85c4122
Compare
Merge activity
|
VSCode has a couple violations. examples:
```
x oxc(no-accumulating-spread): Do not spread accumulators in loops
,-[src/vs/workbench/services/textMate/common/TMGrammarFactory.ts:65:5]
64 | let injections: string[] = [];
65 | for (let i = 1; i <= scopeParts.length; i++) {
: ^|^
: `-- For this loop
66 | const subScopeName = scopeParts.slice(0, i).join('.');
67 | injections = [...injections, ...(this._injections[subScopeName] || [])];
: ^^^^^^|^^^^^^
: `-- From this spread
68 | }
`----
help: Consider using `Object.assign()` or `Array.prototype.push()` to mutate the accumulator instead.
Using spreads within accumulators leads to `O(n^2)` time complexity.
x oxc(no-accumulating-spread): Do not spread accumulators in loops
,-[src/vs/base/common/actions.ts:205:3]
204 | let out: IAction[] = [];
205 | for (const list of actionLists) {
: ^|^
: `-- For this loop
206 | if (!list.length) {
207 | // skip
208 | } else if (out.length) {
209 | out = [...out, new Separator(), ...list];
: ^^^|^^
: `-- From this spread
210 | } else {
`----
help: Consider using `Object.assign()` or `Array.prototype.push()` to mutate the accumulator instead.
Using spreads within accumulators leads to `O(n^2)` time complexity.
help: It looks like you're spreading an `Array`. Consider using the `Array.push` or `Array.concat` methods to mutate the accumulator instead.
Using spreads within accumulators leads to `O(n^2)` time complexity.
x oxc(no-accumulating-spread): Do not spread accumulators in loops
,-[src/vs/workbench/contrib/extensions/browser/extensionsActions.ts:302:3]
301 | let actions: IAction[] = [];
302 | for (const visibleActions of actionsGroups) {
: ^|^
: `-- For this loop
303 | if (visibleActions.length) {
304 | actions = [...actions, ...visibleActions, new Separator()];
: ^^^^^|^^^^
: `-- From this spread
305 | }
`----
help: Consider using `Object.assign()` or `Array.prototype.push()` to mutate the accumulator instead.
Using spreads within accumulators leads to `O(n^2)` time complexity.
x oxc(no-accumulating-spread): Do not spread accumulators in loops
,-[src/vs/workbench/contrib/extensions/browser/extensionsActions.ts:1141:3]
1140 | let actions: IAction[] = [];
1141 | for (const menuActions of menuActionGroups) {
: ^|^
: `-- For this loop
1142 | actions = [...actions, ...menuActions, new Separator()];
: ^^^^^|^^^^
: `-- From this spread
1143 | }
`----
help: Consider using `Object.assign()` or `Array.prototype.push()` to mutate the accumulator instead.
Using spreads within accumulators leads to `O(n^2)` time complexity.
x oxc(no-accumulating-spread): Do not spread accumulators in loops
,-[src/vs/workbench/contrib/extensions/browser/extensionsViews.ts:334:4]
333 | let actions: IAction[] = [];
334 | for (const menuActions of groups) {
: ^|^
: `-- For this loop
335 | actions = [...actions, ...menuActions, new Separator()];
: ^^^^^|^^^^
: `-- From this spread
336 | }
`----
help: Consider using `Object.assign()` or `Array.prototype.push()` to mutate the accumulator instead.
Using spreads within accumulators leads to `O(n^2)` time complexity.
```
85c4122 to
b103737
Compare
…d` (#5373) mentioned here: #5302 (comment) it's not exactly clear why we check that it's a `let` declaration kind.
## [0.9.2] - 2024-09-02 ### Features - f81e8a1 linter: Add `oxc/no-async-endpoint-handlers` (#5364) (DonIsaac) - b103737 linter: Improve no-accumulating-spread (#5302) (camc314) - 9c22ce9 linter: Add hyperlinks to diagnostic messages (#5318) (DonIsaac) - 1967c67 linter/eslint: Implement no-new-func (#5360) (dalaoshu) - b867e5f linter/eslint-plugin-promise: Implement catch-or-return (#5121) (Jelle van der Waa) - 8d781e7 linter/oxc: Differentiate between array/object in `no-accumulating-spread` loop diagnostic (#5375) (camc314) - db55444 linter/oxc: Add fixer for `double-comparisons` (#5378) (camc314) - e5c755a linter/promise: Add `spec-only` rule (#5124) (Jelle van der Waa) - 4c0861f linter/unicorn: Add fixer for `prefer-type-error` (#5311) (camc314) - 084c2d1 linter/vitest: Implement prefer-to-be-object (#5321) (dalaoshu) ### Bug Fixes - 11b93af linter/unicorn: Consistent-function-scoping false positive on assignment expression (#5312) (Arian94) ### Performance - f052a6d linter: `react/jsx_no_undef` faster check for unbound references (#5349) (overlookmotel) - 05636b7 linter: Avoid unnecessary work in `jsx_a11y/anchor_is_valid` rule (#5341) (overlookmotel) ### Refactor - afb038e linter: `react/jsx_no_undef` use loop instead of recursion (#5347) (overlookmotel) - fe62687 linter: Simplify skipping JSX elements in `unicorn/consistent_function_scoping` (#5351) (overlookmotel) - 381d9fe linter: Shorten code in `react/jsx_no_useless_fragment` (#5350) (overlookmotel) - 83b9a82 linter: Fix indentation in `nextjs/no_script_component_in_head` rule (#5338) (overlookmotel) - 89f0188 linter: Improve docs for `react/jsx_no_target_blank` rule (#5342) (overlookmotel) - 57050ab linter: Shorten code in `jsx_a11y/aria_activedescendant_has_tabindex` rule (#5340) (overlookmotel) - ed31d67 linter/jest: Fix indentation in code comment (#5372) (camc314) - 2499cb9 linter/oxc: Update rule docs for `erasing-op` (#5376) (camc314) - 69493d2 linter/oxc: Improve diagnostic for `no-accumulating-spread` in loops (#5374) (camc314) - 024b585 linter/oxc: Improve code comment for `no-accumulating-spread` (#5373) (camc314) Co-authored-by: Boshen <[email protected]>

VSCode has a couple violations. examples: