feat: infer autoLocalize template meta fields - #93
Conversation
There was a problem hiding this comment.
Pull request overview
This PR completes the next phase of autoLocalize by adding a unified template-based localization configuration that can generate enum name, item label, and item meta field locale keys at runtime, while also improving TypeScript inference for instance-level template-declared meta fields.
Changes:
- Add
src/auto-localize.tshelper utilities (normalize/merge config, resolve templates, detect template meta fields). - Update enum runtime + types to generate and type-infer
autoLocalize.itemTemplatemeta fields on items anditems.meta. - Add/extend tests and document the new
autoLocalizeAPI in README and Storybook guides (EN/ZH).
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| test/test-suites/localization.ts | Adds runtime coverage for global templates, instance overrides, shorthand/function templates, and enum name templates. |
| test/test-suites/interface.ts | Adds type-level assertions that instance-level template meta fields are inferred and readonly. |
| test/auto-localize.test.ts | Introduces focused unit tests for helper functions (normalization, template resolution, merge behavior, meta detection). |
| src/global-config.ts | Adds autoLocalize to global Enum.config typing. |
| src/enum.ts | Threads an OP generic through Enum/IEnum typing so instance options can drive inference (including autoLocalize meta fields). |
| src/enum-items.ts | Collects template-declared meta keys into items.meta and updates typing to include inferred template meta arrays. |
| src/enum-item.ts | Generates getters for template-declared meta fields and routes localization through autoLocalize templates. |
| src/enum-collection.ts | Applies autoLocalize.nameTemplate when resolving the enum’s display name. |
| src/auto-localize.ts | New module implementing autoLocalize config normalization/merge, template resolution, and meta-field detection. |
| README-FULL.md | Documents autoLocalize in the full English README, including merge semantics and inference guidance. |
| README-FULL.zh-CN.md | Documents autoLocalize in the full Chinese README, including legacy naming clarifications. |
| .storybook/docs-source/ApiGuide.en-US.md | Adds Storybook API guide documentation for autoLocalize (EN). |
| .storybook/docs-source/ApiGuide.zh-CN.md | Adds Storybook API guide documentation for autoLocalize (ZH). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const config = mergeAutoLocalizeConfig(resolvedOptions?.autoLocalize); | ||
| return field in (config?.itemTemplate ?? {}); |
ea03ff3 to
a51536e
Compare
|
Note
|
| Layer / File(s) | Summary |
|---|---|
Localization contracts and configuration src/auto-localize.ts, src/enum.ts, src/global-config.ts, src/extension.d.ts, src/types.ts |
Defines template types, merging and resolution helpers, metadata-field detection, global configuration, enum configuration, and item extension types. |
Enum and item localization flow src/enum-collection.ts, src/enum-item.ts, src/enum-items.ts |
Resolves enum and item templates before localization. It also exposes template-derived metadata fields and preserves raw non-localized metadata. |
Typed item and collection propagation src/enum.ts, src/enum-item.ts, src/enum-items.ts, src/enum-collection.ts |
Propagates initialization options through item, lookup, list, map, named, and metadata types. Template-derived fields are included in item and metadata typings. |
Behavior validation and usage documentation test/.auto-localize.test.ts, test/test-suites/*, .storybook/docs-source/*, README-FULL* |
Tests template resolution, global and instance overrides, generated metadata, and inferred fields. English and Chinese documentation describe the new configuration. |
Estimated code review effort: 4 (Complex) | ~45 minutes
Sequence Diagram(s)
sequenceDiagram
participant EnumConfig
participant AutoLocalizeHelpers
participant EnumCollectionClass
participant EnumItemClass
participant Localizer
EnumConfig->>AutoLocalizeHelpers: merge global and instance templates
EnumCollectionClass->>AutoLocalizeHelpers: resolve enum name template
AutoLocalizeHelpers-->>EnumCollectionClass: enum localization key
EnumCollectionClass->>Localizer: localize enum name
EnumItemClass->>AutoLocalizeHelpers: resolve item field template
AutoLocalizeHelpers-->>EnumItemClass: item localization key
EnumItemClass->>Localizer: localize item field and metadata
Possibly related PRs
- shijistar/enum-plus#96: Refines localization tests related to the auto-localization implementation.
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title clearly and concisely describes the main change: inferring metadata fields from autoLocalize templates. |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
- Create stacked PR
- Commit on current branch
🛠️ Fix failing CI checks 💡
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
feat/auto-localize-config
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
a51536e to
802744e
Compare
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/enum-item.ts (2)
21-32: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winNormalize the
EnumItemInterfacegeneric chain.
src/enum-item.ts#L21defines four type parameters, whilesrc/enum-items.ts#L610and the primitive branches pass five. KeepEnumItemInterfacewith four parameters and pass the existing label-prefix option to allitem()return branches, including the value lookup branch, so the enum item generic chain remains consistent.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/enum-item.ts` around lines 21 - 32, The generic chain is inconsistent between EnumItemInterface and item() return branches. In src/enum-item.ts lines 21-32, keep EnumItemInterface defined with four type parameters; in src/enum-items.ts lines 610-622, pass the existing label-prefix option to every item() return branch, including the value-lookup branch, so all branches consistently use the four-parameter EnumItemInterface chain.Sources: Path instructions, Linters/SAST tools
238-264: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winUse the item context discriminator.
resolveAutoLocalizeTemplaterequirestypeto be'item'or'name'. Passing the metadata field name here violates the context type, andcontext.type === 'item'is the only branch that replaces{key}, so metadata templates cannot expand{key}with this call.Proposed fix
- type: field, + type: 'item',🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/enum-item.ts` around lines 238 - 264, Update the resolveAutoLocalizeTemplate call in _localizeResource to pass the item context discriminator ('item') instead of the metadata field variable. Preserve field for selecting the template and ensure item and metadata templates can expand {key} through the item context.Sources: Path instructions, Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.storybook/docs-source/ApiGuide.en-US.md:
- Around line 342-374: The autoLocalize documentation claims unsupported
template tokens. Update the resolver logic in the auto-localization
implementation to replace the documented {item} and {field} tokens alongside
{name}, or revise this guide to document only the implemented {key} token and
remove the {field} claim; ensure the examples no longer produce literal
placeholders.
In @.storybook/docs-source/ApiGuide.zh-CN.md:
- Around line 339-371: Update the auto-localization template documentation to
match the resolver implementation around the auto-localize template handling:
either implement replacement for the documented {item} and {field} tokens, or
revise the documentation and examples to use the supported {key} token and
remove the unsupported {field} claim. Ensure all token descriptions and sample
templates consistently reflect the chosen behavior.
In `@README-FULL.md`:
- Around line 635-676: Align the autoLocalize documentation with the token
behavior implemented by the resolver near auto-localize template resolution:
either extend the resolver to replace the documented {item} and {field} tokens
while preserving existing {name} and {key} support, or revise the README
examples and descriptions to use only the currently supported tokens. Ensure the
documented description and abbr templates resolve correctly.
In `@README-FULL.zh-CN.md`:
- Around line 630-671: 使 README 中声明的占位符与运行时解析保持一致:优先更新 auto-localize 模板
resolver,使其在现有 {name} 和 {key} 基础上正确解析文档中的 {item} 与 {field},并确保示例生成对应的本地化
key;同步保留现有模板行为。
In `@src/auto-localize.ts`:
- Around line 13-21: Update the item-template context type and its callers to
use type: 'item' consistently, and add/pass a separate field: string metadata
property when the template needs the field name. Ensure
resolveAutoLocalizeTemplate receives this context shape so {key} replacement
remains active for item templates.
In `@src/enum-collection.ts`:
- Around line 127-133: The item type chain must consistently propagate OP.
Update EnumItemInterface, EnumItemClass, EnumCollectionClass, __options__, and
_ds to accept and preserve OP while retaining existing option/meta template
access; then carry OP through EnumItemsArray, IEnumItems.named, and
InheritableEnumItems.item. Apply these changes in src/enum-collection.ts lines
127-133, src/enum.ts lines 337-355, and src/enum.ts lines 435-476.
In `@src/enum-item.ts`:
- Around line 317-324: Update the autoLocalize property in EnumItemOptions to
use an item-typed localization option compatible with T extending
EnumItemInit<V>, reusing an existing item-specific type or introducing a
dedicated local type. Keep the option parameter constrained to the item type and
avoid widening it to EnumInit<K, V>.
In `@src/extension.d.ts`:
- Around line 14-25: In the Chinese documentation for the EnumItemExtension
interface, replace the incorrect phrase “类型生命扩展” with “类型声明扩展” while leaving the
rest of the comment unchanged.
In `@test/auto-localize.test.ts`:
- Around line 64-66: Update resolveAutoLocalizeTemplate so {name}, {item}, and
{field} are replaced with empty values when their context is absent, while
preserving existing supported-token behavior. In
test/auto-localize.test.ts:64-66, retain the expectation; in
test/test-suites/localization.ts:723-758 and 761-789, resolve {item} before
global label/abbr localization and instance overrides. Update
.storybook/docs-source/ApiGuide.en-US.md:342-374,
.storybook/docs-source/ApiGuide.zh-CN.md:339-371, README-FULL.md:635-676, and
README-FULL.zh-CN.md:630-671 to document only supported tokens and align
examples and callback-token guidance with the resolver.
---
Outside diff comments:
In `@src/enum-item.ts`:
- Around line 21-32: The generic chain is inconsistent between EnumItemInterface
and item() return branches. In src/enum-item.ts lines 21-32, keep
EnumItemInterface defined with four type parameters; in src/enum-items.ts lines
610-622, pass the existing label-prefix option to every item() return branch,
including the value-lookup branch, so all branches consistently use the
four-parameter EnumItemInterface chain.
- Around line 238-264: Update the resolveAutoLocalizeTemplate call in
_localizeResource to pass the item context discriminator ('item') instead of the
metadata field variable. Preserve field for selecting the template and ensure
item and metadata templates can expand {key} through the item context.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 2003b852-9168-47b6-ad7f-0eacfad91857
📒 Files selected for processing (14)
.storybook/docs-source/ApiGuide.en-US.md.storybook/docs-source/ApiGuide.zh-CN.mdREADME-FULL.mdREADME-FULL.zh-CN.mdsrc/auto-localize.tssrc/enum-collection.tssrc/enum-item.tssrc/enum-items.tssrc/enum.tssrc/extension.d.tssrc/global-config.tstest/auto-localize.test.tstest/test-suites/interface.tstest/test-suites/localization.ts
| ## ⚙️ autoLocalize | ||
|
|
||
| `{ nameTemplate?: string | Function, itemTemplate?: Record<string, string | Function> }` | ||
|
|
||
| 自动为枚举名称、枚举项标签和枚举项元数据字段生成本地化 key。这是新的统一配置方式。旧的 `labelPrefix`、`autoLabel`、`autoLocalizeMeta` 仍继续兼容。 | ||
|
|
||
| ```ts | ||
| Enum.config.autoLocalize = { | ||
| nameTemplate: 'enum.{name}.name', | ||
| itemTemplate: { | ||
| label: 'enum.{name}.{item}.label', | ||
| description: 'enum.{name}.{item}.description', | ||
| }, | ||
| }; | ||
|
|
||
| const WeekEnum = Enum( | ||
| { Sunday: { value: 0 }, Monday: { value: 1 } }, | ||
| { | ||
| name: 'week', | ||
| autoLocalize: { | ||
| itemTemplate: { abbr: 'enum.{name}.{item}.abbr' }, | ||
| }, | ||
| }, | ||
| ); | ||
|
|
||
| WeekEnum.named.Sunday.description; // localize('enum.week.Sunday.description') | ||
| WeekEnum.named.Sunday.abbr; // localize('enum.week.Sunday.abbr') | ||
| WeekEnum.items.meta.description; // string[] | ||
| ``` | ||
|
|
||
| 模板支持 `{name}`、`{item}`、`{field}`。实例级 item templates 会和全局 templates 按字段合并,并覆盖同名字段。模板声明的元数据字段即使没有出现在原始枚举项中,也会自动生成。TypeScript 类型推导建议使用实例级字面量模板字段。 | ||
|
|
||
| > `autoLocalizeMeta` 仍然是正确的旧 API 名称。`autoLocalizedMeta` 和 `!abbr` 排除语法均不支持。 |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Document the implemented template tokens.
此文档说明支持 {item} 和 {field}。src/auto-localize.ts:96-119 只替换 {name} 和 {key}。示例中的 {item} 会保留为字面量。
请让 resolver 支持文档中的占位符,或者改为说明 {key} 并删除 {field} 的说明。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.storybook/docs-source/ApiGuide.zh-CN.md around lines 339 - 371, Update the
auto-localization template documentation to match the resolver implementation
around the auto-localize template handling: either implement replacement for the
documented {item} and {field} tokens, or revise the documentation and examples
to use the supported {key} token and remove the unsupported {field} claim.
Ensure all token descriptions and sample templates consistently reflect the
chosen behavior.
| /** | ||
| * **EN:** Enum global localization extension | ||
| * - **EN:** Add global extension field definitions for enumeration items. It can be used to add | ||
| * type definitions for fields globally added to `Enum.config.autoLocalize`. | ||
| * - **CN:** 为枚举项添加全局扩展字段定义。可以用来为`Enum.config.autoLocalize`全局添加的字段,添加类型生命扩展。 | ||
| * | ||
| * **CN:** 枚举本地化的全局扩展 | ||
| * @template {extends EnumInit<K, V>} T - The type of the enumeration | ||
| * @template {extends EnumKey<T> = EnumKey<T>} K - The key type of the enumeration | ||
| * @template {extends EnumValue = ValueTypeFromSingleInit<T[K], K>} V - The value type of the | ||
| * enumeration | ||
| */ | ||
| // eslint-disable-next-line @typescript-eslint/no-empty-interface, @typescript-eslint/no-unused-vars | ||
| interface EnumItemExtension<T, K, V> {} |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the Chinese type-extension wording.
Replace 类型生命扩展 with 类型声明扩展.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/extension.d.ts` around lines 14 - 25, In the Chinese documentation for
the EnumItemExtension interface, replace the incorrect phrase “类型生命扩展” with
“类型声明扩展” while leaving the rest of the comment unchanged.
| test('resolves string templates without optional context values', () => { | ||
| expect(resolveAutoLocalizeTemplate('{name}.{item}.{field}', { type: 'label' })).toBe('..label'); | ||
| }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Implement the documented template placeholder contract.
src/auto-localize.ts:96-119 replaces {name} only when a name exists and replaces {key} only for an item context. It does not replace {item} or {field}. The new helper test therefore fails, runtime templates generate incorrect keys, and all four documentation pages describe unsupported behavior.
test/auto-localize.test.ts#L64-L66: retain this expectation only after the resolver replaces missing{name},{item}, and{field}values.test/test-suites/localization.ts#L723-L758: resolve{item}before localizing the globallabelandabbrkeys.test/test-suites/localization.ts#L761-L789: resolve{item}before applying the instance override..storybook/docs-source/ApiGuide.en-US.md#L342-L374: document only tokens that the resolver supports..storybook/docs-source/ApiGuide.zh-CN.md#L339-L371: document only tokens that the resolver supports.README-FULL.md#L635-L676: align examples and callback-token documentation with the resolver.README-FULL.zh-CN.md#L630-L671: align examples and callback-token documentation with the resolver.
📍 Affects 6 files
test/auto-localize.test.ts#L64-L66(this comment)test/test-suites/localization.ts#L723-L758test/test-suites/localization.ts#L761-L789.storybook/docs-source/ApiGuide.en-US.md#L342-L374.storybook/docs-source/ApiGuide.zh-CN.md#L339-L371README-FULL.md#L635-L676README-FULL.zh-CN.md#L630-L671
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/auto-localize.test.ts` around lines 64 - 66, Update
resolveAutoLocalizeTemplate so {name}, {item}, and {field} are replaced with
empty values when their context is absent, while preserving existing
supported-token behavior. In test/auto-localize.test.ts:64-66, retain the
expectation; in test/test-suites/localization.ts:723-758 and 761-789, resolve
{item} before global label/abbr localization and instance overrides. Update
.storybook/docs-source/ApiGuide.en-US.md:342-374,
.storybook/docs-source/ApiGuide.zh-CN.md:339-371, README-FULL.md:635-676, and
README-FULL.zh-CN.md:630-671 to document only supported tokens and align
examples and callback-token guidance with the resolver.
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
test/test-suites/enum-items.ts (1)
184-208: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAssert the configured
ssmetadata behavior.Lines 184-190 add an
sstemplate, but the test never reads or searches that field. A broken template propagation path would still pass.Assert the generated item field, the
items.meta.sscollection, andfindBy('ss', ...). Replace the incomplete comment on Line 208 with the assertion.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/test-suites/enum-items.ts` around lines 184 - 208, Extend the enum-items test for compactWeekEnum to validate the configured ss metadata: assert the generated item ss value, the items.meta.ss collection, and findBy('ss', ...) behavior. Replace the trailing “compactWeekEnum.named.Friday” comment with these assertions, using the expected Friday metadata and undefined behavior for an invalid value as appropriate.test/test-suites/localization.ts (1)
732-788: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winReset global template configuration in
finally.If an assertion fails, Lines 757 and 787 do not run.
Enum.config.templatesthen leaks into later tests and can create unrelated failures.Wrap each assertion callback in
try/finallyand resetEnum.config.templatesin thefinallyblock.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/test-suites/localization.ts` around lines 732 - 788, Update both assertion callbacks in the localization tests to wrap their expectations in try/finally blocks, and move the Enum.config.templates reset into each finally block. Ensure the global template configuration is cleared whether assertions pass or throw.test/test-suites/interface.ts (1)
109-115: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winMake enum item metadata fields readonly in
EnumItemInterface.
EnumItemInterfacemaps template fields as mutable strings, so this assignment currently passes the type check even though template-derived metadata is read-only on frozen enum items. Change the mapped field toreadonlyand add@ts-expect-errorto the assignment guard.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/test-suites/interface.ts` around lines 109 - 115, Update EnumItemInterface so its mapped template fields are readonly, matching the frozen enum item metadata contract. Mark the guarded assignment to weekEnum.named.Sunday.description with `@ts-expect-error` while preserving the existing type assertions.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/auto-localize.ts`:
- Line 33: Update the items type in LocalizeTemplate so the item-template map is
partial and keyed by strings, allowing callers to provide only generated
metadata field templates. Preserve exclusion of key, value, and label, and do
not require templates for every raw item property.
In `@src/enum-item.ts`:
- Around line 32-36: Update the template-derived field mapping in
EnumItemInterface to mark each generated field readonly, matching the
getter-only and frozen-instance behavior of EnumItemClass while preserving the
existing field names and string value types.
In `@src/enum-items.ts`:
- Around line 958-974: In the mapped-type key selector logic, replace the
invalid EnumInitOptions<KS, ...> predicate with the existing ExactEqual<KS,
EnumItemFields | ((item: EnumItemInterface<T, T[K], K, V, LP, OPTIONS>) =>
unknown)> check. Preserve the surrounding value/key selector branches and use
the corrected predicate to determine whether KS selects the enum item value.
In `@src/enum.ts`:
- Around line 233-234: Align the public Enum.config template property with the
source used by mergeLocalizeTemplatesConfig: update the relevant Enum config
interface and internalConfig exposure to use autoLocalize, or consistently map
templates to internalConfig.autoLocalize. Ensure Enum.config and template
merging read the same value, and remove the unused public alias if it cannot be
made consistent.
In `@test/.auto-localize.test.ts`:
- Around line 49-51: Align the test with the actual placeholder contract of
resolveLocalizeTemplate: inspect its supported placeholders and update the
assertion and newly added localization templates to use only that syntax,
preserving {name} when no name is provided. Alternatively, if {item} and {field}
are intended to be supported, extend resolveLocalizeTemplate in
src/auto-localize.ts to substitute them consistently, then retain the test
expectation.
- Around line 24-43: The expectations around mergeLocalizeTemplatesConfig should
use the helper’s returned field names, name and items, instead of nameTemplate
and itemTemplate. Update both expected objects while preserving their existing
values.
- Around line 1-2: Update the root Jest CJS and ESM test configuration patterns
used by jest --coverage and test-node-{cjs,esm}-core to include
test/.auto-localize.test.ts alongside the existing tslib/test and tses/test
matches. Preserve the current Vitest inclusion and ensure both Jest module
variants execute this test.
In `@test/test-suites/localization.ts`:
- Around line 791-820: Restore the commented runtime test around the engine.test
flow to actively exercise function-form global templates, function-form item
metadata, omitted raw fields, and inferred enum names. Preserve the existing
assertions for unnamedEnum, labelEnum, and metaEnum, including the abbreviation
lookup, and retain cleanup of Enum.config.templates after the test.
---
Outside diff comments:
In `@test/test-suites/enum-items.ts`:
- Around line 184-208: Extend the enum-items test for compactWeekEnum to
validate the configured ss metadata: assert the generated item ss value, the
items.meta.ss collection, and findBy('ss', ...) behavior. Replace the trailing
“compactWeekEnum.named.Friday” comment with these assertions, using the expected
Friday metadata and undefined behavior for an invalid value as appropriate.
In `@test/test-suites/interface.ts`:
- Around line 109-115: Update EnumItemInterface so its mapped template fields
are readonly, matching the frozen enum item metadata contract. Mark the guarded
assignment to weekEnum.named.Sunday.description with `@ts-expect-error` while
preserving the existing type assertions.
In `@test/test-suites/localization.ts`:
- Around line 732-788: Update both assertion callbacks in the localization tests
to wrap their expectations in try/finally blocks, and move the
Enum.config.templates reset into each finally block. Ensure the global template
configuration is cleared whether assertions pass or throw.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 7ce6f84f-c309-4427-9deb-206dfe057813
📒 Files selected for processing (11)
src/auto-localize.tssrc/enum-collection.tssrc/enum-item.tssrc/enum-items.tssrc/enum.tssrc/global-config.tssrc/types.tstest/.auto-localize.test.tstest/test-suites/enum-items.tstest/test-suites/interface.tstest/test-suites/localization.ts
| V extends EnumValue = ValueTypeFromSingleInit<T[K], K>, | ||
| > { | ||
| name?: LocalizeTemplate<T, K, V>; | ||
| items?: Record<Exclude<keyof T[keyof T], 'key' | 'value' | 'label'>, LocalizeTemplate<T, K, V>>; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg 'src/(auto-localize|enum-item|types|extension)\.ts$' || true
echo "== auto-localize outline =="
ast-grep outline src/auto-localize.ts --view expanded || true
echo "== auto-localize relevant lines =="
cat -n src/auto-localize.ts | sed -n '1,90p'
echo "== enum-item relevant lines =="
cat -n src/enum-item.ts | sed -n '1,180p'
echo "== types relevant mentions =="
rg -n "LocalizeTemplate|AutoLocalize|item" src/types.ts src/enum-item.ts src/auto-localize.ts src/extension.d.tsRepository: shijistar/enum-plus
Length of output: 19983
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== enum-item localization resource implementation =="
cat -n src/enum-item.ts | sed -n '230,285p'
echo "== auto-localize helper implementation =="
cat -n src/auto-localize.ts | sed -n '87,135p'
echo "== enum-init/types definitions =="
cat -n src/types.ts | sed -n '1,240p'
echo "== tests involving templates/items,label =="
git ls-files | rg '\.test\.(ts|tsx)$|test' | while read -r f; do
if rg -q "templates|AutoLocalize|items:|localize|label" "$f"; then
echo "--- $f"
rg -n "templates|AutoLocalize|items:|localize|label" "$f" -C 3
fi
doneRepository: shijistar/enum-plus
Length of output: 50376
Allow partial item-template maps.
Runtime does not apply templates.items.label; the label path only uses raw labels and auto-label behavior. The current constraint still makes every configured item-template key required, so callers cannot add one generated metadata template field without providing localizations for every raw item key. Use a partial string-keyed item-template map for generated metadata fields.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/auto-localize.ts` at line 33, Update the items type in LocalizeTemplate
so the item-template map is partial and keyed by strings, allowing callers to
provide only generated metadata field templates. Preserve exclusion of key,
value, and label, and do not require templates for every raw item property.
Source: Path instructions
| { | ||
| [key in Exclude<keyof T, 'value' | 'label' | 'key'>]: T[key]; | ||
| }; | ||
| } & (OPTIONS extends { templates: { items: infer ItemTemplates } } | ||
| ? { [key in keyof ItemTemplates]: string } | ||
| : unknown) & |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Repository files matching enum-item.ts:\n'
fd -a 'enum-item\.ts$' . | sed 's#^\./##'
printf '\nOutline:\n'
ast-grep outline src/enum-item.ts --view expanded || true
printf '\nRelevant src/enum-item.ts lines:\n'
cat -n src/enum-item.ts | sed -n '1,140p'
printf '\nSearch template-related definitions/usages:\n'
rg -n "ItemTemplates|templates|description|freeze|Object\.freeze|constructor|class EnumItem" src/enum-item.ts src -SRepository: shijistar/enum-plus
Length of output: 10650
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Relevant auto-localize.ts lines:\n'
cat -n src/auto-localize.ts | sed -n '1,80p'
printf '\nRelevant template config/type lines:\n'
rg -n "LocalizeTemplatesConfig|type Localize|interface Localize|ItemTemplates|LiteralStringKeys|description|template" src -S
printf '\nRead-only JS verifier for getter definition + freeze behavior:\n'
node - <<'JS'
function buildItem() {
const item = { key: 'A', value: 1 };
const metaKeys = ['description'];
metaKeys.forEach((metaKey) => {
Object.defineProperty(item, metaKey, {
get: function get() {
return metaKey + '-getter';
},
enumerable: true,
});
get._metaKey = metaKey;
});
Object.freeze(item);
return item;
}
const item = buildItem();
console.log('getter value:', item.description);
try {
item.description = 'manual';
console.log('assignment result:', item.description);
console.log('result: write succeeded without exception');
} catch (e) {
console.log('write throws:', e.name + ': ' + e.message);
}
JSRepository: shijistar/enum-plus
Length of output: 10995
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Relevant auto-localize localizer implementation:\n'
cat -n src/auto-localize.ts | sed -n '91,180p'
printf '\nRead-only JS verifier for getter definition + freeze behavior:\n'
node - <<'JS'
function buildItem() {
const item = { key: 'A', value: 1 };
const metaKeys = ['description'];
metaKeys.forEach((metaKey) => {
Object.defineProperty(item, metaKey, {
get: function () {
return metaKey + '-getter';
},
enumerable: true,
});
});
Object.freeze(item);
return item;
}
const item = buildItem();
console.log('getter value:', item.description);
try {
item.description = 'manual';
console.log('assignment result:', item.description);
console.log('result: write succeeded without exception');
} catch (e) {
console.log('write throws:', e.name + ': ' + e.message);
}
JSRepository: shijistar/enum-plus
Length of output: 1885
Mark generated template fields as readonly.
EnumItemInterface exposes template-derived fields as writable, but EnumItemClass creates getters for these fields and freezes the instance. Code that assigns item.description = 'text' compiles but violates the getter/freeze contract.
Proposed fix
- ? { [key in keyof ItemTemplates]: string }
+ ? { readonly [key in keyof ItemTemplates]: string }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| { | |
| [key in Exclude<keyof T, 'value' | 'label' | 'key'>]: T[key]; | |
| }; | |
| } & (OPTIONS extends { templates: { items: infer ItemTemplates } } | |
| ? { [key in keyof ItemTemplates]: string } | |
| : unknown) & | |
| { | |
| [key in Exclude<keyof T, 'value' | 'label' | 'key'>]: T[key]; | |
| } & (OPTIONS extends { templates: { items: infer ItemTemplates } } | |
| ? { readonly [key in keyof ItemTemplates]: string } | |
| : unknown) & |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/enum-item.ts` around lines 32 - 36, Update the template-derived field
mapping in EnumItemInterface to mark each generated field readonly, matching the
getter-only and frozen-instance behavior of EnumItemClass while preserving the
existing field names and string value types.
Source: Path instructions
| [key in EnumInitOptions< | ||
| KS, | ||
| EnumItemFields | ((item: EnumItemInterface<T, T[K], K, V, LP, OPTIONS>) => unknown), | ||
| LP | ||
| > extends true | ||
| ? // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| EnumItemInterface<T[K], K, V, LP>['value'] & keyof any | ||
| EnumItemInterface<T, T[K], K, V, LP, OPTIONS>['value'] & keyof any | ||
| : KS extends EnumItemFields | ||
| ? // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| EnumItemInterface<T[K], K, V, LP>[KS] & keyof any | ||
| EnumItemInterface<T, T[K], K, V, LP, OPTIONS>[KS] & keyof any | ||
| : // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| KS extends (item: any) => infer R | ||
| ? R | ||
| : never]: ExactEqual<VS, EnumItemFields | ((item: EnumItemInterface<T[K], K, V, LP>) => unknown)> extends true | ||
| ? ExactEqual<KS, EnumItemFields | ((item: EnumItemInterface<T[K], K, V, LP>) => string | symbol)> extends true | ||
| : never]: ExactEqual< | ||
| VS, | ||
| EnumItemFields | ((item: EnumItemInterface<T, T[K], K, V, LP, OPTIONS>) => unknown) | ||
| > extends true |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Files matching enum-items.ts:\n'
fd -a 'enum-items\.ts$' . || true
printf '\nRelevant outline:\n'
ast-grep outline src/enum-items.ts --view expanded 2>/dev/null | sed -n '1,220p' || true
printf '\nRelevant lines around MapResult and EnumInitOptions definitions:\n'
sed -n '1,140p' src/enum-items.ts
printf '\n---\n'
sed -n '900,1030p' src/enum-items.ts
printf '\nSearch EnumInitOptions and ExactEqual definitions/usages:\n'
rg -n "type EnumInitOptions|interface EnumInitOptions|type ExactEqual|interface ExactEqual|EnumInitOptions<|ExactEqual<" src -C 2Repository: shijistar/enum-plus
Length of output: 19679
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Behavioral/type-shape verifier: inspect whether EnumInitOptions is an initializer
# type accepting (item, options) and whether selector KS is passed as first arg by
# the code under review.
python3 - <<'PY'
from pathlib import Path
import re
p = Path('src/enum-items.ts')
text = p.read_text()
print('EnumInitOptions declarations:')
for m in re.finditer(r'^(?:export\s+)?(?:type|interface)\s+EnumInitOptions<[^=]*=>[^;]+', text, re.M | re.S):
line = text[:m.start()].count('\n') + 1
print(f'lines {line}-{text[:m.end()].count(chr(10))}: {m.group(0)[:400]}')
print('\nExactEqual declarations:')
for m in re.finditer(r'^(?:export\s+)?(?:type|interface)\s+ExactEqual<[^=]*=>[^;]+', text, re.M | re.S):
line = text[:m.start()].count('\n') + 1
print(f'lines {line}-{text[:m.end()].count(chr(10))}: {m.group(0)[:400]}')
print('\nTarget line 958 context:')
lines = text.splitlines()
for i in range(945, 985):
if i <= len(lines):
print(f'{i}: {lines[i-1]}')
PYRepository: shijistar/enum-plus
Length of output: 2260
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
src = Path('src/enum.ts').read_text()
m = re.search(r'export interface EnumInitOptions<[\s\S]+?\n\}', src)
if m:
print('EnumInitOptions declaration:')
print(m.group(0))
else:
print('EnumInitOptions declaration not found')
types = Path('src/types.ts').read_text()
m = re.search(r'export type ExactEqual<[\s\S]+?\n;', types)
if m:
print('\nExactEqual declaration:')
print(m.group(0))
else:
print('\nExactEqual declaration not found')
PYRepository: shijistar/enum-plus
Length of output: 683
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '520,555p' src/enum.ts
sed -n '240,252p' src/types.tsRepository: shijistar/enum-plus
Length of output: 1922
Replace the EnumInitOptions selector predicate.
EnumInitOptions<T, K, V, LP> describes enum initialization options and has different generic arity, so passing selector type KS here is invalid. MapResult should use the existing ExactEqual<KS, ...> predicate for the key selector.
Proposed fix
- [key in EnumInitOptions<
+ [key in ExactEqual<
KS,
EnumItemFields | ((item: EnumItemInterface<T, T[K], K, V, LP, OPTIONS>) => unknown),
- LP
> extends true📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| [key in EnumInitOptions< | |
| KS, | |
| EnumItemFields | ((item: EnumItemInterface<T, T[K], K, V, LP, OPTIONS>) => unknown), | |
| LP | |
| > extends true | |
| ? // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| EnumItemInterface<T[K], K, V, LP>['value'] & keyof any | |
| EnumItemInterface<T, T[K], K, V, LP, OPTIONS>['value'] & keyof any | |
| : KS extends EnumItemFields | |
| ? // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| EnumItemInterface<T[K], K, V, LP>[KS] & keyof any | |
| EnumItemInterface<T, T[K], K, V, LP, OPTIONS>[KS] & keyof any | |
| : // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| KS extends (item: any) => infer R | |
| ? R | |
| : never]: ExactEqual<VS, EnumItemFields | ((item: EnumItemInterface<T[K], K, V, LP>) => unknown)> extends true | |
| ? ExactEqual<KS, EnumItemFields | ((item: EnumItemInterface<T[K], K, V, LP>) => string | symbol)> extends true | |
| : never]: ExactEqual< | |
| VS, | |
| EnumItemFields | ((item: EnumItemInterface<T, T[K], K, V, LP, OPTIONS>) => unknown) | |
| > extends true | |
| [key in ExactEqual< | |
| KS, | |
| EnumItemFields | ((item: EnumItemInterface<T, T[K], K, V, LP, OPTIONS>) => unknown), | |
| > extends true | |
| ? // eslint-disable-next-line `@typescript-eslint/no-explicit-any` | |
| EnumItemInterface<T, T[K], K, V, LP, OPTIONS>['value'] & keyof any | |
| : KS extends EnumItemFields | |
| ? // eslint-disable-next-line `@typescript-eslint/no-explicit-any` | |
| EnumItemInterface<T, T[K], K, V, LP, OPTIONS>[KS] & keyof any | |
| : // eslint-disable-next-line `@typescript-eslint/no-explicit-any` | |
| KS extends (item: any) => infer R | |
| ? R | |
| : never]: ExactEqual< | |
| VS, | |
| EnumItemFields | ((item: EnumItemInterface<T, T[K], K, V, LP, OPTIONS>) => unknown) | |
| > extends true |
🧰 Tools
🪛 GitHub Check: test / install-and-build
[failure] 959-959:
Type 'KS' does not satisfy the constraint 'EnumInit<EnumItemFields | ((item: EnumItemInterface<T, T[K], K, V, LP, OPTIONS>) => unknown), LP>'.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/enum-items.ts` around lines 958 - 974, In the mapped-type key selector
logic, replace the invalid EnumInitOptions<KS, ...> predicate with the existing
ExactEqual<KS, EnumItemFields | ((item: EnumItemInterface<T, T[K], K, V, LP,
OPTIONS>) => unknown)> check. Preserve the surrounding value/key selector
branches and use the corrected predicate to determine whether KS selects the
enum item value.
Source: Linters/SAST tools
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| templates?: LocalizeTemplatesConfig<any>; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
ast-grep outline src --items all --match 'Enum|internalConfig|config'
rg -n -C 5 'Enum\.config|internalConfig|autoLocalize|templates' srcRepository: shijistar/enum-plus
Length of output: 19697
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- src/global-config.ts ---\n'
cat -n src/global-config.ts
printf '\n--- src/enum.ts relevant sections ---\n'
sed -n '200,280p' src/enum.ts | cat -n -v
sed -n '1,80p' src/enum.ts | cat -n -v
printf '\n--- mergeLocalizeTemplatesConfig implementation ---\n'
sed -n '44,85p' src/auto-localize.ts | cat -n -v
printf '\n--- Read-only structural verifier ---\n'
python3 - <<'PY'
from pathlib import Path
import re
enum_src = Path('src/enum.ts').read_text()
global_src = Path('src/global-config.ts').read_text()
auto_src = Path('src/auto-localize.ts').read_text()
checks = {
'Enum.config returns internalConfig': 'return internalConfig;' in enum_src[enum_src.find("define(Enum, 'config'"):enum_src.find("define(Enum, 'config'")+600],
'global config exposes templates': bool(re.search(r'templates\?\s*:\s*LocalizeTemplatesConfig<\s*any\s*>', enum_src)),
'global config exposes autoLocalize': 'autoLocalize?: LocalizeTemplatesConfig<any>;' in global_src,
'mergeLocalizeTemplatesConfig reads internalConfig.autoLocalize': 'const globalConfig = internalConfig.autoLocalize;' in auto_src,
'mergeLocalizeTemplatesConfig merges template items': 'items?: {...' in auto_src and global_src.count('autoLocalize') > 0,
'no direct mapping from Enum.config.templates to internalConfig.autoLocalize': not bool(re.search(r'Enum\.config\s*\.\s*templates\s*=|internalConfig\.autoLocalize\s*=.*Enum\.config\.templates|config\.templates\s*=.*internalConfig\.autoLocalize', enum_src + auto_src + global_src)),
}
for k, v in checks.items():
print(f'{k}: {v}')
PYRepository: shijistar/enum-plus
Length of output: 13351
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- src/global-config.ts ---\n'
cat -n src/global-config.ts
printf '\n--- src/enum.ts relevant sections ---\n'
sed -n '200,280p' src/enum.ts | cat -n -v
sed -n '1,80p' src/enum.ts | cat -n -v
printf '\n--- mergeLocalizeTemplatesConfig implementation ---\n'
sed -n '44,85p' src/auto-localize.ts | cat -n -v
printf '\n--- Read-only structural verifier ---\n'
python3 - <<'PY'
from pathlib import Path
import re
enum_src = Path('src/enum.ts').read_text()
global_src = Path('src/global-config.ts').read_text()
auto_src = Path('src/auto-localize.ts').read_text()
checks = {
'Enum.config returns internalConfig': 'return internalConfig;' in enum_src[enum_src.find("define(Enum, 'config'"):enum_src.find("define(Enum, 'config'")+600],
'global config exposes templates': bool(re.search(r'templates\?\s*:\s*LocalizeTemplatesConfig<\s*any\s*>', enum_src)),
'global config exposes autoLocalize': 'autoLocalize?: LocalizeTemplatesConfig<any>;' in global_src,
'merge_LOCALIZE_TEMPLATES_CONFIG reads internalConfig.autoLocalize': 'const globalConfig = internalConfig.autoLocalize;' in auto_src,
'merge_LOCALIZE_TEMPLATES_CONFIG merges template items': 'items?: {...' in auto_src and global_src.count('autoLocalize') > 0,
'no direct mapping from Enum.config.templates to internalConfig.autoLocalize': not bool(re.search(r'Enum\.config\s*\.\s*templates\s*=|internalConfig\.autoLocalize\s*=.*Enum\.config\.templates|config\.templates\s*=.*internalConfig\.autoLocalize', enum_src + auto_src + global_src)),
}
for k, v in checks.items():
print(f'{k}: {v}')
PYRepository: shijistar/enum-plus
Length of output: 13357
Align Enum.config.templates with the global template source or remove the public property.
Enum.config returns internalConfig, but internalConfig exposes only autoLocalize while mergeLocalizeTemplatesConfig reads that same source. This makes Enum.config.templates a public alias that does not participate in template resolution; either use autoLocalize in the public config/interface or map templates to internalConfig.autoLocalize consistently.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/enum.ts` around lines 233 - 234, Align the public Enum.config template
property with the source used by mergeLocalizeTemplatesConfig: update the
relevant Enum config interface and internalConfig exposure to use autoLocalize,
or consistently map templates to internalConfig.autoLocalize. Ensure Enum.config
and template merging read the same value, and remove the unused public alias if
it cannot be made consistent.
| import { Enum } from '../src'; | ||
| import { isAutoLocalizeMetaField, mergeLocalizeTemplatesConfig, resolveLocalizeTemplate } from '../src/auto-localize'; |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 4 --glob '!node_modules/**' \
'auto-localize|testMatch|testRegex|testPathIgnorePatterns|include:|exclude:' \
jest-cjs.config.js jest-esm.config.js package.json test 2>/dev/null || true
fd -HI -t f 'vitest.*\.config\..*' . -x \
rg -n -C 4 'include:|exclude:|auto-localize|testMatch|testRegex' {} \; 2>/dev/null || trueRepository: shijistar/enum-plus
Length of output: 7554
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== config files =="
git ls-files | rg '(^|/)jest-(cjs|esm)\.config\.js$|(^|/)vitest.*\.config\.[jt]s$|^package\.json$|^test/\.auto-localize\.test\.ts$' || true
echo
echo "== relevant Jest CJS config =="
if [ -f jest-cjs.config.js ]; then
cat -n jest-cjs.config.js | sed -n '1,70p'
else
echo "jest-cjs.config.js not found"
fi
echo
echo "== relevant Jest ESM config =="
if [ -f jest-esm.config.js ]; then
cat -n jest-esm.config.js | sed -n '1,70p'
else
echo "jest-esm.config.js not found"
fi
echo
echo "== Vitest config snippets =="
for f in $(git ls-files | rg '(^|/)vitest.*\.config\.[jt]s$'); do
echo "-- $f --"
cat -n "$f" | sed -n '1,80p'
done
echo
echo "== deterministic pattern probe =="
python3 - <<'PY'
from pathlib import Path
for root in [Path('tslib/test'), Path('tses/test'), Path('test')]:
p = root / '.auto-localize.test.ts'
print(f"{p}: exists={p.exists()}")
PYRepository: shijistar/enum-plus
Length of output: 6223
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== package scripts/config =="
node - <<'JS'
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json','utf8'));
for (const key of ['scripts','jest','test','vitest','packageManager','devDependencies','dependencies']) {
if (pkg[key] !== undefined) {
console.log(`--- ${key} ---`);
console.log(pkg[key]);
}
}
JS
echo
echo "== top-level and package vitest config include/exclude =="
for f in vitest.config.* packages/*/*/vitest.config.ts packages/*/*/vitest.config.js; do
[ -f "$f" ] || continue
echo "-- $f --"
rg -n -C 3 '(include|exclude)!:' "$f" || true
done
echo
echo "== any explicit dot-prefix ignore or vitest globs with leading dot =="
rg -n --glob '!node_modules/**' --glob '!test/engines/playwright-types.d.ts' \
'(\*\*/)@|[^.]dot|dot|\.auto-localize|test/\.\w+|include:\s*\[\s*.*test/\.\w+|exclude:\s*\[\s*.*test/\.\w+' \
. 2>/dev/null || trueRepository: shijistar/enum-plus
Length of output: 6407
Make the Jest configs cover the new dot-prefix test.
test/.auto-localize.test.ts exists under test/ and is already included by the Vitest test/**/*.{test,spec}.ts includes, but the configured root Jest CJS and Jest ESM patterns only match tslib/test/... and tses/test/..., so the test is excluded from jest --coverage and test-node-{cjs,esm}-core unless it is moved/generated into those outputs or the Jest patterns are updated.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/.auto-localize.test.ts` around lines 1 - 2, Update the root Jest CJS and
ESM test configuration patterns used by jest --coverage and
test-node-{cjs,esm}-core to include test/.auto-localize.test.ts alongside the
existing tslib/test and tses/test matches. Preserve the current Vitest inclusion
and ensure both Jest module variants execute this test.
Source: Path instructions
| expect(mergeLocalizeTemplatesConfig({ name: 'local.{name}' })).toEqual({ | ||
| nameTemplate: 'local.{name}', | ||
| itemTemplate: { | ||
| description: 'global.{item}.description', | ||
| }, | ||
| }); | ||
| } finally { | ||
| Enum.config.templates = undefined; | ||
| } | ||
|
|
||
| Enum.config.templates = { | ||
| name: 'global.{name}', | ||
| }; | ||
| try { | ||
| expect(mergeLocalizeTemplatesConfig({ items: { abbr: 'local.{item}.abbr' } })).toEqual({ | ||
| nameTemplate: 'global.{name}', | ||
| itemTemplate: { | ||
| abbr: 'local.{item}.abbr', | ||
| }, | ||
| }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Use the helper output field names.
mergeLocalizeTemplatesConfig returns name and items. It does not return nameTemplate or itemTemplate. Both expectations will fail.
Update the expected objects, or change the helper contract if the legacy field names are required.
Proposed test correction
- nameTemplate: 'local.{name}',
- itemTemplate: {
+ name: 'local.{name}',
+ items: {
...
- nameTemplate: 'global.{name}',
- itemTemplate: {
+ name: 'global.{name}',
+ items: {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| expect(mergeLocalizeTemplatesConfig({ name: 'local.{name}' })).toEqual({ | |
| nameTemplate: 'local.{name}', | |
| itemTemplate: { | |
| description: 'global.{item}.description', | |
| }, | |
| }); | |
| } finally { | |
| Enum.config.templates = undefined; | |
| } | |
| Enum.config.templates = { | |
| name: 'global.{name}', | |
| }; | |
| try { | |
| expect(mergeLocalizeTemplatesConfig({ items: { abbr: 'local.{item}.abbr' } })).toEqual({ | |
| nameTemplate: 'global.{name}', | |
| itemTemplate: { | |
| abbr: 'local.{item}.abbr', | |
| }, | |
| }); | |
| expect(mergeLocalizeTemplatesConfig({ name: 'local.{name}' })).toEqual({ | |
| name: 'local.{name}', | |
| items: { | |
| description: 'global.{item}.description', | |
| }, | |
| }); | |
| } finally { | |
| Enum.config.templates = undefined; | |
| } | |
| Enum.config.templates = { | |
| name: 'global.{name}', | |
| }; | |
| try { | |
| expect(mergeLocalizeTemplatesConfig({ items: { abbr: 'local.{item}.abbr' } })).toEqual({ | |
| name: 'global.{name}', | |
| items: { | |
| abbr: 'local.{item}.abbr', | |
| }, | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/.auto-localize.test.ts` around lines 24 - 43, The expectations around
mergeLocalizeTemplatesConfig should use the helper’s returned field names, name
and items, instead of nameTemplate and itemTemplate. Update both expected
objects while preserving their existing values.
| test('resolves string templates without optional context values', () => { | ||
| expect(resolveLocalizeTemplate('{name}.{item}.{field}', { type: 'label' })).toBe('..label'); | ||
| }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Align placeholder semantics with the resolver.
resolveLocalizeTemplate does not replace {item} or {field}. It also preserves {name} when no name exists. Line 50 therefore returns {name}.{item}.{field}, not ..label.
Define one placeholder contract. If {item} and {field} are supported syntax, implement those substitutions in src/auto-localize.ts. Otherwise, update this test and the new localization templates to use the resolver syntax.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/.auto-localize.test.ts` around lines 49 - 51, Align the test with the
actual placeholder contract of resolveLocalizeTemplate: inspect its supported
placeholders and update the assertion and newly added localization templates to
use only that syntax, preserving {name} when no name is provided. Alternatively,
if {item} and {field} are intended to be supported, extend
resolveLocalizeTemplate in src/auto-localize.ts to substitute them consistently,
then retain the test expectation.
| // engine.test( | ||
| // 'autoLocalize function shorthand and templates support omitted raw fields and enum name', | ||
| // ({ EnumPlus: { Enum, defaultLocalize }, WeekConfig: { setLang, getLocales }, i18n: { enUS } }) => { | ||
| // setLang('en-US', Enum, getLocales, defaultLocalize); | ||
| // Enum.config.templates = { name: 'weekDay.name' }; | ||
| // const unnamedEnum = Enum({ Sunday: 0 }); | ||
| // const unnamedEnumName = unnamedEnum.name; | ||
| // Enum.config.templates = ({ item }) => `weekday.${item?.key}`; | ||
| // const labelEnum = Enum({ Sunday: undefined, Monday: undefined }); | ||
| // const metaEnum = Enum( | ||
| // { Sunday: undefined, Monday: undefined }, | ||
| // { | ||
| // autoLocalize: { | ||
| // nameTemplate: 'weekDay.name', | ||
| // itemTemplate: { | ||
| // abbr: ({ item }) => `weekday.${item?.key}Abbr`, | ||
| // }, | ||
| // }, | ||
| // }, | ||
| // ); | ||
| // return { Enum, unnamedEnumName, labelEnum, metaEnum, enUS }; | ||
| // }, | ||
| // ({ Enum, unnamedEnumName, labelEnum, metaEnum, enUS }) => { | ||
| // engine.expect(unnamedEnumName).toBe(enUS['weekDay.name']); | ||
| // engine.expect(labelEnum.named.Sunday.label).toBe(enUS['weekday.Sunday']); | ||
| // engine.expect(metaEnum.name).toBe(enUS['weekDay.name']); | ||
| // engine.expect((metaEnum.named.Sunday as unknown as { abbr: string }).abbr).toBe(enUS['weekday.SundayAbbr']); | ||
| // Enum.config.templates = undefined; | ||
| // }, | ||
| // ); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Restore runtime coverage for function templates and omitted raw fields.
This block is commented out, so it does not verify function-form global templates, function-form item metadata, omitted raw fields, or inferred enum names. The direct helper test does not cover the enum runtime flow.
Enable this test or replace it with active runtime assertions before merge.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@test/test-suites/localization.ts` around lines 791 - 820, Restore the
commented runtime test around the engine.test flow to actively exercise
function-form global templates, function-form item metadata, omitted raw fields,
and inferred enum names. Preserve the existing assertions for unnamedEnum,
labelEnum, and metaEnum, including the abbreviation lookup, and retain cleanup
of Enum.config.templates after the test.
Background
Continue issue #89 by completing the second phase of the
autoLocalizework after the runtime support commit.Changes
autoLocalize.itemTemplatemeta fields into enum item anditems.metaTypeScript types.Record<string, any>.autoLocalizeconfig normalization, template resolution, merge behavior, and meta-field detection.autoLocalizein full README and Storybook API guide in both English and Chinese.autoLocalizeMetaremains the correct legacy API name, whileautoLocalizedMetaand!abbrexclusion syntax are not supported.Verification
npm run testnpm run build:libnpm run build-storybooknpm run buildgit diff --checkNotes / Risks
"use client"module directives and large chunks, but completes successfully./usr/bin/ghin this environment.Summary by CodeRabbit
New Features
Documentation