runtime-reporter 0.3.0 → 0.4.1

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,18 +2,20 @@
2
2
 
3
3
  Structured runtime events for applications and frameworks. A composable foundation for logging, messaging, and runtime reporting.
4
4
 
5
+ Modern applications often rely on complex logging solutions or ad-hoc messaging systems to understand runtime behavior. These approaches can be difficult to integrate or are tightly coupled to specific environments. Runtime Reporter provides a lightweight, structured runtime event layer designed to simplify logging and messaging while remaining performant, secure, and framework-agnostic.
6
+
5
7
  ## Features
6
8
 
7
- - **Security focused**: Pass an empty message set in production to avoid exposing internal messaging.
8
- - **Centralized messages**: Define message text once; reference by a unique code everywhere else.
9
- - **Tokenized templates**: Apply runtime data to messages via templated strings and tokenized variables.
10
- - **Type-safe**: Autocomplete and compile-time validation for message codes and token names.
11
- - **Tree-shakeable**: Pass an empty message set in production to reduce your bundle size
12
- - **Test friendly**: Use `message()` to assert on final output without duplicating message text.
13
- - **Code-based messaging**: Coded messages make it easy to identify errors to perform debugging tasks.
14
- - **Small footprint**: Minimal bundle size (~2 KB minified) so it adds negligible weight to your app.
15
- - **Zero dependencies**: No runtime dependencies; the published package is fully self-contained.
16
- - **Scalable pattern**: Can scale to fit your specific needs regardless of your project's size.
9
+ - **Centralized messages**: Define message text once and reference it everywhere using stable message codes.
10
+ - **Code-based messaging**: Structured message identifiers make debugging and tracing runtime behavior easier.
11
+ - **Security conscious**: Prevent accidental exposure of sensitive data by omitting message definitions in production.
12
+ - **Type-safe**: Autocomplete and compile-time validation for message codes and template tokens.
13
+ - **Tokenized templates**: Inject runtime data using structured, reusable message templates.
14
+ - **Test friendly**: Assert against resolved messages without duplicating message text in tests.
15
+ - **Tree-shakeable**: Ship an empty message set in production to minimize bundle size.
16
+ - **Small footprint**: ~2 KB minified with negligible runtime overhead.
17
+ - **Zero dependencies**: Fully self-contained with no runtime dependencies.
18
+ - **Scales with your application**: Works equally well for small projects and large frameworks.
17
19
 
18
20
  ## Installation
19
21
 
@@ -25,25 +27,23 @@ npm install runtime-reporter
25
27
 
26
28
  ### 1) Define your messages
27
29
 
28
- Define the message schema (code + template + tokens), then create a `messages` record keyed by the codes.
30
+ Define your messages by creating an object with the message "schema" (code + template + tokens) and keyed by their codes.
29
31
 
30
32
  ```ts
31
33
  import type { RuntimeReporterMessages } from "runtime-reporter";
32
34
 
33
- type MyMessages =
35
+ const messages: RuntimeReporterMessages<
34
36
  | {
35
37
  code: "ERR01";
36
- template: "{{ componentName }} failed to mount";
37
- tokens: ["componentName"];
38
+ template: "{{ componentName }} failed at {{ phase }}";
39
+ tokens: "componentName" | "phase";
38
40
  }
39
41
  | {
40
42
  code: "INFO01";
41
43
  template: "Ready";
42
- tokens?: undefined;
43
- };
44
-
45
- const messages: RuntimeReporterMessages<MyMessages> = {
46
- ERR01: "{{ componentName }} failed to mount",
44
+ }
45
+ > = {
46
+ ERR01: "{{ componentName }} failed at {{ phase }}",
47
47
  INFO01: "Ready",
48
48
  };
49
49
  ```
