@team-monolith/cds 1.129.2-alpha.2 → 1.129.3-alpha

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.
Files changed (128) hide show
  1. package/dist/CdsProvider.js +180 -180
  2. package/dist/components/AlertDialog/AlertDialogTitle.js +15 -15
  3. package/dist/components/Banner.js +28 -28
  4. package/dist/components/FileTypeAlertDialog.js +16 -16
  5. package/dist/components/Pagination.js +22 -22
  6. package/dist/emotion.d.ts +185 -0
  7. package/dist/i18n/i18n.js +14 -14
  8. package/dist/index.d.ts +8 -1
  9. package/dist/node_modules/.pnpm/html-parse-stringify@3.0.1/node_modules/html-parse-stringify/dist/html-parse-stringify.module.js +78 -0
  10. package/dist/node_modules/.pnpm/react-i18next@15.7.3_i18next@25.5.2_typescript@5.5.4__react-dom@18.2.0_react@18.2.0__react@18.2.0_typescript@5.5.4/node_modules/react-i18next/dist/es/I18nextProvider.js +12 -0
  11. package/dist/node_modules/.pnpm/react-i18next@15.7.3_i18next@25.5.2_typescript@5.5.4__react-dom@18.2.0_react@18.2.0__react@18.2.0_typescript@5.5.4/node_modules/react-i18next/dist/es/Trans.js +26 -0
  12. package/dist/node_modules/.pnpm/react-i18next@15.7.3_i18next@25.5.2_typescript@5.5.4__react-dom@18.2.0_react@18.2.0__react@18.2.0_typescript@5.5.4/node_modules/react-i18next/dist/es/TransWithoutContext.js +174 -0
  13. package/dist/node_modules/.pnpm/react-i18next@15.7.3_i18next@25.5.2_typescript@5.5.4__react-dom@18.2.0_react@18.2.0__react@18.2.0_typescript@5.5.4/node_modules/react-i18next/dist/es/context.js +20 -0
  14. package/dist/node_modules/.pnpm/react-i18next@15.7.3_i18next@25.5.2_typescript@5.5.4__react-dom@18.2.0_react@18.2.0__react@18.2.0_typescript@5.5.4/node_modules/react-i18next/dist/es/defaults.js +24 -0
  15. package/dist/node_modules/.pnpm/react-i18next@15.7.3_i18next@25.5.2_typescript@5.5.4__react-dom@18.2.0_react@18.2.0__react@18.2.0_typescript@5.5.4/node_modules/react-i18next/dist/es/i18nInstance.js +6 -0
  16. package/dist/node_modules/.pnpm/react-i18next@15.7.3_i18next@25.5.2_typescript@5.5.4__react-dom@18.2.0_react@18.2.0__react@18.2.0_typescript@5.5.4/node_modules/react-i18next/dist/es/initReactI18next.js +11 -0
  17. package/dist/node_modules/.pnpm/react-i18next@15.7.3_i18next@25.5.2_typescript@5.5.4__react-dom@18.2.0_react@18.2.0__react@18.2.0_typescript@5.5.4/node_modules/react-i18next/dist/es/unescape.js +25 -0
  18. package/dist/node_modules/.pnpm/react-i18next@15.7.3_i18next@25.5.2_typescript@5.5.4__react-dom@18.2.0_react@18.2.0__react@18.2.0_typescript@5.5.4/node_modules/react-i18next/dist/es/useTranslation.js +69 -0
  19. package/dist/node_modules/.pnpm/react-i18next@15.7.3_i18next@25.5.2_typescript@5.5.4__react-dom@18.2.0_react@18.2.0__react@18.2.0_typescript@5.5.4/node_modules/react-i18next/dist/es/utils.js +35 -0
  20. package/dist/patterns/LexicalEditor/Plugins.js +64 -64
  21. package/dist/patterns/LexicalEditor/components/FileSelectInput.js +19 -19
  22. package/dist/patterns/LexicalEditor/components/InsertImageDialog/ImagePreview.js +6 -6
  23. package/dist/patterns/LexicalEditor/components/InsertImageDialog/InsertImageDialog.js +34 -34
  24. package/dist/patterns/LexicalEditor/components/UploadFileDialog/UploadFileDialog.js +14 -14
  25. package/dist/patterns/LexicalEditor/nodes/FileNode/FileDownloadButton.js +17 -17
  26. package/dist/patterns/LexicalEditor/nodes/ImageNode/ImageComponent.js +62 -62
  27. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/InputComponent.js +25 -25
  28. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/SettingForm/FormPlaceholder.js +7 -7
  29. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/SettingForm/FormSolution.js +24 -23
  30. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/SettingForm/SettingForm.js +48 -47
  31. package/dist/patterns/LexicalEditor/nodes/ProblemInputNode/SettingForm/TextTypeDropdown.js +11 -11
  32. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectBox/SelectBoxView.js +15 -15
  33. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SelectComponent.js +28 -28
  34. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/FormSelection.js +30 -30
  35. package/dist/patterns/LexicalEditor/nodes/ProblemSelectNode/SettingForm/SettingForm.js +35 -35
  36. package/dist/patterns/LexicalEditor/nodes/SelfEvaluationNode/EvaluationComponent/Evaluation/SettingForm/FormIconAndLabel/FormIconAndLabel.js +21 -21
  37. package/dist/patterns/LexicalEditor/nodes/SelfEvaluationNode/EvaluationComponent/Evaluation/SettingForm/FormIconAndLabel/FormLabel.js +15 -15
  38. package/dist/patterns/LexicalEditor/nodes/SelfEvaluationNode/EvaluationComponent/Evaluation/SettingForm/FormQuestion.js +17 -17
  39. package/dist/patterns/LexicalEditor/nodes/SelfEvaluationNode/EvaluationComponent/Evaluation/SettingForm/SettingForm.js +30 -30
  40. package/dist/patterns/LexicalEditor/nodes/SelfEvaluationNode/EvaluationComponent/EvaluationComponent.js +20 -20
  41. package/dist/patterns/LexicalEditor/nodes/SheetInputNode/InputComponent.js +24 -24
  42. package/dist/patterns/LexicalEditor/nodes/SheetInputNode/SettingForm.js +28 -28
  43. package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/SelectBox/SelectBoxView.js +11 -11
  44. package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/SelectComponent.js +26 -26
  45. package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/SettingForm/FormAllowMultipleAnswers.js +8 -8
  46. package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/SettingForm/FormSelection.js +27 -27
  47. package/dist/patterns/LexicalEditor/nodes/SheetSelectNode/SelectComponent/SettingForm/SettingForm.js +33 -33
  48. package/dist/patterns/LexicalEditor/nodes/VideoNode/VideoComponent.js +21 -21
  49. package/dist/patterns/LexicalEditor/plugins/ComponentAdderPlugin/ComponentAdderPlugin.js +99 -99
  50. package/dist/patterns/LexicalEditor/plugins/ComponentAdderPlugin/useContextMenuOptions.js +50 -50
  51. package/dist/patterns/LexicalEditor/plugins/ComponentPickerMenuPlugin/ComponentPickerMenuPlugin.js +85 -85
  52. package/dist/patterns/LexicalEditor/plugins/DragDropPastePlugin/index.js +13 -13
  53. package/dist/patterns/LexicalEditor/plugins/FloatingLinkEditorPlugin/FloatingLinkEditor.js +48 -48
  54. package/dist/patterns/LexicalEditor/plugins/ImagesPlugin/useImageNodeTransform.js +16 -16
  55. package/dist/patterns/ToggleButtonGroup/ToggleButton.js +17 -17
  56. package/package.json +15 -18
  57. package/@types/emotion.d.ts +0 -197
  58. package/node_modules/react-i18next/.eslintrc.json +0 -74
  59. package/node_modules/react-i18next/.husky/pre-commit +0 -1
  60. package/node_modules/react-i18next/.prettierignore +0 -4
  61. package/node_modules/react-i18next/CHANGELOG.md +0 -1433
  62. package/node_modules/react-i18next/LICENSE +0 -22
  63. package/node_modules/react-i18next/README.md +0 -181
  64. package/node_modules/react-i18next/TransWithoutContext.d.mts +0 -1
  65. package/node_modules/react-i18next/TransWithoutContext.d.ts +0 -129
  66. package/node_modules/react-i18next/dist/amd/react-i18next.js +0 -867
  67. package/node_modules/react-i18next/dist/amd/react-i18next.min.js +0 -1
  68. package/node_modules/react-i18next/dist/commonjs/I18nextProvider.js +0 -21
  69. package/node_modules/react-i18next/dist/commonjs/Trans.js +0 -54
  70. package/node_modules/react-i18next/dist/commonjs/TransWithoutContext.js +0 -330
  71. package/node_modules/react-i18next/dist/commonjs/Translation.js +0 -19
  72. package/node_modules/react-i18next/dist/commonjs/context.js +0 -81
  73. package/node_modules/react-i18next/dist/commonjs/defaults.js +0 -26
  74. package/node_modules/react-i18next/dist/commonjs/i18nInstance.js +0 -13
  75. package/node_modules/react-i18next/dist/commonjs/index.js +0 -128
  76. package/node_modules/react-i18next/dist/commonjs/initReactI18next.js +0 -15
  77. package/node_modules/react-i18next/dist/commonjs/unescape.js +0 -32
  78. package/node_modules/react-i18next/dist/commonjs/useSSR.js +0 -34
  79. package/node_modules/react-i18next/dist/commonjs/useTranslation.js +0 -114
  80. package/node_modules/react-i18next/dist/commonjs/utils.js +0 -76
  81. package/node_modules/react-i18next/dist/commonjs/withSSR.js +0 -27
  82. package/node_modules/react-i18next/dist/commonjs/withTranslation.js +0 -39
  83. package/node_modules/react-i18next/dist/es/I18nextProvider.js +0 -15
  84. package/node_modules/react-i18next/dist/es/Trans.js +0 -43
  85. package/node_modules/react-i18next/dist/es/TransWithoutContext.js +0 -321
  86. package/node_modules/react-i18next/dist/es/Translation.js +0 -12
  87. package/node_modules/react-i18next/dist/es/context.js +0 -42
  88. package/node_modules/react-i18next/dist/es/defaults.js +0 -18
  89. package/node_modules/react-i18next/dist/es/i18nInstance.js +0 -5
  90. package/node_modules/react-i18next/dist/es/index.js +0 -18
  91. package/node_modules/react-i18next/dist/es/initReactI18next.js +0 -9
  92. package/node_modules/react-i18next/dist/es/package.json +0 -1
  93. package/node_modules/react-i18next/dist/es/unescape.js +0 -25
  94. package/node_modules/react-i18next/dist/es/useSSR.js +0 -27
  95. package/node_modules/react-i18next/dist/es/useTranslation.js +0 -107
  96. package/node_modules/react-i18next/dist/es/utils.js +0 -62
  97. package/node_modules/react-i18next/dist/es/withSSR.js +0 -20
  98. package/node_modules/react-i18next/dist/es/withTranslation.js +0 -32
  99. package/node_modules/react-i18next/dist/umd/react-i18next.js +0 -871
  100. package/node_modules/react-i18next/dist/umd/react-i18next.min.js +0 -1
  101. package/node_modules/react-i18next/helpers.d.ts +0 -3
  102. package/node_modules/react-i18next/icu.macro.d.mts +0 -1
  103. package/node_modules/react-i18next/icu.macro.d.ts +0 -103
  104. package/node_modules/react-i18next/icu.macro.js +0 -729
  105. package/node_modules/react-i18next/index.d.mts +0 -1
  106. package/node_modules/react-i18next/index.d.ts +0 -209
  107. package/node_modules/react-i18next/initReactI18next.d.mts +0 -1
  108. package/node_modules/react-i18next/initReactI18next.d.ts +0 -3
  109. package/node_modules/react-i18next/lint-staged.config.mjs +0 -4
  110. package/node_modules/react-i18next/package.json +0 -167
  111. package/node_modules/react-i18next/react-i18next.js +0 -871
  112. package/node_modules/react-i18next/react-i18next.min.js +0 -1
  113. package/node_modules/react-i18next/src/I18nextProvider.js +0 -7
  114. package/node_modules/react-i18next/src/Trans.js +0 -45
  115. package/node_modules/react-i18next/src/TransWithoutContext.js +0 -479
  116. package/node_modules/react-i18next/src/Translation.js +0 -14
  117. package/node_modules/react-i18next/src/context.js +0 -54
  118. package/node_modules/react-i18next/src/defaults.js +0 -20
  119. package/node_modules/react-i18next/src/i18nInstance.js +0 -7
  120. package/node_modules/react-i18next/src/index.js +0 -22
  121. package/node_modules/react-i18next/src/initReactI18next.js +0 -11
  122. package/node_modules/react-i18next/src/unescape.js +0 -31
  123. package/node_modules/react-i18next/src/useSSR.js +0 -33
  124. package/node_modules/react-i18next/src/useTranslation.js +0 -171
  125. package/node_modules/react-i18next/src/utils.js +0 -93
  126. package/node_modules/react-i18next/src/withSSR.js +0 -21
  127. package/node_modules/react-i18next/src/withTranslation.js +0 -35
  128. package/node_modules/react-i18next/vitest.workspace.typescript.mts +0 -52
