Repository navigation
Commit 8293c74
refactor(lint): move the i18n translatable-key walk from the CLI into @objectstack/lint (#30375)
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} -->
_Requested by **Yibo Wang** · [project
thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBRFy5DNS3Wj4k6EK58wgcaR)_
Part of #30285
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:把「哪些翻译键存在、各自原文是什么」的遍历(`collectExpectedEntries`,2,520 行)原样从 CLI 挪进
`@objectstack/lint`,CLI 改为再导出;不改任何键、骨架或覆盖率结论。
- 为什么改:#30285 要在 Studio 里做「原文 / 译文」对照表,浏览器必须跑同一套遍历;CLI 是 Node
包,浏览器用不了,lint 已被控制台打包使用。
- 风险与回滚:纯搬移。PR 计 +879 / −682(1561 行,低于 3000
行的人工合并线,`check-governed-merges --pr 30375` 读数)。回滚即 revert 本 PR。
- 先看:`packages/lint/src/i18n-walk.ts`(重命名自
`packages/cli/src/utils/i18n-extract.ts`,看头部说明与删掉的尾部)、`packages/cli/src/utils/i18n-bundle-extract.ts`(保留的打包/序列化与再导出)、`packages/cli/test/i18n-bundle-extract-exports.pin.test.ts`(导出不变的钉测)。
- 两分钟验证:`pnpm --filter @objectstack/cli exec vitest run
test/i18n-bundle-extract-exports.pin.test.ts
test/i18n-walk-output-parity.test.ts`,预期全部通过。
- 需要你做的:无。不是受管面,也未过行数线,席位直接落地。
## What changes
`collectExpectedEntries`, the one definition of which translation keys a
stack can carry and the source text each one translates, moves from
`packages/cli/src/utils/i18n-extract.ts` to
`packages/lint/src/i18n-walk.ts`. It is exported from the
`@objectstack/lint` root together with `authorWarnedTranslationGroups`,
`humanizeFieldPath` and the `ExpectedEntry` / `ExpectedEntryOptions`
types. The point is that a browser can run the same walk the CLI runs.
The follow-up PR for #30285 builds Studio's source-to-translation table
from it.
- **Layout.** The walk keeps git's rename: `i18n-extract.ts →
lint/src/i18n-walk.ts`, 17 lines added and 618 removed in place. The
removed lines are the extract types and the tail: bundle assembly,
`extractTranslations` and serialization. That tail stays in the CLI as a
new file, `packages/cli/src/utils/i18n-bundle-extract.ts` (631 lines).
It imports the walk from `@objectstack/lint` and re-exports it, so the
CLI module offers exactly the names the old one did.
- **Importers.** 44 CLI importers (src and test) are repointed from
`i18n-extract` to `i18n-bundle-extract`, with no other edit.
`normalized-call-sites.test.ts` renames its key to the new path.
- **Ledgers and scripts.** The `action` and `view` liveness ledgers cite
the walk at its new path (4 cites). `check-i18n-walk-parity.mjs` reads
the walk source at its new path and adds it to its watch hints.
`dispatch-gates.self-test.mjs` uses the new CLI file as its specimen.
Comment-only path repoints are in `i18n-bundle-surface.mjs`,
`check-i18n-bundles.mjs` and three lint files.
- **Browser default.** In a browser the walk cannot read the liveness
ledger from disk (`resolveLivenessDir` answers null), so its default
leaves no translation group out. That is the same set the CLI leaves out
today, because the ledger warns on no translation group. A lint test
pins it, so the day a group is warned, the test fails and a browser
caller has to pass `warnedGroups`.
- **Changeset.** `@objectstack/lint`, `@objectstack/cli` and
`@objectstack/spec` patch (spec for the liveness cites).
No key, skeleton or coverage verdict changes. The walk's code moved as
is.
## Tests
- `packages/lint/src/i18n-walk.test.ts` (new): a stack with an object, a
select field with options and an app with navigation yields the expected
keys, each with its source text and `source`. A warned group is left
out. The shipped ledger warns on no translation group (the
browser-parity pin).
- `packages/cli/test/i18n-bundle-extract-exports.pin.test.ts` (new): the
CLI module's runtime exports equal the old module's 12 names exactly.
The walk functions are lint's own (`toBe`), not a copy. The six type
exports are still offered (held by type-check).
- The CLI's existing i18n suites (about 45 files) reach the walk through
the re-export unchanged.
## Acceptance notes
- **Size.** `check-governed-merges --pr 30375` puts 0 of 61 paths on the
register and reads the size from the PR object, as the queue guard does:
+879 / −682 = 1561, under the 3000-line human-merge line. The `--branch`
forecast below counts with `--no-renames` (+3382 / −3185 = 6567) and
over-reads a rename; it is not the reading the queue guard applies. lint
cannot import from cli, because cli depends on lint.
- **Stale comment cites left as they are** (comments only, no
behaviour): spec `i18n-resolver.ts` (3),
`i18n-resolver.object-list-views.test.ts`, platform-objects
`source-hash.ts`, two echo-decisions tests, cli `tsconfig.test.json` and
`test-typecheck-debt.json`. They name the old path in prose, and editing
them would widen the diff into packages this move does not otherwise
touch.
- **Gate derivation gap (not fixed here).** `check:i18n` and
`check:i18n-coverage` derive from `packages/cli/src/**` only, so a later
edit to `packages/lint/src/i18n-walk.ts` alone does not derive them
locally. CI still runs them. This PR touches `packages/cli/src`, so both
were derived and run here.
## Verification
<details><summary>lint and cli, under os-verify-lock</summary>
```
lint test :: exit 0
lint typecheck :: exit 0
cli unit :: exit 0
cli typecheck :: exit 0
VERDICT command-exit 0 · held the lock 913s (shared box)
```
</details>
<details><summary>dispatch-gates: 87 derived, 87 run, all exit 0 (--ran:
0 NOT-MEASURED, 0 UNRUN)</summary>
```
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0
node scripts/check-comment-mask-adoption.mjs :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-declaration-mirrors.mjs --self-test :: exit 0
node scripts/check-declaration-mirrors.mjs :: exit 0
node scripts/check-dev-prereqs.mjs --self-test :: exit 0
node scripts/check-dts-emitted.mjs --self-test :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-issue-citations.mjs :: exit 0
node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0
node scripts/check-plugin-teardown-shape.mjs :: exit 0
node scripts/check-self-test-wired.mjs --self-test :: exit 0
node scripts/check-self-test-wired.mjs :: exit 0
node scripts/check-self-test-workflow-commands.mjs --self-test :: exit 0
node scripts/check-self-test-workflow-commands.mjs :: exit 0
node scripts/check-whole-set-label-write.mjs --self-test :: exit 0
node scripts/check-whole-set-label-write.mjs :: exit 0
node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0
node scripts/docs-audit/check-affected-docs.mjs :: exit 0
node scripts/docs-audit/check-drift-comment.mjs :: exit 0
node scripts/pm/bare-root-worklist.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm --filter @objectstack/spec run check:empty-state :: exit 0
pnpm --filter @objectstack/spec run check:liveness :: exit 0
pnpm --filter @objectstack/spec run check:strictness-ledger :: exit 0
pnpm --filter @objectstack/spec run check:variant-docs :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:bash32-floor :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:cli-command-ids :: exit 0
pnpm check:cli-test-child-env :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:docs-transcript-drift :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:dts-closure :: exit 0
pnpm check:dual-build-cjs-loads :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:entry-guard :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:i18n :: exit 0
pnpm check:i18n-coverage :: exit 0
pnpm check:i18n-walk-parity :: exit 0
pnpm check:issue-citations :: exit 0
pnpm check:keyed-text-bounds :: exit 0
pnpm check:lean-entry-closure :: exit 0
pnpm check:logger-receiver-detach :: exit 0
pnpm check:merge-driver :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:objectql-double-limit :: exit 0
pnpm check:org-identifier :: exit 0
pnpm check:page-declaration-shape :: exit 0
pnpm check:parse-guard :: exit 0
pnpm check:platform-checklist :: exit 0
pnpm check:platform-object-tenancy-census :: exit 0
pnpm check:pm-dispatch-gates :: exit 0
pnpm check:pnpm-filter-targets :: exit 0
pnpm check:pnpm-flag-spellings :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:ratchet-remedy-authority :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:registry-log-declared :: exit 0
pnpm check:rest-log-spy-declared :: exit 0
pnpm check:scripts-symbol-anchors :: exit 0
pnpm check:slot-lookup :: exit 0
pnpm check:sourcemap-no-sources-content :: exit 0
pnpm check:system-context-census :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
```
`check-plugin-teardown-shape.mjs --self-test` first exited 3 because
this shallow clone could not read its pinned positive-control commit
(621a487). After `git fetch --depth=1 origin 621a487…` it exits 0 (48
cases). That is an environment condition, not this diff.
The 87 ran serially under os-verify-lock on a shared box (40m14s).
</details>
<details><summary>check-governed-merges --branch
claude/project-thread-eme43k (head f6ecb06)</summary>
```
governed-surface predicate: 0 of 61 path(s) hit the register
size: +3382 / -3185 over 61 file(s) (--no-renames)
HUMAN MERGE OR AUTHORIZED APPROVAL - 6567 changed line(s) > 3000
exit 3
```
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01WGufzfqCqBH59yrHmuqXH3)_
<!-- signed: domain:ui#1 · os-support-ai ·
session_01WGufzfE4V9fzZgJLrLDmMC -->
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 1013ef1 commit 8293c74
60 files changed
Lines changed: 879 additions & 682 deletions
File tree
- .changeset
- packages
- cli
- src
- commands/i18n
- utils
- test
- lint/src
- spec/liveness
- scripts
- pm
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
| 33 | + | |
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| |||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
10 | | - | |
11 | | - | |
| 10 | + | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | | - | |
| 47 | + | |
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
| 25 | + | |
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
| 23 | + | |
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| |||
0 commit comments