runtime-reporter 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,24 +2,22 @@
2
2
 
3
3
  Replace ad-hoc logging with structured, code-based messaging.
4
4
 
5
- Runtime Reporter provides centralized, type-safe reporting that is convenient in development and secure in production.
5
+ Runtime Reporter is an extremely lightweight and self-contained package that provides centralized, type-safe runtime reporting that is convenient in development and secure in production.
6
6
 
7
7
  ```ts
8
8
  // ./src/my-reporter.ts
9
-
10
9
  import { createReporter } from "runtime-reporter";
11
10
 
12
- export const reporter = createReporter({
11
+ export default createReporter({
13
12
  ERR01: "Something went wrong",
14
13
  });
15
14
 
16
15
  // ./src/MyComponent.ts
17
-
18
- import { reporter } from "./my-reporter";
16
+ import myReporter from "./my-reporter";
19
17
 
20
18
  export function MyComponent() {
21
19
  useEffect(() => {
22
- reporter.error("ERR01");
20
+ myReporter.error("ERR01");
23
21
  }, []);
24
22
  }
25
23
  ```
@@ -40,8 +38,6 @@ by introducing these features:
40
38
  - test assertions without string duplication
41
39
  - safer production output (no sensitive data exposure)
42
40
 
43
- in a lightweight, self-contained package (less than 1 KB gzipped).
44
-
45
41
  ## Who is this for?
46
42
 
47
43
  - Front-end frameworks and libraries
@@ -84,7 +80,9 @@ const messages: RuntimeReporterMessages<
84
80
  };
85
81
 
86
82
  /** The runtime reporter for <project-name> */
87
- const reporter = createReporter(messages);
83
+ const reporter = createReporter(
84
+ process.env.NODE_ENV === "production" ? ({} as typeof messages) : messages
85
+ );
88
86
 
89
87
  export default reporter;
90
88
  ```
@@ -120,7 +118,7 @@ reporter.error("ERR01", { componentName: "MyComponent" });
120
118
  // ✅ Logs: "MyComponent failed to mount (ERR01)"
121
119
  ```
122
120
 
123
- ### 3. Development vs. production
121
+ ### 3. Production-ready
124
122
 
125
123
  Pass an empty object to the `createReporter` function in production environments for better security and a smaller bundle size.
126
124
 
@@ -203,7 +201,7 @@ reporter.error("ERR01");
203
201
  // ✅ Sends a POST request with the following payload:
204
202
  // {
205
203
  // code: "ERR01",
206
- // message: "MyComponent failed to mount (ERR01)",
204
+ // message: "MyComponent failed to mount",
207
205
  // level: "error",
208
206
  // }
