Skip to content
Open
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
20 changes: 0 additions & 20 deletions eslint.config.mjs

This file was deleted.

1 change: 1 addition & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ iife
stefanzweifel
badgen
vite
oxlint
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@
"scripts": {
"build": "vp pack",
"type-check": "tsc",
"lint": "pnpm run lint:ci -- --fix",
"lint:ci": "eslint . --ext .js,.ts,.tsx",
"lint": "vp lint",
"test": "vp test",
"test:coverage": "vp test --coverage",
"prepublishOnly": "pkg-ok",
Expand All @@ -42,17 +41,17 @@
"devDependencies": {
"@commitlint/cli": "20.2.0",
"@commitlint/config-conventional": "20.2.0",
"@fullstacksjs/eslint-config": "13.8.2",
"@fullstacksjs/oxlint-config": "0.6.1",
"@semantic-release/github": "12.0.2",
"@semantic-release/npm": "13.1.3",
"@semantic-release/release-notes-generator": "14.1.0",
"@types/node": "24.9.1",
"@vitest/coverage-v8": "4.1.10",
"cspell": "10.0.1",
"eslint": "9.38.0",
"husky": "9.1.7",
"lint-staged": "16.2.7",
"npm-run-all": "4.1.5",
"oxlint": "1.76.0",
"pkg-ok": "3.0.0",
"semantic-release": "25.0.2",
"typescript": "5.9.3",
Expand Down
2,747 changes: 452 additions & 2,295 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ peerDependencyRules:
vitest: '*'
allowBuilds:
unrs-resolver: true
minimumReleaseAgeExclude:
- '@fullstacksjs/oxlint-config@0.6.1'
2 changes: 1 addition & 1 deletion src/guards/isPlainObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function isPlainObject(o: unknown): o is ObjectType {

if (ctor == null) return true;

const prototype = ctor.prototype;
const { prototype } = ctor;
if (!isObject(prototype)) return false;

// If constructor does not have an Object-specific method
Expand Down
1 change: 1 addition & 0 deletions src/nullable/asyncNullableTryCatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export async function asyncNullableTryCatch<T>(
): Promise<T | null> {
try {
return await fn();
// oxlint-disable-next-line preserve-caught-error
} catch {
return null;
}
Expand Down
1 change: 1 addition & 0 deletions src/nullable/nullableTryCatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
export function nullableTryCatch<T>(fn: (...args: any[]) => T): T | null {
try {
return fn();
// oxlint-disable-next-line preserve-caught-error
} catch {
return null;
}
Expand Down
7 changes: 2 additions & 5 deletions src/object/clone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,13 @@ function clonePlainObject<T extends ObjectType>(input: T): T {
if (!isPlainObject(input)) return input;

return Object.keys(input).reduce(
(prevState, key) => ({
...prevState,
[key]: clone(input[key]),
}),
(prevState, key) => Object.assign(prevState, { [key]: clone(input[key]) }),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve __proto__ as an own property when cloning

When input has an own enumerable __proto__ property, such as an object returned by JSON.parse, Object.assign invokes the inherited __proto__ setter instead of defining that property. Consequently, clone(input) drops the own key and gives the clone an attacker-controlled prototype (for example, a supplied polluted property becomes inherited), whereas the previous object-spread reducer preserved the data safely.

Useful? React with 👍 / 👎.

{},
) as T;
}

function cloneArray<T extends any[]>(input: T): T {
return input.reduce((prevState, value) => [...prevState, clone(value)], []);
return input.map(value => clone(value)) as T;
}

function cloneMap<T extends Map<any, any>>(input: T): T {
Expand Down
5 changes: 2 additions & 3 deletions src/object/merge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ export function merge<T extends ObjectType, U extends ObjectType>(
const v1 = oV1[key];
const v2 = oV2[key];

return {
...state,
return Object.assign(state, {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve __proto__ keys in merged objects

When either merged object contains an own enumerable __proto__ key, for example from untrusted JSON, this assignment invokes Object.prototype.__proto__'s setter. The merged result therefore loses the own key and acquires the supplied object as its prototype, allowing attacker-controlled inherited properties to affect consumers; the previous spread expression defined __proto__ as an ordinary own property.

Useful? React with 👍 / 👎.

[key]: composer({
v1,
v2,
Expand All @@ -81,7 +80,7 @@ export function merge<T extends ObjectType, U extends ObjectType>(
extract,
path: `${path}.${key}`,
}),
};
});
}, {});
}

Expand Down
2 changes: 1 addition & 1 deletion src/regex/escapeRegex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@
* new RegExp(escapeRegex('^a$')).test('a') // false
*/
export function escapeRegex(s: string): string {
return s.replace(/[$(-+.?[-^{|}]/g, '\\$&');
return s.replace(/[$()*+.?[\\\]^{|}]/g, '\\$&');
}
4 changes: 1 addition & 3 deletions src/types/result.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import type { Result } from './result.ts';

import { Err, Ok } from './result.ts';
import { Err, Ok, type Result } from './result.ts';

describe('result, Ok, Err, AsyncResult', () => {
it('ok wraps value correctly', () => {
Expand Down
15 changes: 15 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
/// <reference types="vitest" />
import { defineConfig } from 'vite-plus';
import { defineOxlintConfig } from '@fullstacksjs/oxlint-config';

export default defineConfig({
staged: {
'*': 'vp check --fix',
},
lint: defineOxlintConfig({
ignorePatterns: [
'node_modules',
'dist',
'docs',
'coverage',
'*.mdx',
'AGENTS.md',
],
modules: {},
rules: {
'max-params': 'off',
},
}),
fmt: {
arrowParens: 'avoid',
bracketSpacing: true,
Expand Down
Loading