@@ -66,8 +66,8 @@ export const reporter = createReporter(
66
66
  Call the various reporter methods wherever you need them.
67
67
 
68
68
  ```ts
69
- reporter.error("ERR01", { componentName: "MyComponent" });
70
- // logs: "MyComponent failed to mount (ERR01)"
69
+ reporter.error("ERR01", { componentName: "Router", phase: "mount" });
70
+ // logs: "Router failed at mount (ERR01)"
71
71
 
72
72
  reporter.message("INFO01");
73
73
  // returns: "Ready (INFO01)"
@@ -117,6 +117,32 @@ reporter.message("INFO01");
117
117
  // "[INFO01] Ready"
118
118
  ```
119
119
 
120
+ ### Using the reporter in production
121
+
122
+ When the `createReporter` function is called in production with an empty message set, the `fail` method will use the customizable `defaultTemplate` option which defaults to "An error occurred". This message is intended to be generic so that it does not reveal sensitive information about the system, while still providing a code for debugging purposes.
123
+
124
+ ```ts
125
+ const reporter = createReporter(
126
+ // Pass an empty object in production for better security and a smaller bundle size
127
+ process.env.NODE_ENV === "production" ? ({} as typeof messages) : messages
128
+ );
129
+
130
+ reporter.fail("ERR01", { componentName: "Router", phase: "mount" });
131
+ // throws: "An error occurred (ERR01)"
132
+ ```
133
+
134
+ The remaining reporter methods will not log anything in production when the code is missing from the message set.
135
+
136
+ ```ts
137
+ const reporter = createReporter(
138
+ // Pass an empty object in production for better security and a smaller bundle size
139
+ process.env.NODE_ENV === "production" ? ({} as typeof messages) : messages
140
+ );
141
+
142
+ reporter.error("ERR01", { componentName: "Router", phase: "mount" });
143
+ // does not log anything
144
+ ```
145
+
120
146
  ### Using `message()` in tests
121
147
 
122
148
  The `message` method returns the resolved string without side effects, allowing you to validate precise messaging without duplicating text.
@@ -137,11 +163,44 @@ describe("reporter messages", () => {
137
163
  });
138
164
  ```
139
165
 
166
+ ### Using the reporter without TypeScript
167
+
168
+ You can use the reporter without TypeScript, you will just lose the type safety and autocomplete.
169
+
170
+ ```js
171
+ import { createReporter } from "runtime-reporter";
172
+
173
+ const reporter = createReporter({
174
+ ERR01: "{{ componentName }} failed at {{ phase }}",
175
+ });
176
+
177
+ reporter.error("ERR01", { componentName: "Router", phase: "mount" });
178
+ // logs: "Router failed at mount (ERR01)"
179
+ ```
180
+
181
+ However, you can still get the same benefits as TypeScript by using JSDoc-style type annotations.
182
+
183
+ ```js
184
+ /**
185
+ * @type {import("runtime-reporter").RuntimeReporterMessages<{
186
+ * code: "ERR01";
187
+ * template: "{{ componentName }} failed at {{ phase }}";
188
+ * tokens: "componentName" | "phase";
189
+ * } | {
190
+ * code: "INFO01";
191
+ * template: "Ready";
192
+ * }>}
193
+ */
194
+ const messages = {
195
+ ERR01: "{{ componentName }} failed at {{ phase }}",
196
+ INFO01: "Ready",
197
+ };
198
+ ```
199
+
140
200
  ### CommonJS support
141
201
 
142
202
  If needed, Common JS imports are also available.
143
203
 
144
204
  ```js
145
- // CJS
146
205
  const { createReporter } = require("runtime-reporter");
147
206
  ```
package/dist/index.cjs CHANGED
@@ -40,27 +40,26 @@ function createReporter(messages, options = {}) {
40
40
  formatMessage = (message, code) => `${message} (${code})`,
41
41
  defaultTemplate = "An error occurred"
42
42
  } = options;
43
+ const messagesByCode = messages;
43
44
  const getMessage = function getMessage2(code, ...args) {
44
- const template = messages[code] || defaultTemplate;
45
+ const template = messagesByCode[code] || defaultTemplate;
45
46
  const tokens = args[0];
46
47
  const text = resolveTemplate(template, tokens);
47
48
  return formatMessage(text, code);
48
49
  };
49
50
  return {
50
- message: (code, ...args) => {
51
- return getMessage(code, ...args);
52
- },
51
+ message: (code, ...args) => getMessage(code, ...args),
53
52
  error: (code, ...args) => {
54
53
  const message = getMessage(code, ...args);
55
- if (messages[code]) console.error(message);
54
+ if (messagesByCode[code]) console.error(message);
56
55
  },
57
56
  warn: (code, ...args) => {
58
57
  const message = getMessage(code, ...args);
59
- if (messages[code]) console.warn(message);
58
+ if (messagesByCode[code]) console.warn(message);
60
59
  },
61
60
  log: (code, ...args) => {
62
61
  const message = getMessage(code, ...args);
63
- if (messages[code]) console.log(message);
62
+ if (messagesByCode[code]) console.log(message);
64
63
  },
65
64
  fail: (code, ...args) => {
66
65
  const message = getMessage(code, ...args);
@@ -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 RuntimeReporterTokensArgs<\n T extends RuntimeReporterMessages<RuntimeReporterMessage>,\n U extends keyof T,\n> =\n T extends RuntimeReporterMessages<infer V extends RuntimeReporterMessage>\n ? Extract<V, { code: U }>[\"tokens\"] extends infer Tokens\n ? Tokens extends readonly string[]\n ? [tokens: Record<Tokens[number], RuntimeReporterToken>]\n : []\n : []\n : never;\n\n/**\n * The runtime report object with all of it's associated methods; the result\n * of the primary export: `createReporter`\n * @private\n */\ninterface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessage>> {\n /**\n * Retrieves the full text of the targeted message\n *\n * _Tip: This method is particularly useful in the test environment; allowing you\n * to make precise assertions without having to duplicate an 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 Extract<keyof T, string>>(\n code: U,\n ...args: RuntimeReporterTokensArgs<T, U>\n ): string;\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 Extract<keyof T, string>>(\n code: U,\n ...args: RuntimeReporterTokensArgs<T, U>\n ): 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 Extract<keyof T, string>>(\n code: U,\n ...args: RuntimeReporterTokensArgs<T, U>\n ): 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 Extract<keyof T, string>>(\n code: U,\n ...args: RuntimeReporterTokensArgs<T, U>\n ): 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: \"<defaultTemplate> (<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 Extract<keyof T, string>>(\n code: U,\n ...args: RuntimeReporterTokensArgs<T, U>\n ): void;\n}\n\nexport interface RuntimeReporterOptions {\n /**\n * A hook to format the message text universally. By default, it\n * outputs the message in the following format: \"<message> (<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/**\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 */\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 reporter object with various helpful runtime 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 */\nexport function createReporter<T extends RuntimeReporterMessages<RuntimeReporterMessage>>(\n messages: T,\n options: RuntimeReporterOptions = {}\n): RuntimeReporter<T> {\n const {\n formatMessage = (message, code) => `${message} (${code})`,\n defaultTemplate = \"An error occurred\",\n } = options;\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 = messages[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 return getMessage(code, ...args);\n },\n error: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (messages[code]) console.error(message);\n },\n warn: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (messages[code]) console.warn(message);\n },\n log: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (messages[code]) console.log(message);\n },\n fail: (code, ...args) => {\n const message = getMessage(code, ...args);\n throw new Error(message);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmJA,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;AAQO,SAAS,eACZ,UACA,UAAkC,CAAC,GACjB;AAClB,QAAM;AAAA,IACF,gBAAgB,CAAC,SAAS,SAAS,GAAG,OAAO,KAAK,IAAI;AAAA,IACtD,kBAAkB;AAAA,EACtB,IAAI;AAQJ,QAAM,aAAa,SAASC,YACxB,SACG,MACG;AACN,UAAM,WAAW,SAAS,IAAI,KAAK;AACnC,UAAM,SAAS,KAAK,CAAC;AACrB,UAAM,OAAO,gBAAgB,UAAU,MAAM;AAC7C,WAAO,cAAc,MAAM,IAAI;AAAA,EACnC;AAEA,SAAO;AAAA,IACH,SAAS,CAAC,SAAS,SAAS;AACxB,aAAO,WAAW,MAAM,GAAG,IAAI;AAAA,IACnC;AAAA,IACA,OAAO,CAAC,SAAS,SAAS;AACtB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAS,IAAI,EAAG,SAAQ,MAAM,OAAO;AAAA,IAC7C;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAS,IAAI,EAAG,SAAQ,KAAK,OAAO;AAAA,IAC5C;AAAA,IACA,KAAK,CAAC,SAAS,SAAS;AACpB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAS,IAAI,EAAG,SAAQ,IAAI,OAAO;AAAA,IAC3C;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,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; the result\n * 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: \"<defaultTemplate> (<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>): void;\n}\n\nexport interface RuntimeReporterOptions {\n /**\n * A hook to format the message text universally. By default, it\n * outputs the message in the following format: \"<message> (<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/**\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 */\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 reporter object with various helpful runtime 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 */\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 } = 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 (messagesByCode[code]) console.error(message);\n },\n warn: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (messagesByCode[code]) console.warn(message);\n },\n log: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (messagesByCode[code]) console.log(message);\n },\n fail: (code, ...args) => {\n const message = getMessage(code, ...args);\n throw new Error(message);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoJA,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;AAQO,SAAS,eACZ,UACA,UAAkC,CAAC,GACjB;AAClB,QAAM;AAAA,IACF,gBAAgB,CAAC,SAAS,SAAS,GAAG,OAAO,KAAK,IAAI;AAAA,IACtD,kBAAkB;AAAA,EACtB,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,eAAe,IAAI,EAAG,SAAQ,MAAM,OAAO;AAAA,IACnD;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,eAAe,IAAI,EAAG,SAAQ,KAAK,OAAO;AAAA,IAClD;AAAA,IACA,KAAK,CAAC,SAAS,SAAS;AACpB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,eAAe,IAAI,EAAG,SAAQ,IAAI,OAAO;AAAA,IACjD;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,YAAM,IAAI,MAAM,OAAO;AAAA,IAC3B;AAAA,EACJ;AACJ;","names":["resolveTemplate","getMessage"]}
package/dist/index.d.cts CHANGED
@@ -5,7 +5,7 @@
5
5
  type RuntimeReporterMessage = {
6
6
  code: string;
7
7
  template: string;
8
- tokens?: string[];
8
+ tokens?: string;
9
9
  };
10
10
  /**
11
11
  * The type for a full list of messages with their associated code and template
@@ -30,24 +30,38 @@ type RuntimeReporterTokens = Record<string, RuntimeReporterToken>;
30
30
  * A utility type used to determine the second argument of the runtime reporter methods
31
31
  * @private
32
32
  */
33
- type RuntimeReporterTokensArgs<T extends RuntimeReporterMessages<RuntimeReporterMessage>, U extends keyof T> = T extends RuntimeReporterMessages<infer V extends RuntimeReporterMessage> ? Extract<V, {
33
+ type ReporterTokensArgs<T extends RuntimeReporterMessage, U extends T["code"]> = Extract<T, {
34
34
  code: U;
35
- }>["tokens"] extends infer Tokens ? Tokens extends readonly string[] ? [tokens: Record<Tokens[number], RuntimeReporterToken>] : [] : [] : never;
35
+ }>["tokens"] extends infer Tokens ? [Tokens] extends [string] ? [tokens: Record<Tokens, RuntimeReporterToken>] : [] : [];
36
+ /**
37
+ * Return type for message(); displays the template + code in default format on hover.
38
+ * The runtime value is the resolved string (tokens substituted); the type is for DX only.
39
+ * @private
40
+ */
41
+ type MessageReturnType<T extends RuntimeReporterMessage, U extends T["code"]> = Extract<T, {
42
+ code: U;
43
+ }> extends {
44
+ template: infer Template;
45
+ } ? Template extends string ? `${Template} (${U})` : string : string;
36
46
  /**
37
47
  * The runtime report object with all of it's associated methods; the result
38
48
  * of the primary export: `createReporter`
39
49
  * @private
40
50
  */
41
- interface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessage>> {
51
+ interface RuntimeReporter<T extends RuntimeReporterMessage> {
42
52
  /**
43
53
  * Retrieves the full text of the targeted message
44
54
  *
55
+ * _Note: As a convenience, the return type will attempt to show the literal type of the template
56
+ * pattern and code suffix (in the default format) for the message on hover; the actual output may
57
+ * vary based on the tokens provided and the `formatMessage` option._
58
+ *
45
59
  * _Tip: This method is particularly useful in the test environment; allowing you
46
- * to make precise assertions without having to duplicate an of the raw message text._
60
+ * to make precise assertions without having to duplicate any of the raw message text._
47
61
  * @param code A direct reference to the unique code for the targeted message
48
62
  * @param args The remaining optional argument for the function; a record containing the placeholder token values
49
63
  */
50
- message<U extends Extract<keyof T, string>>(code: U, ...args: RuntimeReporterTokensArgs<T, U>): string;
64
+ message<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): MessageReturnType<T, U>;
51
65
  /**
52
66
  * Logs a warning to the console with the full text of the targeted message in non-production environments
53
67
  *
@@ -57,7 +71,7 @@ interface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessa
57
71
  * @param code A direct reference to the unique code for the targeted message
58
72
  * @param args The remaining optional argument for the function; a record containing the placeholder token values
59
73
  */
60
- warn<U extends Extract<keyof T, string>>(code: U, ...args: RuntimeReporterTokensArgs<T, U>): void;
74
+ warn<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
61
75
  /**
62
76
  * Logs an error to the console with the full text of the targeted message in non-production environments
63
77
  *
@@ -67,7 +81,7 @@ interface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessa
67
81
  * @param code A direct reference to the unique code for the targeted message
68
82
  * @param args The remaining optional argument for the function; a record containing the placeholder token values
69
83
  */
70
- error<U extends Extract<keyof T, string>>(code: U, ...args: RuntimeReporterTokensArgs<T, U>): void;
84
+ error<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
71
85
  /**
72
86
  * Logs a message to the console with the full text of the targeted message in non-production environments
73
87
  *
@@ -77,7 +91,7 @@ interface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessa
77
91
  * @param code A direct reference to the unique code for the targeted message
78
92
  * @param args The remaining optional argument for the function; a record containing the placeholder token values
79
93
  */
80
- log<U extends Extract<keyof T, string>>(code: U, ...args: RuntimeReporterTokensArgs<T, U>): void;
94
+ log<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
81
95
  /**
82
96
  * Throws an error with the full text of the targeted message in all environments
83
97
  *
@@ -86,7 +100,7 @@ interface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessa
86
100
  * @param code A direct reference to the unique code for the targeted message
87
101
  * @param args The remaining optional argument for the function; a record containing the placeholder token values
88
102
  */
89
- fail<U extends Extract<keyof T, string>>(code: U, ...args: RuntimeReporterTokensArgs<T, U>): void;
103
+ fail<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
90
104
  }
91
105
  interface RuntimeReporterOptions {
92
106
  /**
@@ -112,6 +126,6 @@ interface RuntimeReporterOptions {
112
126
  * @param options Optional configuration options
113
127
  * @returns A runtime report object
114
128
  */
115
- declare function createReporter<T extends RuntimeReporterMessages<RuntimeReporterMessage>>(messages: T, options?: RuntimeReporterOptions): RuntimeReporter<T>;
129
+ declare function createReporter<T extends RuntimeReporterMessage>(messages: RuntimeReporterMessages<T>, options?: RuntimeReporterOptions): RuntimeReporter<T>;
116
130
 
117
131
  export { type RuntimeReporterMessage, type RuntimeReporterMessages, type RuntimeReporterOptions, type RuntimeReporterToken, type RuntimeReporterTokens, createReporter };
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  type RuntimeReporterMessage = {
6
6
  code: string;
7
7
  template: string;
8
- tokens?: string[];
8
+ tokens?: string;
9
9
  };
10
10
  /**
11
11
  * The type for a full list of messages with their associated code and template
@@ -30,24 +30,38 @@ type RuntimeReporterTokens = Record<string, RuntimeReporterToken>;
30
30
  * A utility type used to determine the second argument of the runtime reporter methods
31
31
  * @private
32
32
  */
33
- type RuntimeReporterTokensArgs<T extends RuntimeReporterMessages<RuntimeReporterMessage>, U extends keyof T> = T extends RuntimeReporterMessages<infer V extends RuntimeReporterMessage> ? Extract<V, {
33
+ type ReporterTokensArgs<T extends RuntimeReporterMessage, U extends T["code"]> = Extract<T, {
34
34
  code: U;
35
- }>["tokens"] extends infer Tokens ? Tokens extends readonly string[] ? [tokens: Record<Tokens[number], RuntimeReporterToken>] : [] : [] : never;
35
+ }>["tokens"] extends infer Tokens ? [Tokens] extends [string] ? [tokens: Record<Tokens, RuntimeReporterToken>] : [] : [];
36
+ /**
37
+ * Return type for message(); displays the template + code in default format on hover.
38
+ * The runtime value is the resolved string (tokens substituted); the type is for DX only.
39
+ * @private
40
+ */
41
+ type MessageReturnType<T extends RuntimeReporterMessage, U extends T["code"]> = Extract<T, {
42
+ code: U;
43
+ }> extends {
44
+ template: infer Template;
45
+ } ? Template extends string ? `${Template} (${U})` : string : string;
36
46
  /**
37
47
  * The runtime report object with all of it's associated methods; the result
38
48
  * of the primary export: `createReporter`
39
49
  * @private
40
50
  */
41
- interface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessage>> {
51
+ interface RuntimeReporter<T extends RuntimeReporterMessage> {
42
52
  /**
43
53
  * Retrieves the full text of the targeted message
44
54
  *
55
+ * _Note: As a convenience, the return type will attempt to show the literal type of the template
56
+ * pattern and code suffix (in the default format) for the message on hover; the actual output may
57
+ * vary based on the tokens provided and the `formatMessage` option._
58
+ *
45
59
  * _Tip: This method is particularly useful in the test environment; allowing you
46
- * to make precise assertions without having to duplicate an of the raw message text._
60
+ * to make precise assertions without having to duplicate any of the raw message text._
47
61
  * @param code A direct reference to the unique code for the targeted message
48
62
  * @param args The remaining optional argument for the function; a record containing the placeholder token values
49
63
  */
50
- message<U extends Extract<keyof T, string>>(code: U, ...args: RuntimeReporterTokensArgs<T, U>): string;
64
+ message<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): MessageReturnType<T, U>;
51
65
  /**
52
66
  * Logs a warning to the console with the full text of the targeted message in non-production environments
53
67
  *
@@ -57,7 +71,7 @@ interface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessa
57
71
  * @param code A direct reference to the unique code for the targeted message
58
72
  * @param args The remaining optional argument for the function; a record containing the placeholder token values
59
73
  */
60
- warn<U extends Extract<keyof T, string>>(code: U, ...args: RuntimeReporterTokensArgs<T, U>): void;
74
+ warn<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
61
75
  /**
62
76
  * Logs an error to the console with the full text of the targeted message in non-production environments
63
77
  *
@@ -67,7 +81,7 @@ interface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessa
67
81
  * @param code A direct reference to the unique code for the targeted message
68
82
  * @param args The remaining optional argument for the function; a record containing the placeholder token values
69
83
  */
70
- error<U extends Extract<keyof T, string>>(code: U, ...args: RuntimeReporterTokensArgs<T, U>): void;
84
+ error<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
71
85
  /**
72
86
  * Logs a message to the console with the full text of the targeted message in non-production environments
73
87
  *
@@ -77,7 +91,7 @@ interface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessa
77
91
  * @param code A direct reference to the unique code for the targeted message
78
92
  * @param args The remaining optional argument for the function; a record containing the placeholder token values
79
93
  */
80
- log<U extends Extract<keyof T, string>>(code: U, ...args: RuntimeReporterTokensArgs<T, U>): void;
94
+ log<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
81
95
  /**
82
96
  * Throws an error with the full text of the targeted message in all environments
83
97
  *
@@ -86,7 +100,7 @@ interface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessa
86
100
  * @param code A direct reference to the unique code for the targeted message
87
101
  * @param args The remaining optional argument for the function; a record containing the placeholder token values
88
102
  */
89
- fail<U extends Extract<keyof T, string>>(code: U, ...args: RuntimeReporterTokensArgs<T, U>): void;
103
+ fail<U extends T["code"]>(code: U, ...args: ReporterTokensArgs<T, U>): void;
90
104
  }
91
105
  interface RuntimeReporterOptions {
92
106
  /**
@@ -112,6 +126,6 @@ interface RuntimeReporterOptions {
112
126
  * @param options Optional configuration options
113
127
  * @returns A runtime report object
114
128
  */
115
- declare function createReporter<T extends RuntimeReporterMessages<RuntimeReporterMessage>>(messages: T, options?: RuntimeReporterOptions): RuntimeReporter<T>;
129
+ declare function createReporter<T extends RuntimeReporterMessage>(messages: RuntimeReporterMessages<T>, options?: RuntimeReporterOptions): RuntimeReporter<T>;
116
130
 
117
131
  export { type RuntimeReporterMessage, type RuntimeReporterMessages, type RuntimeReporterOptions, type RuntimeReporterToken, type RuntimeReporterTokens, createReporter };
package/dist/index.js CHANGED
@@ -16,27 +16,26 @@ function createReporter(messages, options = {}) {
16
16
  formatMessage = (message, code) => `${message} (${code})`,
17
17
  defaultTemplate = "An error occurred"
18
18
  } = options;
19
+ const messagesByCode = messages;
19
20
  const getMessage = function getMessage2(code, ...args) {
20
- const template = messages[code] || defaultTemplate;
21
+ const template = messagesByCode[code] || defaultTemplate;
21
22
  const tokens = args[0];
22
23
  const text = resolveTemplate(template, tokens);
23
24
  return formatMessage(text, code);
24
25
  };
25
26
  return {
26
- message: (code, ...args) => {
27
- return getMessage(code, ...args);
28
- },
27
+ message: (code, ...args) => getMessage(code, ...args),
29
28
  error: (code, ...args) => {
30
29
  const message = getMessage(code, ...args);
31
- if (messages[code]) console.error(message);
30
+ if (messagesByCode[code]) console.error(message);
32
31
  },
33
32
  warn: (code, ...args) => {
34
33
  const message = getMessage(code, ...args);
35
- if (messages[code]) console.warn(message);
34
+ if (messagesByCode[code]) console.warn(message);
36
35
  },
37
36
  log: (code, ...args) => {
38
37
  const message = getMessage(code, ...args);
39
- if (messages[code]) console.log(message);
38
+ if (messagesByCode[code]) console.log(message);
40
39
  },
41
40
  fail: (code, ...args) => {
42
41
  const message = getMessage(code, ...args);
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 RuntimeReporterTokensArgs<\n T extends RuntimeReporterMessages<RuntimeReporterMessage>,\n U extends keyof T,\n> =\n T extends RuntimeReporterMessages<infer V extends RuntimeReporterMessage>\n ? Extract<V, { code: U }>[\"tokens\"] extends infer Tokens\n ? Tokens extends readonly string[]\n ? [tokens: Record<Tokens[number], RuntimeReporterToken>]\n : []\n : []\n : never;\n\n/**\n * The runtime report object with all of it's associated methods; the result\n * of the primary export: `createReporter`\n * @private\n */\ninterface RuntimeReporter<T extends RuntimeReporterMessages<RuntimeReporterMessage>> {\n /**\n * Retrieves the full text of the targeted message\n *\n * _Tip: This method is particularly useful in the test environment; allowing you\n * to make precise assertions without having to duplicate an 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 Extract<keyof T, string>>(\n code: U,\n ...args: RuntimeReporterTokensArgs<T, U>\n ): string;\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 Extract<keyof T, string>>(\n code: U,\n ...args: RuntimeReporterTokensArgs<T, U>\n ): 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 Extract<keyof T, string>>(\n code: U,\n ...args: RuntimeReporterTokensArgs<T, U>\n ): 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 Extract<keyof T, string>>(\n code: U,\n ...args: RuntimeReporterTokensArgs<T, U>\n ): 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: \"<defaultTemplate> (<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 Extract<keyof T, string>>(\n code: U,\n ...args: RuntimeReporterTokensArgs<T, U>\n ): void;\n}\n\nexport interface RuntimeReporterOptions {\n /**\n * A hook to format the message text universally. By default, it\n * outputs the message in the following format: \"<message> (<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/**\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 */\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 reporter object with various helpful runtime 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 */\nexport function createReporter<T extends RuntimeReporterMessages<RuntimeReporterMessage>>(\n messages: T,\n options: RuntimeReporterOptions = {}\n): RuntimeReporter<T> {\n const {\n formatMessage = (message, code) => `${message} (${code})`,\n defaultTemplate = \"An error occurred\",\n } = options;\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 = messages[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 return getMessage(code, ...args);\n },\n error: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (messages[code]) console.error(message);\n },\n warn: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (messages[code]) console.warn(message);\n },\n log: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (messages[code]) console.log(message);\n },\n fail: (code, ...args) => {\n const message = getMessage(code, ...args);\n throw new Error(message);\n },\n };\n}\n"],"mappings":";AAmJA,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;AAQO,SAAS,eACZ,UACA,UAAkC,CAAC,GACjB;AAClB,QAAM;AAAA,IACF,gBAAgB,CAAC,SAAS,SAAS,GAAG,OAAO,KAAK,IAAI;AAAA,IACtD,kBAAkB;AAAA,EACtB,IAAI;AAQJ,QAAM,aAAa,SAASC,YACxB,SACG,MACG;AACN,UAAM,WAAW,SAAS,IAAI,KAAK;AACnC,UAAM,SAAS,KAAK,CAAC;AACrB,UAAM,OAAO,gBAAgB,UAAU,MAAM;AAC7C,WAAO,cAAc,MAAM,IAAI;AAAA,EACnC;AAEA,SAAO;AAAA,IACH,SAAS,CAAC,SAAS,SAAS;AACxB,aAAO,WAAW,MAAM,GAAG,IAAI;AAAA,IACnC;AAAA,IACA,OAAO,CAAC,SAAS,SAAS;AACtB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAS,IAAI,EAAG,SAAQ,MAAM,OAAO;AAAA,IAC7C;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAS,IAAI,EAAG,SAAQ,KAAK,OAAO;AAAA,IAC5C;AAAA,IACA,KAAK,CAAC,SAAS,SAAS;AACpB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,SAAS,IAAI,EAAG,SAAQ,IAAI,OAAO;AAAA,IAC3C;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,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; the result\n * 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: \"<defaultTemplate> (<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>): void;\n}\n\nexport interface RuntimeReporterOptions {\n /**\n * A hook to format the message text universally. By default, it\n * outputs the message in the following format: \"<message> (<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/**\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 */\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 reporter object with various helpful runtime 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 */\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 } = 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 (messagesByCode[code]) console.error(message);\n },\n warn: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (messagesByCode[code]) console.warn(message);\n },\n log: (code, ...args) => {\n const message = getMessage(code, ...args);\n if (messagesByCode[code]) console.log(message);\n },\n fail: (code, ...args) => {\n const message = getMessage(code, ...args);\n throw new Error(message);\n },\n };\n}\n"],"mappings":";AAoJA,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;AAQO,SAAS,eACZ,UACA,UAAkC,CAAC,GACjB;AAClB,QAAM;AAAA,IACF,gBAAgB,CAAC,SAAS,SAAS,GAAG,OAAO,KAAK,IAAI;AAAA,IACtD,kBAAkB;AAAA,EACtB,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,eAAe,IAAI,EAAG,SAAQ,MAAM,OAAO;AAAA,IACnD;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,eAAe,IAAI,EAAG,SAAQ,KAAK,OAAO;AAAA,IAClD;AAAA,IACA,KAAK,CAAC,SAAS,SAAS;AACpB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,UAAI,eAAe,IAAI,EAAG,SAAQ,IAAI,OAAO;AAAA,IACjD;AAAA,IACA,MAAM,CAAC,SAAS,SAAS;AACrB,YAAM,UAAU,WAAW,MAAM,GAAG,IAAI;AACxC,YAAM,IAAI,MAAM,OAAO;AAAA,IAC3B;AAAA,EACJ;AACJ;","names":["resolveTemplate","getMessage"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runtime-reporter",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Structured runtime events for applications and frameworks. A composable foundation for logging, messaging, and runtime reporting.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",