209
207
  ```
@@ -228,7 +226,7 @@ Takes a messages object, an optional set of configuration options, and returns a
228
226
 
229
227
  | Property | Type | Required | Description |
230
228
  | --------------- | ------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
231
- | formatMessage | `(message: string, code: string) => string` | No | Customize the final output of every message. By default, messages are in the format: `"<message> (<code>)"`. |
229
+ | formatMessage | `(message: string, code: string) => string` | No | Customize the final output of every message. By default, messages are in the format: `"<message> (<code>)"`. This option does not affect the message provided to the `onReport` hook. |
232
230
  | defaultTemplate | `string` | No | Fallback message text used when the code does not exist in `messages`. Defaults to `"An error occurred"`. This is mostly relevant for `fail()` in production when you pass an empty message set. |
233
231
  | onReport | `(payload: RuntimeReporterReportPayload) => void` | No | A hook to perform custom actions when a report is made via `error`, `warn`, `log`, or `fail`. |
234
232
 
@@ -240,11 +238,11 @@ Takes a messages object, an optional set of configuration options, and returns a
240
238
 
241
239
  ### `RuntimeReporterReportPayload`
242
240
 
243
- | Property | Type | Description |
244
- | --------- | -------- | ------------------------------------------------------------------------------------- | ----- | ------- | --------------------------------- |
245
- | `code` | `string` | The unique code associated with the message. |
246
- | `message` | `string` | The resolved message text; the placeholders have been replaced by their token values. |
247
- | `level` | `"error" | "warn" | "log" | "fail"` | The severity level of the report. |
241
+ | Property | Type | Description |
242
+ | --------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
243
+ | `code` | `string` | The unique code associated with the message. |
244
+ | `message` | `string` | The resolved message text; the placeholders have been replaced by their token values but, it has not been formatted by the `formatMessage` option. |
245
+ | `level` | `"error" \| "warn" \| "log" \| "fail"` | The severity level of the report. |
248
246
 
249
247
  ## Examples
250
248
 
package/dist/index.cjs CHANGED
@@ -42,33 +42,40 @@ function createReporter(messages, options = {}) {
42
42
  onReport
43
43
  } = options;
44
44
  const messagesByCode = messages;
45
- const getMessage = function getMessage2(code, ...args) {
45
+ const resolveMessage = function getMessage(code, ...args) {
46
46
  const template = messagesByCode[code] || defaultTemplate;
47
47
  const tokens = args[0];
48
- const text = resolveTemplate(template, tokens);
49
- return formatMessage(text, code);
48
+ return resolveTemplate(template, tokens);
50
49
  };
51
50
  return {
52
- message: (code, ...args) => getMessage(code, ...args),
51
+ message: (code, ...args) => {
52
+ const message = resolveMessage(code, ...args);
53
+ const formattedMessage = formatMessage(message, code);
54
+ return formattedMessage;
55
+ },
53
56
  error: (code, ...args) => {
54
- const message = getMessage(code, ...args);
57
+ const message = resolveMessage(code, ...args);
58
+ const formattedMessage = formatMessage(message, code);
55
59
  if (onReport) onReport({ code, message, level: "error" });
56
- if (messagesByCode[code]) console.error(message);
60
+ if (messagesByCode[code]) console.error(formattedMessage);
57
61
  },
58
62
  warn: (code, ...args) => {
59
- const message = getMessage(code, ...args);
63
+ const message = resolveMessage(code, ...args);
64
+ const formattedMessage = formatMessage(message, code);
60
65
  if (onReport) onReport({ code, message, level: "warn" });
61
- if (messagesByCode[code]) console.warn(message);
66
+ if (messagesByCode[code]) console.warn(formattedMessage);
62
67
  },
63
68
  log: (code, ...args) => {
64
- const message = getMessage(code, ...args);
69
+ const message = resolveMessage(code, ...args);
70
+ const formattedMessage = formatMessage(message, code);
65
71
  if (onReport) onReport({ code, message, level: "log" });
66
- if (messagesByCode[code]) console.log(message);
72
+ if (messagesByCode[code]) console.log(formattedMessage);
67
73
  },
68
74
  fail: (code, ...args) => {
69
- const message = getMessage(code, ...args);
75
+ const message = resolveMessage(code, ...args);
76
+ const formattedMessage = formatMessage(message, code);
70
77
  if (onReport) onReport({ code, message, level: "fail" });
71
- throw new Error(message);
78
+ throw new Error(formattedMessage);
72
79
  }
73
80
  };
74
81
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * The type information for a single runtime reporter message\n * @since v0.1.0\n */\nexport type RuntimeReporterMessage = {\n code: string;\n template: string;\n tokens?: string;\n};\n\n/**\n * The type for a full list of messages with their associated code and template\n * @since v0.1.0\n */\nexport type RuntimeReporterMessages<T extends RuntimeReporterMessage> = {\n [K in T[\"code\"]]: Extract<T, { code: K }>[\"template\"];\n};\n\n/**\n * The type for the supported values of a placeholder token\n * @since v0.1.0\n */\nexport type RuntimeReporterToken = string | number | boolean | Error | null | undefined;\n\n/**\n * The type for a record of placeholder token names and their values\n * @since v0.2.0\n */\nexport type RuntimeReporterTokens = Record<string, RuntimeReporterToken>;\n\n/**\n * A utility type used to determine the second argument of the runtime reporter methods\n * @private\n */\ntype ReporterTokensArgs<T extends RuntimeReporterMessage, U extends T[\"code\"]> = Extract<\n T,\n { code: U }\n>[\"tokens\"] extends infer Tokens\n ? [Tokens] extends [string]\n ? [tokens: Record<Tokens, RuntimeReporterToken>]\n : []\n : [];\n\n/**\n * Return type for message(); displays the template + code in default format on hover.\n * The runtime value is the resolved string (tokens substituted); the type is for DX only.\n * @private\n */\ntype MessageReturnType<T extends RuntimeReporterMessage, U extends T[\"code\"]> =\n Extract<T, { code: U }> extends { template: infer Template }\n ? Template extends string\n ? `${Template} (${U})`\n : string\n : string;\n\n/**\n * The runtime report object with all of it's associated methods;\n * the result of the primary export: `createReporter`\n * @private\n */\ninterface RuntimeReporter<T extends RuntimeReporterMessage> {\n /**\n * Retrieves the full text of the targeted message\n *\n * _Note: As a convenience, the return type will attempt to show the literal type of the template\n * pattern and code suffix (in the default format) for the message on hover; the actual output may\n * vary based on the tokens provided and the `formatMessage` option._\n *\n * _Tip: This method is particularly useful in the test environment; allowing you\n * to make precise assertions without having to duplicate any of the raw message text._\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n message<U extends T[\"code\"]>(\n code: U,\n ...args: ReporterTokensArgs<T, U>\n ): MessageReturnType<T, U>;\n\n /**\n * Logs a warning to the console with the full text of the targeted message in non-production environments\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n warn<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Logs an error to the console with the full text of the targeted message in non-production environments\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n error<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Logs a message to the console with the full text of the targeted message in non-production environments\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n log<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Throws an error with the full text of the targeted message in all environments\n *\n * _Note: When the `createReporter` function is called in production with an empty\n * message set, this method will use the \"defaultTemplate\" option in this format: \"&lt;defaultTemplate> (&lt;code>)\"_\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n fail<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): never;\n}\n\n/**\n * The payload for the onReport hook\n */\nexport type RuntimeReporterReportPayload = {\n /**\n * The unique code associated with the message\n */\n code: string;\n\n /**\n * The resolved message text; the placeholders have been replaced by their token values\n */\n message: string;\n\n /**\n * The severity level of the report\n */\n level: \"error\" | \"warn\" | \"log\" | \"fail\";\n};\n\n/**\n * The configuration options for createReporter()\n * @since v0.1.0\n */\nexport interface RuntimeReporterOptions {\n /**\n * A hook to format the message text that is logged to the console. By default, it\n * outputs the message in the following format: \"&lt;message> (&lt;code>)\"\n * @param message The resolved message text; the placeholders have been replaced by their token values\n * @param code The unique code associated with the message\n * @returns The final, fully formatted message\n */\n formatMessage?: (message: string, code: string) => string;\n\n /**\n * The default template to fallback on when a provided code does not\n * have an associated message. Defaults to \"An error occurred\"\n *\n * _Note: This is only used when the `fail` method is called in production\n * environments when the `createReporter` function is provided an empty message set._\n */\n defaultTemplate?: string;\n\n /**\n * A hook to perform custom actions when any of the report methods (minus the\n * `message` method) are called. This is useful for logging to a remote service,\n * or for performing other actions based on the report.\n * @param payload The payload for the report\n */\n onReport?: (payload: RuntimeReporterReportPayload) => void;\n}\n\n/**\n * Resolves the message text via the message template and the associated tokens\n * @param template The template string for the reported message\n * @param tokens The token names and values for the instance\n * @returns The resolved message text; returns an empty string if the template is falsy\n * @private\n */\nconst resolveTemplate = function resolveTemplate(\n template: string,\n tokens?: Record<string, RuntimeReporterToken>\n): string {\n let message = template;\n\n if (message) {\n Object.entries(tokens || {}).forEach((entry) => {\n const [token, value] = entry;\n const replace = value instanceof Error ? value.message : String(value ?? \"\");\n const sanitized = token.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n message = message.replace(new RegExp(`\\\\{\\\\{\\\\s*${sanitized}\\\\s*\\\\}\\\\}`, \"g\"), replace);\n });\n }\n\n return message;\n};\n\n/**\n * Creates a new runtime reporter object with all of it's associated methods\n * @param messages The messages record organized by code and template\n * @param options Optional configuration options\n * @returns A runtime report object\n * @since v0.1.0\n */\nexport function createReporter<T extends RuntimeReporterMessage>(\n messages: RuntimeReporterMessages<T>,\n options: RuntimeReporterOptions = {}\n): RuntimeReporter<T> {\n const {\n formatMessage = (message, code) => `${message} (${code})`,\n defaultTemplate = \"An error occurred\",\n onReport,\n } = options;\n const messagesByCode = messages as Record<string, string>;\n\n /**\n * Retrieves the final message for a give code and its associated tokens\n * @param code The unique code associated with the message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n * @returns The fully resolve message or an empty string if there was no template\n */\n const getMessage = function getMessage(\n code: string,\n ...args: Array<Record<string, RuntimeReporterToken>>\n ): string {\n const template = messagesByCode[code] || defaultTemplate;\n const tokens = args[0];\n const text = resolveTemplate(template, tokens);\n return formatMessage(text, code);\n };\n\n return {\n message: (code, ...args) =>\n getMessage(code, ...args) as MessageReturnType<T, typeof code & T[\"code\"]>,\n error: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (onReport) onReport({ code, message, level: \"error\" });\n if (messagesByCode[code]) console.error(message);\n },\n warn: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (onReport) onReport({ code, message, level: \"warn\" });\n if (messagesByCode[code]) console.warn(message);\n },\n log: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (onReport) onReport({ code, message, level: \"log\" });\n if (messagesByCode[code]) console.log(message);\n },\n fail: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (onReport) onReport({ code, message, level: \"fail\" });\n throw new Error(message);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqLA,IAAM,kBAAkB,SAASA,iBAC7B,UACA,QACM;AACN,MAAI,UAAU;AAEd,MAAI,SAAS;AACT,WAAO,QAAQ,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU;AAC5C,YAAM,CAAC,OAAO,KAAK,IAAI;AACvB,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,SAAS,EAAE;AAC3E,YAAM,YAAY,MAAM,QAAQ,uBAAuB,MAAM;AAC7D,gBAAU,QAAQ,QAAQ,IAAI,OAAO,aAAa,SAAS,cAAc,GAAG,GAAG,OAAO;AAAA,IAC1F,CAAC;AAAA,EACL;AAEA,SAAO;AACX;AASO,SAAS,eACZ,UACA,UAAkC,CAAC,GACjB;AAClB,QAAM;AAAA,IACF,gBAAgB,CAAC,SAAS,SAAS,GAAG,OAAO,KAAK,IAAI;AAAA,IACtD,kBAAkB;AAAA,IAClB;AAAA,EACJ,IAAI;AACJ,QAAM,iBAAiB;AAQvB,QAAM,aAAa,SAASC,YACxB,SACG,MACG;AACN,UAAM,WAAW,eAAe,IAAI,KAAK;AACzC,UAAM,SAAS,KAAK,CAAC;AACrB,UAAM,OAAO,gBAAgB,UAAU,MAAM;AAC7C,WAAO,cAAc,MAAM,IAAI;AAAA,EACnC;AAEA,SAAO;AAAA,IACH,SAAS,CAAC,SAAS,SACf,WAAW,MAAM,GAAG,IAAI;AAAA,IAC5B,OAAO,CAAC,SAAS,SAAS;AACtB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,QAAQ,CAAC;AACxD,UAAI,eAAe,IAAI,EAAG,SAAQ,MAAM,OAAO;AAAA,IACnD;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,OAAO,CAAC;AACvD,UAAI,eAAe,IAAI,EAAG,SAAQ,KAAK,OAAO;AAAA,IAClD;AAAA,IACA,KAAK,CAAC,SAAS,SAAS;AACpB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,MAAM,CAAC;AACtD,UAAI,eAAe,IAAI,EAAG,SAAQ,IAAI,OAAO;AAAA,IACjD;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,OAAO,CAAC;AACvD,YAAM,IAAI,MAAM,OAAO;AAAA,IAC3B;AAAA,EACJ;AACJ;","names":["resolveTemplate","getMessage"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * The type information for a single runtime reporter message\n * @since v0.1.0\n */\nexport type RuntimeReporterMessage = {\n code: string;\n template: string;\n tokens?: string;\n};\n\n/**\n * The type for a full list of messages with their associated code and template\n * @since v0.1.0\n */\nexport type RuntimeReporterMessages<T extends RuntimeReporterMessage> = {\n [K in T[\"code\"]]: Extract<T, { code: K }>[\"template\"];\n};\n\n/**\n * The type for the supported values of a placeholder token\n * @since v0.1.0\n */\nexport type RuntimeReporterToken = string | number | boolean | Error | null | undefined;\n\n/**\n * The type for a record of placeholder token names and their values\n * @since v0.2.0\n */\nexport type RuntimeReporterTokens = Record<string, RuntimeReporterToken>;\n\n/**\n * A utility type used to determine the second argument of the runtime reporter methods\n * @private\n */\ntype ReporterTokensArgs<T extends RuntimeReporterMessage, U extends T[\"code\"]> = Extract<\n T,\n { code: U }\n>[\"tokens\"] extends infer Tokens\n ? [Tokens] extends [string]\n ? [tokens: Record<Tokens, RuntimeReporterToken>]\n : []\n : [];\n\n/**\n * Return type for message(); displays the template + code in default format on hover.\n * The runtime value is the resolved string (tokens substituted); the type is for DX only.\n * @private\n */\ntype MessageReturnType<T extends RuntimeReporterMessage, U extends T[\"code\"]> =\n Extract<T, { code: U }> extends { template: infer Template }\n ? Template extends string\n ? `${Template} (${U})`\n : string\n : string;\n\n/**\n * The runtime report object with all of it's associated methods;\n * the result of the primary export: `createReporter`\n * @private\n */\ninterface RuntimeReporter<T extends RuntimeReporterMessage> {\n /**\n * Retrieves the full text of the targeted message\n *\n * _Note: As a convenience, the return type will attempt to show the literal type of the template\n * pattern and code suffix (in the default format) for the message on hover; the actual output may\n * vary based on the tokens provided and the `formatMessage` option._\n *\n * _Tip: This method is particularly useful in the test environment; allowing you\n * to make precise assertions without having to duplicate any of the raw message text._\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n message<U extends T[\"code\"]>(\n code: U,\n ...args: ReporterTokensArgs<T, U>\n ): MessageReturnType<T, U>;\n\n /**\n * Logs a warning to the console with the full text of the targeted message\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args A record containing the placeholder token values for the message\n */\n warn<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Logs an error to the console with the full text of the targeted message\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args A record containing the placeholder token values for the message\n */\n error<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Logs a message to the console with the full text of the targeted message\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args A record containing the placeholder token values for the message\n */\n log<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Throws an error with the full text of the targeted message in all environments\n *\n * _Note: When the `createReporter` function is called in production with an empty\n * message set, this method will use the \"defaultTemplate\" option in this format: \"&lt;defaultTemplate> (&lt;code>)\"_\n * @param code A direct reference to the unique code for the targeted message\n * @param args A record containing the placeholder token values for the message\n */\n fail<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): never;\n}\n\n/**\n * The payload for the onReport hook\n */\nexport type RuntimeReporterReportPayload = {\n /**\n * The unique code associated with the message\n */\n code: string;\n\n /**\n * The resolved message text; the placeholders have been replaced by their token values\n * but, it has not been formatted by the `formatMessage` option.\n */\n message: string;\n\n /**\n * The severity level of the report\n */\n level: \"error\" | \"warn\" | \"log\" | \"fail\";\n};\n\n/**\n * The configuration options for createReporter()\n * @since v0.1.0\n */\nexport interface RuntimeReporterOptions {\n /**\n * A hook to format the message text that is logged to the console. By default, it\n * outputs the message in the following format: \"&lt;message> (&lt;code>)\".\n *\n * _Note: This option does not affect the message provided to the `onReport` hook._\n * @param message The resolved message text; the placeholders have been replaced by their token values\n * @param code The unique code associated with the message\n * @returns The final, fully formatted message\n */\n formatMessage?: (message: string, code: string) => string;\n\n /**\n * The default template to fallback on when a provided code does not\n * have an associated message. Defaults to \"An error occurred\"\n */\n defaultTemplate?: string;\n\n /**\n * A hook to perform custom actions when any of the report methods (minus the\n * `message` method) are called. This is useful for logging to a remote service,\n * or for performing other actions based on the report.\n * @param payload The payload for the report\n */\n onReport?: (payload: RuntimeReporterReportPayload) => void;\n}\n\n/**\n * Resolves the message text via the message template and the associated tokens\n * @param template The template string for the reported message\n * @param tokens The token names and values for the instance\n * @returns The resolved message text; returns an empty string if the template is falsy\n * @private\n */\nconst resolveTemplate = function resolveTemplate(\n template: string,\n tokens?: Record<string, RuntimeReporterToken>\n): string {\n let message = template;\n\n if (message) {\n Object.entries(tokens || {}).forEach((entry) => {\n const [token, value] = entry;\n const replace = value instanceof Error ? value.message : String(value ?? \"\");\n const sanitized = token.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n message = message.replace(new RegExp(`\\\\{\\\\{\\\\s*${sanitized}\\\\s*\\\\}\\\\}`, \"g\"), replace);\n });\n }\n\n return message;\n};\n\n/**\n * Creates a new runtime reporter object with all of it's associated methods\n * @param messages The messages record organized by code and template\n * @param options Optional configuration options\n * @returns A runtime report object\n * @since v0.1.0\n */\nexport function createReporter<T extends RuntimeReporterMessage>(\n messages: RuntimeReporterMessages<T>,\n options: RuntimeReporterOptions = {}\n): RuntimeReporter<T> {\n const {\n formatMessage = (message, code) => `${message} (${code})`,\n defaultTemplate = \"An error occurred\",\n onReport,\n } = options;\n const messagesByCode = messages as Record<string, string>;\n\n /**\n * Retrieves the resolved message text for a given code and its associated tokens\n * @param code The unique code associated with the message\n * @param args The record containing the placeholder token values\n * @returns The fully resolved message\n */\n const resolveMessage = function getMessage(\n code: string,\n ...args: Array<Record<string, RuntimeReporterToken>>\n ): string {\n const template = messagesByCode[code] || defaultTemplate;\n const tokens = args[0];\n return resolveTemplate(template, tokens);\n };\n\n return {\n message: (code, ...args) => {\n const message = resolveMessage(code, ...args);\n const formattedMessage = formatMessage(message, code);\n return formattedMessage as MessageReturnType<T, typeof code & T[\"code\"]>;\n },\n error: (code, ...args) => {\n const message = resolveMessage(code, ...args);\n const formattedMessage = formatMessage(message, code);\n if (onReport) onReport({ code, message, level: \"error\" });\n if (messagesByCode[code]) console.error(formattedMessage);\n },\n warn: (code, ...args) => {\n const message = resolveMessage(code, ...args);\n const formattedMessage = formatMessage(message, code);\n if (onReport) onReport({ code, message, level: \"warn\" });\n if (messagesByCode[code]) console.warn(formattedMessage);\n },\n log: (code, ...args) => {\n const message = resolveMessage(code, ...args);\n const formattedMessage = formatMessage(message, code);\n if (onReport) onReport({ code, message, level: \"log\" });\n if (messagesByCode[code]) console.log(formattedMessage);\n },\n fail: (code, ...args) => {\n const message = resolveMessage(code, ...args);\n const formattedMessage = formatMessage(message, code);\n if (onReport) onReport({ code, message, level: \"fail\" });\n throw new Error(formattedMessage);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqLA,IAAM,kBAAkB,SAASA,iBAC7B,UACA,QACM;AACN,MAAI,UAAU;AAEd,MAAI,SAAS;AACT,WAAO,QAAQ,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU;AAC5C,YAAM,CAAC,OAAO,KAAK,IAAI;AACvB,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,SAAS,EAAE;AAC3E,YAAM,YAAY,MAAM,QAAQ,uBAAuB,MAAM;AAC7D,gBAAU,QAAQ,QAAQ,IAAI,OAAO,aAAa,SAAS,cAAc,GAAG,GAAG,OAAO;AAAA,IAC1F,CAAC;AAAA,EACL;AAEA,SAAO;AACX;AASO,SAAS,eACZ,UACA,UAAkC,CAAC,GACjB;AAClB,QAAM;AAAA,IACF,gBAAgB,CAAC,SAAS,SAAS,GAAG,OAAO,KAAK,IAAI;AAAA,IACtD,kBAAkB;AAAA,IAClB;AAAA,EACJ,IAAI;AACJ,QAAM,iBAAiB;AAQvB,QAAM,iBAAiB,SAAS,WAC5B,SACG,MACG;AACN,UAAM,WAAW,eAAe,IAAI,KAAK;AACzC,UAAM,SAAS,KAAK,CAAC;AACrB,WAAO,gBAAgB,UAAU,MAAM;AAAA,EAC3C;AAEA,SAAO;AAAA,IACH,SAAS,CAAC,SAAS,SAAS;AACxB,YAAM,UAAU,eAAe,MAAM,GAAG,IAAI;AAC5C,YAAM,mBAAmB,cAAc,SAAS,IAAI;AACpD,aAAO;AAAA,IACX;AAAA,IACA,OAAO,CAAC,SAAS,SAAS;AACtB,YAAM,UAAU,eAAe,MAAM,GAAG,IAAI;AAC5C,YAAM,mBAAmB,cAAc,SAAS,IAAI;AACpD,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,QAAQ,CAAC;AACxD,UAAI,eAAe,IAAI,EAAG,SAAQ,MAAM,gBAAgB;AAAA,IAC5D;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,eAAe,MAAM,GAAG,IAAI;AAC5C,YAAM,mBAAmB,cAAc,SAAS,IAAI;AACpD,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,OAAO,CAAC;AACvD,UAAI,eAAe,IAAI,EAAG,SAAQ,KAAK,gBAAgB;AAAA,IAC3D;AAAA,IACA,KAAK,CAAC,SAAS,SAAS;AACpB,YAAM,UAAU,eAAe,MAAM,GAAG,IAAI;AAC5C,YAAM,mBAAmB,cAAc,SAAS,IAAI;AACpD,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,MAAM,CAAC;AACtD,UAAI,eAAe,IAAI,EAAG,SAAQ,IAAI,gBAAgB;AAAA,IAC1D;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,eAAe,MAAM,GAAG,IAAI;AAC5C,YAAM,mBAAmB,cAAc,SAAS,IAAI;AACpD,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,OAAO,CAAC;AACvD,YAAM,IAAI,MAAM,gBAAgB;AAAA,IACpC;AAAA,EACJ;AACJ;","names":["resolveTemplate"]}
package/dist/index.d.cts CHANGED
@@ -63,33 +63,33 @@ interface RuntimeReporter<T extends RuntimeReporterMessage> {
63
63
  */
64
64
  message<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): MessageReturnType<T, U>;
65
65
  /**
66
- * Logs a warning to the console with the full text of the targeted message in non-production environments
66
+ * Logs a warning to the console with the full text of the targeted message
67
67
  *
68
68
  * _Note: This method will only log when the message associated with the code is found;
69
69
  * meaning it will not be called in production if the `createReporter` function
70
70
  * is provided an empty message set._
71
71
  * @param code A direct reference to the unique code for the targeted message
72
- * @param args The remaining optional argument for the function; a record containing the placeholder token values
72
+ * @param args A record containing the placeholder token values for the message
73
73
  */
74
74
  warn<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
75
75
  /**
76
- * Logs an error to the console with the full text of the targeted message in non-production environments
76
+ * Logs an error to the console with the full text of the targeted message
77
77
  *
78
78
  * _Note: This method will only log when the message associated with the code is found;
79
79
  * meaning it will not be called in production if the `createReporter` function
80
80
  * is provided an empty message set._
81
81
  * @param code A direct reference to the unique code for the targeted message
82
- * @param args The remaining optional argument for the function; a record containing the placeholder token values
82
+ * @param args A record containing the placeholder token values for the message
83
83
  */
84
84
  error<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
85
85
  /**
86
- * Logs a message to the console with the full text of the targeted message in non-production environments
86
+ * Logs a message to the console with the full text of the targeted message
87
87
  *
88
88
  * _Note: This method will only log when the message associated with the code is found;
89
89
  * meaning it will not be called in production if the `createReporter` function
90
90
  * is provided an empty message set._
91
91
  * @param code A direct reference to the unique code for the targeted message
92
- * @param args The remaining optional argument for the function; a record containing the placeholder token values
92
+ * @param args A record containing the placeholder token values for the message
93
93
  */
94
94
  log<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
95
95
  /**
@@ -98,7 +98,7 @@ interface RuntimeReporter<T extends RuntimeReporterMessage> {
98
98
  * _Note: When the `createReporter` function is called in production with an empty
99
99
  * message set, this method will use the "defaultTemplate" option in this format: "&lt;defaultTemplate> (&lt;code>)"_
100
100
  * @param code A direct reference to the unique code for the targeted message
101
- * @param args The remaining optional argument for the function; a record containing the placeholder token values
101
+ * @param args A record containing the placeholder token values for the message
102
102
  */
103
103
  fail<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): never;
104
104
  }
@@ -112,6 +112,7 @@ type RuntimeReporterReportPayload = {
112
112
  code: string;
113
113
  /**
114
114
  * The resolved message text; the placeholders have been replaced by their token values
115
+ * but, it has not been formatted by the `formatMessage` option.
115
116
  */
116
117
  message: string;
117
118
  /**
@@ -126,7 +127,9 @@ type RuntimeReporterReportPayload = {
126
127
  interface RuntimeReporterOptions {
127
128
  /**
128
129
  * A hook to format the message text that is logged to the console. By default, it
129
- * outputs the message in the following format: "&lt;message> (&lt;code>)"
130
+ * outputs the message in the following format: "&lt;message> (&lt;code>)".
131
+ *
132
+ * _Note: This option does not affect the message provided to the `onReport` hook._
130
133
  * @param message The resolved message text; the placeholders have been replaced by their token values
131
134
  * @param code The unique code associated with the message
132
135
  * @returns The final, fully formatted message
@@ -135,9 +138,6 @@ interface RuntimeReporterOptions {
135
138
  /**
136
139
  * The default template to fallback on when a provided code does not
137
140
  * have an associated message. Defaults to "An error occurred"
138
- *
139
- * _Note: This is only used when the `fail` method is called in production
140
- * environments when the `createReporter` function is provided an empty message set._
141
141
  */
142
142
  defaultTemplate?: string;
143
143
  /**
package/dist/index.d.ts CHANGED
@@ -63,33 +63,33 @@ interface RuntimeReporter<T extends RuntimeReporterMessage> {
63
63
  */
64
64
  message<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): MessageReturnType<T, U>;
65
65
  /**
66
- * Logs a warning to the console with the full text of the targeted message in non-production environments
66
+ * Logs a warning to the console with the full text of the targeted message
67
67
  *
68
68
  * _Note: This method will only log when the message associated with the code is found;
69
69
  * meaning it will not be called in production if the `createReporter` function
70
70
  * is provided an empty message set._
71
71
  * @param code A direct reference to the unique code for the targeted message
72
- * @param args The remaining optional argument for the function; a record containing the placeholder token values
72
+ * @param args A record containing the placeholder token values for the message
73
73
  */
74
74
  warn<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
75
75
  /**
76
- * Logs an error to the console with the full text of the targeted message in non-production environments
76
+ * Logs an error to the console with the full text of the targeted message
77
77
  *
78
78
  * _Note: This method will only log when the message associated with the code is found;
79
79
  * meaning it will not be called in production if the `createReporter` function
80
80
  * is provided an empty message set._
81
81
  * @param code A direct reference to the unique code for the targeted message
82
- * @param args The remaining optional argument for the function; a record containing the placeholder token values
82
+ * @param args A record containing the placeholder token values for the message
83
83
  */
84
84
  error<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
85
85
  /**
86
- * Logs a message to the console with the full text of the targeted message in non-production environments
86
+ * Logs a message to the console with the full text of the targeted message
87
87
  *
88
88
  * _Note: This method will only log when the message associated with the code is found;
89
89
  * meaning it will not be called in production if the `createReporter` function
90
90
  * is provided an empty message set._
91
91
  * @param code A direct reference to the unique code for the targeted message
92
- * @param args The remaining optional argument for the function; a record containing the placeholder token values
92
+ * @param args A record containing the placeholder token values for the message
93
93
  */
94
94
  log<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
95
95
  /**
@@ -98,7 +98,7 @@ interface RuntimeReporter<T extends RuntimeReporterMessage> {
98
98
  * _Note: When the `createReporter` function is called in production with an empty
99
99
  * message set, this method will use the "defaultTemplate" option in this format: "&lt;defaultTemplate> (&lt;code>)"_
100
100
  * @param code A direct reference to the unique code for the targeted message
101
- * @param args The remaining optional argument for the function; a record containing the placeholder token values
101
+ * @param args A record containing the placeholder token values for the message
102
102
  */
103
103
  fail<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): never;
104
104
  }
@@ -112,6 +112,7 @@ type RuntimeReporterReportPayload = {
112
112
  code: string;
113
113
  /**
114
114
  * The resolved message text; the placeholders have been replaced by their token values
115
+ * but, it has not been formatted by the `formatMessage` option.
115
116
  */
116
117
  message: string;
117
118
  /**
@@ -126,7 +127,9 @@ type RuntimeReporterReportPayload = {
126
127
  interface RuntimeReporterOptions {
127
128
  /**
128
129
  * A hook to format the message text that is logged to the console. By default, it
129
- * outputs the message in the following format: "&lt;message> (&lt;code>)"
130
+ * outputs the message in the following format: "&lt;message> (&lt;code>)".
131
+ *
132
+ * _Note: This option does not affect the message provided to the `onReport` hook._
130
133
  * @param message The resolved message text; the placeholders have been replaced by their token values
131
134
  * @param code The unique code associated with the message
132
135
  * @returns The final, fully formatted message
@@ -135,9 +138,6 @@ interface RuntimeReporterOptions {
135
138
  /**
136
139
  * The default template to fallback on when a provided code does not
137
140
  * have an associated message. Defaults to "An error occurred"
138
- *
139
- * _Note: This is only used when the `fail` method is called in production
140
- * environments when the `createReporter` function is provided an empty message set._
141
141
  */
142
142
  defaultTemplate?: string;
143
143
  /**
package/dist/index.js CHANGED
@@ -18,33 +18,40 @@ function createReporter(messages, options = {}) {
18
18
  onReport
19
19
  } = options;
20
20
  const messagesByCode = messages;
21
- const getMessage = function getMessage2(code, ...args) {
21
+ const resolveMessage = function getMessage(code, ...args) {
22
22
  const template = messagesByCode[code] || defaultTemplate;
23
23
  const tokens = args[0];
24
- const text = resolveTemplate(template, tokens);
25
- return formatMessage(text, code);
24
+ return resolveTemplate(template, tokens);
26
25
  };
27
26
  return {
28
- message: (code, ...args) => getMessage(code, ...args),
27
+ message: (code, ...args) => {
28
+ const message = resolveMessage(code, ...args);
29
+ const formattedMessage = formatMessage(message, code);
30
+ return formattedMessage;
31
+ },
29
32
  error: (code, ...args) => {
30
- const message = getMessage(code, ...args);
33
+ const message = resolveMessage(code, ...args);
34
+ const formattedMessage = formatMessage(message, code);
31
35
  if (onReport) onReport({ code, message, level: "error" });
32
- if (messagesByCode[code]) console.error(message);
36
+ if (messagesByCode[code]) console.error(formattedMessage);
33
37
  },
34
38
  warn: (code, ...args) => {
35
- const message = getMessage(code, ...args);
39
+ const message = resolveMessage(code, ...args);
40
+ const formattedMessage = formatMessage(message, code);
36
41
  if (onReport) onReport({ code, message, level: "warn" });
37
- if (messagesByCode[code]) console.warn(message);
42
+ if (messagesByCode[code]) console.warn(formattedMessage);
38
43
  },
39
44
  log: (code, ...args) => {
40
- const message = getMessage(code, ...args);
45
+ const message = resolveMessage(code, ...args);
46
+ const formattedMessage = formatMessage(message, code);
41
47
  if (onReport) onReport({ code, message, level: "log" });
42
- if (messagesByCode[code]) console.log(message);
48
+ if (messagesByCode[code]) console.log(formattedMessage);
43
49
  },
44
50
  fail: (code, ...args) => {
45
- const message = getMessage(code, ...args);
51
+ const message = resolveMessage(code, ...args);
52
+ const formattedMessage = formatMessage(message, code);
46
53
  if (onReport) onReport({ code, message, level: "fail" });
47
- throw new Error(message);
54
+ throw new Error(formattedMessage);
48
55
  }
49
56
  };
50
57
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * The type information for a single runtime reporter message\n * @since v0.1.0\n */\nexport type RuntimeReporterMessage = {\n code: string;\n template: string;\n tokens?: string;\n};\n\n/**\n * The type for a full list of messages with their associated code and template\n * @since v0.1.0\n */\nexport type RuntimeReporterMessages<T extends RuntimeReporterMessage> = {\n [K in T[\"code\"]]: Extract<T, { code: K }>[\"template\"];\n};\n\n/**\n * The type for the supported values of a placeholder token\n * @since v0.1.0\n */\nexport type RuntimeReporterToken = string | number | boolean | Error | null | undefined;\n\n/**\n * The type for a record of placeholder token names and their values\n * @since v0.2.0\n */\nexport type RuntimeReporterTokens = Record<string, RuntimeReporterToken>;\n\n/**\n * A utility type used to determine the second argument of the runtime reporter methods\n * @private\n */\ntype ReporterTokensArgs<T extends RuntimeReporterMessage, U extends T[\"code\"]> = Extract<\n T,\n { code: U }\n>[\"tokens\"] extends infer Tokens\n ? [Tokens] extends [string]\n ? [tokens: Record<Tokens, RuntimeReporterToken>]\n : []\n : [];\n\n/**\n * Return type for message(); displays the template + code in default format on hover.\n * The runtime value is the resolved string (tokens substituted); the type is for DX only.\n * @private\n */\ntype MessageReturnType<T extends RuntimeReporterMessage, U extends T[\"code\"]> =\n Extract<T, { code: U }> extends { template: infer Template }\n ? Template extends string\n ? `${Template} (${U})`\n : string\n : string;\n\n/**\n * The runtime report object with all of it's associated methods;\n * the result of the primary export: `createReporter`\n * @private\n */\ninterface RuntimeReporter<T extends RuntimeReporterMessage> {\n /**\n * Retrieves the full text of the targeted message\n *\n * _Note: As a convenience, the return type will attempt to show the literal type of the template\n * pattern and code suffix (in the default format) for the message on hover; the actual output may\n * vary based on the tokens provided and the `formatMessage` option._\n *\n * _Tip: This method is particularly useful in the test environment; allowing you\n * to make precise assertions without having to duplicate any of the raw message text._\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n message<U extends T[\"code\"]>(\n code: U,\n ...args: ReporterTokensArgs<T, U>\n ): MessageReturnType<T, U>;\n\n /**\n * Logs a warning to the console with the full text of the targeted message in non-production environments\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n warn<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Logs an error to the console with the full text of the targeted message in non-production environments\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n error<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Logs a message to the console with the full text of the targeted message in non-production environments\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n log<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Throws an error with the full text of the targeted message in all environments\n *\n * _Note: When the `createReporter` function is called in production with an empty\n * message set, this method will use the \"defaultTemplate\" option in this format: \"&lt;defaultTemplate> (&lt;code>)\"_\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n fail<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): never;\n}\n\n/**\n * The payload for the onReport hook\n */\nexport type RuntimeReporterReportPayload = {\n /**\n * The unique code associated with the message\n */\n code: string;\n\n /**\n * The resolved message text; the placeholders have been replaced by their token values\n */\n message: string;\n\n /**\n * The severity level of the report\n */\n level: \"error\" | \"warn\" | \"log\" | \"fail\";\n};\n\n/**\n * The configuration options for createReporter()\n * @since v0.1.0\n */\nexport interface RuntimeReporterOptions {\n /**\n * A hook to format the message text that is logged to the console. By default, it\n * outputs the message in the following format: \"&lt;message> (&lt;code>)\"\n * @param message The resolved message text; the placeholders have been replaced by their token values\n * @param code The unique code associated with the message\n * @returns The final, fully formatted message\n */\n formatMessage?: (message: string, code: string) => string;\n\n /**\n * The default template to fallback on when a provided code does not\n * have an associated message. Defaults to \"An error occurred\"\n *\n * _Note: This is only used when the `fail` method is called in production\n * environments when the `createReporter` function is provided an empty message set._\n */\n defaultTemplate?: string;\n\n /**\n * A hook to perform custom actions when any of the report methods (minus the\n * `message` method) are called. This is useful for logging to a remote service,\n * or for performing other actions based on the report.\n * @param payload The payload for the report\n */\n onReport?: (payload: RuntimeReporterReportPayload) => void;\n}\n\n/**\n * Resolves the message text via the message template and the associated tokens\n * @param template The template string for the reported message\n * @param tokens The token names and values for the instance\n * @returns The resolved message text; returns an empty string if the template is falsy\n * @private\n */\nconst resolveTemplate = function resolveTemplate(\n template: string,\n tokens?: Record<string, RuntimeReporterToken>\n): string {\n let message = template;\n\n if (message) {\n Object.entries(tokens || {}).forEach((entry) => {\n const [token, value] = entry;\n const replace = value instanceof Error ? value.message : String(value ?? \"\");\n const sanitized = token.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n message = message.replace(new RegExp(`\\\\{\\\\{\\\\s*${sanitized}\\\\s*\\\\}\\\\}`, \"g\"), replace);\n });\n }\n\n return message;\n};\n\n/**\n * Creates a new runtime reporter object with all of it's associated methods\n * @param messages The messages record organized by code and template\n * @param options Optional configuration options\n * @returns A runtime report object\n * @since v0.1.0\n */\nexport function createReporter<T extends RuntimeReporterMessage>(\n messages: RuntimeReporterMessages<T>,\n options: RuntimeReporterOptions = {}\n): RuntimeReporter<T> {\n const {\n formatMessage = (message, code) => `${message} (${code})`,\n defaultTemplate = \"An error occurred\",\n onReport,\n } = options;\n const messagesByCode = messages as Record<string, string>;\n\n /**\n * Retrieves the final message for a give code and its associated tokens\n * @param code The unique code associated with the message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n * @returns The fully resolve message or an empty string if there was no template\n */\n const getMessage = function getMessage(\n code: string,\n ...args: Array<Record<string, RuntimeReporterToken>>\n ): string {\n const template = messagesByCode[code] || defaultTemplate;\n const tokens = args[0];\n const text = resolveTemplate(template, tokens);\n return formatMessage(text, code);\n };\n\n return {\n message: (code, ...args) =>\n getMessage(code, ...args) as MessageReturnType<T, typeof code & T[\"code\"]>,\n error: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (onReport) onReport({ code, message, level: \"error\" });\n if (messagesByCode[code]) console.error(message);\n },\n warn: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (onReport) onReport({ code, message, level: \"warn\" });\n if (messagesByCode[code]) console.warn(message);\n },\n log: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (onReport) onReport({ code, message, level: \"log\" });\n if (messagesByCode[code]) console.log(message);\n },\n fail: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (onReport) onReport({ code, message, level: \"fail\" });\n throw new Error(message);\n },\n };\n}\n"],"mappings":";AAqLA,IAAM,kBAAkB,SAASA,iBAC7B,UACA,QACM;AACN,MAAI,UAAU;AAEd,MAAI,SAAS;AACT,WAAO,QAAQ,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU;AAC5C,YAAM,CAAC,OAAO,KAAK,IAAI;AACvB,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,SAAS,EAAE;AAC3E,YAAM,YAAY,MAAM,QAAQ,uBAAuB,MAAM;AAC7D,gBAAU,QAAQ,QAAQ,IAAI,OAAO,aAAa,SAAS,cAAc,GAAG,GAAG,OAAO;AAAA,IAC1F,CAAC;AAAA,EACL;AAEA,SAAO;AACX;AASO,SAAS,eACZ,UACA,UAAkC,CAAC,GACjB;AAClB,QAAM;AAAA,IACF,gBAAgB,CAAC,SAAS,SAAS,GAAG,OAAO,KAAK,IAAI;AAAA,IACtD,kBAAkB;AAAA,IAClB;AAAA,EACJ,IAAI;AACJ,QAAM,iBAAiB;AAQvB,QAAM,aAAa,SAASC,YACxB,SACG,MACG;AACN,UAAM,WAAW,eAAe,IAAI,KAAK;AACzC,UAAM,SAAS,KAAK,CAAC;AACrB,UAAM,OAAO,gBAAgB,UAAU,MAAM;AAC7C,WAAO,cAAc,MAAM,IAAI;AAAA,EACnC;AAEA,SAAO;AAAA,IACH,SAAS,CAAC,SAAS,SACf,WAAW,MAAM,GAAG,IAAI;AAAA,IAC5B,OAAO,CAAC,SAAS,SAAS;AACtB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,QAAQ,CAAC;AACxD,UAAI,eAAe,IAAI,EAAG,SAAQ,MAAM,OAAO;AAAA,IACnD;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,OAAO,CAAC;AACvD,UAAI,eAAe,IAAI,EAAG,SAAQ,KAAK,OAAO;AAAA,IAClD;AAAA,IACA,KAAK,CAAC,SAAS,SAAS;AACpB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,MAAM,CAAC;AACtD,UAAI,eAAe,IAAI,EAAG,SAAQ,IAAI,OAAO;AAAA,IACjD;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,OAAO,CAAC;AACvD,YAAM,IAAI,MAAM,OAAO;AAAA,IAC3B;AAAA,EACJ;AACJ;","names":["resolveTemplate","getMessage"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * The type information for a single runtime reporter message\n * @since v0.1.0\n */\nexport type RuntimeReporterMessage = {\n code: string;\n template: string;\n tokens?: string;\n};\n\n/**\n * The type for a full list of messages with their associated code and template\n * @since v0.1.0\n */\nexport type RuntimeReporterMessages<T extends RuntimeReporterMessage> = {\n [K in T[\"code\"]]: Extract<T, { code: K }>[\"template\"];\n};\n\n/**\n * The type for the supported values of a placeholder token\n * @since v0.1.0\n */\nexport type RuntimeReporterToken = string | number | boolean | Error | null | undefined;\n\n/**\n * The type for a record of placeholder token names and their values\n * @since v0.2.0\n */\nexport type RuntimeReporterTokens = Record<string, RuntimeReporterToken>;\n\n/**\n * A utility type used to determine the second argument of the runtime reporter methods\n * @private\n */\ntype ReporterTokensArgs<T extends RuntimeReporterMessage, U extends T[\"code\"]> = Extract<\n T,\n { code: U }\n>[\"tokens\"] extends infer Tokens\n ? [Tokens] extends [string]\n ? [tokens: Record<Tokens, RuntimeReporterToken>]\n : []\n : [];\n\n/**\n * Return type for message(); displays the template + code in default format on hover.\n * The runtime value is the resolved string (tokens substituted); the type is for DX only.\n * @private\n */\ntype MessageReturnType<T extends RuntimeReporterMessage, U extends T[\"code\"]> =\n Extract<T, { code: U }> extends { template: infer Template }\n ? Template extends string\n ? `${Template} (${U})`\n : string\n : string;\n\n/**\n * The runtime report object with all of it's associated methods;\n * the result of the primary export: `createReporter`\n * @private\n */\ninterface RuntimeReporter<T extends RuntimeReporterMessage> {\n /**\n * Retrieves the full text of the targeted message\n *\n * _Note: As a convenience, the return type will attempt to show the literal type of the template\n * pattern and code suffix (in the default format) for the message on hover; the actual output may\n * vary based on the tokens provided and the `formatMessage` option._\n *\n * _Tip: This method is particularly useful in the test environment; allowing you\n * to make precise assertions without having to duplicate any of the raw message text._\n * @param code A direct reference to the unique code for the targeted message\n * @param args The remaining optional argument for the function; a record containing the placeholder token values\n */\n message<U extends T[\"code\"]>(\n code: U,\n ...args: ReporterTokensArgs<T, U>\n ): MessageReturnType<T, U>;\n\n /**\n * Logs a warning to the console with the full text of the targeted message\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args A record containing the placeholder token values for the message\n */\n warn<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Logs an error to the console with the full text of the targeted message\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args A record containing the placeholder token values for the message\n */\n error<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Logs a message to the console with the full text of the targeted message\n *\n * _Note: This method will only log when the message associated with the code is found;\n * meaning it will not be called in production if the `createReporter` function\n * is provided an empty message set._\n * @param code A direct reference to the unique code for the targeted message\n * @param args A record containing the placeholder token values for the message\n */\n log<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;\n\n /**\n * Throws an error with the full text of the targeted message in all environments\n *\n * _Note: When the `createReporter` function is called in production with an empty\n * message set, this method will use the \"defaultTemplate\" option in this format: \"&lt;defaultTemplate> (&lt;code>)\"_\n * @param code A direct reference to the unique code for the targeted message\n * @param args A record containing the placeholder token values for the message\n */\n fail<U extends T[\"code\"]>(code: U, ...args: ReporterTokensArgs<T, U>): never;\n}\n\n/**\n * The payload for the onReport hook\n */\nexport type RuntimeReporterReportPayload = {\n /**\n * The unique code associated with the message\n */\n code: string;\n\n /**\n * The resolved message text; the placeholders have been replaced by their token values\n * but, it has not been formatted by the `formatMessage` option.\n */\n message: string;\n\n /**\n * The severity level of the report\n */\n level: \"error\" | \"warn\" | \"log\" | \"fail\";\n};\n\n/**\n * The configuration options for createReporter()\n * @since v0.1.0\n */\nexport interface RuntimeReporterOptions {\n /**\n * A hook to format the message text that is logged to the console. By default, it\n * outputs the message in the following format: \"&lt;message> (&lt;code>)\".\n *\n * _Note: This option does not affect the message provided to the `onReport` hook._\n * @param message The resolved message text; the placeholders have been replaced by their token values\n * @param code The unique code associated with the message\n * @returns The final, fully formatted message\n */\n formatMessage?: (message: string, code: string) => string;\n\n /**\n * The default template to fallback on when a provided code does not\n * have an associated message. Defaults to \"An error occurred\"\n */\n defaultTemplate?: string;\n\n /**\n * A hook to perform custom actions when any of the report methods (minus the\n * `message` method) are called. This is useful for logging to a remote service,\n * or for performing other actions based on the report.\n * @param payload The payload for the report\n */\n onReport?: (payload: RuntimeReporterReportPayload) => void;\n}\n\n/**\n * Resolves the message text via the message template and the associated tokens\n * @param template The template string for the reported message\n * @param tokens The token names and values for the instance\n * @returns The resolved message text; returns an empty string if the template is falsy\n * @private\n */\nconst resolveTemplate = function resolveTemplate(\n template: string,\n tokens?: Record<string, RuntimeReporterToken>\n): string {\n let message = template;\n\n if (message) {\n Object.entries(tokens || {}).forEach((entry) => {\n const [token, value] = entry;\n const replace = value instanceof Error ? value.message : String(value ?? \"\");\n const sanitized = token.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n message = message.replace(new RegExp(`\\\\{\\\\{\\\\s*${sanitized}\\\\s*\\\\}\\\\}`, \"g\"), replace);\n });\n }\n\n return message;\n};\n\n/**\n * Creates a new runtime reporter object with all of it's associated methods\n * @param messages The messages record organized by code and template\n * @param options Optional configuration options\n * @returns A runtime report object\n * @since v0.1.0\n */\nexport function createReporter<T extends RuntimeReporterMessage>(\n messages: RuntimeReporterMessages<T>,\n options: RuntimeReporterOptions = {}\n): RuntimeReporter<T> {\n const {\n formatMessage = (message, code) => `${message} (${code})`,\n defaultTemplate = \"An error occurred\",\n onReport,\n } = options;\n const messagesByCode = messages as Record<string, string>;\n\n /**\n * Retrieves the resolved message text for a given code and its associated tokens\n * @param code The unique code associated with the message\n * @param args The record containing the placeholder token values\n * @returns The fully resolved message\n */\n const resolveMessage = function getMessage(\n code: string,\n ...args: Array<Record<string, RuntimeReporterToken>>\n ): string {\n const template = messagesByCode[code] || defaultTemplate;\n const tokens = args[0];\n return resolveTemplate(template, tokens);\n };\n\n return {\n message: (code, ...args) => {\n const message = resolveMessage(code, ...args);\n const formattedMessage = formatMessage(message, code);\n return formattedMessage as MessageReturnType<T, typeof code & T[\"code\"]>;\n },\n error: (code, ...args) => {\n const message = resolveMessage(code, ...args);\n const formattedMessage = formatMessage(message, code);\n if (onReport) onReport({ code, message, level: \"error\" });\n if (messagesByCode[code]) console.error(formattedMessage);\n },\n warn: (code, ...args) => {\n const message = resolveMessage(code, ...args);\n const formattedMessage = formatMessage(message, code);\n if (onReport) onReport({ code, message, level: \"warn\" });\n if (messagesByCode[code]) console.warn(formattedMessage);\n },\n log: (code, ...args) => {\n const message = resolveMessage(code, ...args);\n const formattedMessage = formatMessage(message, code);\n if (onReport) onReport({ code, message, level: \"log\" });\n if (messagesByCode[code]) console.log(formattedMessage);\n },\n fail: (code, ...args) => {\n const message = resolveMessage(code, ...args);\n const formattedMessage = formatMessage(message, code);\n if (onReport) onReport({ code, message, level: \"fail\" });\n throw new Error(formattedMessage);\n },\n };\n}\n"],"mappings":";AAqLA,IAAM,kBAAkB,SAASA,iBAC7B,UACA,QACM;AACN,MAAI,UAAU;AAEd,MAAI,SAAS;AACT,WAAO,QAAQ,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU;AAC5C,YAAM,CAAC,OAAO,KAAK,IAAI;AACvB,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,SAAS,EAAE;AAC3E,YAAM,YAAY,MAAM,QAAQ,uBAAuB,MAAM;AAC7D,gBAAU,QAAQ,QAAQ,IAAI,OAAO,aAAa,SAAS,cAAc,GAAG,GAAG,OAAO;AAAA,IAC1F,CAAC;AAAA,EACL;AAEA,SAAO;AACX;AASO,SAAS,eACZ,UACA,UAAkC,CAAC,GACjB;AAClB,QAAM;AAAA,IACF,gBAAgB,CAAC,SAAS,SAAS,GAAG,OAAO,KAAK,IAAI;AAAA,IACtD,kBAAkB;AAAA,IAClB;AAAA,EACJ,IAAI;AACJ,QAAM,iBAAiB;AAQvB,QAAM,iBAAiB,SAAS,WAC5B,SACG,MACG;AACN,UAAM,WAAW,eAAe,IAAI,KAAK;AACzC,UAAM,SAAS,KAAK,CAAC;AACrB,WAAO,gBAAgB,UAAU,MAAM;AAAA,EAC3C;AAEA,SAAO;AAAA,IACH,SAAS,CAAC,SAAS,SAAS;AACxB,YAAM,UAAU,eAAe,MAAM,GAAG,IAAI;AAC5C,YAAM,mBAAmB,cAAc,SAAS,IAAI;AACpD,aAAO;AAAA,IACX;AAAA,IACA,OAAO,CAAC,SAAS,SAAS;AACtB,YAAM,UAAU,eAAe,MAAM,GAAG,IAAI;AAC5C,YAAM,mBAAmB,cAAc,SAAS,IAAI;AACpD,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,QAAQ,CAAC;AACxD,UAAI,eAAe,IAAI,EAAG,SAAQ,MAAM,gBAAgB;AAAA,IAC5D;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,eAAe,MAAM,GAAG,IAAI;AAC5C,YAAM,mBAAmB,cAAc,SAAS,IAAI;AACpD,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,OAAO,CAAC;AACvD,UAAI,eAAe,IAAI,EAAG,SAAQ,KAAK,gBAAgB;AAAA,IAC3D;AAAA,IACA,KAAK,CAAC,SAAS,SAAS;AACpB,YAAM,UAAU,eAAe,MAAM,GAAG,IAAI;AAC5C,YAAM,mBAAmB,cAAc,SAAS,IAAI;AACpD,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,MAAM,CAAC;AACtD,UAAI,eAAe,IAAI,EAAG,SAAQ,IAAI,gBAAgB;AAAA,IAC1D;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,eAAe,MAAM,GAAG,IAAI;AAC5C,YAAM,mBAAmB,cAAc,SAAS,IAAI;AACpD,UAAI,SAAU,UAAS,EAAE,MAAM,SAAS,OAAO,OAAO,CAAC;AACvD,YAAM,IAAI,MAAM,gBAAgB;AAAA,IACpC;AAAA,EACJ;AACJ;","names":["resolveTemplate"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runtime-reporter",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Replace ad-hoc logging with structured, code-based messaging",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",