diff --git a/.changeset/bright-foxes-refuse.md b/.changeset/bright-foxes-refuse.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/bright-foxes-refuse.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 00000000000..5753ce8563c --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,431 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["typescript", "import", "jsx-a11y", "react", "unicorn"], + "categories": { + "correctness": "off" + }, + "env": { + "builtin": true, + "es2021": true, + "commonjs": true + }, + "ignorePatterns": [ + ".cache", + ".idea", + ".next", + ".turbo", + ".vscode", + ".yalc", + "!.*.js", + "**/.turbo/*", + "**/build/*", + "**/coverage/*", + "**/dist/*", + "**/integration/templates/**/*", + "**/node_modules/**", + "*.snap", + "commitlint.config.ts", + "packages/*/dist/**", + "packages/*/examples", + "playground/*", + "pnpm-lock.json", + "eslint.config.mjs", + "typedoc.config.mjs", + "vitest.workspace.mjs", + "packages/*/jest.config.js", + "packages/astro/src/astro-components/**/*.ts", + "packages/backend/src/runtime/**/*", + "packages/clerk-js/rspack.config.js", + "packages/shared/src/compiled/path-to-regexp/index.js" + ], + "rules": { + "for-direction": "error", + "no-async-promise-executor": "error", + "no-case-declarations": "error", + "no-class-assign": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": "error", + "no-const-assign": "error", + "no-constant-binary-expression": "error", + "no-constant-condition": "error", + "no-control-regex": "error", + "no-debugger": "error", + "no-delete-var": "error", + "no-dupe-class-members": "error", + "no-dupe-else-if": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-empty": "error", + "no-empty-character-class": "error", + "no-empty-pattern": "error", + "no-empty-static-block": "error", + "no-ex-assign": "error", + "no-extra-boolean-cast": "error", + "no-fallthrough": "error", + "no-func-assign": "error", + "no-global-assign": "error", + "no-import-assign": "error", + "no-invalid-regexp": "error", + "no-irregular-whitespace": "error", + "no-loss-of-precision": "error", + "no-new-native-nonconstructor": "error", + "no-nonoctal-decimal-escape": "error", + "no-obj-calls": "error", + "no-prototype-builtins": "error", + "no-redeclare": "error", + "no-regex-spaces": "error", + "no-self-assign": "error", + "no-setter-return": "error", + "no-shadow-restricted-names": "error", + "no-sparse-arrays": "error", + "no-this-before-super": "error", + "no-unexpected-multiline": "off", + "no-unsafe-finally": "error", + "no-unsafe-negation": "error", + "no-unsafe-optional-chaining": "error", + "no-unused-labels": "error", + "no-unused-private-class-members": "error", + "no-unused-vars": [ + "error", + { + "args": "after-used", + "argsIgnorePattern": "^_", + "ignoreRestSiblings": true, + "vars": "all", + "varsIgnorePattern": "^_" + } + ], + "no-useless-backreference": "error", + "no-useless-catch": "error", + "no-useless-escape": "error", + "no-with": "error", + "require-yield": "error", + "use-isnan": "error", + "valid-typeof": "error", + "@typescript-eslint/ban-ts-comment": [ + "warn", + { + "ts-ignore": "allow-with-description", + "ts-expect-error": "allow-with-description", + "ts-check": "allow-with-description" + } + ], + "no-array-constructor": "error", + "@typescript-eslint/no-duplicate-enum-values": "error", + "@typescript-eslint/no-empty-object-type": "error", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-extra-non-null-assertion": "error", + "@typescript-eslint/no-misused-new": "error", + "@typescript-eslint/no-namespace": "error", + "@typescript-eslint/no-non-null-asserted-optional-chain": "error", + "@typescript-eslint/no-require-imports": "error", + "@typescript-eslint/no-this-alias": "error", + "@typescript-eslint/no-unnecessary-type-constraint": "error", + "@typescript-eslint/no-unsafe-declaration-merging": "off", + "@typescript-eslint/no-unsafe-function-type": "error", + "no-unused-expressions": "error", + "@typescript-eslint/no-wrapper-object-types": "error", + "no-throw-literal": "off", + "@typescript-eslint/prefer-as-const": "error", + "@typescript-eslint/prefer-namespace-keyword": "error", + "prefer-promise-reject-errors": "off", + "require-await": "off", + "@typescript-eslint/triple-slash-reference": "error", + "import/namespace": "error", + "import/default": "error", + "import/no-named-as-default": "warn", + "import/no-named-as-default-member": "warn", + "import/no-duplicates": "warn", + "jsx-a11y/alt-text": "warn", + "jsx-a11y/anchor-ambiguous-text": "off", + "jsx-a11y/anchor-has-content": "error", + "jsx-a11y/anchor-is-valid": "error", + "jsx-a11y/aria-activedescendant-has-tabindex": "error", + "jsx-a11y/aria-props": "error", + "jsx-a11y/aria-role": "error", + "jsx-a11y/aria-unsupported-elements": "error", + "jsx-a11y/autocomplete-valid": "error", + "jsx-a11y/click-events-have-key-events": "error", + "jsx-a11y/heading-has-content": "error", + "jsx-a11y/html-has-lang": "warn", + "jsx-a11y/iframe-has-title": "error", + "jsx-a11y/img-redundant-alt": "error", + "jsx-a11y/label-has-associated-control": "error", + "jsx-a11y/media-has-caption": "error", + "jsx-a11y/mouse-events-have-key-events": "error", + "jsx-a11y/no-access-key": "error", + "jsx-a11y/no-autofocus": "warn", + "jsx-a11y/no-distracting-elements": "error", + "jsx-a11y/no-noninteractive-tabindex": [ + "error", + { + "tags": [], + "roles": ["tabpanel"], + "allowExpressionValues": true + } + ], + "jsx-a11y/no-redundant-roles": "error", + "jsx-a11y/role-has-required-aria-props": "error", + "jsx-a11y/role-supports-aria-props": "error", + "jsx-a11y/scope": "error", + "jsx-a11y/tabindex-no-positive": "error", + "react/jsx-key": "warn", + "react/jsx-no-comment-textnodes": "warn", + "react/jsx-no-duplicate-props": "warn", + "react/jsx-no-target-blank": [ + "error", + { + "allowReferrer": true + } + ], + "react/jsx-no-undef": "warn", + "react/no-children-prop": "warn", + "react/no-danger-with-children": "warn", + "react/no-direct-mutation-state": "warn", + "react/no-find-dom-node": "warn", + "react/no-is-mounted": "warn", + "react/no-render-return-value": "warn", + "react/no-string-refs": "warn", + "react/no-unescaped-entities": "warn", + "react/no-unknown-property": [ + "error", + { + "ignore": ["css"] + } + ], + "react/react-in-jsx-scope": "off", + "curly": "off", + "no-label-var": "error", + "no-restricted-imports": [ + "error", + { + "paths": [ + { + "message": "Please always import from '@clerk/shared/' instead of '@clerk/shared'.", + "name": "@clerk/shared" + } + ], + "patterns": [ + { + "group": ["!@clerk/shared/*"], + "message": "ignore this line -- eslint matching workaround to allow all imports except @clerk/shared" + }, + { + "group": ["@emotion/*"], + "message": "Please do not import emotion directly. Import helpers from ./design-system or ./primitives instead." + } + ] + } + ], + "react/button-has-type": "warn", + "react/jsx-boolean-value": "warn", + "react/jsx-curly-brace-presence": "off", + "react/jsx-no-useless-fragment": "warn", + "react/no-array-index-key": "warn", + "react/self-closing-comp": "warn", + "sort-imports": "off", + "@typescript-eslint/consistent-type-imports": [ + "error", + { + "prefer": "type-imports", + "disallowTypeAnnotations": true, + "fixStyle": "separate-type-imports" + } + ], + "react-hooks/rules-of-hooks": "warn", + "react-hooks/exhaustive-deps": "warn", + "unicorn/empty-brace-spaces": "off", + "unicorn/no-nested-ternary": "off", + "unicorn/number-literal-case": "off" + }, + "overrides": [ + { + "files": ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"], + "rules": { + "no-class-assign": "off", + "no-const-assign": "off", + "no-dupe-class-members": "off", + "no-dupe-keys": "off", + "no-func-assign": "off", + "no-import-assign": "off", + "no-new-native-nonconstructor": "off", + "no-obj-calls": "off", + "no-redeclare": "off", + "no-setter-return": "off", + "no-this-before-super": "off", + "no-unsafe-negation": "off", + "no-var": "error", + "no-with": "off", + "prefer-rest-params": "error", + "prefer-spread": "error" + } + }, + { + "files": ["**/*.cjs", "**/*.js", "**/*.jsx", "**/*.mjs"], + "rules": { + "no-unused-vars": [ + "error", + { + "args": "after-used", + "argsIgnorePattern": "^_", + "ignoreRestSiblings": true, + "vars": "all", + "varsIgnorePattern": "^_" + } + ] + } + }, + { + "files": ["**/*.cts", "**/*.mts", "**/*.ts", "**/*.tsx"], + "env": { + "es2018": true + } + }, + { + "files": ["**/*.cts", "**/*.mts", "**/*.ts", "**/*.tsx"], + "rules": { + "no-unused-vars": "off", + "@typescript-eslint/no-non-null-assertion": "error" + } + }, + { + "files": ["**/*.test.js", "**/*.test.jsx", "**/*.test.ts", "**/*.test.tsx", "**/test/**", "**/__tests__/**"], + "env": { + "jest": true + } + }, + { + "files": ["packages/expo-passkeys/src/**/*"], + "rules": { + "no-restricted-imports": [ + "error", + { + "patterns": ["node:*"] + } + ] + } + }, + { + "files": ["packages/upgrade/src/**/*"], + "rules": { + "react/no-unescaped-entities": "off" + } + }, + { + "files": ["integration/tests/**"], + "rules": { + "no-empty-pattern": "off" + }, + "globals": { + "AbortController": "readonly", + "AbortSignal": "readonly", + "atob": "readonly", + "Blob": "readonly", + "BroadcastChannel": "readonly", + "btoa": "readonly", + "ByteLengthQueuingStrategy": "readonly", + "clearInterval": "readonly", + "clearTimeout": "readonly", + "CompressionStream": "readonly", + "console": "readonly", + "CountQueuingStrategy": "readonly", + "crypto": "readonly", + "Crypto": "readonly", + "CryptoKey": "readonly", + "CustomEvent": "readonly", + "DecompressionStream": "readonly", + "DOMException": "readonly", + "Event": "readonly", + "EventTarget": "readonly", + "fetch": "readonly", + "File": "readonly", + "FormData": "readonly", + "Headers": "readonly", + "Intl": "readonly", + "MessageChannel": "readonly", + "MessageEvent": "readonly", + "MessagePort": "readonly", + "performance": "readonly", + "PerformanceEntry": "readonly", + "PerformanceMark": "readonly", + "PerformanceMeasure": "readonly", + "PerformanceObserver": "readonly", + "PerformanceObserverEntryList": "readonly", + "PerformanceResourceTiming": "readonly", + "queueMicrotask": "readonly", + "ReadableByteStreamController": "readonly", + "ReadableStream": "readonly", + "ReadableStreamBYOBReader": "readonly", + "ReadableStreamBYOBRequest": "readonly", + "ReadableStreamDefaultController": "readonly", + "ReadableStreamDefaultReader": "readonly", + "Request": "readonly", + "Response": "readonly", + "setInterval": "readonly", + "setTimeout": "readonly", + "structuredClone": "readonly", + "SubtleCrypto": "readonly", + "TextDecoder": "readonly", + "TextDecoderStream": "readonly", + "TextEncoder": "readonly", + "TextEncoderStream": "readonly", + "TransformStream": "readonly", + "TransformStreamDefaultController": "readonly", + "URL": "readonly", + "URLSearchParams": "readonly", + "WebAssembly": "readonly", + "WritableStream": "readonly", + "WritableStreamDefaultController": "readonly", + "WritableStreamDefaultWriter": "readonly" + } + }, + { + "files": ["packages/shared/src/**/*.{ts,tsx}"], + "rules": { + "jsdoc/check-access": "warn", + "jsdoc/check-property-names": "warn", + "jsdoc/check-tag-names": [ + "warn", + { + "definedTags": ["inline", "unionReturnHeadings", "displayFunctionSignature", "paramExtension"], + "typed": false + } + ], + "jsdoc/empty-tags": "warn", + "jsdoc/implements-on-classes": "warn", + "jsdoc/no-defaults": "warn", + "jsdoc/require-param": [ + "warn", + { + "ignoreWhenAllParamsMissing": true + } + ], + "jsdoc/require-param-description": "warn", + "jsdoc/require-param-name": "warn", + "jsdoc/require-param-type": "off", + "jsdoc/require-property": "warn", + "jsdoc/require-property-description": "warn", + "jsdoc/require-property-name": "warn", + "jsdoc/require-property-type": "off", + "jsdoc/require-returns": "off", + "jsdoc/require-returns-description": "warn", + "jsdoc/require-returns-type": "off", + "jsdoc/require-yields": "warn" + }, + "plugins": ["jsdoc"] + }, + { + "files": ["*.yaml", "**/*.yaml", "*.yml", "**/*.yml"], + "rules": { + "no-irregular-whitespace": "off", + "no-unused-vars": "off" + } + }, + { + "files": ["packages/shared/src/compiled/path-to-regexp/index.js"], + "rules": { + "no-unused-expressions": "off" + } + } + ] +} diff --git a/package.json b/package.json index 4d60d2d2302..fe45bb7bb6a 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "lint:packages": "FORCE_COLOR=1 turbo lint", "lint:publint": "FORCE_COLOR=1 turbo lint:publint", "nuke": "node ./scripts/nuke.mjs", + "oxlint": "oxlint --quiet", "prepare": "husky install", "release": "changeset publish && git push --follow-tags", "release:canary": "changeset publish --tag canary --no-git-tag", @@ -120,6 +121,7 @@ "json5": "2.2.3", "jsonwebtoken": "9.0.2", "lint-staged": "^14.0.1", + "oxlint": "^1.0.0", "prettier": "^3.5.3", "prettier-plugin-packagejson": "^2.5.15", "prettier-plugin-tailwindcss": "^0.6.12", diff --git a/packages/agent-toolkit/package.json b/packages/agent-toolkit/package.json index d163a80a879..43a5e475e02 100644 --- a/packages/agent-toolkit/package.json +++ b/packages/agent-toolkit/package.json @@ -41,6 +41,7 @@ "dev": "tsup --watch", "lint": "eslint src", "lint:attw": "attw --pack . --profile esm-only", + "lint:oxlint": "oxlint src", "lint:publint": "publint", "test": "vitest run" }, diff --git a/packages/astro/package.json b/packages/astro/package.json index 7324cbc829a..eebb6a3296e 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -82,6 +82,7 @@ "dev": "tsup --watch --onSuccess \"pnpm build:dts\"", "lint": "eslint src env.d.ts", "lint:attw": "attw --pack . --profile esm-only --ignore-rules internal-resolution-error", + "lint:oxlint": "oxlint --quiet src env.d.ts", "lint:publint": "pnpm copy:components && publint", "publish:local": "pnpm yalc push --replace --sig" }, diff --git a/packages/astro/src/astro-components/control/ProtectCSR.astro b/packages/astro/src/astro-components/control/ProtectCSR.astro index 18a02b18128..e83d023f846 100644 --- a/packages/astro/src/astro-components/control/ProtectCSR.astro +++ b/packages/astro/src/astro-components/control/ProtectCSR.astro @@ -44,10 +44,12 @@ class ClerkProtect extends BaseClerkControlElement { !state.userId || ((role || permission) && !has?.({ role, permission } as Parameters[0])); if (this.defaultSlot) { + // oxlint-disable-next-line no-unused-expressions isUnauthorized ? this.defaultSlot.setAttribute('hidden', '') : this.defaultSlot.removeAttribute('hidden'); } if (this.fallbackSlot) { + // oxlint-disable-next-line no-unused-expressions isUnauthorized ? this.fallbackSlot.removeAttribute('hidden') : this.fallbackSlot.setAttribute('hidden', ''); } } diff --git a/packages/astro/src/react/controlComponents.tsx b/packages/astro/src/react/controlComponents.tsx index fee04db533a..fc378db4a4d 100644 --- a/packages/astro/src/react/controlComponents.tsx +++ b/packages/astro/src/react/controlComponents.tsx @@ -49,24 +49,24 @@ const useSafeIsLoaded = () => { return isLoaded; }; -export const ClerkLoaded = ({ children }: React.PropsWithChildren): JSX.Element | null => { +export const ClerkLoaded = ({ children }: React.PropsWithChildren): React.ReactNode => { const isLoaded = useSafeIsLoaded(); if (!isLoaded) { return null; } - return <>{children}; + return children; }; -export const ClerkLoading = ({ children }: React.PropsWithChildren): JSX.Element | null => { +export const ClerkLoading = ({ children }: React.PropsWithChildren): React.ReactNode => { const isLoaded = useSafeIsLoaded(); if (isLoaded) { return null; } - return <>{children}; + return children; }; export type ProtectProps = React.PropsWithChildren< @@ -85,7 +85,12 @@ export type ProtectProps = React.PropsWithChildren< * Unauthorized

} /> * ``` */ -export const Protect = ({ children, fallback, treatPendingAsSignedOut, ...restAuthorizedParams }: ProtectProps) => { +export const Protect = ({ + children, + fallback, + treatPendingAsSignedOut, + ...restAuthorizedParams +}: ProtectProps): React.ReactNode => { const { isLoaded, has, userId } = useAuth({ treatPendingAsSignedOut }); /** @@ -98,9 +103,9 @@ export const Protect = ({ children, fallback, treatPendingAsSignedOut, ...restAu /** * Fallback to UI provided by user or `null` if authorization checks failed */ - const unauthorized = <>{fallback ?? null}; + const unauthorized = fallback ?? null; - const authorized = <>{children}; + const authorized = children; if (!userId) { return unauthorized; @@ -137,7 +142,7 @@ export const AuthenticateWithRedirectCallback = withClerk( ({ clerk, ...handleRedirectCallbackParams }: WithClerkProp) => { React.useEffect(() => { void clerk?.handleRedirectCallback(handleRedirectCallbackParams); - }, []); + }, []); // eslint-disable-line react-hooks/exhaustive-deps return null; }, diff --git a/packages/backend/package.json b/packages/backend/package.json index 337bcce1ad4..87468a1e031 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -95,6 +95,7 @@ "dev:publish": "pnpm dev -- --env.publish", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16 --ignore-rules false-cjs", + "lint:oxlint": "oxlint src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "run-s test:node test:edge-runtime test:cloudflare-miniflare", diff --git a/packages/backend/src/runtime/node/crypto.js b/packages/backend/src/runtime/node/crypto.js index dc45bca829a..f30eb1a83ed 100644 --- a/packages/backend/src/runtime/node/crypto.js +++ b/packages/backend/src/runtime/node/crypto.js @@ -1 +1,2 @@ +// eslint-disable-next-line @typescript-eslint/no-require-imports module.exports.webcrypto = require('node:crypto').webcrypto; diff --git a/packages/chrome-extension/package.json b/packages/chrome-extension/package.json index 6fa55142202..b7cdc1a82c1 100644 --- a/packages/chrome-extension/package.json +++ b/packages/chrome-extension/package.json @@ -40,6 +40,7 @@ "dev:publish": "pnpm dev -- --env.publish", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16", + "lint:oxlint": "oxlint src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "jest", diff --git a/packages/clerk-js/headless/index.js b/packages/clerk-js/headless/index.js index eb34c85affa..abd1e490328 100644 --- a/packages/clerk-js/headless/index.js +++ b/packages/clerk-js/headless/index.js @@ -1 +1,2 @@ +// oxlint-disable-next-line @typescript-eslint/no-require-imports module.exports = require('../dist/clerk.headless'); diff --git a/packages/clerk-js/no-rhc/index.js b/packages/clerk-js/no-rhc/index.js index f29fe6cfcfa..7570a01cb97 100644 --- a/packages/clerk-js/no-rhc/index.js +++ b/packages/clerk-js/no-rhc/index.js @@ -1 +1,2 @@ +// oxlint-disable-next-line @typescript-eslint/no-require-imports module.exports = require('../dist/clerk.no-rhc'); diff --git a/packages/clerk-js/package.json b/packages/clerk-js/package.json index 36c01bbcb9c..9a6dd19447d 100644 --- a/packages/clerk-js/package.json +++ b/packages/clerk-js/package.json @@ -46,6 +46,7 @@ "dev:sandbox": "rspack serve --config rspack.config.js --env devOrigin=http://localhost:4000 --env sandbox=1", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16 --ignore-rules named-exports", + "lint:oxlint": "oxlint --quiet src", "lint:publint": "publint || true", "test": "jest && vitest --watch=false", "test:cache:clear": "jest --clearCache --useStderr", diff --git a/packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts b/packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts index 5426968522b..82ad8c9ae31 100644 --- a/packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts +++ b/packages/clerk-js/src/core/modules/commerce/CommerceBilling.ts @@ -50,7 +50,7 @@ export class CommerceBilling implements CommerceBillingNamespace { search: convertPageToOffsetSearchParams(rest), }).then(res => { const { data: subscriptions, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + res?.response as unknown as ClerkPaginatedResponse; // oxlint-disable-line no-unsafe-optional-chaining return { total_count, @@ -68,7 +68,7 @@ export class CommerceBilling implements CommerceBillingNamespace { search: convertPageToOffsetSearchParams(rest), }).then(res => { const { data: statements, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + res?.response as unknown as ClerkPaginatedResponse; // oxlint-disable-line no-unsafe-optional-chaining return { total_count, @@ -87,6 +87,7 @@ export class CommerceBilling implements CommerceBillingNamespace { method: 'GET', search: convertPageToOffsetSearchParams(rest), }).then(res => { + // oxlint-disable-next-line no-unsafe-optional-chaining const { data: payments, total_count } = res as unknown as ClerkPaginatedResponse; return { diff --git a/packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts b/packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts index 5ce956d4f65..e9f732be8cc 100644 --- a/packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts +++ b/packages/clerk-js/src/core/modules/commerce/payment-source-methods.ts @@ -46,7 +46,7 @@ export const getPaymentSources = async (params: GetPaymentSourcesParams) => { search: convertPageToOffsetSearchParams(rest), }).then(res => { const { data: paymentSources, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + res?.response as unknown as ClerkPaginatedResponse; // oxlint-disable-line no-unsafe-optional-chaining return { total_count, data: paymentSources.map(paymentSource => new CommercePaymentSource(paymentSource)), diff --git a/packages/clerk-js/src/core/resources/Organization.ts b/packages/clerk-js/src/core/resources/Organization.ts index 424b373b89a..9e12ad4970e 100644 --- a/packages/clerk-js/src/core/resources/Organization.ts +++ b/packages/clerk-js/src/core/resources/Organization.ts @@ -98,6 +98,7 @@ export class Organization extends BaseResource implements OrganizationResource { forceUpdateClient: true, }, ).then(res => { + // oxlint-disable-next-line no-unsafe-optional-chaining const { data: roles, total_count } = res?.response as unknown as ClerkPaginatedResponse; return { @@ -120,6 +121,7 @@ export class Organization extends BaseResource implements OrganizationResource { forceUpdateClient: true, }, ).then(res => { + // oxlint-disable-next-line no-unsafe-optional-chaining const { data: invites, total_count } = res?.response as unknown as ClerkPaginatedResponse; return { @@ -148,7 +150,7 @@ export class Organization extends BaseResource implements OrganizationResource { search: convertPageToOffsetSearchParams(getRequestParam), }).then(res => { const { data: requests, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + res?.response as unknown as ClerkPaginatedResponse; // oxlint-disable-line no-unsafe-optional-chaining return { total_count, @@ -170,7 +172,7 @@ export class Organization extends BaseResource implements OrganizationResource { search: convertPageToOffsetSearchParams({ ...getMembershipsParams, paginated: true }), }).then(res => { const { data: suggestions, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + res?.response as unknown as ClerkPaginatedResponse; // oxlint-disable-line no-unsafe-optional-chaining return { total_count, @@ -193,7 +195,7 @@ export class Organization extends BaseResource implements OrganizationResource { }, ).then(res => { const { data: requests, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + res?.response as unknown as ClerkPaginatedResponse; // oxlint-disable-line no-unsafe-optional-chaining return { total_count, @@ -242,7 +244,7 @@ export class Organization extends BaseResource implements OrganizationResource { search: convertPageToOffsetSearchParams(getSubscriptionsParams), }).then(res => { const { data: subscriptions, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + res?.response as unknown as ClerkPaginatedResponse; // oxlint-disable-line no-unsafe-optional-chaining return { total_count, diff --git a/packages/clerk-js/src/core/resources/OrganizationMembership.ts b/packages/clerk-js/src/core/resources/OrganizationMembership.ts index 489c9baa0f8..a525806758e 100644 --- a/packages/clerk-js/src/core/resources/OrganizationMembership.ts +++ b/packages/clerk-js/src/core/resources/OrganizationMembership.ts @@ -40,7 +40,7 @@ export class OrganizationMembership extends BaseResource implements Organization }).then(res => { // TODO: Fix typing const { data: suggestions, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + res?.response as unknown as ClerkPaginatedResponse; // oxlint-disable-line no-unsafe-optional-chaining return { total_count, diff --git a/packages/clerk-js/src/core/resources/OrganizationSuggestion.ts b/packages/clerk-js/src/core/resources/OrganizationSuggestion.ts index 2f6d42bd7ed..30e3b2bb943 100644 --- a/packages/clerk-js/src/core/resources/OrganizationSuggestion.ts +++ b/packages/clerk-js/src/core/resources/OrganizationSuggestion.ts @@ -32,7 +32,7 @@ export class OrganizationSuggestion extends BaseResource implements Organization search: convertPageToOffsetSearchParams(params), }).then(res => { const { data: suggestions, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + res?.response as unknown as ClerkPaginatedResponse; // oxlint-disable-line no-unsafe-optional-chaining return { total_count, diff --git a/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts b/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts index 37c86d0076d..7452c93a4ee 100644 --- a/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts +++ b/packages/clerk-js/src/core/resources/UserOrganizationInvitation.ts @@ -30,7 +30,7 @@ export class UserOrganizationInvitation extends BaseResource implements UserOrga search: convertPageToOffsetSearchParams(params), }).then(res => { const { data: invites, total_count } = - res?.response as unknown as ClerkPaginatedResponse; + res?.response as unknown as ClerkPaginatedResponse; // oxlint-disable-line no-unsafe-optional-chaining return { total_count, diff --git a/packages/clerk-js/src/utils/url.ts b/packages/clerk-js/src/utils/url.ts index d5b69503538..dcdc9fb57cd 100644 --- a/packages/clerk-js/src/utils/url.ts +++ b/packages/clerk-js/src/utils/url.ts @@ -244,6 +244,7 @@ export function relativeToAbsoluteUrl(url: string, origin: string | URL): URL { // Regular expression to detect disallowed patterns const disallowedPatterns = [ + // oxlint-disable-next-line no-control-regex /\0/, // Null bytes /^\/\//, // Protocol-relative // eslint-disable-next-line no-control-regex @@ -258,6 +259,12 @@ export function isProblematicUrl(url: URL): boolean { if (hasBannedProtocol(url)) { return true; } + + // Check for null bytes in pathname + if (url.pathname.includes('\0')) { + return true; + } + // Check against disallowed patterns for (const pattern of disallowedPatterns) { if (pattern.test(url.pathname)) { diff --git a/packages/clerk-js/svgTransform.js b/packages/clerk-js/svgTransform.js index 949e48ebd58..9f1c6f96100 100644 --- a/packages/clerk-js/svgTransform.js +++ b/packages/clerk-js/svgTransform.js @@ -1,5 +1,5 @@ // eslint-disable-next-line @typescript-eslint/no-var-requires -const path = require('path'); +const path = require('path'); // oxlint-disable-line @typescript-eslint/no-require-imports module.exports = { process(src, filePath) { diff --git a/packages/dev-cli/package.json b/packages/dev-cli/package.json index 1739eb141e9..161ffef81e2 100644 --- a/packages/dev-cli/package.json +++ b/packages/dev-cli/package.json @@ -19,7 +19,8 @@ "clerk-dev": "bin/cli.js" }, "scripts": { - "lint": "eslint src" + "lint": "eslint src", + "lint:oxlint": "oxlint src" }, "dependencies": { "commander": "^12.1.0", diff --git a/packages/elements/package.json b/packages/elements/package.json index 7c67fe3e4ad..7ee52aa01ed 100644 --- a/packages/elements/package.json +++ b/packages/elements/package.json @@ -65,6 +65,7 @@ "dev:example": "concurrently \"pnpm dev\" \"pnpm app:dev\"", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16", + "lint:oxlint": "oxlint --quiet src", "lint:publint": "publint", "test": "jest", "test:cache:clear": "jest --clearCache --useStderr" diff --git a/packages/expo-passkeys/package.json b/packages/expo-passkeys/package.json index ceab7aa361c..e0594c256c8 100644 --- a/packages/expo-passkeys/package.json +++ b/packages/expo-passkeys/package.json @@ -26,6 +26,7 @@ "dev": "tsup --watch", "dev:publish": "pnpm dev -- --env.publish", "lint": "eslint src", + "lint:oxlint": "oxlint src", "open:android": "open -a \"Android Studio\" example/android", "open:ios": "xed example/ios", "publish:local": "pnpm yalc push --replace --sig" diff --git a/packages/expo/package.json b/packages/expo/package.json index 4f394796e9a..5b45a1f00ff 100644 --- a/packages/expo/package.json +++ b/packages/expo/package.json @@ -72,6 +72,7 @@ "dev": "tsup --watch", "dev:publish": "pnpm dev -- --env.publish", "lint": "eslint src", + "lint:oxlint": "oxlint --quiet src", "publish:local": "pnpm yalc push --replace --sig", "test": "vitest run", "test:watch": "vitest watch" diff --git a/packages/express/package.json b/packages/express/package.json index de0c08614f7..0e8feecc265 100644 --- a/packages/express/package.json +++ b/packages/express/package.json @@ -59,6 +59,7 @@ "dev:publish": "pnpm dev -- --env.publish", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16", + "lint:oxlint": "oxlint src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "jest", diff --git a/packages/fastify/package.json b/packages/fastify/package.json index 57f13504ce6..d7d5450617e 100644 --- a/packages/fastify/package.json +++ b/packages/fastify/package.json @@ -57,6 +57,7 @@ "dev": "tsup --watch", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16 --ignore-rules unexpected-module-syntax", + "lint:oxlint": "oxlint src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "jest", diff --git a/packages/localizations/package.json b/packages/localizations/package.json index fe49d3d2cc8..969fcc01570 100644 --- a/packages/localizations/package.json +++ b/packages/localizations/package.json @@ -101,7 +101,8 @@ "dev": "tsup --watch", "generate": "tsc src/utils/generate.ts && node src/utils/generate.js && prettier --write src/*.ts", "lint": "eslint src", - "lint:attw": "attw --pack . --profile node16" + "lint:attw": "attw --pack . --profile node16", + "lint:oxlint": "oxlint src" }, "dependencies": { "@clerk/types": "workspace:^" diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index cafe62880d9..4173ac1205f 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -66,6 +66,7 @@ "dev:publish": "pnpm dev -- --env.publish", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16 --ignore-rules unexpected-module-syntax", + "lint:oxlint": "oxlint --quiet src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "vitest run", diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index ec33ecebbd9..6ba04d386d7 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -61,6 +61,7 @@ "dev": "tsup --watch", "lint": "eslint src", "lint:attw": "attw --pack . --profile esm-only", + "lint:oxlint": "oxlint --quiet src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "vitest run", diff --git a/packages/react-router/package.json b/packages/react-router/package.json index 1872ae34fc8..d0978723355 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -74,6 +74,7 @@ "dev": "tsup --watch", "lint": "eslint src", "lint:attw": "attw --pack . --profile esm-only", + "lint:oxlint": "oxlint --quiet src", "lint:publint": "publint", "publish:local": "pnpm dlx yalc push --replace --sig", "test": "vitest run", diff --git a/packages/react/package.json b/packages/react/package.json index 1b079d1466f..7f935b15e1a 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -70,6 +70,7 @@ "dev:publish": "pnpm dev --env.publish", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16", + "lint:oxlint": "oxlint --quiet src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "vitest run", diff --git a/packages/remix/package.json b/packages/remix/package.json index 1121c9bfb74..4694807e25e 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -69,6 +69,7 @@ "dev:publish": "pnpm dev -- --env.publish", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16", + "lint:oxlint": "oxlint --quiet src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "vitest run", diff --git a/packages/shared/package.json b/packages/shared/package.json index 8bcada7b085..82f3847f7b9 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -134,6 +134,7 @@ "postinstall": "node ./scripts/postinstall.mjs", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16", + "lint:oxlint": "oxlint --quiet src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "jest", diff --git a/packages/shared/scripts/postinstall.mjs b/packages/shared/scripts/postinstall.mjs index cafc989333c..f77e8f73b56 100755 --- a/packages/shared/scripts/postinstall.mjs +++ b/packages/shared/scripts/postinstall.mjs @@ -49,7 +49,7 @@ async function notifyAboutTelemetry() { let config = {}; try { config = JSON.parse(await fs.readFile(configFile, 'utf8')); - } catch (err) { + } catch { // File can't be read and parsed, continue } diff --git a/packages/tanstack-react-start/package.json b/packages/tanstack-react-start/package.json index ddc0529518e..76538b922f9 100644 --- a/packages/tanstack-react-start/package.json +++ b/packages/tanstack-react-start/package.json @@ -61,6 +61,7 @@ "dev:publish": "pnpm dev -- --env.publish", "lint": "eslint src", "lint:attw": "attw --pack . --profile esm-only", + "lint:oxlint": "oxlint src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "vitest run", diff --git a/packages/testing/package.json b/packages/testing/package.json index 7a09f65fbba..0c079406e80 100644 --- a/packages/testing/package.json +++ b/packages/testing/package.json @@ -69,7 +69,8 @@ "build": "tsup --env.NODE_ENV production", "clean": "rimraf ./dist", "dev": "tsup --watch", - "lint": "eslint src" + "lint": "eslint src", + "lint:oxlint": "oxlint src" }, "dependencies": { "@clerk/backend": "workspace:^", diff --git a/packages/themes/package.json b/packages/themes/package.json index 0451197a688..58f5ac09d55 100644 --- a/packages/themes/package.json +++ b/packages/themes/package.json @@ -35,7 +35,8 @@ "clean": "rimraf ./dist", "dev": "tsc -p tsconfig.build.json --watch", "lint": "eslint src", - "lint:attw": "attw --pack . --profile node16" + "lint:attw": "attw --pack . --profile node16", + "lint:oxlint": "oxlint src" }, "dependencies": { "@clerk/types": "workspace:^", diff --git a/packages/types/package.json b/packages/types/package.json index b406f0eb27e..b7215ad9fa9 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -36,6 +36,7 @@ "dev": "tsup --watch", "lint": "eslint src", "lint:attw": "attw --pack . --profile node16", + "lint:oxlint": "oxlint src", "publish:local": "pnpm yalc push --replace --sig" }, "dependencies": { diff --git a/packages/upgrade/package.json b/packages/upgrade/package.json index 062162c869c..886e60b34c3 100644 --- a/packages/upgrade/package.json +++ b/packages/upgrade/package.json @@ -20,6 +20,7 @@ "clean": "rm -rf dist/*", "dev": "babel --keep-file-extension --out-dir=dist --watch src --copy-files", "lint": "eslint src/", + "lint:oxlint": "oxlint --quiet src", "lint:publint": "publint", "test": "vitest run", "test:watch": "vitest watch" diff --git a/packages/vue/package.json b/packages/vue/package.json index d16dfc9ee21..1248ed58329 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -50,6 +50,7 @@ "dev": "tsup --watch", "lint": "eslint src", "lint:attw": "attw --pack . --profile esm-only --ignore-rules internal-resolution-error", + "lint:oxlint": "oxlint src", "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "vitest run", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9707e66b295..f8ed1b7d418 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -241,6 +241,9 @@ importers: lint-staged: specifier: ^14.0.1 version: 14.0.1(enquirer@2.4.1) + oxlint: + specifier: ^1.0.0 + version: 1.0.0 prettier: specifier: ^3.5.3 version: 3.5.3 @@ -3834,6 +3837,46 @@ packages: '@oxc-project/types@0.60.0': resolution: {integrity: sha512-prhfNnb3ATFHOCv7mzKFfwLij5RzoUz6Y1n525ZhCEqfq5wreCXL+DyVoq3ShukPo7q45ZjYIdjFUgjj+WKzng==} + '@oxlint/darwin-arm64@1.0.0': + resolution: {integrity: sha512-Ei8wLh65Th/si5EY6mfQIXVpdXbJWOoh56FaxxPgVxTeJaj3NHUIlxICHkvTZ5dz8bnOFcbS/+9MaW8Qkzfm9g==} + cpu: [arm64] + os: [darwin] + + '@oxlint/darwin-x64@1.0.0': + resolution: {integrity: sha512-dbdtQ+rJTUb4jFKTzV+j08yYcR8lZssLF10n7MggK/jI7pBtoQN04cupzYdkxOWSy6uDXjDmWYFDIqlTqV7zOg==} + cpu: [x64] + os: [darwin] + + '@oxlint/linux-arm64-gnu@1.0.0': + resolution: {integrity: sha512-71wy9zMxsAeRhCFQjUkDLT8N5tm10L5FxNxsUcEsezgM187X9tPGP1gwlFpYig7F+bg2X1dijFuTA/FSe0YpKg==} + cpu: [arm64] + os: [linux] + + '@oxlint/linux-arm64-musl@1.0.0': + resolution: {integrity: sha512-UbD4+2k7aGZOFtKK/yeESX7Fv0w9gQbcjrjr1HGY7QOYg7XlFlqzycZdPS6XbAuKA5oOXFpafaYOD4AyX3p2AA==} + cpu: [arm64] + os: [linux] + + '@oxlint/linux-x64-gnu@1.0.0': + resolution: {integrity: sha512-0NXWqsm65I3VaLgADW4y9r7Pwurqgs2fr1lqoTyTIlidD18LQ3UMAWp8NzBPMCYzw8c/rTgOzsFf0gLtxzMtwg==} + cpu: [x64] + os: [linux] + + '@oxlint/linux-x64-musl@1.0.0': + resolution: {integrity: sha512-AY1NLnVQI+tBeuaB8KCriWfiD6O1zZFAQHphRDcZiqSz4mauNq9FFuffW0N9RSR9hYttGr0UVdQ6eK72RhzOYg==} + cpu: [x64] + os: [linux] + + '@oxlint/win32-arm64@1.0.0': + resolution: {integrity: sha512-X9y2KAdoqT/jy/sITGDZNMJHJAmhDhofItBnCf2DWS1HPakdtCAKGX9KMx6SivTbtPn1+JpZgfHn4Y7rNMvujQ==} + cpu: [arm64] + os: [win32] + + '@oxlint/win32-x64@1.0.0': + resolution: {integrity: sha512-x2eQwZCfRUi6GG0lhRuC54O6TK2uW7UbIvERh83vPi0ftd+rtGUuJauNdyC+pPx+iwFToFVet43/5MBMu4bMWg==} + cpu: [x64] + os: [win32] + '@parcel/watcher-android-arm64@2.5.1': resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} engines: {node: '>= 10.0.0'} @@ -11113,6 +11156,11 @@ packages: resolution: {integrity: sha512-MNT32sqiTFeSbQZP2WZIRQ/mlIpNNq4sua+/4hBG4qT5aef2iQe+1/BjezZURPlvucZeSfN1Y6b60l7OgBdyUA==} engines: {node: '>=14.0.0'} + oxlint@1.0.0: + resolution: {integrity: sha512-yyeryHnd21wPBLBEF4Uf8hvzJlftrIGHxyUaqFaP2JYiZ9cbiColygZhrezvv/Z/aThCmYu3j6iJMxlVPxNt6g==} + engines: {node: '>=8.*'} + hasBin: true + p-event@5.0.1: resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -18041,6 +18089,30 @@ snapshots: '@oxc-project/types@0.60.0': {} + '@oxlint/darwin-arm64@1.0.0': + optional: true + + '@oxlint/darwin-x64@1.0.0': + optional: true + + '@oxlint/linux-arm64-gnu@1.0.0': + optional: true + + '@oxlint/linux-arm64-musl@1.0.0': + optional: true + + '@oxlint/linux-x64-gnu@1.0.0': + optional: true + + '@oxlint/linux-x64-musl@1.0.0': + optional: true + + '@oxlint/win32-arm64@1.0.0': + optional: true + + '@oxlint/win32-x64@1.0.0': + optional: true + '@parcel/watcher-android-arm64@2.5.1': optional: true @@ -27797,6 +27869,17 @@ snapshots: '@oxc-parser/binding-win32-arm64-msvc': 0.56.5 '@oxc-parser/binding-win32-x64-msvc': 0.56.5 + oxlint@1.0.0: + optionalDependencies: + '@oxlint/darwin-arm64': 1.0.0 + '@oxlint/darwin-x64': 1.0.0 + '@oxlint/linux-arm64-gnu': 1.0.0 + '@oxlint/linux-arm64-musl': 1.0.0 + '@oxlint/linux-x64-gnu': 1.0.0 + '@oxlint/linux-x64-musl': 1.0.0 + '@oxlint/win32-arm64': 1.0.0 + '@oxlint/win32-x64': 1.0.0 + p-event@5.0.1: dependencies: p-timeout: 5.1.0 diff --git a/turbo.json b/turbo.json index 0e3eeac08d7..3a55917f4ec 100644 --- a/turbo.json +++ b/turbo.json @@ -102,6 +102,27 @@ "cache": false }, "lint": { + "dependsOn": ["lint:oxlint"], + "inputs": [ + "**/*.js", + "**/*.jsx", + "**/*.ts", + "**/*.tsx", + "**/*.json", + "**/*.md", + "**/*.mdx", + ".github/**", + "!*/package.json", + "!**/__snapshots__/**", + "!CHANGELOG.md", + "!coverage/**", + "!dist/**", + "!examples/**", + "!node_modules/**" + ], + "outputs": [] + }, + "lint:oxlint": { "dependsOn": ["^build"], "inputs": [ "**/*.js",