@prestack/thread-ui 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/CHANGELOG.md +177 -0
  2. package/dist/ui/animations/anm_appear.ts +13 -0
  3. package/dist/ui/animations/anm_blur_in.ts +19 -0
  4. package/dist/ui/animations/anm_blur_out.ts +18 -0
  5. package/dist/ui/animations/anm_dismiss.ts +18 -0
  6. package/dist/ui/animations/anm_drop.ts +19 -0
  7. package/dist/ui/animations/anm_fall.ts +18 -0
  8. package/dist/ui/animations/anm_flash.ts +18 -0
  9. package/dist/ui/animations/anm_glow.ts +16 -0
  10. package/dist/ui/animations/anm_lift.ts +16 -0
  11. package/dist/ui/animations/anm_nudge.ts +16 -0
  12. package/dist/ui/animations/anm_pop_in.ts +23 -0
  13. package/dist/ui/animations/anm_pop_out.ts +22 -0
  14. package/dist/ui/animations/anm_press.ts +12 -0
  15. package/dist/ui/animations/anm_pulse.ts +13 -0
  16. package/dist/ui/animations/anm_rise.ts +19 -0
  17. package/dist/ui/animations/anm_shake.ts +13 -0
  18. package/dist/ui/animations/anm_slide_in_left.ts +19 -0
  19. package/dist/ui/animations/anm_slide_in_right.ts +19 -0
  20. package/dist/ui/animations/anm_slide_out_left.ts +18 -0
  21. package/dist/ui/animations/anm_slide_out_right.ts +18 -0
  22. package/dist/ui/animations/anm_spin.ts +12 -0
  23. package/dist/ui/animations/anm_swell.ts +16 -0
  24. package/dist/ui/animations/anm_wobble.ts +24 -0
  25. package/dist/ui/animations/anm_zoom_in.ts +19 -0
  26. package/dist/ui/animations/anm_zoom_out.ts +18 -0
  27. package/dist/ui/animations.js +2 -3
  28. package/dist/ui/animations.ts +316 -0
  29. package/dist/ui/attach.js +13 -10
  30. package/dist/ui/attach.ts +607 -0
  31. package/dist/ui/charts.tsx +74 -0
  32. package/dist/ui/checked.d.ts +2 -2
  33. package/dist/ui/checked.ts +32 -0
  34. package/dist/ui/collector.ts +140 -0
  35. package/dist/ui/compositions.d.ts +11 -2
  36. package/dist/ui/compositions.js +283 -59
  37. package/dist/ui/compositions.ts +633 -0
  38. package/dist/ui/consent.ts +55 -0
  39. package/dist/ui/content.tsx +39 -0
  40. package/dist/ui/contrast.ts +27 -0
  41. package/dist/ui/controls.tsx +30 -0
  42. package/dist/ui/disclosure.tsx +22 -0
  43. package/dist/ui/dismiss-layer.ts +87 -0
  44. package/dist/ui/door.ts +140 -0
  45. package/dist/ui/drag.ts +316 -0
  46. package/dist/ui/elements/accordion.js +2 -2
  47. package/dist/ui/elements/accordion.tsx +47 -0
  48. package/dist/ui/elements/accordion.works.ts +66 -0
  49. package/dist/ui/elements/aspect-ratio.js +1 -1
  50. package/dist/ui/elements/aspect-ratio.tsx +30 -0
  51. package/dist/ui/elements/aspect-ratio.works.ts +5 -0
  52. package/dist/ui/elements/avatar.js +1 -1
  53. package/dist/ui/elements/avatar.tsx +33 -0
  54. package/dist/ui/elements/avatar.works.ts +16 -0
  55. package/dist/ui/elements/badge.js +1 -1
  56. package/dist/ui/elements/badge.tsx +32 -0
  57. package/dist/ui/elements/badge.works.ts +9 -0
  58. package/dist/ui/elements/bars.js +2 -2
  59. package/dist/ui/elements/bars.tsx +49 -0
  60. package/dist/ui/elements/bars.works.ts +29 -0
  61. package/dist/ui/elements/box.js +3 -2
  62. package/dist/ui/elements/box.tsx +35 -0
  63. package/dist/ui/elements/breadcrumb.js +2 -2
  64. package/dist/ui/elements/breadcrumb.tsx +37 -0
  65. package/dist/ui/elements/breadcrumb.works.ts +24 -0
  66. package/dist/ui/elements/button.js +1 -1
  67. package/dist/ui/elements/button.tsx +45 -0
  68. package/dist/ui/elements/button.works.tsx +52 -0
  69. package/dist/ui/elements/column.js +1 -1
  70. package/dist/ui/elements/column.tsx +28 -0
  71. package/dist/ui/elements/consent.js +2 -2
  72. package/dist/ui/elements/consent.tsx +70 -0
  73. package/dist/ui/elements/consent.works.tsx +132 -0
  74. package/dist/ui/elements/donut.js +2 -2
  75. package/dist/ui/elements/donut.tsx +44 -0
  76. package/dist/ui/elements/donut.works.ts +42 -0
  77. package/dist/ui/elements/each.js +1 -1
  78. package/dist/ui/elements/each.tsx +33 -0
  79. package/dist/ui/elements/each.works.tsx +82 -0
  80. package/dist/ui/elements/empty.js +1 -1
  81. package/dist/ui/elements/empty.tsx +32 -0
  82. package/dist/ui/elements/field.js +1 -1
  83. package/dist/ui/elements/field.tsx +44 -0
  84. package/dist/ui/elements/field.works.ts +65 -0
  85. package/dist/ui/elements/funnel.js +2 -2
  86. package/dist/ui/elements/funnel.tsx +49 -0
  87. package/dist/ui/elements/funnel.works.ts +37 -0
  88. package/dist/ui/elements/gauge.js +1 -1
  89. package/dist/ui/elements/gauge.tsx +39 -0
  90. package/dist/ui/elements/gauge.works.ts +42 -0
  91. package/dist/ui/elements/glyph.js +1 -1
  92. package/dist/ui/elements/glyph.tsx +29 -0
  93. package/dist/ui/elements/glyph.works.tsx +42 -0
  94. package/dist/ui/elements/grid.js +1 -1
  95. package/dist/ui/elements/grid.tsx +28 -0
  96. package/dist/ui/elements/heatmap.js +2 -2
  97. package/dist/ui/elements/heatmap.tsx +47 -0
  98. package/dist/ui/elements/heatmap.works.ts +24 -0
  99. package/dist/ui/elements/hit-box.js +1 -1
  100. package/dist/ui/elements/hit-box.tsx +46 -0
  101. package/dist/ui/elements/hit-box.works.tsx +576 -0
  102. package/dist/ui/elements/image.js +1 -1
  103. package/dist/ui/elements/image.tsx +28 -0
  104. package/dist/ui/elements/line-chart.js +2 -2
  105. package/dist/ui/elements/line-chart.tsx +44 -0
  106. package/dist/ui/elements/line-chart.works.ts +41 -0
  107. package/dist/ui/elements/link.js +1 -1
  108. package/dist/ui/elements/link.tsx +37 -0
  109. package/dist/ui/elements/link.works.ts +25 -0
  110. package/dist/ui/elements/media.js +1 -1
  111. package/dist/ui/elements/media.tsx +56 -0
  112. package/dist/ui/elements/menu.js +2 -2
  113. package/dist/ui/elements/menu.tsx +50 -0
  114. package/dist/ui/elements/menu.works.tsx +153 -0
  115. package/dist/ui/elements/money.js +1 -1
  116. package/dist/ui/elements/money.tsx +28 -0
  117. package/dist/ui/elements/money.works.ts +9 -0
  118. package/dist/ui/elements/pagination.js +2 -2
  119. package/dist/ui/elements/pagination.tsx +38 -0
  120. package/dist/ui/elements/pagination.works.ts +20 -0
  121. package/dist/ui/elements/progress.js +1 -1
  122. package/dist/ui/elements/progress.tsx +33 -0
  123. package/dist/ui/elements/progress.works.ts +8 -0
  124. package/dist/ui/elements/radio-group.js +2 -2
  125. package/dist/ui/elements/radio-group.tsx +49 -0
  126. package/dist/ui/elements/radio-group.works.ts +33 -0
  127. package/dist/ui/elements/row.js +1 -1
  128. package/dist/ui/elements/row.tsx +28 -0
  129. package/dist/ui/elements/scatter.js +1 -1
  130. package/dist/ui/elements/scatter.tsx +41 -0
  131. package/dist/ui/elements/scatter.works.ts +38 -0
  132. package/dist/ui/elements/select.js +2 -2
  133. package/dist/ui/elements/select.tsx +42 -0
  134. package/dist/ui/elements/select.works.ts +5 -0
  135. package/dist/ui/elements/separator.js +1 -1
  136. package/dist/ui/elements/separator.tsx +30 -0
  137. package/dist/ui/elements/skeleton.js +1 -1
  138. package/dist/ui/elements/skeleton.tsx +30 -0
  139. package/dist/ui/elements/slider.js +1 -1
  140. package/dist/ui/elements/slider.tsx +33 -0
  141. package/dist/ui/elements/slider.works.ts +5 -0
  142. package/dist/ui/elements/sparkline.js +1 -1
  143. package/dist/ui/elements/sparkline.tsx +36 -0
  144. package/dist/ui/elements/sparkline.works.ts +32 -0
  145. package/dist/ui/elements/spinner.js +1 -1
  146. package/dist/ui/elements/spinner.tsx +32 -0
  147. package/dist/ui/elements/stack.js +1 -1
  148. package/dist/ui/elements/stack.tsx +28 -0
  149. package/dist/ui/elements/stat.js +1 -1
  150. package/dist/ui/elements/stat.tsx +35 -0
  151. package/dist/ui/elements/stat.works.ts +14 -0
  152. package/dist/ui/elements/surface.js +1 -1
  153. package/dist/ui/elements/surface.tsx +35 -0
  154. package/dist/ui/elements/surface.works.ts +9 -0
  155. package/dist/ui/elements/table.js +2 -2
  156. package/dist/ui/elements/table.tsx +61 -0
  157. package/dist/ui/elements/table.works.ts +30 -0
  158. package/dist/ui/elements/tabs.js +2 -2
  159. package/dist/ui/elements/tabs.tsx +47 -0
  160. package/dist/ui/elements/tabs.works.ts +84 -0
  161. package/dist/ui/elements/text.js +1 -1
  162. package/dist/ui/elements/text.tsx +32 -0
  163. package/dist/ui/elements/textarea.js +1 -1
  164. package/dist/ui/elements/textarea.tsx +37 -0
  165. package/dist/ui/elements/textarea.works.ts +5 -0
  166. package/dist/ui/elements/time.js +1 -1
  167. package/dist/ui/elements/time.tsx +34 -0
  168. package/dist/ui/elements/time.works.ts +25 -0
  169. package/dist/ui/elements/toggle.js +1 -1
  170. package/dist/ui/elements/toggle.tsx +33 -0
  171. package/dist/ui/elements/toggle.works.ts +5 -0
  172. package/dist/ui/elements/tooltip.js +1 -1
  173. package/dist/ui/elements/tooltip.tsx +39 -0
  174. package/dist/ui/elements/tooltip.works.ts +77 -0
  175. package/dist/ui/elements/value.js +1 -1
  176. package/dist/ui/elements/value.tsx +30 -0
  177. package/dist/ui/elements/value.works.ts +9 -0
  178. package/dist/ui/elements.ts +127 -0
  179. package/dist/ui/focus-scope.ts +121 -0
  180. package/dist/ui/fonts.ts +355 -0
  181. package/dist/ui/generators/dev.js +2 -1
  182. package/dist/ui/generators/dev.ts +80 -0
  183. package/dist/ui/generators/elements.d.ts +1 -11
  184. package/dist/ui/generators/elements.js +44 -14
  185. package/dist/ui/generators/elements.ts +794 -0
  186. package/dist/ui/generators/i18n.js +2 -3
  187. package/dist/ui/generators/i18n.ts +300 -0
  188. package/dist/ui/generators/icons.js +3 -12
  189. package/dist/ui/generators/icons.ts +214 -0
  190. package/dist/ui/generators/react.js +13 -5
  191. package/dist/ui/generators/react.ts +269 -0
  192. package/dist/ui/generators/routes.d.ts +1 -0
  193. package/dist/ui/generators/routes.js +99 -83
  194. package/dist/ui/generators/routes.ts +743 -0
  195. package/dist/ui/generators/show.js +4 -12
  196. package/dist/ui/generators/show.ts +260 -0
  197. package/dist/ui/generators/styles.js +3 -4
  198. package/dist/ui/generators/styles.ts +669 -0
  199. package/dist/ui/generators/variants.js +2 -3
  200. package/dist/ui/generators/variants.ts +204 -0
  201. package/dist/ui/i18n/catalogs/en.ts +191 -0
  202. package/dist/ui/i18n/format.ts +221 -0
  203. package/dist/ui/i18n/locales.ts +33 -0
  204. package/dist/ui/i18n/parse.ts +315 -0
  205. package/dist/ui/i18n/translator.ts +31 -0
  206. package/dist/ui/i18n/types.ts +96 -0
  207. package/dist/ui/icons.ts +331 -0
  208. package/dist/ui/islands/map.ts +58 -0
  209. package/dist/ui/localizations.ts +75 -0
  210. package/dist/ui/material.ts +236 -0
  211. package/dist/ui/materials/mat_bordered.ts +13 -0
  212. package/dist/ui/materials/mat_ceramic.ts +13 -0
  213. package/dist/ui/materials/mat_clay.ts +13 -0
  214. package/dist/ui/materials/mat_elevated.ts +24 -0
  215. package/dist/ui/materials/mat_flat.ts +34 -0
  216. package/dist/ui/materials/mat_glass.ts +20 -0
  217. package/dist/ui/materials/mat_lit.ts +13 -0
  218. package/dist/ui/materials/mat_moulded.ts +11 -0
  219. package/dist/ui/materials.js +2 -3
  220. package/dist/ui/materials.ts +205 -0
  221. package/dist/ui/modes.ts +44 -0
  222. package/dist/ui/navigation.tsx +32 -0
  223. package/dist/ui/positioning.ts +90 -0
  224. package/dist/ui/presented.tsx +119 -0
  225. package/dist/ui/provider.d.ts +2 -0
  226. package/dist/ui/provider.js +7 -1
  227. package/dist/ui/provider.tsx +182 -0
  228. package/dist/ui/render-loop.ts +133 -0
  229. package/dist/ui/roving-focus.ts +161 -0
  230. package/dist/ui/screens.js +22 -22
  231. package/dist/ui/screens.ts +141 -0
  232. package/dist/ui/scroll-lock.ts +28 -0
  233. package/dist/ui/series.ts +97 -0
  234. package/dist/ui/signals.ts +386 -0
  235. package/dist/ui/styleguide.ts +231 -0
  236. package/dist/ui/styleguides.ts +374 -0
  237. package/dist/ui/themes.ts +22 -0
  238. package/dist/ui/token.js +1 -1
  239. package/dist/ui/token.ts +78 -0
  240. package/dist/ui/tokens/shadow.ts +25 -0
  241. package/dist/ui/tokens.js +1 -2
  242. package/dist/ui/tokens.ts +234 -0
  243. package/dist/ui/validators.ts +232 -0
  244. package/dist/ui/variant.d.ts +1 -0
  245. package/dist/ui/variant.js +3 -0
  246. package/dist/ui/variant.ts +352 -0
  247. package/dist/ui/variants/var_avatar-round.ts +14 -0
  248. package/dist/ui/variants/var_bubble-me.ts +14 -0
  249. package/dist/ui/variants/var_bubble-them.ts +13 -0
  250. package/dist/ui/variants/var_button-border.ts +76 -0
  251. package/dist/ui/variants/var_button-cta.ts +76 -0
  252. package/dist/ui/variants/var_button-destructive-ghost.ts +72 -0
  253. package/dist/ui/variants/var_button-destructive.ts +76 -0
  254. package/dist/ui/variants/var_button-fill.ts +76 -0
  255. package/dist/ui/variants/var_button-ghost.ts +72 -0
  256. package/dist/ui/variants/var_button-glass.ts +55 -0
  257. package/dist/ui/variants/var_button-normal.ts +76 -0
  258. package/dist/ui/variants/var_button-quiet.ts +74 -0
  259. package/dist/ui/variants/var_card.ts +17 -0
  260. package/dist/ui/variants/var_chip.ts +13 -0
  261. package/dist/ui/variants/var_choice.ts +15 -0
  262. package/dist/ui/variants/var_framed.ts +10 -0
  263. package/dist/ui/variants/var_glyph-plain.ts +11 -0
  264. package/dist/ui/variants/var_input.ts +43 -0
  265. package/dist/ui/variants/var_link-inline.ts +29 -0
  266. package/dist/ui/variants/var_list-row.ts +34 -0
  267. package/dist/ui/variants/var_rule.ts +10 -0
  268. package/dist/ui/variants/var_skeleton-block.ts +12 -0
  269. package/dist/ui/variants/var_spinner-turning.ts +12 -0
  270. package/dist/ui/variants/var_stat-tile.ts +13 -0
  271. package/dist/ui/variants/var_tab-bar.ts +15 -0
  272. package/dist/ui/variants/var_tap-target.ts +25 -0
  273. package/dist/ui/variants.ts +64 -0
  274. package/dist/ui/wrappers.d.ts +4 -1
  275. package/dist/ui/wrappers.js +60 -20
  276. package/dist/ui/wrappers.tsx +426 -0
  277. package/package.json +8 -2
  278. package/dist/ui/makers/message.d.ts +0 -1
  279. package/dist/ui/makers/message.js +0 -230
