diff --git a/apps/oxlint/src-js/index.ts b/apps/oxlint/src-js/index.ts index 817ac5e0f9c13..e6947d1317b19 100644 --- a/apps/oxlint/src-js/index.ts +++ b/apps/oxlint/src-js/index.ts @@ -1,11 +1,11 @@ -import { assertIsNonNull } from './plugins/utils.js'; +import { assertIsNonNull } from './utils/asserts.js'; import type { Context, FileContext, LanguageOptions } from './plugins/context.ts'; import type { CreateOnceRule, Plugin, Rule } from './plugins/load.ts'; import type { Settings } from './plugins/settings.ts'; import type { SourceCode } from './plugins/source_code.ts'; import type { BeforeHook, Visitor, VisitorWithHooks } from './plugins/types.ts'; -import type { SetNullable } from './plugins/utils.ts'; +import type { SetNullable } from './utils/types.ts'; export type * as ESTree from './generated/types.d.ts'; export type { Context, LanguageOptions } from './plugins/context.ts'; diff --git a/apps/oxlint/src-js/plugins/comments.ts b/apps/oxlint/src-js/plugins/comments.ts index 862558033ebdb..fa3d77ab03f7d 100644 --- a/apps/oxlint/src-js/plugins/comments.ts +++ b/apps/oxlint/src-js/plugins/comments.ts @@ -3,7 +3,7 @@ */ import { ast, initAst, sourceText } from './source_code.js'; -import { assertIsNonNull } from './utils.js'; +import { assertIsNonNull } from '../utils/asserts.js'; import type { Comment, Node, NodeOrToken } from './types.ts'; diff --git a/apps/oxlint/src-js/plugins/context.ts b/apps/oxlint/src-js/plugins/context.ts index 6b923056f0a12..3ac912b865bdb 100644 --- a/apps/oxlint/src-js/plugins/context.ts +++ b/apps/oxlint/src-js/plugins/context.ts @@ -29,7 +29,7 @@ import { ast, initAst, SOURCE_CODE } from './source_code.js'; import { report } from './report.js'; import { settings, initSettings } from './settings.js'; -import { assertIsNonNull } from './utils.js'; +import { assertIsNonNull } from '../utils/asserts.js'; import type { Options, RuleDetails } from './load.ts'; import type { Diagnostic } from './report.ts'; diff --git a/apps/oxlint/src-js/plugins/fix.ts b/apps/oxlint/src-js/plugins/fix.ts index 8a47d2c101b2b..00943a065f00b 100644 --- a/apps/oxlint/src-js/plugins/fix.ts +++ b/apps/oxlint/src-js/plugins/fix.ts @@ -1,4 +1,4 @@ -import { assertIs } from './utils.js'; +import { assertIs } from '../utils/asserts.js'; import type { RuleDetails } from './load.ts'; import type { Range, Ranged } from './location.ts'; diff --git a/apps/oxlint/src-js/plugins/lint.ts b/apps/oxlint/src-js/plugins/lint.ts index b62f53187d7b5..70cd9f15e53b9 100644 --- a/apps/oxlint/src-js/plugins/lint.ts +++ b/apps/oxlint/src-js/plugins/lint.ts @@ -3,7 +3,8 @@ import { registeredRules } from './load.js'; import { diagnostics } from './report.js'; import { setSettingsForFile, resetSettings } from './settings.js'; import { ast, initAst, resetSourceAndAst, setupSourceForFile } from './source_code.js'; -import { assertIs, assertIsNonNull, getErrorMessage } from './utils.js'; +import { assertIs, assertIsNonNull } from '../utils/asserts.js'; +import { getErrorMessage } from '../utils/utils.js'; import { addVisitorToCompiled, compiledVisitor, finalizeCompiledVisitor, initCompiledVisitor } from './visitor.js'; // Lazy implementation diff --git a/apps/oxlint/src-js/plugins/load.ts b/apps/oxlint/src-js/plugins/load.ts index 504b54bf615e6..8d3e294c7cc4c 100644 --- a/apps/oxlint/src-js/plugins/load.ts +++ b/apps/oxlint/src-js/plugins/load.ts @@ -1,14 +1,14 @@ import { pathToFileURL } from 'node:url'; import { createContext } from './context.js'; -import { getErrorMessage } from './utils.js'; +import { getErrorMessage } from '../utils/utils.js'; import type { Writable } from 'type-fest'; import type { Context } from './context.ts'; import type { JsonValue } from './json.ts'; import type { RuleMeta } from './rule_meta.ts'; import type { AfterHook, BeforeHook, Visitor, VisitorWithHooks } from './types.ts'; -import type { SetNullable } from './utils.ts'; +import type { SetNullable } from '../utils/types.ts'; const ObjectKeys = Object.keys; diff --git a/apps/oxlint/src-js/plugins/location.ts b/apps/oxlint/src-js/plugins/location.ts index 4f73cfbeabcc9..e8f3d508faede 100644 --- a/apps/oxlint/src-js/plugins/location.ts +++ b/apps/oxlint/src-js/plugins/location.ts @@ -4,7 +4,7 @@ */ import { initSourceText, sourceText } from './source_code.js'; -import { assertIsNonNull } from './utils.js'; +import { assertIsNonNull } from '../utils/asserts.js'; import type { Node } from './types.ts'; diff --git a/apps/oxlint/src-js/plugins/scope.ts b/apps/oxlint/src-js/plugins/scope.ts index 801ddaa4dbfd0..f1b8c1c256fb4 100644 --- a/apps/oxlint/src-js/plugins/scope.ts +++ b/apps/oxlint/src-js/plugins/scope.ts @@ -8,10 +8,10 @@ import { type ScopeManager as TSESLintScopeManager, } from '@typescript-eslint/scope-manager'; import { ast, initAst } from './source_code.js'; -import { assertIs, assertIsNonNull } from './utils.js'; +import { assertIs, assertIsNonNull } from '../utils/asserts.js'; import type * as ESTree from '../generated/types.d.ts'; -import type { SetNullable } from './utils.ts'; +import type { SetNullable } from '../utils/types.ts'; export interface Scope { type: ScopeType; diff --git a/apps/oxlint/src-js/plugins/settings.ts b/apps/oxlint/src-js/plugins/settings.ts index 9e0b442757110..1bd262259d570 100644 --- a/apps/oxlint/src-js/plugins/settings.ts +++ b/apps/oxlint/src-js/plugins/settings.ts @@ -3,7 +3,7 @@ */ import { deepFreezeJsonValue } from './json.js'; -import { assertIsNonNull } from './utils.js'; +import { assertIsNonNull } from '../utils/asserts.js'; import type { JsonObject } from './json.ts'; diff --git a/apps/oxlint/src-js/plugins/source_code.ts b/apps/oxlint/src-js/plugins/source_code.ts index be298a5195389..72d96c0141b79 100644 --- a/apps/oxlint/src-js/plugins/source_code.ts +++ b/apps/oxlint/src-js/plugins/source_code.ts @@ -18,7 +18,7 @@ import { import { resetScopeManager, SCOPE_MANAGER } from './scope.js'; import * as scopeMethods from './scope.js'; import * as tokenMethods from './tokens.js'; -import { assertIsNonNull } from './utils.js'; +import { assertIsNonNull } from '../utils/asserts.js'; import type { Program } from '../generated/types.d.ts'; import type { Ranged } from './location.ts'; diff --git a/apps/oxlint/src-js/plugins/tokens.ts b/apps/oxlint/src-js/plugins/tokens.ts index 576e59fea8618..71c6c6824640f 100644 --- a/apps/oxlint/src-js/plugins/tokens.ts +++ b/apps/oxlint/src-js/plugins/tokens.ts @@ -3,7 +3,7 @@ */ import { sourceText, initSourceText } from './source_code.js'; -import { assertIsNonNull } from './utils.js'; +import { assertIsNonNull } from '../utils/asserts.js'; import type { Comment, Node, NodeOrToken, Token } from './types.ts'; diff --git a/apps/oxlint/src-js/plugins/utils.ts b/apps/oxlint/src-js/plugins/utils.ts deleted file mode 100644 index e496510acab5f..0000000000000 --- a/apps/oxlint/src-js/plugins/utils.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Get error message from an error. - * - * `err` is expected to be an `Error` object, but can be anything. - * - * * If it's an `Error`, the error message and stack trace is returned. - * * If it's another object with a string `message` property, `message` is returned. - * * Otherwise, a generic "Unknown error" message is returned. - * - * This function will never throw, and always returns a non-empty string, even if: - * - * * `err` is `null` or `undefined`. - * * `err` is an object with a getter for `message` property which throws. - * * `err` has a getter for `stack` or `message` property which returns a different value each time it's accessed. - * - * @param err - Error - * @returns Error message - */ -export function getErrorMessage(err: unknown): string { - try { - if (err instanceof Error) { - // Note: `stack` includes the error message - const { stack } = err; - if (typeof stack === 'string' && stack !== '') return stack; - } - - const { message } = err as { message?: unknown }; - if (typeof message === 'string' && message !== '') return message; - } catch {} - - return 'Unknown error'; -} - -/** - * Assert a value is of a certain type. - * - * Has no runtime effect - only for guiding the type-checker. - * Minification removes this function and all calls to it, so it has zero runtime cost. - * - * @param value - Value - */ -// oxlint-disable-next-line no-unused-vars -export function assertIs(value: unknown): asserts value is T {} - -/** - * Assert a value is not `null` or `undefined`. - * - * In release builds, is a no-op. Only does runtime checks in debug builds. - * Minification removes this function and all calls to it in release builds, so it has zero runtime cost. - * - * @param value - Value - */ -// oxlint-disable-next-line no-unused-vars -export function assertIsNonNull(value: T | null | undefined): asserts value is T { - if (!DEBUG) return; - - if (value === null || value === undefined) { - // oxlint-disable-next-line typescript/restrict-template-expressions - throw new Error(`Expected non-null value, got ${value}`); - } -} - -/** - * Utility type to make specified properties of a type nullable. - * - * @example - * ```ts - * type Foo = { str: string, num: number }; - * type FooWithNullableNum = SetNullable; - * // { str: string, num: number | null } - * ``` - */ -export type SetNullable = { - [Key in keyof BaseType]: Key extends Keys ? BaseType[Key] | null : BaseType[Key]; -}; diff --git a/apps/oxlint/src-js/plugins/visitor.ts b/apps/oxlint/src-js/plugins/visitor.ts index c9a4ed066f54e..c1b19f82f11ed 100644 --- a/apps/oxlint/src-js/plugins/visitor.ts +++ b/apps/oxlint/src-js/plugins/visitor.ts @@ -76,7 +76,7 @@ import { LEAF_NODE_TYPES_COUNT, NODE_TYPE_IDS_MAP, NODE_TYPES_COUNT } from '../g import { parseSelector, wrapVisitFnWithSelectorMatch } from './selector.js'; import type { CompiledVisitorEntry, EnterExit, Node, VisitFn, Visitor } from './types.ts'; -import { assertIs, assertIsNonNull } from './utils.js'; +import { assertIs, assertIsNonNull } from '../utils/asserts.js'; const ObjectKeys = Object.keys, { isArray } = Array; diff --git a/apps/oxlint/src-js/utils/asserts.ts b/apps/oxlint/src-js/utils/asserts.ts new file mode 100644 index 0000000000000..7996d8d7078d4 --- /dev/null +++ b/apps/oxlint/src-js/utils/asserts.ts @@ -0,0 +1,27 @@ +/** + * Assert a value is of a certain type. + * + * Has no runtime effect - only for guiding the type-checker. + * Minification removes this function and all calls to it, so it has zero runtime cost. + * + * @param value - Value + */ +// oxlint-disable-next-line no-unused-vars +export function assertIs(value: unknown): asserts value is T {} + +/** + * Assert a value is not `null` or `undefined`. + * + * In release builds, is a no-op. Only does runtime checks in debug builds. + * Minification removes this function and all calls to it in release builds, so it has zero runtime cost. + * + * @param value - Value + */ +export function assertIsNonNull(value: T | null | undefined): asserts value is T { + if (!DEBUG) return; + + if (value === null || value === undefined) { + // oxlint-disable-next-line typescript/restrict-template-expressions + throw new Error(`Expected non-null value, got ${value}`); + } +} diff --git a/apps/oxlint/src-js/utils/types.ts b/apps/oxlint/src-js/utils/types.ts new file mode 100644 index 0000000000000..1f660b4241172 --- /dev/null +++ b/apps/oxlint/src-js/utils/types.ts @@ -0,0 +1,13 @@ +/** + * Utility type to make specified properties of a type nullable. + * + * @example + * ```ts + * type Foo = { str: string, num: number }; + * type FooWithNullableNum = SetNullable; + * // { str: string, num: number | null } + * ``` + */ +export type SetNullable = { + [Key in keyof BaseType]: Key extends Keys ? BaseType[Key] | null : BaseType[Key]; +}; diff --git a/apps/oxlint/src-js/utils/utils.ts b/apps/oxlint/src-js/utils/utils.ts new file mode 100644 index 0000000000000..119d52689f1fe --- /dev/null +++ b/apps/oxlint/src-js/utils/utils.ts @@ -0,0 +1,32 @@ +/** + * Get error message from an error. + * + * `err` is expected to be an `Error` object, but can be anything. + * + * * If it's an `Error`, the error message and stack trace is returned. + * * If it's another object with a string `message` property, `message` is returned. + * * Otherwise, a generic "Unknown error" message is returned. + * + * This function will never throw, and always returns a non-empty string, even if: + * + * * `err` is `null` or `undefined`. + * * `err` is an object with a getter for `message` property which throws. + * * `err` has a getter for `stack` or `message` property which returns a different value each time it's accessed. + * + * @param err - Error + * @returns Error message + */ +export function getErrorMessage(err: unknown): string { + try { + if (err instanceof Error) { + // Note: `stack` includes the error message + const { stack } = err; + if (typeof stack === 'string' && stack !== '') return stack; + } + + const { message } = err as { message?: unknown }; + if (typeof message === 'string' && message !== '') return message; + } catch {} + + return 'Unknown error'; +}