@discord/intl 0.13.0 → 0.13.2

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/dist/format.d.ts CHANGED
@@ -20,12 +20,12 @@ import { AstNode } from '@discord/intl-ast';
20
20
  import { Formatters } from 'intl-messageformat';
21
21
  import type { FormatConfig } from './format-config';
22
22
  import type { RichTextTagNames } from './types';
23
- export declare abstract class FormatBuilder<Result> {
23
+ export declare abstract class FormatBuilder<Result, ObjectType = Result extends object ? Result : never> {
24
24
  abstract pushRichTextTag(tag: RichTextTagNames, children: Result[], control: Result[]): void;
25
25
  abstract pushLiteralText(text: string): void;
26
- abstract pushObject(value: object): void;
26
+ abstract pushObject(value: ObjectType): void;
27
27
  abstract finish(): Result[];
28
28
  }
29
29
  export type FormatBuilderConstructor<Result> = new () => FormatBuilder<Result>;
30
- export declare function bindFormatValuesWithBuilder<T, Builder extends FormatBuilder<T>>(builder: Builder, nodes: AstNode[], locales: string | string[], formatters: Formatters, formatConfig: FormatConfig, values?: Record<string, string | object>, currentPluralValue?: number, originalMessage?: string): void;
30
+ export declare function bindFormatValuesWithBuilder<T, ObjectType, Builder extends FormatBuilder<T, ObjectType>>(builder: Builder, nodes: AstNode[], locales: string | string[], formatters: Formatters, formatConfig: FormatConfig, values?: Record<string, string | object>, currentPluralValue?: number, originalMessage?: string): void;
31
31
  export declare function bindFormatValues<Result>(Builder: FormatBuilderConstructor<Result>, nodes: string | AstNode[], locales: string | string[], formatters: Formatters, formatConfig: FormatConfig, values?: Record<string, string | object>, currentPluralValue?: number): Result[];
package/dist/format.js CHANGED
@@ -67,6 +67,13 @@ function bindFormatValuesWithBuilder(builder, nodes, locales, formatters, format
67
67
  const value = values[variableName];
68
68
  switch (nodeType) {
69
69
  case intl_ast_1.FormatJsNodeType.Argument:
70
+ // `function` here captures ReactNodes, which can be functions that
71
+ // return elements. Basically everything else fits in the `object`
72
+ // type, and the generic type requires that an explicit ObjectType
73
+ // be specified for cases where it's not. That means there's an
74
+ // escape hatch that _might_ break this, but it would have to be
75
+ // intentionally set by internal code to function that way, so we'll
76
+ // operate on a promise that it won't for now.
70
77
  if (typeof value === 'object' || typeof value === 'function') {
71
78
  builder.pushObject(value);
72
79
  }
@@ -12,17 +12,7 @@ export declare enum RichTextNodeType {
12
12
  Strikethrough = "s",
13
13
  Code = "inlineCode",
14
14
  Link = "link",
15
- Paragraph = "paragraph",
16
- /**
17
- * A special extension for when the value of a placeholder is an object.
18
- * Rather than casting to a string here, the object is preserved as-is for a
19
- * future formatter to render as appropriate (i.e., using an object as a
20
- * value when formatting to an AST should keep that object structure so that
21
- * the final AST is accurate for what the user expects, but when rendering to
22
- * a plain string, the final formatter can just cast that object to a string
23
- * using its `toString` method or some other mechanism).
24
- */
25
- Object = "object"
15
+ Paragraph = "paragraph"
26
16
  }
27
17
  interface RichTextNodeBase<ContentType> {
28
18
  type: RichTextNodeType;
@@ -48,12 +38,9 @@ interface RichTextParagraphNode extends RichTextNodeBase<RichTextNode[]> {
48
38
  }
49
39
  interface RichTextLinkNode extends RichTextNodeBase<RichTextNode[]> {
50
40
  type: RichTextNodeType.Link;
51
- target: string;
41
+ target: object;
52
42
  }
53
- interface RichTextObjectNode extends RichTextNodeBase<object> {
54
- type: RichTextNodeType.Object;
55
- }
56
- export type RichTextNode = RichTextTextNode | RichTextStrongNode | RichTextEmphasisNode | RichTextStrikethroughNode | RichTextCodeNode | RichTextParagraphNode | RichTextLinkNode | RichTextObjectNode;
43
+ export type RichTextNode = RichTextTextNode | RichTextStrongNode | RichTextEmphasisNode | RichTextStrikethroughNode | RichTextCodeNode | RichTextParagraphNode | RichTextLinkNode;
57
44
  /**
58
45
  * Format the given message in the current locale with the provided values.
59
46
  * The returned values is _always_ an Array of parts, even if the message is
@@ -15,16 +15,6 @@ var RichTextNodeType;
15
15
  RichTextNodeType["Code"] = "inlineCode";
16
16
  RichTextNodeType["Link"] = "link";
17
17
  RichTextNodeType["Paragraph"] = "paragraph";
18
- /**
19
- * A special extension for when the value of a placeholder is an object.
20
- * Rather than casting to a string here, the object is preserved as-is for a
21
- * future formatter to render as appropriate (i.e., using an object as a
22
- * value when formatting to an AST should keep that object structure so that
23
- * the final AST is accurate for what the user expects, but when rendering to
24
- * a plain string, the final formatter can just cast that object to a string
25
- * using its `toString` method or some other mechanism).
26
- */
27
- RichTextNodeType["Object"] = "object";
28
18
  })(RichTextNodeType || (exports.RichTextNodeType = RichTextNodeType = {}));
29
19
  const AST_RICH_TEXT_ELEMENTS = {
30
20
  $b: (content) => ({ type: RichTextNodeType.Strong, content }),
@@ -33,7 +23,7 @@ const AST_RICH_TEXT_ELEMENTS = {
33
23
  $code: (content) => ({ type: RichTextNodeType.Code, content }),
34
24
  $link: (content, _, [target]) => ({
35
25
  type: RichTextNodeType.Link,
36
- target: target.content,
26
+ target,
37
27
  content,
38
28
  }),
39
29
  $p: (content) => ({ type: RichTextNodeType.Paragraph, content }),
@@ -65,7 +55,7 @@ class AstBuilder extends format_1.FormatBuilder {
65
55
  }
66
56
  }
67
57
  pushObject(value) {
68
- this.result.push({ type: RichTextNodeType.Object, content: value });
58
+ this.result.push(value);
69
59
  }
70
60
  finish() {
71
61
  return this.result;
@@ -41,8 +41,6 @@ function createReactBuilder(richTextElements) {
41
41
  }
42
42
  }
43
43
  pushObject(value) {
44
- // @ts-expect-error this is technically invalid, but we'll just assume that if a format
45
- // returns an object, it'll be acting as some form of ReactNode.
46
44
  this.result.push(value);
47
45
  }
48
46
  finish() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@discord/intl",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "license": "MIT",
5
5
  "description": "Client runtime for managing messages and translations in a React project.",
6
6
  "main": "./dist/index.js",
@@ -23,7 +23,7 @@
23
23
  "@formatjs/intl": "^2.10.1",
24
24
  "@intrnl/xxhash64": "^0.1.2",
25
25
  "intl-messageformat": "^10.5.11",
26
- "@discord/intl-ast": "0.13.0"
26
+ "@discord/intl-ast": "0.13.2"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@swc/cli": "^0.3.12",
package/src/format.ts CHANGED
@@ -36,16 +36,20 @@ function isRichTextTag(name: string) {
36
36
  return name[0] === '$';
37
37
  }
38
38
 
39
- export abstract class FormatBuilder<Result> {
39
+ export abstract class FormatBuilder<Result, ObjectType = Result extends object ? Result : never> {
40
40
  abstract pushRichTextTag(tag: RichTextTagNames, children: Result[], control: Result[]): void;
41
41
  abstract pushLiteralText(text: string): void;
42
- abstract pushObject(value: object): void;
42
+ abstract pushObject(value: ObjectType): void;
43
43
  abstract finish(): Result[];
44
44
  }
45
45
 
46
46
  export type FormatBuilderConstructor<Result> = new () => FormatBuilder<Result>;
47
47
 
48
- export function bindFormatValuesWithBuilder<T, Builder extends FormatBuilder<T>>(
48
+ export function bindFormatValuesWithBuilder<
49
+ T,
50
+ ObjectType,
51
+ Builder extends FormatBuilder<T, ObjectType>,
52
+ >(
49
53
  builder: Builder,
50
54
  nodes: AstNode[],
51
55
  locales: string | string[],
@@ -89,8 +93,15 @@ export function bindFormatValuesWithBuilder<T, Builder extends FormatBuilder<T>>
89
93
  const value = values[variableName];
90
94
  switch (nodeType) {
91
95
  case FormatJsNodeType.Argument:
96
+ // `function` here captures ReactNodes, which can be functions that
97
+ // return elements. Basically everything else fits in the `object`
98
+ // type, and the generic type requires that an explicit ObjectType
99
+ // be specified for cases where it's not. That means there's an
100
+ // escape hatch that _might_ break this, but it would have to be
101
+ // intentionally set by internal code to function that way, so we'll
102
+ // operate on a promise that it won't for now.
92
103
  if (typeof value === 'object' || typeof value === 'function') {
93
- builder.pushObject(value);
104
+ builder.pushObject(value as ObjectType);
94
105
  } else {
95
106
  // Taken from FormatJS: non-objects (strings, numbers, and falsy
96
107
  // values) all get cast to strings immediately as literal nodes.
@@ -25,16 +25,6 @@ export enum RichTextNodeType {
25
25
  Code = 'inlineCode',
26
26
  Link = 'link',
27
27
  Paragraph = 'paragraph',
28
- /**
29
- * A special extension for when the value of a placeholder is an object.
30
- * Rather than casting to a string here, the object is preserved as-is for a
31
- * future formatter to render as appropriate (i.e., using an object as a
32
- * value when formatting to an AST should keep that object structure so that
33
- * the final AST is accurate for what the user expects, but when rendering to
34
- * a plain string, the final formatter can just cast that object to a string
35
- * using its `toString` method or some other mechanism).
36
- */
37
- Object = 'object',
38
28
  }
39
29
 
40
30
  interface RichTextNodeBase<ContentType> {
@@ -61,10 +51,7 @@ interface RichTextParagraphNode extends RichTextNodeBase<RichTextNode[]> {
61
51
  }
62
52
  interface RichTextLinkNode extends RichTextNodeBase<RichTextNode[]> {
63
53
  type: RichTextNodeType.Link;
64
- target: string;
65
- }
66
- interface RichTextObjectNode extends RichTextNodeBase<object> {
67
- type: RichTextNodeType.Object;
54
+ target: object;
68
55
  }
69
56
 
70
57
  export type RichTextNode =
@@ -74,8 +61,7 @@ export type RichTextNode =
74
61
  | RichTextStrikethroughNode
75
62
  | RichTextCodeNode
76
63
  | RichTextParagraphNode
77
- | RichTextLinkNode
78
- | RichTextObjectNode;
64
+ | RichTextLinkNode;
79
65
 
80
66
  const AST_RICH_TEXT_ELEMENTS: RichTextFormattingMap<AstFunctionTypes['hook']> = {
81
67
  $b: (content) => ({ type: RichTextNodeType.Strong, content }),
@@ -84,7 +70,7 @@ const AST_RICH_TEXT_ELEMENTS: RichTextFormattingMap<AstFunctionTypes['hook']> =
84
70
  $code: (content) => ({ type: RichTextNodeType.Code, content }),
85
71
  $link: (content, _, [target]) => ({
86
72
  type: RichTextNodeType.Link,
87
- target: target.content as string,
73
+ target,
88
74
  content,
89
75
  }),
90
76
  $p: (content) => ({ type: RichTextNodeType.Paragraph, content }),
@@ -114,8 +100,8 @@ class AstBuilder extends FormatBuilder<RichTextNode> {
114
100
  }
115
101
  }
116
102
 
117
- pushObject(value: object) {
118
- this.result.push({ type: RichTextNodeType.Object, content: value });
103
+ pushObject(value: RichTextNode) {
104
+ this.result.push(value);
119
105
  }
120
106
 
121
107
  finish(): RichTextNode[] {
@@ -66,9 +66,7 @@ function createReactBuilder(richTextElements: RichTextFormattingMap<ReactFunctio
66
66
  }
67
67
  }
68
68
 
69
- pushObject(value: object) {
70
- // @ts-expect-error this is technically invalid, but we'll just assume that if a format
71
- // returns an object, it'll be acting as some form of ReactNode.
69
+ pushObject(value: React.ReactNode) {
72
70
  this.result.push(value);
73
71
  }
74
72