prosebook 0.3.0 → 0.5.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 (125) hide show
  1. package/README.md +357 -26
  2. package/dist/bind-BIZNv8nU.js +62 -0
  3. package/dist/bind-BIZNv8nU.js.map +1 -0
  4. package/dist/bind-ZS86jHXk.d.ts +31 -0
  5. package/dist/bind-ZS86jHXk.d.ts.map +1 -0
  6. package/dist/bun.d.ts +12 -3
  7. package/dist/bun.d.ts.map +1 -1
  8. package/dist/bun.js +77 -26
  9. package/dist/bun.js.map +1 -1
  10. package/dist/{bundle-KD-DiiFa.d.ts → bundle-CLHY_97D.d.ts} +3 -3
  11. package/dist/bundle-CLHY_97D.d.ts.map +1 -0
  12. package/dist/bundle-Ut6Y2X6N.js +217 -0
  13. package/dist/bundle-Ut6Y2X6N.js.map +1 -0
  14. package/dist/cli.js +55 -12
  15. package/dist/cli.js.map +1 -1
  16. package/dist/{config-BPSmoYel.js → config-7T4hX_f7.js} +13 -5
  17. package/dist/{config-BPSmoYel.js.map → config-7T4hX_f7.js.map} +1 -1
  18. package/dist/{config-DdMkKt_N.d.ts → config-CzaJJQ60.d.ts} +19 -5
  19. package/dist/{config-DdMkKt_N.d.ts.map → config-CzaJJQ60.d.ts.map} +1 -1
  20. package/dist/config.d.ts +1 -1
  21. package/dist/config.js +1 -1
  22. package/dist/{copy-B3V_QRkT.d.ts → copy-BXn0aYQn.d.ts} +37 -3
  23. package/dist/copy-BXn0aYQn.d.ts.map +1 -0
  24. package/dist/copy-Bv6S-Hr2.js +235 -0
  25. package/dist/copy-Bv6S-Hr2.js.map +1 -0
  26. package/dist/endpoints-Dhgowovz.js +217 -0
  27. package/dist/endpoints-Dhgowovz.js.map +1 -0
  28. package/dist/generate-1BeQAd1O.d.ts +72 -0
  29. package/dist/generate-1BeQAd1O.d.ts.map +1 -0
  30. package/dist/{generate-9pR3i5Bj.js → generate-CKv86Iki.js} +1724 -627
  31. package/dist/generate-CKv86Iki.js.map +1 -0
  32. package/dist/index.d.ts +2 -2
  33. package/dist/index.js +2 -2
  34. package/dist/next-loader.d.ts +9 -2
  35. package/dist/next-loader.d.ts.map +1 -1
  36. package/dist/next-loader.js +12 -3
  37. package/dist/next-loader.js.map +1 -1
  38. package/dist/next.d.ts +11 -3
  39. package/dist/next.d.ts.map +1 -1
  40. package/dist/next.js +94 -21
  41. package/dist/next.js.map +1 -1
  42. package/dist/preact/index.d.ts +34 -0
  43. package/dist/preact/index.d.ts.map +1 -0
  44. package/dist/preact/index.js +72 -0
  45. package/dist/preact/index.js.map +1 -0
  46. package/dist/react/index.d.ts +5 -14
  47. package/dist/react/index.d.ts.map +1 -1
  48. package/dist/react/index.js +9 -33
  49. package/dist/react/index.js.map +1 -1
  50. package/dist/react/server.d.ts +1 -1
  51. package/dist/react/server.js +1 -1
  52. package/dist/{sarif-CWyTAQ0y.js → sarif-BnwYC78_.js} +8 -98
  53. package/dist/sarif-BnwYC78_.js.map +1 -0
  54. package/dist/{scan-Bx0_yDSi.js → scan-C0ap4Mpp.js} +145 -20
  55. package/dist/scan-C0ap4Mpp.js.map +1 -0
  56. package/dist/solid/index.d.ts +29 -0
  57. package/dist/solid/index.d.ts.map +1 -0
  58. package/dist/solid/index.js +48 -0
  59. package/dist/solid/index.js.map +1 -0
  60. package/dist/svelte/Text.svelte +13 -0
  61. package/dist/svelte/Text.svelte.d.ts +20 -0
  62. package/dist/svelte/index.d.ts +31 -0
  63. package/dist/svelte/index.d.ts.map +1 -0
  64. package/dist/svelte/index.js +35 -0
  65. package/dist/svelte/index.js.map +1 -0
  66. package/dist/tools.d.ts +44 -65
  67. package/dist/tools.d.ts.map +1 -1
  68. package/dist/tools.js +5 -5
  69. package/dist/vite.d.ts +13 -3
  70. package/dist/vite.d.ts.map +1 -1
  71. package/dist/vite.js +82 -25
  72. package/dist/vite.js.map +1 -1
  73. package/dist/vue/index.d.ts +43 -0
  74. package/dist/vue/index.d.ts.map +1 -0
  75. package/dist/vue/index.js +76 -0
  76. package/dist/vue/index.js.map +1 -0
  77. package/package.json +63 -7
  78. package/src/bun.ts +77 -20
  79. package/src/cli.ts +62 -8
  80. package/src/index.ts +1 -1
  81. package/src/next-loader.ts +17 -5
  82. package/src/next.ts +120 -16
  83. package/src/preact/index.ts +91 -0
  84. package/src/react/index.tsx +12 -42
  85. package/src/runtime/bind.ts +96 -0
  86. package/src/runtime/copy.ts +148 -24
  87. package/src/solid/index.ts +67 -0
  88. package/src/svelte/Text.svelte +13 -0
  89. package/src/svelte/Text.svelte.d.ts +20 -0
  90. package/src/svelte/index.ts +65 -0
  91. package/src/tools/bundle.ts +143 -2
  92. package/src/tools/catalog.ts +10 -1
  93. package/src/tools/chunks.ts +142 -0
  94. package/src/tools/config.ts +25 -7
  95. package/src/tools/entry.ts +19 -20
  96. package/src/tools/exchange.ts +275 -0
  97. package/src/tools/extract.ts +2 -2
  98. package/src/tools/generate.ts +7 -1
  99. package/src/tools/index.ts +2 -1
  100. package/src/tools/native/android.ts +186 -0
  101. package/src/tools/native/apple.ts +201 -0
  102. package/src/tools/native/date.ts +219 -0
  103. package/src/tools/native/index.ts +17 -5
  104. package/src/tools/native/kotlin.ts +47 -6
  105. package/src/tools/native/model.ts +67 -29
  106. package/src/tools/native/printf.ts +137 -0
  107. package/src/tools/native/rust.ts +86 -5
  108. package/src/tools/native/swift.ts +62 -6
  109. package/src/tools/scan.ts +146 -25
  110. package/src/tools/todo.ts +6 -1
  111. package/src/vite.ts +121 -28
  112. package/src/vue/index.ts +117 -0
  113. package/dist/bundle-DboItAre.js +0 -111
  114. package/dist/bundle-DboItAre.js.map +0 -1
  115. package/dist/bundle-KD-DiiFa.d.ts.map +0 -1
  116. package/dist/compile-xF3F4oIp.d.ts +0 -16
  117. package/dist/compile-xF3F4oIp.d.ts.map +0 -1
  118. package/dist/copy-B3V_QRkT.d.ts.map +0 -1
  119. package/dist/copy-Bo_FIoLy.js +0 -154
  120. package/dist/copy-Bo_FIoLy.js.map +0 -1
  121. package/dist/endpoints-CnUfCkIk.js +0 -96
  122. package/dist/endpoints-CnUfCkIk.js.map +0 -1
  123. package/dist/generate-9pR3i5Bj.js.map +0 -1
  124. package/dist/sarif-CWyTAQ0y.js.map +0 -1
  125. package/dist/scan-Bx0_yDSi.js.map +0 -1
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * The `prosebook` command. Each subcommand is a function of the resolved config; `check` runs the\n * ones CI needs in one go.\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join, relative, resolve } from 'node:path';\nimport { parseArgs } from 'node:util';\n\nimport { watchCatalog } from './tools/bundle.ts';\nimport { CatalogError, entryLocator, whereOf, type Catalog, type Problem } from './tools/catalog.ts';\nimport { CONFIG_FILES, loadConfig, type ResolvedConfig } from './tools/config.ts';\nimport { applyFixes, importTranslations } from './tools/entry.ts';\nimport { applyExtract, planExtract } from './tools/extract.ts';\nimport { generate, render } from './tools/generate.ts';\nimport { lint, type Finding } from './tools/lint.ts';\nimport { changeOf, type StaleTranslation } from './tools/lock.ts';\nimport { applyMigrate, planMigrate } from './tools/migrate.ts';\nimport { SarifReport } from './tools/sarif.ts';\nimport { isReferenced, scan, sourceFiles } from './tools/scan.ts';\nimport { SYNTAX_NAME } from './tools/syntax.ts';\nimport { todoOf } from './tools/todo.ts';\n\nconst HELP = `prosebook: every string your app shows, in one typed catalog\n\nUsage: prosebook <command> [options]\n\nCommands:\n init Create a config and a first catalog file\n generate Compile the catalog into typed modules (--check: fail if out of date, --watch)\n lint Check the messages and their translations against the writing rules\n (--fix: write the fixes the rules know, such as spellings and …)\n status Translation coverage and stale translations per locale (--strict, --verbose)\n accept <locale> [keys] Mark stale translations as still right (--all for every stale one)\n todo <locale> Print the missing and stale entries of a locale, ready to translate\n (--prompt: as a prompt for a model, saying how to reply)\n import <locale> [file] Write translations from todo's YAML filled in, or a model's reply to --prompt\n (stdin without a file); each is checked first, and one that fails is left out\n scan Find hardcoded text in JSX and catalog keys no code reads (--strict)\n extract [paths] Move hardcoded JSX text into the catalog and rewrite the code to read it\n (dry run unless --write; --area <name> puts every entry in one area)\n migrate <1|2> Rewrite the catalog and translations in ICU MessageFormat (1) or MessageFormat 2\n (dry run unless --write)\n check generate --check, lint and status --strict together, for CI\n\nOptions:\n --root <dir> Project root (default: the current directory)\n --format <text|sarif> With lint, scan, status and check: sarif writes a SARIF 2.1.0 log to stdout\n for code scanning, and the usual text to stderr\n -h, --help Show this help\n`;\n\nconst SARIF_COMMANDS = ['lint', 'scan', 'status', 'check'];\n\n/** What the checks that aren't lint rules hold the project to, for the rules in a SARIF log. */\nconst RULES = {\n catalog: 'The catalog and its translations parse, and each translation keeps the placeholders of its source.',\n 'out-of-date': 'The generated modules match the catalog: run `prosebook generate`.',\n 'missing-translation': 'Every locale translates every entry.',\n 'stale-translation': 'A translation was made from the source text as it is now.',\n 'hardcoded-text': 'Text a person reads comes from the catalog, not from a literal in JSX.',\n 'unused-key': 'Code reads every catalog key.',\n allow: \"An entry's exemption names a rule the entry breaks, and says why in a sentence.\",\n};\n\n/** Text for people. Under `--format sarif` stdout holds only the log, so this goes to stderr. */\nlet out = (s = '') => process.stdout.write(`${s}\\n`);\nconst err = (s = '') => process.stderr.write(`${s}\\n`);\n\nasync function main(argv: string[]): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n root: { type: 'string' },\n check: { type: 'boolean' },\n watch: { type: 'boolean' },\n strict: { type: 'boolean' },\n verbose: { type: 'boolean' },\n all: { type: 'boolean' },\n write: { type: 'boolean' },\n fix: { type: 'boolean' },\n prompt: { type: 'boolean' },\n area: { type: 'string' },\n format: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n const [command, ...rest] = positionals;\n if (values.help || command === undefined) {\n out(HELP);\n return 0;\n }\n if (values.format !== undefined && values.format !== 'text' && values.format !== 'sarif') {\n err(`prosebook: --format is text or sarif, not \"${values.format}\"`);\n return 1;\n }\n const report = values.format === 'sarif' ? new SarifReport() : undefined;\n if (report !== undefined) {\n if (!SARIF_COMMANDS.includes(command)) {\n err(`prosebook: --format sarif works with ${SARIF_COMMANDS.join(', ')}`);\n return 1;\n }\n out = err;\n }\n const root = values.root ?? process.cwd();\n if (command === 'init') return init(root);\n const config = await loadConfig(root);\n let code: number;\n try {\n switch (command) {\n case 'generate':\n case 'gen':\n if (values.watch) return watchMode(config);\n return runGenerate(config, values.check === true);\n case 'lint':\n code = runLint(config, report, values.fix === true);\n break;\n case 'status':\n code = runStatus(config, values.strict === true, values.verbose === true, report);\n break;\n case 'accept':\n return runAccept(config, rest, values.all === true);\n case 'todo':\n return runTodo(config, rest[0], values.prompt === true);\n case 'import':\n return runImport(config, rest[0], rest[1]);\n case 'scan':\n code = runScan(config, values.strict === true, report);\n break;\n case 'extract':\n return runExtract(config, rest, values.write === true, values.area);\n case 'migrate':\n return runMigrate(config, rest[0], values.write === true);\n case 'check': {\n const results = [runGenerate(config, true, report), runLint(config, report), runStatus(config, true, false, report)];\n code = results.some((r) => r !== 0) ? 1 : 0;\n break;\n }\n default:\n err(`prosebook: no command \"${command}\"\\n`);\n out(HELP);\n return 1;\n }\n } catch (e) {\n if (!(e instanceof CatalogError)) throw e;\n reportProblems(config, e.problems, report);\n err(`\\n${e.problems.filter((p) => p.severity === 'error').length} error(s) in the catalog.`);\n code = 1;\n }\n if (report !== undefined) process.stdout.write(`${JSON.stringify(report.toJSON(config.root, tool()), null, 2)}\\n`);\n return code;\n}\n\nfunction tool() {\n const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) as { version: string; homepage: string };\n return { name: 'prosebook', version: pkg.version, informationUri: pkg.homepage };\n}\n\nfunction reportProblems(config: ResolvedConfig, problems: Problem[], report?: SarifReport) {\n for (const p of problems) err(`${p.severity === 'error' ? 'error' : 'warn '} ${whereOf(p)}: ${p.message}`);\n if (report === undefined) return;\n const locate = entryLocator(config.root);\n report.rule('catalog', RULES.catalog);\n for (const p of problems) {\n report.add({\n rule: 'catalog',\n level: p.severity === 'error' ? 'error' : 'warning',\n message: p.message,\n file: p.file,\n ...(p.file !== undefined && p.key !== undefined ? locate(p.file, p.key) : {}),\n });\n }\n}\n\nfunction rel(config: ResolvedConfig, path: string) {\n return relative(config.root, path).replaceAll('\\\\', '/');\n}\n\nfunction runGenerate(config: ResolvedConfig, check: boolean, report?: SarifReport): number {\n const { changed, catalog, stale } = generate(config, { check });\n reportProblems(config, catalog.problems, report);\n const staleCount = [...stale.values()].reduce((n, s) => n + s.size, 0);\n const summary = `${catalog.messages.length} messages, ${catalog.locales.length + 1} locale(s)${staleCount > 0 ? `, ${staleCount} stale translation(s)` : ''}`;\n if (check) {\n if (changed.length === 0) {\n out(`prosebook: generated files are up to date (${summary})`);\n return 0;\n }\n err(`prosebook: out of date, run \\`prosebook generate\\`:\\n ${changed.map((p) => rel(config, p)).join('\\n ')}`);\n report?.rule('out-of-date', RULES['out-of-date']);\n for (const p of changed)\n report?.add({ rule: 'out-of-date', level: 'error', message: 'out of date: run `prosebook generate`', file: rel(config, p) });\n return 1;\n }\n out(`prosebook: ${changed.length === 0 ? 'nothing changed' : `wrote ${changed.length} file(s)`} (${summary})`);\n return 0;\n}\n\nfunction watchMode(config: ResolvedConfig): Promise<number> {\n const regenerate = () => {\n try {\n runGenerate(config, false);\n } catch (e) {\n if (e instanceof CatalogError) reportProblems(config, e.problems);\n else err(String(e));\n }\n };\n regenerate();\n watchCatalog(config, regenerate);\n out('prosebook: watching the catalog for changes');\n return new Promise(() => {});\n}\n\nfunction runLint(config: ResolvedConfig, report?: SarifReport, fix = false): number {\n let { catalog } = render(config);\n let findings = lint(catalog.messages, config);\n if (fix) {\n const { fixed, problems } = applyFixes(config, catalog, findings);\n if (problems.length > 0) {\n reportProblems(config, problems, report);\n err('The fixes would break the catalog, so nothing was written.');\n return 1;\n }\n if (fixed > 0) {\n out(`prosebook: fixed ${fixed} finding(s); run prosebook generate to compile them`);\n ({ catalog } = render(config));\n findings = lint(catalog.messages, config);\n }\n }\n const placed = printFindings(config, findings);\n if (report !== undefined) {\n for (const [name, { rule }] of Object.entries(config.lint.rules)) report.rule(name, rule.description);\n report.rule('allow', RULES.allow);\n for (const f of placed) {\n report.add({\n rule: f.rule,\n level: f.severity === 'error' ? 'error' : 'warning',\n message: `${f.key}: ${f.message}`,\n file: f.file,\n line: f.line,\n column: f.column,\n });\n }\n }\n const errors = findings.filter((f) => f.severity === 'error').length;\n const fixable = findings.filter((f) => f.fix !== undefined).length;\n if (findings.length === 0) {\n out(`prosebook: ${catalog.messages.length} messages pass the writing rules`);\n } else {\n err(\n `\\n${errors} error(s), ${findings.length - errors} warning(s). Fix the string, or add \\`allow: { <rule>: <why> }\\` where the rule is wrong about it.`,\n );\n if (fixable > 0) err(`${fixable} of them can be fixed with prosebook lint --fix.`);\n }\n return errors > 0 ? 1 : 0;\n}\n\n/** Each finding on its line, placed at its entry's words. */\nfunction printFindings(config: ResolvedConfig, findings: Finding[]) {\n const locate = entryLocator(config.root);\n const placed = findings.map((f) => ({ ...f, ...locate(f.file, f.key, f.at?.start, config.source) }));\n for (const f of placed) {\n const severity = f.severity === 'error' ? 'error' : 'warn ';\n err(`${severity} ${f.file}:${f.line}:${f.column} ${f.key}: [${f.rule}] ${f.message}${f.fix === undefined ? '' : ' (fixable)'}`);\n }\n return placed;\n}\n\nfunction missingKeys(catalog: Catalog, locale: string): string[] {\n return catalog.messages.filter((m) => !m.translations.has(locale)).map((m) => m.key);\n}\n\nfunction runStatus(config: ResolvedConfig, strict: boolean, verbose: boolean, report?: SarifReport): number {\n const { catalog, stale } = render(config);\n if (report !== undefined) reportStatus(config, catalog, stale, strict ? 'error' : 'warning', report);\n const total = catalog.messages.length;\n if (catalog.locales.length === 0) {\n out(`prosebook: ${total} messages in ${config.source}, no translations yet`);\n return 0;\n }\n let incomplete = false;\n out(`${'locale'.padEnd(10)} ${'translated'.padStart(12)} ${'missing'.padStart(8)} ${'stale'.padStart(6)}`);\n for (const locale of catalog.locales) {\n const missing = missingKeys(catalog, locale);\n const staleHere = stale.get(locale) ?? new Map<string, StaleTranslation>();\n const staleKeys = [...staleHere.keys()];\n const done = total - missing.length;\n if (missing.length > 0 || staleKeys.length > 0) incomplete = true;\n const pct = total === 0 ? 100 : Math.floor((done / total) * 100);\n out(\n `${locale.padEnd(10)} ${`${done}/${total} ${String(pct).padStart(3)}%`.padStart(12)} ${String(missing.length).padStart(8)} ${String(staleKeys.length).padStart(6)}`,\n );\n if (verbose) {\n for (const key of missing) out(` missing ${key}`);\n for (const [key, s] of staleHere) out(` stale ${key}: ${changeOf(s)}`);\n }\n }\n if (incomplete && !verbose)\n out('\\n`prosebook status --verbose` lists the keys; `prosebook todo <locale>` prints them ready to translate.');\n return strict && incomplete ? 1 : 0;\n}\n\nfunction reportStatus(\n config: ResolvedConfig,\n catalog: Catalog,\n stale: Map<string, Map<string, StaleTranslation>>,\n level: 'error' | 'warning',\n report: SarifReport,\n) {\n const locate = entryLocator(config.root);\n report.rule('missing-translation', RULES['missing-translation']);\n report.rule('stale-translation', RULES['stale-translation']);\n for (const locale of catalog.locales) {\n for (const m of catalog.messages) {\n if (m.translations.has(locale)) continue;\n const message = `${m.key} has no ${locale} translation: \\`prosebook todo ${locale}\\` prints it ready to translate`;\n report.add({ rule: 'missing-translation', level, message, file: m.file, ...locate(m.file, m.key) });\n }\n for (const [key, s] of stale.get(locale) ?? []) {\n const file = catalog.messages.find((m) => m.key === key)?.translations.get(locale)?.file;\n if (file === undefined) continue;\n const message = `the ${locale} translation of ${key} was made from an earlier source (${changeOf(s)}): update it, or \\`prosebook accept ${locale} ${key}\\` if it is still right`;\n report.add({ rule: 'stale-translation', level, message, file, ...locate(file, key) });\n }\n }\n}\n\nfunction runAccept(config: ResolvedConfig, args: string[], all: boolean): number {\n const [locale, ...keys] = args;\n if (locale === undefined || (keys.length === 0 && !all)) {\n err('Usage: prosebook accept <locale> <key>... | prosebook accept <locale> --all');\n return 1;\n }\n const before = render(config).stale.get(locale) ?? new Map<string, StaleTranslation>();\n const accepting = all ? new Set(before.keys()) : new Set(keys);\n for (const key of accepting) if (!before.has(key)) err(`warn ${locale} ${key} is not stale`);\n generate(config, { accept: new Map([[locale, all ? true : new Set(keys)]]) });\n out(`prosebook: accepted ${[...accepting].filter((k) => before.has(k)).length} translation(s) in ${locale}`);\n return 0;\n}\n\nfunction runTodo(config: ResolvedConfig, locale: string | undefined, prompt: boolean): number {\n if (locale === undefined) {\n err('Usage: prosebook todo <locale> [--prompt]');\n return 1;\n }\n const { catalog, stale } = render(config);\n const todo = todoOf(config, catalog, stale.get(locale) ?? new Map(), locale, prompt);\n out(todo.text);\n if (prompt && todo.count > 0) err(`\\nHand this to a model, save its reply, and \\`prosebook import ${locale} <reply>\\`.`);\n return 0;\n}\n\nfunction runImport(config: ResolvedConfig, locale: string | undefined, file: string | undefined): number {\n if (locale === undefined || ((file === undefined || file === '-') && process.stdin.isTTY)) {\n err('Usage: prosebook import <locale> <file>, or the reply on stdin');\n return 1;\n }\n const reply = readFileSync(file === undefined || file === '-' ? 0 : resolve(file), 'utf8');\n const { written, unchanged, problems } = importTranslations(config, locale, reply);\n reportProblems(config, problems);\n if (written.length + unchanged.length > 0) {\n // A stale translation given back unchanged was looked at and still holds.\n const stale = render(config).stale.get(locale) ?? new Map<string, StaleTranslation>();\n const kept = unchanged.filter((key) => stale.has(key));\n const { catalog } = generate(config, { accept: new Map([[locale, new Set(kept)]]) });\n out(\n `prosebook: imported ${written.length} translation(s) into ${locale}${kept.length > 0 ? `, and accepted ${kept.length} stale one(s) as still right` : ''}`,\n );\n const imported = new Set(written);\n printFindings(\n config,\n lint(\n catalog.messages.filter((m) => imported.has(m.key)),\n config,\n ).filter((f) => f.locale === locale),\n );\n }\n if (problems.length === 0) return 0;\n err(`\\n${problems.length} left out: fix them, or hand these lines back to the model, and import again.`);\n return 1;\n}\n\nfunction runScan(config: ResolvedConfig, strict: boolean, report?: SarifReport): number {\n const { catalog } = render(config);\n const result = scan(config.scan.dirs, config.scan.extensions, config.scan.attributes, config.root, [config.out]);\n for (const h of result.hardcoded)\n err(`${h.file}:${h.line}:${h.column} hardcoded ${h.where === 'text' ? 'text' : `${h.where}=`} \"${h.text}\"`);\n const unused = catalog.messages.filter((m) => !isReferenced(m.key, result.refs));\n for (const m of unused) err(`${m.file} ${m.key}: no code reads this key`);\n if (report !== undefined) {\n const level = strict ? 'error' : 'warning';\n const locate = entryLocator(config.root);\n report.rule('hardcoded-text', RULES['hardcoded-text']);\n report.rule('unused-key', RULES['unused-key']);\n for (const h of result.hardcoded) {\n const what = `${h.where === 'text' ? '' : `${h.where}=`}\"${h.text}\"`;\n const message = `${what} is hardcoded: move it into the catalog with \\`prosebook extract\\`, or mark the line \\`prosebook-ignore\\``;\n report.add({ rule: 'hardcoded-text', level, message, file: h.file, line: h.line, column: h.column });\n }\n for (const m of unused)\n report.add({ rule: 'unused-key', level, message: `no code reads ${m.key}: remove it`, file: m.file, ...locate(m.file, m.key) });\n }\n out(\n `prosebook: scanned ${result.files} file(s): ${result.hardcoded.length} hardcoded string(s), ${unused.length} unused key(s)` +\n (result.hardcoded.length > 0\n ? '. `prosebook extract` moves the text into the catalog; mark a deliberate line `prosebook-ignore`.'\n : ''),\n );\n return strict && result.hardcoded.length + unused.length > 0 ? 1 : 0;\n}\n\nasync function runExtract(config: ResolvedConfig, paths: string[], write: boolean, area: string | undefined): Promise<number> {\n const targets = paths.length > 0 ? paths.map((p) => resolve(config.root, p)) : config.scan.dirs;\n const files = sourceFiles(targets, ['.tsx', '.jsx'], [config.out]).concat(targets.filter((t) => /\\.[jt]sx$/.test(t) && existsSync(t)));\n const plan = await planExtract(config, [...new Set(files)], { area });\n const extractions = plan.files.flatMap((f) => f.extractions);\n for (const x of extractions) {\n out(`${x.file}:${x.line}:${x.column} ${x.where === 'text' ? '' : `${x.where}=`}\"${x.message}\"`);\n out(` → ${x.key}${x.reused ? ' (already in the catalog)' : ''}: ${x.replacement.trim()}`);\n }\n for (const f of plan.files) for (const w of f.warnings) err(`warn ${w}`);\n if (extractions.length === 0) {\n out('prosebook: no hardcoded text to extract');\n return 0;\n }\n const changedFiles = plan.files.filter((f) => f.edits.length > 0).length;\n const areas = [...new Set(plan.entries.map((e) => e.area))].map((a) => `${a}.yaml`);\n const summary = `${extractions.length} string(s) in ${changedFiles} file(s), ${plan.entries.length} new entr${plan.entries.length === 1 ? 'y' : 'ies'}${areas.length > 0 ? ` in ${areas.join(', ')}` : ''}`;\n out(`\nPlaceholder types: ${plan.types === 'syntax' ? 'read from the code alone (no TypeScript 7 project found)' : `from ${plan.types}`}.`);\n if (!write) {\n out(`prosebook: would extract ${summary}. Run again with --write to apply.`);\n return 0;\n }\n applyExtract(config, plan);\n out(`\nprosebook: extracted ${summary}.`);\n out('The new entries are marked `TODO(prosebook extract)`: check each key, kind, context and argument, then run `prosebook lint`.');\n return runGenerate(config, false);\n}\n\nfunction runMigrate(config: ResolvedConfig, target: string | undefined, write: boolean): number {\n const to = target === '1' ? 1 : target === '2' ? 2 : undefined;\n if (to === undefined) {\n err('Usage: prosebook migrate <1|2> [--write]');\n return 1;\n }\n if (config.messageFormat === to) {\n out(`prosebook: the catalog is already in ${SYNTAX_NAME[to]}`);\n return 0;\n }\n const plan = planMigrate(config, to);\n const where = (x: { file: string; key: string; locale: string }) =>\n `${x.file} ${x.key}${x.locale === config.source ? '' : ` (${x.locale})`}`;\n for (const r of plan.rewrites) out(`${where(r)}\\n ${r.after.replaceAll('\\n', '\\n ')}`);\n for (const c of plan.changed) err(`warn ${where(c)}: renders differently for ${c.values}: \"${c.before}\" becomes \"${c.after}\"`);\n for (const b of plan.blocked) err(`error ${where(b)}: ${b.reason}`);\n if (plan.blocked.length > 0) {\n err(`\nprosebook: ${plan.blocked.length} message(s) have no ${SYNTAX_NAME[to]} equivalent. Change them, then migrate again; nothing was written.`);\n return 1;\n }\n const files = new Set(plan.rewrites.map((r) => r.file)).size;\n const summary = `${plan.rewrites.length} message(s) in ${files} file(s) in ${SYNTAX_NAME[to]}`;\n if (!write) {\n out(`\nprosebook: would rewrite ${summary}. Run again with --write to apply.`);\n return 0;\n }\n applyMigrate(config, plan);\n out(`\nprosebook: rewrote ${summary}.`);\n out(`Now set \\`messageFormat: ${to}\\` in the config, then run \\`prosebook generate\\`.`);\n return 0;\n}\n\nconst SAMPLE_CONFIG = `import { defineConfig } from 'prosebook/config';\n\nexport default defineConfig({\n catalog: 'copy/catalog',\n locales: 'copy/locales',\n out: 'src/copy',\n source: 'en',\n // Write messages in Unicode MessageFormat 2 rather than ICU MessageFormat:\n // messageFormat: 2,\n});\n`;\n\nconst SAMPLE_CATALOG = `# yaml-language-server: $schema=./catalog.schema.json\napp.title:\n kind: name\n surface: title\n context: The app's name, in the window title and the header.\n en: My app\n\napp.greeting:\n kind: state\n surface: status\n context: Greets the person signed in, at the top of the home page.\n args:\n name: the person's first name\n en: Welcome back, {name}.\n`;\n\nfunction init(root: string): number {\n const configured = CONFIG_FILES.find((f) => existsSync(join(root, f)));\n if (configured === undefined) {\n writeFileSync(join(root, 'prosebook.config.ts'), SAMPLE_CONFIG);\n out('created prosebook.config.ts');\n }\n const catalogDir = join(root, 'copy', 'catalog');\n if (!existsSync(catalogDir)) {\n mkdirSync(catalogDir, { recursive: true });\n mkdirSync(join(root, 'copy', 'locales'), { recursive: true });\n writeFileSync(join(catalogDir, 'app.yaml'), SAMPLE_CATALOG);\n out('created copy/catalog/app.yaml');\n }\n out('\\nNext: `prosebook generate`, then `createCopy(catalog)` from the generated src/copy.');\n return 0;\n}\n\nmain(process.argv.slice(2)).then(\n (code) => process.exit(code),\n (e: unknown) => {\n err(e instanceof Error ? (e.stack ?? e.message) : String(e));\n process.exit(1);\n },\n);\n"],"mappings":";;;;;;;;;;;;;;AAuBA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6Bb,MAAM,iBAAiB;CAAC;CAAQ;CAAQ;CAAU;AAAO;;AAGzD,MAAM,QAAQ;CACZ,SAAS;CACT,eAAe;CACf,uBAAuB;CACvB,qBAAqB;CACrB,kBAAkB;CAClB,cAAc;CACd,OAAO;AACT;;AAGA,IAAI,OAAO,IAAI,OAAO,QAAQ,OAAO,MAAM,GAAG,EAAE,GAAG;AACnD,MAAM,OAAO,IAAI,OAAO,QAAQ,OAAO,MAAM,GAAG,EAAE,GAAG;AAErD,eAAe,KAAK,MAAiC;CACnD,MAAM,EAAE,QAAQ,gBAAgB,UAAU;EACxC,MAAM;EACN,kBAAkB;EAClB,SAAS;GACP,MAAM,EAAE,MAAM,SAAS;GACvB,OAAO,EAAE,MAAM,UAAU;GACzB,OAAO,EAAE,MAAM,UAAU;GACzB,QAAQ,EAAE,MAAM,UAAU;GAC1B,SAAS,EAAE,MAAM,UAAU;GAC3B,KAAK,EAAE,MAAM,UAAU;GACvB,OAAO,EAAE,MAAM,UAAU;GACzB,KAAK,EAAE,MAAM,UAAU;GACvB,QAAQ,EAAE,MAAM,UAAU;GAC1B,MAAM,EAAE,MAAM,SAAS;GACvB,QAAQ,EAAE,MAAM,SAAS;GACzB,MAAM;IAAE,MAAM;IAAW,OAAO;GAAI;EACtC;CACF,CAAC;CACD,MAAM,CAAC,SAAS,GAAG,QAAQ;CAC3B,IAAI,OAAO,QAAQ,YAAY,KAAA,GAAW;EACxC,IAAI,IAAI;EACR,OAAO;CACT;CACA,IAAI,OAAO,WAAW,KAAA,KAAa,OAAO,WAAW,UAAU,OAAO,WAAW,SAAS;EACxF,IAAI,8CAA8C,OAAO,OAAO,EAAE;EAClE,OAAO;CACT;CACA,MAAM,SAAS,OAAO,WAAW,UAAU,IAAI,YAAY,IAAI,KAAA;CAC/D,IAAI,WAAW,KAAA,GAAW;EACxB,IAAI,CAAC,eAAe,SAAS,OAAO,GAAG;GACrC,IAAI,wCAAwC,eAAe,KAAK,IAAI,GAAG;GACvE,OAAO;EACT;EACA,MAAM;CACR;CACA,MAAM,OAAO,OAAO,QAAQ,QAAQ,IAAI;CACxC,IAAI,YAAY,QAAQ,OAAO,KAAK,IAAI;CACxC,MAAM,SAAS,MAAM,WAAW,IAAI;CACpC,IAAI;CACJ,IAAI;EACF,QAAQ,SAAR;GACE,KAAK;GACL,KAAK;IACH,IAAI,OAAO,OAAO,OAAO,UAAU,MAAM;IACzC,OAAO,YAAY,QAAQ,OAAO,UAAU,IAAI;GAClD,KAAK;IACH,OAAO,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,IAAI;IAClD;GACF,KAAK;IACH,OAAO,UAAU,QAAQ,OAAO,WAAW,MAAM,OAAO,YAAY,MAAM,MAAM;IAChF;GACF,KAAK,UACH,OAAO,UAAU,QAAQ,MAAM,OAAO,QAAQ,IAAI;GACpD,KAAK,QACH,OAAO,QAAQ,QAAQ,KAAK,IAAI,OAAO,WAAW,IAAI;GACxD,KAAK,UACH,OAAO,UAAU,QAAQ,KAAK,IAAI,KAAK,EAAE;GAC3C,KAAK;IACH,OAAO,QAAQ,QAAQ,OAAO,WAAW,MAAM,MAAM;IACrD;GACF,KAAK,WACH,OAAO,WAAW,QAAQ,MAAM,OAAO,UAAU,MAAM,OAAO,IAAI;GACpE,KAAK,WACH,OAAO,WAAW,QAAQ,KAAK,IAAI,OAAO,UAAU,IAAI;GAC1D,KAAK;IAEH,OAAO;KADU,YAAY,QAAQ,MAAM,MAAM;KAAG,QAAQ,QAAQ,MAAM;KAAG,UAAU,QAAQ,MAAM,OAAO,MAAM;IACrG,CAAC,CAAC,MAAM,MAAM,MAAM,CAAC,IAAI,IAAI;IAC1C;GAEF;IACE,IAAI,0BAA0B,QAAQ,IAAI;IAC1C,IAAI,IAAI;IACR,OAAO;EACX;CACF,SAAS,GAAG;EACV,IAAI,EAAE,aAAa,eAAe,MAAM;EACxC,eAAe,QAAQ,EAAE,UAAU,MAAM;EACzC,IAAI,KAAK,EAAE,SAAS,QAAQ,MAAM,EAAE,aAAa,OAAO,CAAC,CAAC,OAAO,0BAA0B;EAC3F,OAAO;CACT;CACA,IAAI,WAAW,KAAA,GAAW,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,OAAO,OAAO,OAAO,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,EAAE,GAAG;CACjH,OAAO;AACT;AAEA,SAAS,OAAO;CACd,MAAM,MAAM,KAAK,MAAM,aAAa,IAAI,IAAI,mBAAmB,YAAY,GAAG,GAAG,MAAM,CAAC;CACxF,OAAO;EAAE,MAAM;EAAa,SAAS,IAAI;EAAS,gBAAgB,IAAI;CAAS;AACjF;AAEA,SAAS,eAAe,QAAwB,UAAqB,QAAsB;CACzF,KAAK,MAAM,KAAK,UAAU,IAAI,GAAG,EAAE,aAAa,UAAU,UAAU,QAAQ,GAAG,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS;CACzG,IAAI,WAAW,KAAA,GAAW;CAC1B,MAAM,SAAS,aAAa,OAAO,IAAI;CACvC,OAAO,KAAK,WAAW,MAAM,OAAO;CACpC,KAAK,MAAM,KAAK,UACd,OAAO,IAAI;EACT,MAAM;EACN,OAAO,EAAE,aAAa,UAAU,UAAU;EAC1C,SAAS,EAAE;EACX,MAAM,EAAE;EACR,GAAI,EAAE,SAAS,KAAA,KAAa,EAAE,QAAQ,KAAA,IAAY,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAC7E,CAAC;AAEL;AAEA,SAAS,IAAI,QAAwB,MAAc;CACjD,OAAO,SAAS,OAAO,MAAM,IAAI,CAAC,CAAC,WAAW,MAAM,GAAG;AACzD;AAEA,SAAS,YAAY,QAAwB,OAAgB,QAA8B;CACzF,MAAM,EAAE,SAAS,SAAS,UAAU,SAAS,QAAQ,EAAE,MAAM,CAAC;CAC9D,eAAe,QAAQ,QAAQ,UAAU,MAAM;CAC/C,MAAM,aAAa,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,QAAQ,GAAG,MAAM,IAAI,EAAE,MAAM,CAAC;CACrE,MAAM,UAAU,GAAG,QAAQ,SAAS,OAAO,aAAa,QAAQ,QAAQ,SAAS,EAAE,YAAY,aAAa,IAAI,KAAK,WAAW,yBAAyB;CACzJ,IAAI,OAAO;EACT,IAAI,QAAQ,WAAW,GAAG;GACxB,IAAI,8CAA8C,QAAQ,EAAE;GAC5D,OAAO;EACT;EACA,IAAI,0DAA0D,QAAQ,KAAK,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,GAAG;EAC/G,QAAQ,KAAK,eAAe,MAAM,cAAc;EAChD,KAAK,MAAM,KAAK,SACd,QAAQ,IAAI;GAAE,MAAM;GAAe,OAAO;GAAS,SAAS;GAAyC,MAAM,IAAI,QAAQ,CAAC;EAAE,CAAC;EAC7H,OAAO;CACT;CACA,IAAI,cAAc,QAAQ,WAAW,IAAI,oBAAoB,SAAS,QAAQ,OAAO,UAAU,IAAI,QAAQ,EAAE;CAC7G,OAAO;AACT;AAEA,SAAS,UAAU,QAAyC;CAC1D,MAAM,mBAAmB;EACvB,IAAI;GACF,YAAY,QAAQ,KAAK;EAC3B,SAAS,GAAG;GACV,IAAI,aAAa,cAAc,eAAe,QAAQ,EAAE,QAAQ;QAC3D,IAAI,OAAO,CAAC,CAAC;EACpB;CACF;CACA,WAAW;CACX,aAAa,QAAQ,UAAU;CAC/B,IAAI,6CAA6C;CACjD,OAAO,IAAI,cAAc,CAAC,CAAC;AAC7B;AAEA,SAAS,QAAQ,QAAwB,QAAsB,MAAM,OAAe;CAClF,IAAI,EAAE,YAAY,OAAO,MAAM;CAC/B,IAAI,WAAW,KAAK,QAAQ,UAAU,MAAM;CAC5C,IAAI,KAAK;EACP,MAAM,EAAE,OAAO,aAAa,WAAW,QAAQ,SAAS,QAAQ;EAChE,IAAI,SAAS,SAAS,GAAG;GACvB,eAAe,QAAQ,UAAU,MAAM;GACvC,IAAI,4DAA4D;GAChE,OAAO;EACT;EACA,IAAI,QAAQ,GAAG;GACb,IAAI,oBAAoB,MAAM,oDAAoD;GAClF,CAAC,CAAE,WAAY,OAAO,MAAM;GAC5B,WAAW,KAAK,QAAQ,UAAU,MAAM;EAC1C;CACF;CACA,MAAM,SAAS,cAAc,QAAQ,QAAQ;CAC7C,IAAI,WAAW,KAAA,GAAW;EACxB,KAAK,MAAM,CAAC,MAAM,EAAE,WAAW,OAAO,QAAQ,OAAO,KAAK,KAAK,GAAG,OAAO,KAAK,MAAM,KAAK,WAAW;EACpG,OAAO,KAAK,SAAS,MAAM,KAAK;EAChC,KAAK,MAAM,KAAK,QACd,OAAO,IAAI;GACT,MAAM,EAAE;GACR,OAAO,EAAE,aAAa,UAAU,UAAU;GAC1C,SAAS,GAAG,EAAE,IAAI,IAAI,EAAE;GACxB,MAAM,EAAE;GACR,MAAM,EAAE;GACR,QAAQ,EAAE;EACZ,CAAC;CAEL;CACA,MAAM,SAAS,SAAS,QAAQ,MAAM,EAAE,aAAa,OAAO,CAAC,CAAC;CAC9D,MAAM,UAAU,SAAS,QAAQ,MAAM,EAAE,QAAQ,KAAA,CAAS,CAAC,CAAC;CAC5D,IAAI,SAAS,WAAW,GACtB,IAAI,cAAc,QAAQ,SAAS,OAAO,iCAAiC;MACtE;EACL,IACE,KAAK,OAAO,aAAa,SAAS,SAAS,OAAO,mGACpD;EACA,IAAI,UAAU,GAAG,IAAI,GAAG,QAAQ,iDAAiD;CACnF;CACA,OAAO,SAAS,IAAI,IAAI;AAC1B;;AAGA,SAAS,cAAc,QAAwB,UAAqB;CAClE,MAAM,SAAS,aAAa,OAAO,IAAI;CACvC,MAAM,SAAS,SAAS,KAAK,OAAO;EAAE,GAAG;EAAG,GAAG,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,OAAO,OAAO,MAAM;CAAE,EAAE;CACnG,KAAK,MAAM,KAAK,QAAQ;EACtB,MAAM,WAAW,EAAE,aAAa,UAAU,UAAU;EACpD,IAAI,GAAG,SAAS,GAAG,EAAE,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,OAAO,GAAG,EAAE,IAAI,KAAK,EAAE,KAAK,IAAI,EAAE,UAAU,EAAE,QAAQ,KAAA,IAAY,KAAK,cAAc;CAChI;CACA,OAAO;AACT;AAEA,SAAS,YAAY,SAAkB,QAA0B;CAC/D,OAAO,QAAQ,SAAS,QAAQ,MAAM,CAAC,EAAE,aAAa,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,GAAG;AACrF;AAEA,SAAS,UAAU,QAAwB,QAAiB,SAAkB,QAA8B;CAC1G,MAAM,EAAE,SAAS,UAAU,OAAO,MAAM;CACxC,IAAI,WAAW,KAAA,GAAW,aAAa,QAAQ,SAAS,OAAO,SAAS,UAAU,WAAW,MAAM;CACnG,MAAM,QAAQ,QAAQ,SAAS;CAC/B,IAAI,QAAQ,QAAQ,WAAW,GAAG;EAChC,IAAI,cAAc,MAAM,eAAe,OAAO,OAAO,sBAAsB;EAC3E,OAAO;CACT;CACA,IAAI,aAAa;CACjB,IAAI,GAAG,SAAS,OAAO,EAAE,EAAE,GAAG,aAAa,SAAS,EAAE,EAAE,GAAG,UAAU,SAAS,CAAC,EAAE,GAAG,QAAQ,SAAS,CAAC,GAAG;CACzG,KAAK,MAAM,UAAU,QAAQ,SAAS;EACpC,MAAM,UAAU,YAAY,SAAS,MAAM;EAC3C,MAAM,YAAY,MAAM,IAAI,MAAM,qBAAK,IAAI,IAA8B;EACzE,MAAM,YAAY,CAAC,GAAG,UAAU,KAAK,CAAC;EACtC,MAAM,OAAO,QAAQ,QAAQ;EAC7B,IAAI,QAAQ,SAAS,KAAK,UAAU,SAAS,GAAG,aAAa;EAC7D,MAAM,MAAM,UAAU,IAAI,MAAM,KAAK,MAAO,OAAO,QAAS,GAAG;EAC/D,IACE,GAAG,OAAO,OAAO,EAAE,EAAE,GAAG,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,CAAC,CAAC,SAAS,CAAC,EAAE,GAAG,SAAS,EAAE,EAAE,GAAG,OAAO,QAAQ,MAAM,CAAC,CAAC,SAAS,CAAC,EAAE,GAAG,OAAO,UAAU,MAAM,CAAC,CAAC,SAAS,CAAC,GAClK;EACA,IAAI,SAAS;GACX,KAAK,MAAM,OAAO,SAAS,IAAI,aAAa,KAAK;GACjD,KAAK,MAAM,CAAC,KAAK,MAAM,WAAW,IAAI,aAAa,IAAI,IAAI,SAAS,CAAC,GAAG;EAC1E;CACF;CACA,IAAI,cAAc,CAAC,SACjB,IAAI,0GAA0G;CAChH,OAAO,UAAU,aAAa,IAAI;AACpC;AAEA,SAAS,aACP,QACA,SACA,OACA,OACA,QACA;CACA,MAAM,SAAS,aAAa,OAAO,IAAI;CACvC,OAAO,KAAK,uBAAuB,MAAM,sBAAsB;CAC/D,OAAO,KAAK,qBAAqB,MAAM,oBAAoB;CAC3D,KAAK,MAAM,UAAU,QAAQ,SAAS;EACpC,KAAK,MAAM,KAAK,QAAQ,UAAU;GAChC,IAAI,EAAE,aAAa,IAAI,MAAM,GAAG;GAChC,MAAM,UAAU,GAAG,EAAE,IAAI,UAAU,OAAO,iCAAiC,OAAO;GAClF,OAAO,IAAI;IAAE,MAAM;IAAuB;IAAO;IAAS,MAAM,EAAE;IAAM,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG;GAAE,CAAC;EACpG;EACA,KAAK,MAAM,CAAC,KAAK,MAAM,MAAM,IAAI,MAAM,KAAK,CAAC,GAAG;GAC9C,MAAM,OAAO,QAAQ,SAAS,MAAM,MAAM,EAAE,QAAQ,GAAG,CAAC,EAAE,aAAa,IAAI,MAAM,CAAC,EAAE;GACpF,IAAI,SAAS,KAAA,GAAW;GACxB,MAAM,UAAU,OAAO,OAAO,kBAAkB,IAAI,oCAAoC,SAAS,CAAC,EAAE,sCAAsC,OAAO,GAAG,IAAI;GACxJ,OAAO,IAAI;IAAE,MAAM;IAAqB;IAAO;IAAS;IAAM,GAAG,OAAO,MAAM,GAAG;GAAE,CAAC;EACtF;CACF;AACF;AAEA,SAAS,UAAU,QAAwB,MAAgB,KAAsB;CAC/E,MAAM,CAAC,QAAQ,GAAG,QAAQ;CAC1B,IAAI,WAAW,KAAA,KAAc,KAAK,WAAW,KAAK,CAAC,KAAM;EACvD,IAAI,6EAA6E;EACjF,OAAO;CACT;CACA,MAAM,SAAS,OAAO,MAAM,CAAC,CAAC,MAAM,IAAI,MAAM,qBAAK,IAAI,IAA8B;CACrF,MAAM,YAAY,MAAM,IAAI,IAAI,OAAO,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI;CAC7D,KAAK,MAAM,OAAO,WAAW,IAAI,CAAC,OAAO,IAAI,GAAG,GAAG,IAAI,SAAS,OAAO,GAAG,IAAI,cAAc;CAC5F,SAAS,QAAQ,EAAE,wBAAQ,IAAI,IAAI,CAAC,CAAC,QAAQ,MAAM,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;CAC5E,IAAI,uBAAuB,CAAC,GAAG,SAAS,CAAC,CAAC,QAAQ,MAAM,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,qBAAqB,QAAQ;CAC3G,OAAO;AACT;AAEA,SAAS,QAAQ,QAAwB,QAA4B,QAAyB;CAC5F,IAAI,WAAW,KAAA,GAAW;EACxB,IAAI,2CAA2C;EAC/C,OAAO;CACT;CACA,MAAM,EAAE,SAAS,UAAU,OAAO,MAAM;CACxC,MAAM,OAAO,OAAO,QAAQ,SAAS,MAAM,IAAI,MAAM,qBAAK,IAAI,IAAI,GAAG,QAAQ,MAAM;CACnF,IAAI,KAAK,IAAI;CACb,IAAI,UAAU,KAAK,QAAQ,GAAG,IAAI,kEAAkE,OAAO,YAAY;CACvH,OAAO;AACT;AAEA,SAAS,UAAU,QAAwB,QAA4B,MAAkC;CACvG,IAAI,WAAW,KAAA,MAAe,SAAS,KAAA,KAAa,SAAS,QAAQ,QAAQ,MAAM,OAAQ;EACzF,IAAI,gEAAgE;EACpE,OAAO;CACT;CACA,MAAM,QAAQ,aAAa,SAAS,KAAA,KAAa,SAAS,MAAM,IAAI,QAAQ,IAAI,GAAG,MAAM;CACzF,MAAM,EAAE,SAAS,WAAW,aAAa,mBAAmB,QAAQ,QAAQ,KAAK;CACjF,eAAe,QAAQ,QAAQ;CAC/B,IAAI,QAAQ,SAAS,UAAU,SAAS,GAAG;EAEzC,MAAM,QAAQ,OAAO,MAAM,CAAC,CAAC,MAAM,IAAI,MAAM,qBAAK,IAAI,IAA8B;EACpF,MAAM,OAAO,UAAU,QAAQ,QAAQ,MAAM,IAAI,GAAG,CAAC;EACrD,MAAM,EAAE,YAAY,SAAS,QAAQ,EAAE,wBAAQ,IAAI,IAAI,CAAC,CAAC,QAAQ,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;EACnF,IACE,uBAAuB,QAAQ,OAAO,uBAAuB,SAAS,KAAK,SAAS,IAAI,kBAAkB,KAAK,OAAO,gCAAgC,IACxJ;EACA,MAAM,WAAW,IAAI,IAAI,OAAO;EAChC,cACE,QACA,KACE,QAAQ,SAAS,QAAQ,MAAM,SAAS,IAAI,EAAE,GAAG,CAAC,GAClD,MACF,CAAC,CAAC,QAAQ,MAAM,EAAE,WAAW,MAAM,CACrC;CACF;CACA,IAAI,SAAS,WAAW,GAAG,OAAO;CAClC,IAAI,KAAK,SAAS,OAAO,8EAA8E;CACvG,OAAO;AACT;AAEA,SAAS,QAAQ,QAAwB,QAAiB,QAA8B;CACtF,MAAM,EAAE,YAAY,OAAO,MAAM;CACjC,MAAM,SAAS,KAAK,OAAO,KAAK,MAAM,OAAO,KAAK,YAAY,OAAO,KAAK,YAAY,OAAO,MAAM,CAAC,OAAO,GAAG,CAAC;CAC/G,KAAK,MAAM,KAAK,OAAO,WACrB,IAAI,GAAG,EAAE,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,OAAO,aAAa,EAAE,UAAU,SAAS,SAAS,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE;CAC5G,MAAM,SAAS,QAAQ,SAAS,QAAQ,MAAM,CAAC,aAAa,EAAE,KAAK,OAAO,IAAI,CAAC;CAC/E,KAAK,MAAM,KAAK,QAAQ,IAAI,GAAG,EAAE,KAAK,GAAG,EAAE,IAAI,yBAAyB;CACxE,IAAI,WAAW,KAAA,GAAW;EACxB,MAAM,QAAQ,SAAS,UAAU;EACjC,MAAM,SAAS,aAAa,OAAO,IAAI;EACvC,OAAO,KAAK,kBAAkB,MAAM,iBAAiB;EACrD,OAAO,KAAK,cAAc,MAAM,aAAa;EAC7C,KAAK,MAAM,KAAK,OAAO,WAAW;GAEhC,MAAM,UAAU,GAAG,GADH,EAAE,UAAU,SAAS,KAAK,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,GAC1C;GACxB,OAAO,IAAI;IAAE,MAAM;IAAkB;IAAO;IAAS,MAAM,EAAE;IAAM,MAAM,EAAE;IAAM,QAAQ,EAAE;GAAO,CAAC;EACrG;EACA,KAAK,MAAM,KAAK,QACd,OAAO,IAAI;GAAE,MAAM;GAAc;GAAO,SAAS,iBAAiB,EAAE,IAAI;GAAc,MAAM,EAAE;GAAM,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG;EAAE,CAAC;CAClI;CACA,IACE,sBAAsB,OAAO,MAAM,YAAY,OAAO,UAAU,OAAO,wBAAwB,OAAO,OAAO,mBAC1G,OAAO,UAAU,SAAS,IACvB,sGACA,GACR;CACA,OAAO,UAAU,OAAO,UAAU,SAAS,OAAO,SAAS,IAAI,IAAI;AACrE;AAEA,eAAe,WAAW,QAAwB,OAAiB,OAAgB,MAA2C;CAC5H,MAAM,UAAU,MAAM,SAAS,IAAI,MAAM,KAAK,MAAM,QAAQ,OAAO,MAAM,CAAC,CAAC,IAAI,OAAO,KAAK;CAC3F,MAAM,QAAQ,YAAY,SAAS,CAAC,QAAQ,MAAM,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,OAAO,QAAQ,QAAQ,MAAM,YAAY,KAAK,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC;CACrI,MAAM,OAAO,MAAM,YAAY,QAAQ,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC;CACpE,MAAM,cAAc,KAAK,MAAM,SAAS,MAAM,EAAE,WAAW;CAC3D,KAAK,MAAM,KAAK,aAAa;EAC3B,IAAI,GAAG,EAAE,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,OAAO,IAAI,EAAE,UAAU,SAAS,KAAK,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,QAAQ,EAAE;EAC/F,IAAI,OAAO,EAAE,MAAM,EAAE,SAAS,8BAA8B,GAAG,IAAI,EAAE,YAAY,KAAK,GAAG;CAC3F;CACA,KAAK,MAAM,KAAK,KAAK,OAAO,KAAK,MAAM,KAAK,EAAE,UAAU,IAAI,SAAS,GAAG;CACxE,IAAI,YAAY,WAAW,GAAG;EAC5B,IAAI,yCAAyC;EAC7C,OAAO;CACT;CACA,MAAM,eAAe,KAAK,MAAM,QAAQ,MAAM,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC;CAClE,MAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,KAAK,QAAQ,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,GAAG,EAAE,MAAM;CAClF,MAAM,UAAU,GAAG,YAAY,OAAO,gBAAgB,aAAa,YAAY,KAAK,QAAQ,OAAO,WAAW,KAAK,QAAQ,WAAW,IAAI,MAAM,QAAQ,MAAM,SAAS,IAAI,OAAO,MAAM,KAAK,IAAI,MAAM;CACvM,IAAI;qBACe,KAAK,UAAU,WAAW,6DAA6D,QAAQ,KAAK,QAAQ,EAAE;CACjI,IAAI,CAAC,OAAO;EACV,IAAI,4BAA4B,QAAQ,mCAAmC;EAC3E,OAAO;CACT;CACA,aAAa,QAAQ,IAAI;CACzB,IAAI;uBACiB,QAAQ,EAAE;CAC/B,IAAI,8HAA8H;CAClI,OAAO,YAAY,QAAQ,KAAK;AAClC;AAEA,SAAS,WAAW,QAAwB,QAA4B,OAAwB;CAC9F,MAAM,KAAK,WAAW,MAAM,IAAI,WAAW,MAAM,IAAI,KAAA;CACrD,IAAI,OAAO,KAAA,GAAW;EACpB,IAAI,0CAA0C;EAC9C,OAAO;CACT;CACA,IAAI,OAAO,kBAAkB,IAAI;EAC/B,IAAI,wCAAwC,YAAY,KAAK;EAC7D,OAAO;CACT;CACA,MAAM,OAAO,YAAY,QAAQ,EAAE;CACnC,MAAM,SAAS,MACb,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,EAAE,WAAW,OAAO,SAAS,KAAK,KAAK,EAAE,OAAO;CACvE,KAAK,MAAM,KAAK,KAAK,UAAU,IAAI,GAAG,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,WAAW,MAAM,MAAM,GAAG;CACvF,KAAK,MAAM,KAAK,KAAK,SAAS,IAAI,SAAS,MAAM,CAAC,EAAE,4BAA4B,EAAE,OAAO,KAAK,EAAE,OAAO,aAAa,EAAE,MAAM,EAAE;CAC9H,KAAK,MAAM,KAAK,KAAK,SAAS,IAAI,SAAS,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ;CAClE,IAAI,KAAK,QAAQ,SAAS,GAAG;EAC3B,IAAI;aACK,KAAK,QAAQ,OAAO,sBAAsB,YAAY,IAAI,mEAAmE;EACtI,OAAO;CACT;CACA,MAAM,QAAQ,IAAI,IAAI,KAAK,SAAS,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;CACxD,MAAM,UAAU,GAAG,KAAK,SAAS,OAAO,iBAAiB,MAAM,cAAc,YAAY;CACzF,IAAI,CAAC,OAAO;EACV,IAAI;2BACmB,QAAQ,mCAAmC;EAClE,OAAO;CACT;CACA,aAAa,QAAQ,IAAI;CACzB,IAAI;qBACe,QAAQ,EAAE;CAC7B,IAAI,4BAA4B,GAAG,mDAAmD;CACtF,OAAO;AACT;AAEA,MAAM,gBAAgB;;;;;;;;;;;AAYtB,MAAM,iBAAiB;;;;;;;;;;;;;;;AAgBvB,SAAS,KAAK,MAAsB;CAElC,IADmB,aAAa,MAAM,MAAM,WAAW,KAAK,MAAM,CAAC,CAAC,CACvD,MAAM,KAAA,GAAW;EAC5B,cAAc,KAAK,MAAM,qBAAqB,GAAG,aAAa;EAC9D,IAAI,6BAA6B;CACnC;CACA,MAAM,aAAa,KAAK,MAAM,QAAQ,SAAS;CAC/C,IAAI,CAAC,WAAW,UAAU,GAAG;EAC3B,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;EACzC,UAAU,KAAK,MAAM,QAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;EAC5D,cAAc,KAAK,YAAY,UAAU,GAAG,cAAc;EAC1D,IAAI,+BAA+B;CACrC;CACA,IAAI,uFAAuF;CAC3F,OAAO;AACT;AAEA,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,MACzB,SAAS,QAAQ,KAAK,IAAI,IAC1B,MAAe;CACd,IAAI,aAAa,QAAS,EAAE,SAAS,EAAE,UAAW,OAAO,CAAC,CAAC;CAC3D,QAAQ,KAAK,CAAC;AAChB,CACF"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * The `prosebook` command. Each subcommand is a function of the resolved config; `check` runs the\n * ones CI needs in one go.\n */\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, extname, join, relative, resolve } from 'node:path';\nimport { parseArgs } from 'node:util';\n\nimport { watchCatalog } from './tools/bundle.ts';\nimport { CatalogError, entryLocator, SCHEMA_LINE, whereOf, type Catalog, type Problem } from './tools/catalog.ts';\nimport { CONFIG_FILES, loadConfig, type ResolvedConfig } from './tools/config.ts';\nimport { applyFixes, importTranslations } from './tools/entry.ts';\nimport { exportOf, type ExchangeFormat } from './tools/exchange.ts';\nimport { applyExtract, planExtract } from './tools/extract.ts';\nimport { generate, render } from './tools/generate.ts';\nimport { lint, type Finding } from './tools/lint.ts';\nimport { changeOf, type StaleTranslation } from './tools/lock.ts';\nimport { applyMigrate, planMigrate } from './tools/migrate.ts';\nimport { SarifReport } from './tools/sarif.ts';\nimport { isReferenced, scan, sourceFiles } from './tools/scan.ts';\nimport { SYNTAX_NAME } from './tools/syntax.ts';\nimport { todoOf } from './tools/todo.ts';\n\nconst HELP = `prosebook: every string your app shows, in one typed catalog\n\nUsage: prosebook <command> [options]\n\nCommands:\n init Create a config and a first catalog file\n generate Compile the catalog into typed modules (--check: fail if out of date, --watch)\n lint Check the messages and their translations against the writing rules\n (--fix: write the fixes the rules know, such as spellings and …)\n status Translation coverage and stale translations per locale (--strict, --verbose)\n accept <locale> [keys] Mark stale translations as still right (--all for every stale one)\n todo <locale> Print the missing and stale entries of a locale, ready to translate\n (--prompt: as a prompt for a model, saying how to reply)\n export <locale> [file] Write the entries todo lists as XLIFF 2.0 or JSON, for a translation tool\n (--all: every entry; the format from the file's extension, or --format)\n import <locale> [file] Write translations from todo's YAML filled in, a model's reply to --prompt,\n or a tool's XLIFF or JSON (stdin without a file); each is checked first,\n and one that fails is left out\n scan Find hardcoded text in JSX and catalog keys no code reads (--strict)\n extract [paths] Move hardcoded JSX text into the catalog and rewrite the code to read it\n (dry run unless --write; --area <name> puts every entry in one area)\n migrate <1|2> Rewrite the catalog and translations in ICU MessageFormat (1) or MessageFormat 2\n (dry run unless --write)\n check generate --check, lint and status --strict together, for CI\n\nOptions:\n --root <dir> Project root (default: the current directory)\n --format <text|sarif> With lint, scan, status and check: sarif writes a SARIF 2.1.0 log to stdout\n for code scanning, and the usual text to stderr\n --format <xliff|json> With export: the file's format (XLIFF by default on stdout)\n -h, --help Show this help\n`;\n\nconst SARIF_COMMANDS = ['lint', 'scan', 'status', 'check'];\nconst EXCHANGE_FORMATS: Record<string, ExchangeFormat> = { xliff: 'xliff', xlf: 'xliff', json: 'json' };\n\n/** What the checks that aren't lint rules hold the project to, for the rules in a SARIF log. */\nconst RULES = {\n catalog: 'The catalog and its translations parse, and each translation keeps the placeholders of its source.',\n 'out-of-date': 'The generated modules match the catalog: run `prosebook generate`.',\n 'missing-translation': 'Every locale translates every entry.',\n 'stale-translation': 'A translation was made from the source text as it is now.',\n 'hardcoded-text': 'Text a person reads comes from the catalog, not from a literal in JSX.',\n 'unused-key': 'Code reads every catalog key.',\n allow: \"An entry's exemption names a rule the entry breaks, and says why in a sentence.\",\n};\n\n/** Text for people. Under `--format sarif` stdout holds only the log, so this goes to stderr. */\nlet out = (s = '') => process.stdout.write(`${s}\\n`);\nconst err = (s = '') => process.stderr.write(`${s}\\n`);\n\nasync function main(argv: string[]): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n root: { type: 'string' },\n check: { type: 'boolean' },\n watch: { type: 'boolean' },\n strict: { type: 'boolean' },\n verbose: { type: 'boolean' },\n all: { type: 'boolean' },\n write: { type: 'boolean' },\n fix: { type: 'boolean' },\n prompt: { type: 'boolean' },\n area: { type: 'string' },\n format: { type: 'string' },\n help: { type: 'boolean', short: 'h' },\n },\n });\n const [command, ...rest] = positionals;\n if (values.help || command === undefined) {\n out(HELP);\n return 0;\n }\n if (command === 'export') {\n if (values.format !== undefined && EXCHANGE_FORMATS[values.format] === undefined) {\n err(`prosebook: export writes xliff or json, not \"${values.format}\"`);\n return 1;\n }\n } else if (values.format !== undefined && values.format !== 'text' && values.format !== 'sarif') {\n err(`prosebook: --format is text or sarif, not \"${values.format}\"`);\n return 1;\n }\n const report = values.format === 'sarif' ? new SarifReport() : undefined;\n if (report !== undefined) {\n if (!SARIF_COMMANDS.includes(command)) {\n err(`prosebook: --format sarif works with ${SARIF_COMMANDS.join(', ')}`);\n return 1;\n }\n out = err;\n }\n const root = values.root ?? process.cwd();\n if (command === 'init') return init(root);\n const config = await loadConfig(root);\n let code: number;\n try {\n switch (command) {\n case 'generate':\n case 'gen':\n if (values.watch) return watchMode(config);\n return runGenerate(config, values.check === true);\n case 'lint':\n code = runLint(config, report, values.fix === true);\n break;\n case 'status':\n code = runStatus(config, values.strict === true, values.verbose === true, report);\n break;\n case 'accept':\n return runAccept(config, rest, values.all === true);\n case 'todo':\n return runTodo(config, rest[0], values.prompt === true);\n case 'export':\n return runExport(config, rest[0], rest[1], values.format, values.all === true);\n case 'import':\n return runImport(config, rest[0], rest[1]);\n case 'scan':\n code = runScan(config, values.strict === true, report);\n break;\n case 'extract':\n return runExtract(config, rest, values.write === true, values.area);\n case 'migrate':\n return runMigrate(config, rest[0], values.write === true);\n case 'check': {\n const results = [runGenerate(config, true, report), runLint(config, report), runStatus(config, true, false, report)];\n code = results.some((r) => r !== 0) ? 1 : 0;\n break;\n }\n default:\n err(`prosebook: no command \"${command}\"\\n`);\n out(HELP);\n return 1;\n }\n } catch (e) {\n if (!(e instanceof CatalogError)) throw e;\n reportProblems(config, e.problems, report);\n err(`\\n${e.problems.filter((p) => p.severity === 'error').length} error(s) in the catalog.`);\n code = 1;\n }\n if (report !== undefined) process.stdout.write(`${JSON.stringify(report.toJSON(config.root, tool()), null, 2)}\\n`);\n return code;\n}\n\nfunction tool() {\n const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) as { version: string; homepage: string };\n return { name: 'prosebook', version: pkg.version, informationUri: pkg.homepage };\n}\n\nfunction reportProblems(config: ResolvedConfig, problems: Problem[], report?: SarifReport) {\n for (const p of problems) err(`${p.severity === 'error' ? 'error' : 'warn '} ${whereOf(p)}: ${p.message}`);\n if (report === undefined) return;\n const locate = entryLocator(config.root);\n report.rule('catalog', RULES.catalog);\n for (const p of problems) {\n report.add({\n rule: 'catalog',\n level: p.severity === 'error' ? 'error' : 'warning',\n message: p.message,\n file: p.file,\n ...(p.file !== undefined && p.key !== undefined ? locate(p.file, p.key) : {}),\n });\n }\n}\n\nfunction rel(config: ResolvedConfig, path: string) {\n return relative(config.root, path).replaceAll('\\\\', '/');\n}\n\nfunction runGenerate(config: ResolvedConfig, check: boolean, report?: SarifReport): number {\n const { changed, catalog, stale } = generate(config, { check });\n reportProblems(config, catalog.problems, report);\n const staleCount = [...stale.values()].reduce((n, s) => n + s.size, 0);\n const summary = `${catalog.messages.length} messages, ${catalog.locales.length + 1} locale(s)${staleCount > 0 ? `, ${staleCount} stale translation(s)` : ''}`;\n if (check) {\n if (changed.length === 0) {\n out(`prosebook: generated files are up to date (${summary})`);\n return 0;\n }\n // A catalog file is listed for its schema line, which generate adds.\n const why = (p: string) =>\n dirname(p) === config.catalog && p.endsWith('.yaml')\n ? `its first line isn't \\`${SCHEMA_LINE}\\`, so editors can't find the schema`\n : 'out of date';\n err(\n `prosebook: out of date, run \\`prosebook generate\\`:\\n ${changed.map((p) => `${rel(config, p)}${why(p) === 'out of date' ? '' : `: ${why(p)}`}`).join('\\n ')}`,\n );\n report?.rule('out-of-date', RULES['out-of-date']);\n for (const p of changed)\n report?.add({ rule: 'out-of-date', level: 'error', message: `${why(p)}: run \\`prosebook generate\\``, file: rel(config, p) });\n return 1;\n }\n out(`prosebook: ${changed.length === 0 ? 'nothing changed' : `wrote ${changed.length} file(s)`} (${summary})`);\n return 0;\n}\n\nfunction watchMode(config: ResolvedConfig): Promise<number> {\n const regenerate = () => {\n try {\n runGenerate(config, false);\n } catch (e) {\n if (e instanceof CatalogError) reportProblems(config, e.problems);\n else err(String(e));\n }\n };\n regenerate();\n watchCatalog(config, regenerate);\n out('prosebook: watching the catalog for changes');\n return new Promise(() => {});\n}\n\nfunction runLint(config: ResolvedConfig, report?: SarifReport, fix = false): number {\n let { catalog } = render(config);\n let findings = lint(catalog.messages, config);\n if (fix) {\n const { fixed, problems } = applyFixes(config, catalog, findings);\n if (problems.length > 0) {\n reportProblems(config, problems, report);\n err('The fixes would break the catalog, so nothing was written.');\n return 1;\n }\n if (fixed > 0) {\n out(`prosebook: fixed ${fixed} finding(s); run prosebook generate to compile them`);\n ({ catalog } = render(config));\n findings = lint(catalog.messages, config);\n }\n }\n const placed = printFindings(config, findings);\n if (report !== undefined) {\n for (const [name, { rule }] of Object.entries(config.lint.rules)) report.rule(name, rule.description);\n report.rule('allow', RULES.allow);\n for (const f of placed) {\n report.add({\n rule: f.rule,\n level: f.severity === 'error' ? 'error' : 'warning',\n message: `${f.key}: ${f.message}`,\n file: f.file,\n line: f.line,\n column: f.column,\n });\n }\n }\n const errors = findings.filter((f) => f.severity === 'error').length;\n const fixable = findings.filter((f) => f.fix !== undefined).length;\n if (findings.length === 0) {\n out(`prosebook: ${catalog.messages.length} messages pass the writing rules`);\n } else {\n err(\n `\\n${errors} error(s), ${findings.length - errors} warning(s). Fix the string, or add \\`allow: { <rule>: <why> }\\` where the rule is wrong about it.`,\n );\n if (fixable > 0) err(`${fixable} of them can be fixed with prosebook lint --fix.`);\n }\n return errors > 0 ? 1 : 0;\n}\n\n/** Each finding on its line, placed at its entry's words. */\nfunction printFindings(config: ResolvedConfig, findings: Finding[]) {\n const locate = entryLocator(config.root);\n const placed = findings.map((f) => ({ ...f, ...locate(f.file, f.key, f.at?.start, config.source) }));\n for (const f of placed) {\n const severity = f.severity === 'error' ? 'error' : 'warn ';\n err(`${severity} ${f.file}:${f.line}:${f.column} ${f.key}: [${f.rule}] ${f.message}${f.fix === undefined ? '' : ' (fixable)'}`);\n }\n return placed;\n}\n\nfunction missingKeys(catalog: Catalog, locale: string): string[] {\n return catalog.messages.filter((m) => !m.translations.has(locale)).map((m) => m.key);\n}\n\nfunction runStatus(config: ResolvedConfig, strict: boolean, verbose: boolean, report?: SarifReport): number {\n const { catalog, stale } = render(config);\n if (report !== undefined) reportStatus(config, catalog, stale, strict ? 'error' : 'warning', report);\n const total = catalog.messages.length;\n if (catalog.locales.length === 0) {\n out(`prosebook: ${total} messages in ${config.source}, no translations yet`);\n return 0;\n }\n let incomplete = false;\n out(`${'locale'.padEnd(10)} ${'translated'.padStart(12)} ${'missing'.padStart(8)} ${'stale'.padStart(6)}`);\n for (const locale of catalog.locales) {\n const missing = missingKeys(catalog, locale);\n const staleHere = stale.get(locale) ?? new Map<string, StaleTranslation>();\n const staleKeys = [...staleHere.keys()];\n const done = total - missing.length;\n if (missing.length > 0 || staleKeys.length > 0) incomplete = true;\n const pct = total === 0 ? 100 : Math.floor((done / total) * 100);\n out(\n `${locale.padEnd(10)} ${`${done}/${total} ${String(pct).padStart(3)}%`.padStart(12)} ${String(missing.length).padStart(8)} ${String(staleKeys.length).padStart(6)}`,\n );\n if (verbose) {\n for (const key of missing) out(` missing ${key}`);\n for (const [key, s] of staleHere) out(` stale ${key}: ${changeOf(s)}`);\n }\n }\n if (incomplete && !verbose)\n out('\\n`prosebook status --verbose` lists the keys; `prosebook todo <locale>` prints them ready to translate.');\n return strict && incomplete ? 1 : 0;\n}\n\nfunction reportStatus(\n config: ResolvedConfig,\n catalog: Catalog,\n stale: Map<string, Map<string, StaleTranslation>>,\n level: 'error' | 'warning',\n report: SarifReport,\n) {\n const locate = entryLocator(config.root);\n report.rule('missing-translation', RULES['missing-translation']);\n report.rule('stale-translation', RULES['stale-translation']);\n for (const locale of catalog.locales) {\n for (const m of catalog.messages) {\n if (m.translations.has(locale)) continue;\n const message = `${m.key} has no ${locale} translation: \\`prosebook todo ${locale}\\` prints it ready to translate`;\n report.add({ rule: 'missing-translation', level, message, file: m.file, ...locate(m.file, m.key) });\n }\n for (const [key, s] of stale.get(locale) ?? []) {\n const file = catalog.messages.find((m) => m.key === key)?.translations.get(locale)?.file;\n if (file === undefined) continue;\n const message = `the ${locale} translation of ${key} was made from an earlier source (${changeOf(s)}): update it, or \\`prosebook accept ${locale} ${key}\\` if it is still right`;\n report.add({ rule: 'stale-translation', level, message, file, ...locate(file, key) });\n }\n }\n}\n\nfunction runAccept(config: ResolvedConfig, args: string[], all: boolean): number {\n const [locale, ...keys] = args;\n if (locale === undefined || (keys.length === 0 && !all)) {\n err('Usage: prosebook accept <locale> <key>... | prosebook accept <locale> --all');\n return 1;\n }\n const before = render(config).stale.get(locale) ?? new Map<string, StaleTranslation>();\n const accepting = all ? new Set(before.keys()) : new Set(keys);\n for (const key of accepting) if (!before.has(key)) err(`warn ${locale} ${key} is not stale`);\n generate(config, { accept: new Map([[locale, all ? true : new Set(keys)]]) });\n out(`prosebook: accepted ${[...accepting].filter((k) => before.has(k)).length} translation(s) in ${locale}`);\n return 0;\n}\n\nfunction runTodo(config: ResolvedConfig, locale: string | undefined, prompt: boolean): number {\n if (locale === undefined) {\n err('Usage: prosebook todo <locale> [--prompt]');\n return 1;\n }\n const { catalog, stale } = render(config);\n const todo = todoOf(config, catalog, stale.get(locale) ?? new Map(), locale, prompt);\n out(todo.text);\n if (prompt && todo.count > 0) err(`\\nHand this to a model, save its reply, and \\`prosebook import ${locale} <reply>\\`.`);\n return 0;\n}\n\nfunction runExport(\n config: ResolvedConfig,\n locale: string | undefined,\n file: string | undefined,\n named: string | undefined,\n all: boolean,\n): number {\n if (locale === undefined) {\n err('Usage: prosebook export <locale> [file] [--all] [--format xliff|json]');\n return 1;\n }\n const format = EXCHANGE_FORMATS[named ?? (file === undefined ? 'xliff' : extname(file).slice(1).toLowerCase())];\n if (format === undefined) {\n err(`prosebook: ${file} is neither .xlf nor .json: name the format with --format xliff or --format json`);\n return 1;\n }\n const { catalog, stale } = render(config);\n const exported = exportOf(config, catalog, stale.get(locale) ?? new Map(), locale, format, all);\n if (exported.count === 0) {\n err(`prosebook: ${locale} is complete; --all exports every entry`);\n return 0;\n }\n if (file === undefined) {\n process.stdout.write(exported.text);\n return 0;\n }\n const path = resolve(file);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, exported.text);\n out(`prosebook: exported ${exported.count} entr${exported.count === 1 ? 'y' : 'ies'} for ${locale} to ${file}`);\n if (locale !== config.source) out(`Translate them, then \\`prosebook import ${locale} ${file}\\`.`);\n return 0;\n}\n\nfunction runImport(config: ResolvedConfig, locale: string | undefined, file: string | undefined): number {\n if (locale === undefined || ((file === undefined || file === '-') && process.stdin.isTTY)) {\n err('Usage: prosebook import <locale> <file>, or the reply on stdin');\n return 1;\n }\n const reply = readFileSync(file === undefined || file === '-' ? 0 : resolve(file), 'utf8');\n const { written, unchanged, problems } = importTranslations(config, locale, reply);\n reportProblems(config, problems);\n if (written.length + unchanged.length > 0) {\n // A stale translation given back unchanged was looked at and still holds.\n const stale = render(config).stale.get(locale) ?? new Map<string, StaleTranslation>();\n const kept = unchanged.filter((key) => stale.has(key));\n const { catalog } = generate(config, { accept: new Map([[locale, new Set(kept)]]) });\n out(\n `prosebook: imported ${written.length} translation(s) into ${locale}${kept.length > 0 ? `, and accepted ${kept.length} stale one(s) as still right` : ''}`,\n );\n const imported = new Set(written);\n printFindings(\n config,\n lint(\n catalog.messages.filter((m) => imported.has(m.key)),\n config,\n ).filter((f) => f.locale === locale),\n );\n }\n if (problems.length === 0) return 0;\n err(`\\n${problems.length} left out: fix them, or hand these lines back to the model, and import again.`);\n return 1;\n}\n\nfunction runScan(config: ResolvedConfig, strict: boolean, report?: SarifReport): number {\n const { catalog } = render(config);\n const result = scan(config.scan.dirs, config.scan.extensions, config.scan.attributes, config.root, [config.out]);\n for (const h of result.hardcoded)\n err(`${h.file}:${h.line}:${h.column} hardcoded ${h.where === 'text' ? 'text' : `${h.where}=`} \"${h.text}\"`);\n const unused = catalog.messages.filter((m) => !isReferenced(m.key, result.refs));\n for (const m of unused) err(`${m.file} ${m.key}: no code reads this key`);\n if (report !== undefined) {\n const level = strict ? 'error' : 'warning';\n const locate = entryLocator(config.root);\n report.rule('hardcoded-text', RULES['hardcoded-text']);\n report.rule('unused-key', RULES['unused-key']);\n for (const h of result.hardcoded) {\n const what = `${h.where === 'text' ? '' : `${h.where}=`}\"${h.text}\"`;\n const message = `${what} is hardcoded: move it into the catalog with \\`prosebook extract\\`, or mark the line \\`prosebook-ignore\\``;\n report.add({ rule: 'hardcoded-text', level, message, file: h.file, line: h.line, column: h.column });\n }\n for (const m of unused)\n report.add({ rule: 'unused-key', level, message: `no code reads ${m.key}: remove it`, file: m.file, ...locate(m.file, m.key) });\n }\n out(\n `prosebook: scanned ${result.files} file(s): ${result.hardcoded.length} hardcoded string(s), ${unused.length} unused key(s)` +\n (result.hardcoded.length > 0\n ? '. `prosebook extract` moves the text into the catalog; mark a deliberate line `prosebook-ignore`.'\n : ''),\n );\n return strict && result.hardcoded.length + unused.length > 0 ? 1 : 0;\n}\n\nasync function runExtract(config: ResolvedConfig, paths: string[], write: boolean, area: string | undefined): Promise<number> {\n const targets = paths.length > 0 ? paths.map((p) => resolve(config.root, p)) : config.scan.dirs;\n const files = sourceFiles(targets, ['.tsx', '.jsx'], [config.out]).concat(targets.filter((t) => /\\.[jt]sx$/.test(t) && existsSync(t)));\n const plan = await planExtract(config, [...new Set(files)], { area });\n const extractions = plan.files.flatMap((f) => f.extractions);\n for (const x of extractions) {\n out(`${x.file}:${x.line}:${x.column} ${x.where === 'text' ? '' : `${x.where}=`}\"${x.message}\"`);\n out(` → ${x.key}${x.reused ? ' (already in the catalog)' : ''}: ${x.replacement.trim()}`);\n }\n for (const f of plan.files) for (const w of f.warnings) err(`warn ${w}`);\n if (extractions.length === 0) {\n out('prosebook: no hardcoded text to extract');\n return 0;\n }\n const changedFiles = plan.files.filter((f) => f.edits.length > 0).length;\n const areas = [...new Set(plan.entries.map((e) => e.area))].map((a) => `${a}.yaml`);\n const summary = `${extractions.length} string(s) in ${changedFiles} file(s), ${plan.entries.length} new entr${plan.entries.length === 1 ? 'y' : 'ies'}${areas.length > 0 ? ` in ${areas.join(', ')}` : ''}`;\n out(`\nPlaceholder types: ${plan.types === 'syntax' ? 'read from the code alone (no TypeScript 7 project found)' : `from ${plan.types}`}.`);\n if (!write) {\n out(`prosebook: would extract ${summary}. Run again with --write to apply.`);\n return 0;\n }\n applyExtract(config, plan);\n out(`\nprosebook: extracted ${summary}.`);\n out('The new entries are marked `TODO(prosebook extract)`: check each key, kind, context and argument, then run `prosebook lint`.');\n return runGenerate(config, false);\n}\n\nfunction runMigrate(config: ResolvedConfig, target: string | undefined, write: boolean): number {\n const to = target === '1' ? 1 : target === '2' ? 2 : undefined;\n if (to === undefined) {\n err('Usage: prosebook migrate <1|2> [--write]');\n return 1;\n }\n if (config.messageFormat === to) {\n out(`prosebook: the catalog is already in ${SYNTAX_NAME[to]}`);\n return 0;\n }\n const plan = planMigrate(config, to);\n const where = (x: { file: string; key: string; locale: string }) =>\n `${x.file} ${x.key}${x.locale === config.source ? '' : ` (${x.locale})`}`;\n for (const r of plan.rewrites) out(`${where(r)}\\n ${r.after.replaceAll('\\n', '\\n ')}`);\n for (const c of plan.changed) err(`warn ${where(c)}: renders differently for ${c.values}: \"${c.before}\" becomes \"${c.after}\"`);\n for (const b of plan.blocked) err(`error ${where(b)}: ${b.reason}`);\n if (plan.blocked.length > 0) {\n err(`\nprosebook: ${plan.blocked.length} message(s) have no ${SYNTAX_NAME[to]} equivalent. Change them, then migrate again; nothing was written.`);\n return 1;\n }\n const files = new Set(plan.rewrites.map((r) => r.file)).size;\n const summary = `${plan.rewrites.length} message(s) in ${files} file(s) in ${SYNTAX_NAME[to]}`;\n if (!write) {\n out(`\nprosebook: would rewrite ${summary}. Run again with --write to apply.`);\n return 0;\n }\n applyMigrate(config, plan);\n out(`\nprosebook: rewrote ${summary}.`);\n out(`Now set \\`messageFormat: ${to}\\` in the config, then run \\`prosebook generate\\`.`);\n return 0;\n}\n\nconst SAMPLE_CONFIG = `import { defineConfig } from 'prosebook/config';\n\nexport default defineConfig({\n catalog: 'copy/catalog',\n locales: 'copy/locales',\n out: 'src/copy',\n source: 'en',\n // Write messages in Unicode MessageFormat 2 rather than ICU MessageFormat:\n // messageFormat: 2,\n});\n`;\n\nconst SAMPLE_CATALOG = `${SCHEMA_LINE}\napp.title:\n kind: name\n surface: title\n context: The app's name, in the window title and the header.\n en: My app\n\napp.greeting:\n kind: state\n surface: status\n context: Greets the person signed in, at the top of the home page.\n args:\n name: the person's first name\n en: Welcome back, {name}.\n`;\n\nfunction init(root: string): number {\n const configured = CONFIG_FILES.find((f) => existsSync(join(root, f)));\n if (configured === undefined) {\n writeFileSync(join(root, 'prosebook.config.ts'), SAMPLE_CONFIG);\n out('created prosebook.config.ts');\n }\n const catalogDir = join(root, 'copy', 'catalog');\n if (!existsSync(catalogDir)) {\n mkdirSync(catalogDir, { recursive: true });\n mkdirSync(join(root, 'copy', 'locales'), { recursive: true });\n writeFileSync(join(catalogDir, 'app.yaml'), SAMPLE_CATALOG);\n out('created copy/catalog/app.yaml');\n }\n out('\\nNext: `prosebook generate`, then `createCopy(catalog)` from the generated src/copy.');\n return 0;\n}\n\nmain(process.argv.slice(2)).then(\n (code) => process.exit(code),\n (e: unknown) => {\n err(e instanceof Error ? (e.stack ?? e.message) : String(e));\n process.exit(1);\n },\n);\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { d as staticLiteral, p as walk, t as TYPE } from "./icu-Dej0mNsF.js";
2
+ import { existsSync, readFileSync } from "node:fs";
2
3
  import { isAbsolute, join, resolve } from "node:path";
3
4
  import { pathToFileURL } from "node:url";
4
- import { existsSync, readFileSync } from "node:fs";
5
5
  // src/tools/lint.ts
6
6
  /** Typed plugin, for `lint.plugins`. */
7
7
  function definePlugin(plugin) {
@@ -917,7 +917,9 @@ const STRICT_LISTS = {
917
917
  const NATIVE_NAMES = {
918
918
  rust: "Locale",
919
919
  swift: "Copy",
920
- kotlin: "Copy"
920
+ kotlin: "Copy",
921
+ android: "strings",
922
+ apple: "Localizable"
921
923
  };
922
924
  /** Typed config, for `prosebook.config.ts`. */
923
925
  function defineConfig(config) {
@@ -978,10 +980,14 @@ function resolveConfig(root, config) {
978
980
  },
979
981
  native: (config.native ?? []).map((target, i) => {
980
982
  if (!(target.language in NATIVE_NAMES)) throw new Error(`native[${i}].language is "${target.language}": name one of ${Object.keys(NATIVE_NAMES).join(", ")}`);
983
+ if (target.plist !== void 0 && target.language !== "apple") throw new Error(`native[${i}].plist names an Info.plist, which only the apple target reads: remove it, or set language to 'apple'`);
984
+ const plist = target.plist === void 0 ? {} : { plist: at(target.plist) };
985
+ const name = target.name ?? (target.plist === void 0 ? NATIVE_NAMES[target.language] : "InfoPlist");
981
986
  return {
982
987
  ...target,
983
988
  out: at(target.out),
984
- name: target.name ?? NATIVE_NAMES[target.language]
989
+ name,
990
+ ...plist
985
991
  };
986
992
  }),
987
993
  scan: {
@@ -992,7 +998,9 @@ function resolveConfig(root, config) {
992
998
  ".js",
993
999
  ".jsx",
994
1000
  ".mts",
995
- ".mjs"
1001
+ ".mjs",
1002
+ ".vue",
1003
+ ".svelte"
996
1004
  ],
997
1005
  attributes: config.scan?.attributes ?? [
998
1006
  "alt",
@@ -1029,4 +1037,4 @@ function lintRules(lint) {
1029
1037
  }
1030
1038
  export { words as _, DEFAULT_KINDS as a, CORE_RULES as c, compileRule as d, definePlugin as f, singularOf as g, sentences as h, resolveConfig as i, HOLE as l, phrase as m, defineConfig as n, DEFAULT_SURFACES as o, lint as p, loadConfig as r, STRICT_LISTS as s, CONFIG_FILES as t, applyEdits as u };
1031
1039
 
1032
- //# sourceMappingURL=config-BPSmoYel.js.map
1040
+ //# sourceMappingURL=config-7T4hX_f7.js.map