Skip to content
Merged
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
9 changes: 1 addition & 8 deletions apps/oxlint/src-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,7 @@ import type { CreateOnceRule, Plugin, Rule } from './plugins/load.ts';
import type { BeforeHook, Visitor, VisitorWithHooks } from './plugins/types.ts';

export type * as ESTree from './generated/types.d.ts';
export type {
Context,
Diagnostic,
DiagnosticBase,
DiagnosticWithLoc,
DiagnosticWithMessageId,
DiagnosticWithNode,
} from './plugins/context.ts';
export type { Context, Diagnostic, DiagnosticBase, DiagnosticWithLoc, DiagnosticWithNode } from './plugins/context.ts';
export type { Fix, Fixer, FixFn } from './plugins/fix.ts';
export type { CreateOnceRule, CreateRule, Plugin, Rule } from './plugins/load.ts';
export type {
Expand Down
49 changes: 28 additions & 21 deletions apps/oxlint/src-js/plugins/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,23 @@ import type { Location, Ranged } from './types.ts';
const { hasOwn, keys: ObjectKeys } = Object;

// Diagnostic in form passed by user to `Context#report()`
export type Diagnostic = DiagnosticWithNode | DiagnosticWithLoc | DiagnosticWithMessageId;
export type Diagnostic = DiagnosticWithNode | DiagnosticWithLoc;

export interface DiagnosticBase {
message?: string;
message?: string | null | undefined;
messageId?: string | null | undefined;
data?: Record<string, string | number> | null | undefined;
fix?: FixFn;
}

export interface DiagnosticWithNode extends DiagnosticBase {
message: string;
node: Ranged;
}

export interface DiagnosticWithLoc extends DiagnosticBase {
message: string;
loc: Location;
}

export interface DiagnosticWithMessageId extends DiagnosticBase {
messageId: string;
node?: Ranged;
loc?: Location;
}

// Diagnostic in form sent to Rust
interface DiagnosticReport {
message: string;
Expand Down Expand Up @@ -158,16 +151,8 @@ export class Context {
report(diagnostic: Diagnostic): void {
const internal = getInternal(this, 'report errors');

// Resolve message from messageId if present
let message: string;
if (hasOwn(diagnostic, 'messageId')) {
message = resolveMessage((diagnostic as DiagnosticWithMessageId).messageId, internal);
} else {
message = diagnostic.message;
if (typeof message !== 'string') {
throw new TypeError('Either `message` or `messageId` is required');
}
}
// Get message, resolving message from `messageId` if present
let message = getMessage(diagnostic, internal);

// Interpolate placeholders {{key}} with data values
if (hasOwn(diagnostic, 'data')) {
Expand Down Expand Up @@ -239,14 +224,36 @@ export class Context {
}
}

/**
* Get message from diagnostic.
* @param diagnostic - Diagnostic object
* @param internal - Internal context object
* @returns Message string
* @throws {Error|TypeError} If neither `message` nor `messageId` provided, or of wrong type
*/
function getMessage(diagnostic: Diagnostic, internal: InternalContext): string {
if (hasOwn(diagnostic, 'messageId')) {
const { messageId } = diagnostic as { messageId: string | null | undefined };
if (messageId != null) return resolveMessageFromMessageId(messageId, internal);
}

if (hasOwn(diagnostic, 'message')) {
const { message } = diagnostic;
if (typeof message === 'string') return message;
if (message != null) throw new TypeError('`message` must be a string');
}

throw new Error('Either `message` or `messageId` is required');
}

/**
* Resolve a message ID to its message string, with optional data interpolation.
* @param messageId - The message ID to resolve
* @param internal - Internal context containing messages
* @returns Resolved message string
* @throws {Error} If `messageId` is not found in `messages`
*/
function resolveMessage(messageId: string, internal: InternalContext): string {
function resolveMessageFromMessageId(messageId: string, internal: InternalContext): string {
const { messages } = internal;
if (messages === null) {
throw new Error(`Cannot use messageId '${messageId}' - rule does not define any messages in meta.messages`);
Expand Down
Loading