@@ -1,729 +0,0 @@
1
- const { createMacro } = require('babel-plugin-macros');
2
-
3
- // copy to:
4
- // https://astexplorer.net/#/gist/642aebbb9e449e959f4ad8907b4adf3a/4a65742e2a3e926eb55eaa3d657d1472b9ac7970
5
- module.exports = createMacro(ICUMacro);
6
-
7
- function ICUMacro({ references, state, babel }) {
8
- const {
9
- Trans = [],
10
- Plural = [],
11
- Select = [],
12
- SelectOrdinal = [],
13
- number = [],
14
- date = [],
15
- select = [],
16
- selectOrdinal = [],
17
- plural = [],
18
- time = [],
19
- } = references;
20
-
21
- // assert we have the react-i18next Trans component imported
22
- addNeededImports(state, babel, references);
23
-
24
- // transform Plural and SelectOrdinal
25
- [...Plural, ...SelectOrdinal].forEach((referencePath) => {
26
- if (referencePath.parentPath.type === 'JSXOpeningElement') {
27
- pluralAsJSX(
28
- referencePath.parentPath,
29
- {
30
- attributes: referencePath.parentPath.get('attributes'),
31
- children: referencePath.parentPath.parentPath.get('children'),
32
- },
33
- babel,
34
- );
35
- } else {
36
- // throw a helpful error message or something :)
37
- }
38
- });
39
-
40
- // transform Select
41
- Select.forEach((referencePath) => {
42
- if (referencePath.parentPath.type === 'JSXOpeningElement') {
43
- selectAsJSX(
44
- referencePath.parentPath,
45
- {
46
- attributes: referencePath.parentPath.get('attributes'),
47
- children: referencePath.parentPath.parentPath.get('children'),
48
- },
49
- babel,
50
- );
51
- } else {
52
- // throw a helpful error message or something :)
53
- }
54
- });
55
-
56
- // transform Trans
57
- Trans.forEach((referencePath) => {
58
- if (referencePath.parentPath.type === 'JSXOpeningElement') {
59
- transAsJSX(
60
- referencePath.parentPath,
61
- {
62
- attributes: referencePath.parentPath.get('attributes'),
63
- children: referencePath.parentPath.parentPath.get('children'),
64
- },
65
- babel,
66
- state,
67
- );
68
- } else {
69
- // throw a helpful error message or something :)
70
- }
71
- });
72
-
73
- // check for number`` and others outside of <Trans>
74
- Object.entries({
75
- number,
76
- date,
77
- time,
78
- select,
79
- plural,
80
- selectOrdinal,
81
- }).forEach(([name, node]) => {
82
- node.forEach((item) => {
83
- let f = item.parentPath;
84
- while (f) {
85
- if (babel.types.isJSXElement(f)) {
86
- if (f.node.openingElement.name.name === 'Trans') {
87
- // this is a valid use of number/date/time/etc.
88
- return;
89
- }
90
- }
91
- f = f.parentPath;
92
- }
93
- throw new Error(
94
- `"${name}\`\`" can only be used inside <Trans> in "${item.node.loc.filename}" on line ${item.node.loc.start.line}`,
95
- );
96
- });
97
- });
98
- }
99
-
100
- function pluralAsJSX(parentPath, { attributes }, babel) {
101
- const t = babel.types;
102
- const toObjectProperty = (name, value) =>
103
- t.objectProperty(t.identifier(name), t.identifier(name), false, !value);
104
-
105
- // plural or selectordinal
106
- const nodeName = parentPath.node.name.name.toLocaleLowerCase();
107
-
108
- // will need to merge count attribute with existing values attribute in some cases
109
- const existingValuesAttribute = findAttribute('values', attributes);
110
- const existingValues = existingValuesAttribute
111
- ? existingValuesAttribute.node.value.expression.properties
112
- : [];
113
-
114
- let componentStartIndex = 0;
115
- const extracted = attributes.reduce(
116
- (mem, attr) => {
117
- if (attr.node.name.name === 'i18nKey') {
118
- // copy the i18nKey
119
- mem.attributesToCopy.push(attr.node);
120
- } else if (attr.node.name.name === 'count') {
121
- // take the count for element
122
- let exprName = attr.node.value.expression.name;
123
- if (!exprName) {
124
- exprName = 'count';
125
- }
126
- if (exprName === 'count') {
127
- // if the prop expression name is also "count", copy it instead: <Plural count={count} --> <Trans count={count}
128
- mem.attributesToCopy.push(attr.node);
129
- } else {
130
- mem.values.unshift(toObjectProperty(exprName));
131
- }
132
- mem.defaults = `{${exprName}, ${nodeName}, ${mem.defaults}`;
133
- } else if (attr.node.name.name === 'values') {
134
- // skip the values attribute, as it has already been processed into mem from existingValues
135
- } else if (attr.node.value.type === 'StringLiteral') {
136
- // take any string node as plural option
137
- let pluralForm = attr.node.name.name;
138
- if (pluralForm.indexOf('$') === 0) pluralForm = pluralForm.replace('$', '=');
139
- mem.defaults = `${mem.defaults} ${pluralForm} {${attr.node.value.value}}`;
140
- } else if (attr.node.value.type === 'JSXExpressionContainer') {
141
- // convert any Trans component to plural option extracting any values and components
142
- const children = attr.node.value.expression.children || [];
143
- const thisTrans = processTrans(children, babel, componentStartIndex);
144
-
145
- let pluralForm = attr.node.name.name;
146
- if (pluralForm.indexOf('$') === 0) pluralForm = pluralForm.replace('$', '=');
147
-
148
- mem.defaults = `${mem.defaults} ${pluralForm} {${thisTrans.defaults}}`;
149
- mem.components = mem.components.concat(thisTrans.components);
150
-
151
- componentStartIndex += thisTrans.components.length;
152
- }
153
- return mem;
154
- },
155
- { attributesToCopy: [], values: existingValues, components: [], defaults: '' },
156
- );
157
-
158
- // replace the node with the new Trans
159
- parentPath.replaceWith(buildTransElement(extracted, extracted.attributesToCopy, t, true));
160
- }
161
-
162
- function selectAsJSX(parentPath, { attributes }, babel) {
163
- const t = babel.types;
164
- const toObjectProperty = (name, value) =>
165
- t.objectProperty(t.identifier(name), t.identifier(name), false, !value);
166
-
167
- // will need to merge switch attribute with existing values attribute
168
- const existingValuesAttribute = findAttribute('values', attributes);
169
- const existingValues = existingValuesAttribute
170
- ? existingValuesAttribute.node.value.expression.properties
171
- : [];
172
-
173
- let componentStartIndex = 0;
174
-
175
- const extracted = attributes.reduce(
176
- (mem, attr) => {
177
- if (attr.node.name.name === 'i18nKey') {
178
- // copy the i18nKey
179
- mem.attributesToCopy.push(attr.node);
180
- } else if (attr.node.name.name === 'switch') {
181
- // take the switch for select element
182
- let exprName = attr.node.value.expression.name;
183
- if (!exprName) {
184
- exprName = 'selectKey';
185
- mem.values.unshift(t.objectProperty(t.identifier(exprName), attr.node.value.expression));
186
- } else {
187
- mem.values.unshift(toObjectProperty(exprName));
188
- }
189
- mem.defaults = `{${exprName}, select, ${mem.defaults}`;
190
- } else if (attr.node.name.name === 'values') {
191
- // skip the values attribute, as it has already been processed into mem as existingValues
192
- } else if (attr.node.value.type === 'StringLiteral') {
193
- // take any string node as select option
194
- mem.defaults = `${mem.defaults} ${attr.node.name.name} {${attr.node.value.value}}`;
195
- } else if (attr.node.value.type === 'JSXExpressionContainer') {
196
- // convert any Trans component to select option extracting any values and components
197
- const children = attr.node.value.expression.children || [];
198
- const thisTrans = processTrans(children, babel, componentStartIndex);
199
-
200
- mem.defaults = `${mem.defaults} ${attr.node.name.name} {${thisTrans.defaults}}`;
201
- mem.components = mem.components.concat(thisTrans.components);
202
-
203
- componentStartIndex += thisTrans.components.length;
204
- }
205
- return mem;
206
- },
207
- { attributesToCopy: [], values: existingValues, components: [], defaults: '' },
208
- );
209
-
210
- // replace the node with the new Trans
211
- parentPath.replaceWith(buildTransElement(extracted, extracted.attributesToCopy, t, true));
212
- }
213
-
214
- function transAsJSX(parentPath, { attributes, children }, babel, { filename }) {
215
- const defaultsAttr = findAttribute('defaults', attributes);
216
- const componentsAttr = findAttribute('components', attributes);
217
- // if there is "defaults" attribute and no "components" attribute, parse defaults and extract from the parsed defaults instead of children
218
- // if a "components" attribute has been provided, we assume they have already constructed a valid "defaults" and it does not need to be parsed
219
- const parseDefaults = defaultsAttr && !componentsAttr;
220
-
221
- let extracted;
222
- if (parseDefaults) {
223
- const defaultsExpression = defaultsAttr.node.value.value;
224
- const parsed = babel.parse(`<>${defaultsExpression}</>`, {
225
- presets: ['@babel/react'],
226
- filename,
227
- }).program.body[0].expression.children;
228
-
229
- extracted = processTrans(parsed, babel);
230
- } else {
231
- extracted = processTrans(children, babel);
232
- }
233
-
234
- let clonedAttributes = cloneExistingAttributes(attributes);
235
- if (parseDefaults) {
236
- // remove existing defaults so it can be replaced later with the new parsed defaults
237
- clonedAttributes = clonedAttributes.filter((node) => node.name.name !== 'defaults');
238
- }
239
-
240
- // replace the node with the new Trans
241
- const replacePath = children.length ? children[0].parentPath : parentPath;
242
- replacePath.replaceWith(
243
- buildTransElement(extracted, clonedAttributes, babel.types, false, !!children.length),
244
- );
245
- }
246
-
247
- function buildTransElement(
248
- extracted,
249
- finalAttributes,
250
- t,
251
- closeDefaults = false,
252
- wasElementWithChildren = false,
253
- ) {
254
- const nodeName = t.jSXIdentifier('Trans');
255
-
256
- // plural, select open { but do not close it while reduce
257
- if (closeDefaults) extracted.defaults += '}';
258
-
259
- // convert arrays into needed expressions
260
- extracted.components = t.arrayExpression(extracted.components);
261
- extracted.values = t.objectExpression(extracted.values);
262
-
263
- // add generated Trans attributes
264
- if (!attributeExistsAlready('defaults', finalAttributes))
265
- if (extracted.defaults.includes(`"`)) {
266
- // wrap defaults that contain double quotes in brackets
267
- finalAttributes.push(
268
- t.jSXAttribute(
269
- t.jSXIdentifier('defaults'),
270
- t.jSXExpressionContainer(t.StringLiteral(extracted.defaults)),
271
- ),
272
- );
273
- } else {
274
- finalAttributes.push(
275
- t.jSXAttribute(t.jSXIdentifier('defaults'), t.StringLiteral(extracted.defaults)),
276
- );
277
- }
278
-
279
- if (!attributeExistsAlready('components', finalAttributes))
280
- finalAttributes.push(
281
- t.jSXAttribute(t.jSXIdentifier('components'), t.jSXExpressionContainer(extracted.components)),
282
- );
283
- if (!attributeExistsAlready('values', finalAttributes))
284
- finalAttributes.push(
285
- t.jSXAttribute(t.jSXIdentifier('values'), t.jSXExpressionContainer(extracted.values)),
286
- );
287
-
288
- // create selfclosing Trans component
289
- const openElement = t.jSXOpeningElement(nodeName, finalAttributes, true);
290
- if (!wasElementWithChildren) return openElement;
291
-
292
- return t.jSXElement(openElement, null, [], true);
293
- }
294
-
295
- function cloneExistingAttributes(attributes) {
296
- return attributes.reduce((mem, attr) => {
297
- mem.push(attr.node);
298
- return mem;
299
- }, []);
300
- }
301
-
302
- function findAttribute(name, attributes) {
303
- return attributes.find((child) => {
304
- const ele = child.node ? child.node : child;
305
- return ele.name.name === name;
306
- });
307
- }
308
-
309
- function attributeExistsAlready(name, attributes) {
310
- return !!findAttribute(name, attributes);
311
- }
312
-
313
- function processTrans(children, babel, componentStartIndex = 0) {
314
- const res = {};
315
-
316
- res.defaults = mergeChildren(children, babel, componentStartIndex);
317
- res.components = getComponents(children, babel);
318
- res.values = getValues(children, babel);
319
-
320
- return res;
321
- }
322
-
323
- const leadingNewLineAndWhitespace = /^\n\s+/g;
324
- const trailingNewLineAndWhitespace = /\n\s+$/g;
325
- function trimIndent(text) {
326
- const newText = text
327
- .replace(leadingNewLineAndWhitespace, '')
328
- .replace(trailingNewLineAndWhitespace, '');
329
- return newText;
330
- }
331
-
332
- /**
333
- * add comma-delimited expressions like `{ val, number }`
334
- */
335
- function mergeCommaExpressions(ele) {
336
- if (ele.expression && ele.expression.expressions) {
337
- return `{${ele.expression.expressions
338
- .reduce((m, i) => {
339
- m.push(i.name || i.value);
340
- return m;
341
- }, [])
342
- .join(', ')}}`;
343
- }
344
- return '';
345
- }
346
-
347
- /**
348
- * this is for supporting complex icu type interpolations
349
- * date`${variable}` and number`{${varName}, ::percent}`
350
- * also, plural`{${count}, one { ... } other { ... }}
351
- */
352
- function mergeTaggedTemplateExpressions(ele, componentFoundIndex, t, babel) {
353
- if (t.isTaggedTemplateExpression(ele.expression)) {
354
- const [, text, index] = getTextAndInterpolatedVariables(
355
- ele.expression.tag.name,
356
- ele.expression,
357
- componentFoundIndex,
358
- babel,
359
- );
360
- return [text, index];
361
- }
362
- return ['', componentFoundIndex];
363
- }
364
-
365
- function mergeChildren(children, babel, componentStartIndex = 0) {
366
- const t = babel.types;
367
- let componentFoundIndex = componentStartIndex;
368
-
369
- return children.reduce((mem, child) => {
370
- const ele = child.node ? child.node : child;
371
- let result = mem;
372
-
373
- // add text, but trim indentation whitespace
374
- if (t.isJSXText(ele) && ele.value) result += trimIndent(ele.value);
375
- // add ?!? forgot
376
- if (ele.expression && ele.expression.value) result += ele.expression.value;
377
- // add `{ val }`
378
- if (ele.expression && ele.expression.name) result += `{${ele.expression.name}}`;
379
- // add `{ val, number }`
380
- result += mergeCommaExpressions(ele);
381
- const [nextText, newIndex] = mergeTaggedTemplateExpressions(ele, componentFoundIndex, t, babel);
382
- result += nextText;
383
- componentFoundIndex = newIndex;
384
- // add <strong>...</strong> with replace to <0>inner string</0>
385
- if (t.isJSXElement(ele)) {
386
- result += `<${componentFoundIndex}>${mergeChildren(
387
- ele.children,
388
- babel,
389
- )}</${componentFoundIndex}>`;
390
- componentFoundIndex += 1;
391
- }
392
-
393
- return result;
394
- }, '');
395
- }
396
-
397
- const extractTaggedTemplateValues = (ele, babel, toObjectProperty) => {
398
- // date`${variable}` and so on
399
- if (ele.expression && ele.expression.type === 'TaggedTemplateExpression') {
400
- const [variables] = getTextAndInterpolatedVariables(
401
- ele.expression.tag.name,
402
- ele.expression,
403
- 0,
404
- babel,
405
- );
406
- return variables.map((vari) => toObjectProperty(vari));
407
- }
408
- return [];
409
- };
410
-
411
- /**
412
- * Extract the names of interpolated value as object properties to pass to Trans
413
- */
414
- function getValues(children, babel) {
415
- const t = babel.types;
416
- const toObjectProperty = (name, value) =>
417
- t.objectProperty(t.identifier(name), t.identifier(name), false, !value);
418
-
419
- return children.reduce((mem, child) => {
420
- const ele = child.node ? child.node : child;
421
- let result = mem;
422
-
423
- // add `{ var }` to values
424
- if (ele.expression && ele.expression.name) mem.push(toObjectProperty(ele.expression.name));
425
- // add `{ var, number }` to values
426
- if (ele.expression && ele.expression.expressions)
427
- result.push(
428
- toObjectProperty(ele.expression.expressions[0].name || ele.expression.expressions[0].value),
429
- );
430
- // add `{ var: 'bar' }` to values
431
- if (ele.expression && ele.expression.properties)
432
- result = result.concat(ele.expression.properties);
433
- // date`${variable}` and so on
434
- result = result.concat(extractTaggedTemplateValues(ele, babel, toObjectProperty));
435
- // recursive add inner elements stuff to values
436
- if (t.isJSXElement(ele)) {
437
- result = result.concat(getValues(ele.children, babel));
438
- }
439
-
440
- return result;
441
- }, []);
442
- }
443
-
444
- /**
445
- * Common logic for adding a child element of Trans to the list of components to hydrate the translation
446
- * @param {JSXElement} jsxElement
447
- * @param {JSXElement[]} mem
448
- */
449
- const processJSXElement = (jsxElement, mem, t) => {
450
- const clone = t.clone(jsxElement);
451
- clone.children = clone.children.reduce((clonedMem, clonedChild) => {
452
- const clonedEle = clonedChild.node ? clonedChild.node : clonedChild;
453
-
454
- // clean out invalid definitions by replacing `{ catchDate, date, short }` with `{ catchDate }`
455
- if (clonedEle.expression && clonedEle.expression.expressions)
456
- clonedEle.expression.expressions = [clonedEle.expression.expressions[0]];
457
-
458
- clonedMem.push(clonedChild);
459
- return clonedMem;
460
- }, []);
461
-
462
- mem.push(jsxElement);
463
- };
464
-
465
- /**
466
- * Extract the React components to pass to Trans as components
467
- */
468
- function getComponents(children, babel) {
469
- const t = babel.types;
470
-
471
- return children.reduce((mem, child) => {
472
- const ele = child.node ? child.node : child;
473
-
474
- if (t.isJSXExpressionContainer(ele)) {
475
- // check for date`` and so on
476
- if (t.isTaggedTemplateExpression(ele.expression)) {
477
- ele.expression.quasi.expressions.forEach((expr) => {
478
- // check for sub-expressions. This can happen with plural`` or select`` or selectOrdinal``
479
- // these can have nested components
480
- if (t.isTaggedTemplateExpression(expr) && expr.quasi.expressions.length) {
481
- mem.push(...getComponents(expr.quasi.expressions, babel));
482
- }
483
- if (!t.isJSXElement(expr)) {
484
- // ignore anything that is not a component
485
- return;
486
- }
487
- processJSXElement(expr, mem, t);
488
- });
489
- }
490
- }
491
- if (t.isJSXElement(ele)) {
492
- processJSXElement(ele, mem, t);
493
- }
494
-
495
- return mem;
496
- }, []);
497
- }
498
-
499
- const icuInterpolators = ['date', 'time', 'number', 'plural', 'select', 'selectOrdinal'];
500
- const importsToAdd = ['Trans'];
501
-
502
- /**
503
- * helper split out of addNeededImports to make codeclimate happy
504
- *
505
- * This does the work of amending an existing import from "react-i18next", or
506
- * creating a new one if it doesn't exist
507
- */
508
- function addImports(state, existingImport, allImportsToAdd, t) {
509
- // append imports to existing or add a new react-i18next import for the Trans and icu tagged template literals
510
- if (existingImport) {
511
- allImportsToAdd.forEach((name) => {
512
- if (
513
- existingImport.specifiers.findIndex(
514
- (specifier) => specifier.imported && specifier.imported.name === name,
515
- ) === -1
516
- ) {
517
- existingImport.specifiers.push(t.importSpecifier(t.identifier(name), t.identifier(name)));
518
- }
519
- });
520
- } else {
521
- state.file.path.node.body.unshift(
522
- t.importDeclaration(
523
- allImportsToAdd.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name))),
524
- t.stringLiteral('react-i18next'),
525
- ),
526
- );
527
- }
528
- }
529
-
530
- /**
531
- * Add `import { Trans, number, date, <etc.> } from "react-i18next"` as needed
532
- */
533
- function addNeededImports(state, babel, references) {
534
- const t = babel.types;
535
-
536
- // check if there is an existing react-i18next import
537
- const existingImport = state.file.path.node.body.find(
538
- (importNode) =>
539
- t.isImportDeclaration(importNode) && importNode.source.value === 'react-i18next',
540
- );
541
- // check for any of the tagged template literals that are used in the source, and add them
542
- const usedRefs = Object.keys(references).filter((importName) => {
543
- if (!icuInterpolators.includes(importName)) {
544
- return false;
545
- }
546
- return references[importName].length;
547
- });
548
-
549
- // combine Trans + any tagged template literals
550
- const allImportsToAdd = importsToAdd.concat(usedRefs);
551
-
552
- addImports(state, existingImport, allImportsToAdd, t);
553
- }
554
-
555
- /**
556
- * iterate over a node detected inside a tagged template literal
557
- *
558
- * This is a helper function for `extractVariableNamesFromQuasiNodes` defined below
559
- *
560
- * this is called using reduce as a way of tricking what would be `.map()`
561
- * into passing in the parameters needed to both modify `componentFoundIndex`,
562
- * `stringOutput`, and `interpolatedVariableNames`
563
- * and to pass in the dependencies babel, and type. Type is the template type.
564
- * For "date``" the type will be `date`. for "number``" the type is `number`, etc.
565
- */
566
- const extractNestedTemplatesAndComponents = (
567
- { componentFoundIndex: lastIndex, babel, stringOutput, type, interpolatedVariableNames },
568
- node,
569
- ) => {
570
- let componentFoundIndex = lastIndex;
571
- if (node.type === 'JSXElement') {
572
- // perform the interpolation of components just as we do in a normal Trans setting
573
- const subText = `<${componentFoundIndex}>${mergeChildren(
574
- node.children,
575
- babel,
576
- )}</${componentFoundIndex}>`;
577
- componentFoundIndex += 1;
578
- stringOutput.push(subText);
579
- } else if (node.type === 'TaggedTemplateExpression') {
580
- // a nested date``/number``/plural`` etc., extract whatever is inside of it
581
- const [variableNames, childText, newIndex] = getTextAndInterpolatedVariables(
582
- node.tag.name,
583
- node,
584
- componentFoundIndex,
585
- babel,
586
- );
587
- interpolatedVariableNames.push(...variableNames);
588
- componentFoundIndex = newIndex;
589
- stringOutput.push(childText);
590
- } else if (node.type === 'Identifier') {
591
- // turn date`${thing}` into `thing, date`
592
- stringOutput.push(`${node.name}, ${type}`);
593
- } else if (node.type === 'TemplateElement') {
594
- // convert all whitespace into a single space for the text in the tagged template literal
595
- stringOutput.push(node.value.cooked.replace(/\s+/g, ' '));
596
- } else {
597
- // unknown node type, ignore
598
- }
599
- return { componentFoundIndex, babel, stringOutput, type, interpolatedVariableNames };
600
- };
601
-
602
- /**
603
- * filter the list of nodes within a tagged template literal to the 4 types we can process,
604
- * and ignore anything else.
605
- *
606
- * this is a helper function for `extractVariableNamesFromQuasiNodes`
607
- */
608
- const filterNodes = (node) => {
609
- if (node.type === 'Identifier') {
610
- // if the node has a name, keep it
611
- return node.name;
612
- }
613
- if (node.type === 'JSXElement' || node.type === 'TaggedTemplateExpression') {
614
- // always keep interpolated elements or other tagged template literals like a nested date`` inside a plural``
615
- return true;
616
- }
617
- if (node.type === 'TemplateElement') {
618
- // return the "cooked" (escaped) text for the text in the template literal (`, ::percent` in number`${varname}, ::percent`)
619
- return node.value.cooked;
620
- }
621
- // unknown node type, ignore
622
- return false;
623
- };
624
-
625
- const errorOnInvalidQuasiNodes = (primaryNode) => {
626
- const noInterpolationError = !primaryNode.quasi.expressions.length;
627
- const wrongOrderError = primaryNode.quasi.quasis[0].value.raw.length;
628
- const message = `${primaryNode.tag.name} argument must be interpolated ${
629
- noInterpolationError ? 'in' : 'at the beginning of'
630
- } "${primaryNode.tag.name}\`\`" in "${primaryNode.loc.filename}" on line ${
631
- primaryNode.loc.start.line
632
- }`;
633
- if (noInterpolationError || wrongOrderError) {
634
- throw new Error(message);
635
- }
636
- };
637
-
638
- const extractNodeVariableNames = (varNode, babel) => {
639
- const interpolatedVariableNames = [];
640
- if (varNode.type === 'JSXElement') {
641
- // extract inner interpolated variables and add to the list
642
- interpolatedVariableNames.push(
643
- ...getValues(varNode.children, babel).map((value) => value.value.name),
644
- );
645
- } else if (varNode.type === 'Identifier') {
646
- // the name of the interpolated variable
647
- interpolatedVariableNames.push(varNode.name);
648
- }
649
- return interpolatedVariableNames;
650
- };
651
-
652
- const extractVariableNamesFromQuasiNodes = (primaryNode, babel) => {
653
- errorOnInvalidQuasiNodes(primaryNode);
654
- // this will contain all the nodes to convert to the ICU messageformat text
655
- // at first they are unsorted, but will be ordered correctly at the end of the function
656
- const text = [];
657
- // the variable names. These are converted to object references as required for the Trans values
658
- // in getValues() (toObjectProperty helper function)
659
- const interpolatedVariableNames = [];
660
- primaryNode.quasi.expressions.forEach((varNode) => {
661
- if (
662
- !babel.types.isIdentifier(varNode) &&
663
- !babel.types.isTaggedTemplateExpression(varNode) &&
664
- !babel.types.isJSXElement(varNode)
665
- ) {
666
- throw new Error(
667
- `Must pass a variable, not an expression to "${primaryNode.tag.name}\`\`" in "${primaryNode.loc.filename}" on line ${primaryNode.loc.start.line}`,
668
- );
669
- }
670
- text.push(varNode);
671
- interpolatedVariableNames.push(...extractNodeVariableNames(varNode, babel));
672
- });
673
- primaryNode.quasi.quasis.forEach((quasiNode) => {
674
- // these are the text surrounding the variable interpolation
675
- // so in date`${varname}, short` it would be `''` and `, short`.
676
- // (the empty string before `${varname}` and the stuff after it)
677
- text.push(quasiNode);
678
- });
679
- return { text, interpolatedVariableNames };
680
- };
681
-
682
- const throwOnInvalidType = (type, primaryNode) => {
683
- if (!icuInterpolators.includes(type)) {
684
- throw new Error(
685
- `Unsupported tagged template literal "${type}", must be one of date, time, number, plural, select, selectOrdinal in "${primaryNode.loc.filename}" on line ${primaryNode.loc.start.line}`,
686
- );
687
- }
688
- };
689
-
690
- /**
691
- * Retrieve the new text to use, and any interpolated variables
692
- *
693
- * This is used to process tagged template literals like date`${variable}` and number`${num}, ::percent`
694
- *
695
- * for the data example, it will return text of `{variable, date}` with a variable of `variable`
696
- * for the number example, it will return text of `{num, number, ::percent}` with a variable of `num`
697
- * @param {string} type the name of the tagged template (`date`, `number`, `plural`, etc. - any valid complex ICU type)
698
- * @param {TaggedTemplateExpression} primaryNode the template expression node
699
- * @param {int} index starting index number of components to be used for interpolations like <0>
700
- * @param {*} babel
701
- */
702
- function getTextAndInterpolatedVariables(type, primaryNode, index, babel) {
703
- throwOnInvalidType(type, primaryNode);
704
- const componentFoundIndex = index;
705
- const { text, interpolatedVariableNames } = extractVariableNamesFromQuasiNodes(
706
- primaryNode,
707
- babel,
708
- );
709
- const { stringOutput, componentFoundIndex: newIndex } = text
710
- .filter(filterNodes)
711
- // sort by the order they appear in the source code
712
- .sort((a, b) => {
713
- if (a.start > b.start) return 1;
714
- return -1;
715
- })
716
- .reduce(extractNestedTemplatesAndComponents, {
717
- babel,
718
- componentFoundIndex,
719
- stringOutput: [],
720
- type,
721
- interpolatedVariableNames,
722
- });
723
- return [
724
- interpolatedVariableNames,
725
- `{${stringOutput.join('')}}`,
726
- // return the new component interpolation index
727
- newIndex,
728
- ];
729
- }