@@ -1,230 +0,0 @@
1
- var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
- if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
- return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
- return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
- });
6
- }
7
- return path;
8
- };
9
- import { readFileSync, writeFileSync } from 'node:fs';
10
- import { join } from 'node:path';
11
- import { argv, exit, stdout } from 'node:process';
12
- import { pathToFileURL } from 'node:url';
13
- import { ELSEWHERE, RECEIPT, answer, answering, asking, given, guidance, issue, marked, named, needed, only, prompted, refuse, spend, within, wordsIn, wrapped } from "@prestack/thread/core/asking";
14
- import { named as packageOf } from "@prestack/thread/core/scope";
15
- import { findTree, inTree } from "@prestack/thread/core/tree";
16
- import { keyProps, keysIn, readWording, walk, wordingFile } from "../generators/i18n.js";
17
- import { fileFor, languagesIn, sourceIn } from "../localizations.js";
18
- const TREE = findTree();
19
- const DOTTED = /^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/;
20
- const KEY = { at: 'key', guide: 'lowercase words joined by dots — `checkout.confirm`, `errors.db.not_found.title`' };
21
- async function languages() {
22
- const path = inTree(TREE, `localizations.${'ts'}`);
23
- let sheet = {};
24
- try {
25
- sheet = (await import(__rewriteRelativeImportExtension(pathToFileURL(path).href)));
26
- }
27
- catch {
28
- sheet = {};
29
- }
30
- if (sheet.LOCALIZATION === undefined) {
31
- refuse(`there is no ${within(TREE.at, path)} declaring a \`LOCALIZATION\` here, so this app is in no ` +
32
- `language and a message has nowhere to go. Run \`npx thread attach ${packageOf('ui')}\`.`);
33
- }
34
- const rows = [...(sheet.LOCALIZATION.holds ?? []), ...(sheet.LOCALIZATION.declares ?? [])];
35
- const held = languagesIn(rows);
36
- const source = sourceIn(rows);
37
- if (held.length === 0 || source === undefined) {
38
- refuse('no language is declared, so there is nothing to write a message in. Add one with `npx thread create language`.');
39
- }
40
- return { held, source };
41
- }
42
- function usage(props) {
43
- const found = new Map();
44
- for (const file of walk(TREE.at)) {
45
- const text = readFileSync(file, 'utf8');
46
- for (const key of new Set(keysIn(text, props))) {
47
- const held = found.get(key) ?? [];
48
- held.push(within(TREE.at, file));
49
- found.set(key, held);
50
- }
51
- }
52
- return found;
53
- }
54
- const mark = (key, said) => marked([key, said]);
55
- function write(at, language, held) {
56
- writeFileSync(join(at, fileFor(language)), wordingFile(held), 'utf8');
57
- }
58
- async function run() {
59
- const { held: spoken, source } = await languages();
60
- const props = keyProps(TREE.at);
61
- if (props.length === 0) {
62
- refuse(`nothing in the installed \`${packageOf('ui')}\` declares a prop of type \`MessageKey\`, so no key could be ` +
63
- 'recognised anywhere. That is a broken install rather than an app with no wording.');
64
- }
65
- const LANGUAGES = spoken.map((one) => ({ at: one.id, guide: `what it says in ${one.name}` }));
66
- const NEW = [KEY, ...LANGUAGES];
67
- const wording = new Map();
68
- for (const one of spoken)
69
- wording.set(one.id, { ...readWording(TREE.at, one.id) });
70
- const written = wording.get(source) ?? {};
71
- const keys = Object.keys(written).sort();
72
- const used = usage(props);
73
- const blank = (key) => spoken.filter((one) => ((wording.get(one.id) ?? {})[key] ?? '') === '').map((one) => one.id);
74
- const listing = [
75
- `${String(keys.length)} message(s), in ${spoken.map((one) => one.id).join(', ')} — written in ${source}:`,
76
- '',
77
- ...keys.map((key) => {
78
- const missing = blank(key);
79
- const said = (written[key] ?? '') || '(nothing yet)';
80
- return (` [${mark(key, written[key] ?? '')}] ${key.padEnd(38)} ${said.length > 46 ? `${said.slice(0, 45)}…` : said}` +
81
- `${missing.length === 0 ? '' : ` · still to write: ${missing.join(', ')}`}` +
82
- `${(used.get(key) ?? []).length === 0 ? ' · named by nothing here' : ''}`);
83
- }),
84
- ].join('\n');
85
- const words = wordsIn(['new']);
86
- const verb = words[0];
87
- const flagged = argv.indexOf(RECEIPT);
88
- if (flagged === -1) {
89
- stdout.write(`${listing}\n`);
90
- const nonce = issue(TREE.at, listing);
91
- stdout.write([
92
- '',
93
- ...answering('message'),
94
- '',
95
- ...guidance(NEW),
96
- '',
97
- ...wrapped('Every language is asked for and none may be left blank. A key that exists in one language and ' +
98
- 'not another is what makes a screen come out half translated, and it is refused here rather ' +
99
- 'than found by whoever is reading the app in the other one.', ' '),
100
- '',
101
- ` npx thread create message new ${RECEIPT} ${nonce}`,
102
- '',
103
- ...ELSEWHERE,
104
- '',
105
- ...wrapped('A rename moves the wording in every language and rewrites every file in the interface that ' +
106
- 'names it, in one run.', ' '),
107
- '',
108
- ].join('\n'));
109
- stdout.write(`create: receipt ${nonce} — spent on use, and stale the moment the wording changes.\n`);
110
- return 0;
111
- }
112
- spend(TREE.at, listing, argv[flagged + 1], `the wording`);
113
- const all = given();
114
- const { piped, ask, shut } = asking(all);
115
- const ASKS = {
116
- new: ['do', ...named(NEW)],
117
- edit: ['do', 'mark', ...named(NEW)],
118
- remove: ['do', 'mark'],
119
- };
120
- const doing = verb ?? (await ask('do', 'new, edit or remove: '));
121
- const allowed = ASKS[doing];
122
- if (allowed === undefined) {
123
- shut();
124
- refuse(`there is nothing called "${doing}" to do here — say new, edit, remove, or read, which needs no receipt`);
125
- }
126
- if (piped)
127
- only(all, allowed, `\`${doing}\``);
128
- if (doing === 'remove' || doing === 'edit') {
129
- const which = words[1] ?? (piped ? needed(all, 'mark', `\`${doing}\``) : await ask('mark', 'mark: '));
130
- const one = keys.find((key) => mark(key, written[key] ?? '') === which);
131
- if (one === undefined) {
132
- shut();
133
- refuse(`\`${which}\` is not a mark this sheet issued — they are printed in brackets beside each message.`);
134
- }
135
- if (doing === 'remove') {
136
- const where = used.get(one) ?? [];
137
- if (where.length > 0) {
138
- shut();
139
- refuse(`\`${one}\` is named by ${where.slice(0, 6).join(', ')}` +
140
- `${where.length > 6 ? ` and ${String(where.length - 6)} more` : ''}. ` +
141
- 'Removing it would leave those asking for wording that does not exist, which throws the moment ' +
142
- 'the screen renders. Take it out of the interface first.');
143
- }
144
- shut();
145
- for (const language of spoken) {
146
- const made = { ...(wording.get(language.id) ?? {}) };
147
- delete made[one];
148
- write(TREE.at, language.id, made);
149
- }
150
- stdout.write(`create: removed ${one} from ${String(spoken.length)} language file(s)\n`);
151
- return 0;
152
- }
153
- const renamed = piped ? (answer(all, KEY.at) ?? '') : await ask(KEY.at, `key (${one}, blank to keep) `);
154
- if (renamed !== '' && !DOTTED.test(renamed)) {
155
- shut();
156
- refuse(`\`${renamed}\` is not a key — lowercase words joined by dots.`);
157
- }
158
- if (renamed !== '' && written[renamed] !== undefined) {
159
- shut();
160
- refuse(`\`${renamed}\` is already a message. Two keys with one name is one key, and the other's wording is lost.`);
161
- }
162
- const said = new Map();
163
- for (const language of spoken) {
164
- const now = (wording.get(language.id) ?? {})[one] ?? '';
165
- const next = piped
166
- ? (answer(all, language.id) ?? '')
167
- : await ask(language.id, `${language.name} (${now || 'nothing yet'}) `);
168
- said.set(language.id, next === '' ? now : next);
169
- }
170
- shut();
171
- const name = renamed === '' ? one : renamed;
172
- for (const language of spoken) {
173
- const made = { ...(wording.get(language.id) ?? {}) };
174
- delete made[one];
175
- made[name] = said.get(language.id) ?? '';
176
- write(TREE.at, language.id, made);
177
- }
178
- let moved = 0;
179
- if (renamed !== '') {
180
- for (const file of walk(TREE.at)) {
181
- const text = readFileSync(file, 'utf8');
182
- if (!keysIn(text, props).includes(one))
183
- continue;
184
- writeFileSync(file, text.replace(new RegExp(`(\\b(?:${props.join('|')})\\s*=\\s*")${one.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(")`, 'g'), `$1${name}$2`), 'utf8');
185
- moved += 1;
186
- }
187
- }
188
- stdout.write(`create: ${one}${renamed === '' ? '' : ` is now ${name}`} — rewritten in ${String(spoken.length)} language file(s)` +
189
- `${moved === 0 ? '' : ` and ${String(moved)} file(s) of the interface`}\n`);
190
- const still = blankIn(said, spoken);
191
- if (still.length > 0) {
192
- stdout.write(`create: still nothing in ${still.join(', ')} — the gate refuses while that holds.\n`);
193
- }
194
- return 0;
195
- }
196
- const key = piped ? needed(all, KEY.at, '`new`') : await ask(KEY.at, prompted(KEY));
197
- if (!DOTTED.test(key)) {
198
- shut();
199
- refuse(`\`${key}\` is not a key — lowercase words joined by dots, like \`checkout.confirm\`.`);
200
- }
201
- if (written[key] !== undefined) {
202
- shut();
203
- refuse(`\`${key}\` is already a message. Edit it by its mark, or choose another key.`);
204
- }
205
- const said = new Map();
206
- for (const language of spoken) {
207
- const next = piped
208
- ? (answer(all, language.id) ?? '')
209
- : await ask(language.id, `what it says in ${language.name}: `);
210
- if (next === '') {
211
- shut();
212
- refuse(`\`${key}\` has nothing to say in ${language.name}. Every language is answered at the moment a key ` +
213
- 'is made, because a key that exists in one language and not another is a screen that comes out ' +
214
- 'half translated. There is no way past this on purpose.');
215
- }
216
- said.set(language.id, next);
217
- }
218
- shut();
219
- for (const language of spoken) {
220
- write(TREE.at, language.id, { ...(wording.get(language.id) ?? {}), [key]: said.get(language.id) ?? '' });
221
- }
222
- stdout.write(`create: wrote ${key} in ${spoken.map((one) => one.id).join(', ')}\n`);
223
- stdout.write(`create: name it in the interface with one of: ${props.join(', ')} — for example \`label="${key}"\`.\n`);
224
- return 0;
225
- }
226
- function blankIn(said, spoken) {
227
- return spoken.filter((one) => (said.get(one.id) ?? '') === '').map((one) => one.id);
228
- }
229
- if (argv[1] !== undefined)
230
- exit(await run());