@@ -9,30 +9,23 @@ import type { Location, Ranged } from './types.ts';
99const { hasOwn, keys : ObjectKeys } = Object ;
1010
1111// Diagnostic in form passed by user to `Context#report()`
12- export type Diagnostic = DiagnosticWithNode | DiagnosticWithLoc | DiagnosticWithMessageId ;
12+ export type Diagnostic = DiagnosticWithNode | DiagnosticWithLoc ;
1313
1414export interface DiagnosticBase {
15- message ?: string ;
15+ message ?: string | null | undefined ;
16+ messageId ?: string | null | undefined ;
1617 data ?: Record < string , string | number > | null | undefined ;
1718 fix ?: FixFn ;
1819}
1920
2021export interface DiagnosticWithNode extends DiagnosticBase {
21- message : string ;
2222 node : Ranged ;
2323}
2424
2525export interface DiagnosticWithLoc extends DiagnosticBase {
26- message : string ;
2726 loc : Location ;
2827}
2928
30- export interface DiagnosticWithMessageId extends DiagnosticBase {
31- messageId : string ;
32- node ?: Ranged ;
33- loc ?: Location ;
34- }
35-
3629// Diagnostic in form sent to Rust
3730interface DiagnosticReport {
3831 message : string ;
@@ -158,16 +151,8 @@ export class Context {
158151 report ( diagnostic : Diagnostic ) : void {
159152 const internal = getInternal ( this , 'report errors' ) ;
160153
161- // Resolve message from messageId if present
162- let message : string ;
163- if ( hasOwn ( diagnostic , 'messageId' ) ) {
164- message = resolveMessage ( ( diagnostic as DiagnosticWithMessageId ) . messageId , internal ) ;
165- } else {
166- message = diagnostic . message ;
167- if ( typeof message !== 'string' ) {
168- throw new TypeError ( 'Either `message` or `messageId` is required' ) ;
169- }
170- }
154+ // Get message, resolving message from `messageId` if present
155+ let message = getMessage ( diagnostic , internal ) ;
171156
172157 // Interpolate placeholders {{key}} with data values
173158 if ( hasOwn ( diagnostic , 'data' ) ) {
@@ -239,14 +224,36 @@ export class Context {
239224 }
240225}
241226
227+ /**
228+ * Get message from diagnostic.
229+ * @param diagnostic - Diagnostic object
230+ * @param internal - Internal context object
231+ * @returns Message string
232+ * @throws {Error|TypeError } If neither `message` nor `messageId` provided, or of wrong type
233+ */
234+ function getMessage ( diagnostic : Diagnostic , internal : InternalContext ) : string {
235+ if ( hasOwn ( diagnostic , 'messageId' ) ) {
236+ const { messageId } = diagnostic as { messageId : string | null | undefined } ;
237+ if ( messageId != null ) return resolveMessageFromMessageId ( messageId , internal ) ;
238+ }
239+
240+ if ( hasOwn ( diagnostic , 'message' ) ) {
241+ const { message } = diagnostic ;
242+ if ( typeof message === 'string' ) return message ;
243+ if ( message != null ) throw new TypeError ( '`message` must be a string' ) ;
244+ }
245+
246+ throw new Error ( 'Either `message` or `messageId` is required' ) ;
247+ }
248+
242249/**
243250 * Resolve a message ID to its message string, with optional data interpolation.
244251 * @param messageId - The message ID to resolve
245252 * @param internal - Internal context containing messages
246253 * @returns Resolved message string
247254 * @throws {Error } If `messageId` is not found in `messages`
248255 */
249- function resolveMessage ( messageId : string , internal : InternalContext ) : string {
256+ function resolveMessageFromMessageId ( messageId : string , internal : InternalContext ) : string {
250257 const { messages } = internal ;
251258 if ( messages === null ) {
252259 throw new Error ( `Cannot use messageId '${ messageId } ' - rule does not define any messages in meta.messages` ) ;
0 commit comments