feat: add system v2 implementation#189
Conversation
|
Warning Rate limit exceeded
To continue reviewing without waiting, purchase usage credits in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
Walkthroughnew-v2 시스템(Core/Compiler/CLI) 패키지를 추가하고 컴파일 파이프라인과 테스트를 도입했습니다. AI SDK 스킬/레퍼런스 문서를 신설했고 워크스페이스/TS 설정을 갱신했습니다. tokens.json은 실질 변경이 없습니다. Changesnew-v2 System Core (타입/DSL 공개 API)
new-v2 System Compiler (정규화→컴파일→렌더)
new-v2 System CLI (jds-system)
AI SDK 스킬/레퍼런스 문서
워크스페이스/리포 구성
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested labels
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 202ed33d46
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const isLeaf = | ||
| values.length > 0 && values.every((mode) => typeof mode === "string") |
There was a problem hiding this comment.
Do not drop numeric semantic token modes
When a semantic token uses an allowed numeric mode value (for example spacing.layout.base: 12, which SemanticTokenValue and the core type tests accept), this leaf check returns false because it only accepts strings. The normalizer then descends into the mode values as if they were groups and emits no semantic token at all, so the compiler silently omits the CSS variable for that token.
Useful? React with 👍 / 👎.
| pushDeclaration(declarations, token.family, { | ||
| property, | ||
| value: toCssVariableReference(prefix, referencedPath), | ||
| }) |
There was a problem hiding this comment.
Preserve raw semantic token values
When a semantic token mode is authored as a raw string value such as #ffffff or 0.75rem (also allowed by the core semantic token API), this always treats the mode value as another token path and emits var(--<prefix>-#ffffff)/similar invalid CSS instead of the raw value. The same assumption is repeated for non-default modes below, so raw semantic values compile to broken variables.
Useful? React with 👍 / 👎.
| export function normalizeTheme<TTheme extends TokenSource>( | ||
| system: SystemDefinition<TTheme>, | ||
| ) { | ||
| return [system.theme, ...(system.presets ?? [])].reduce<RecordObject>( |
There was a problem hiding this comment.
Let system theme override presets
When a project uses a preset and then customizes the same token/recipe key in system.theme, this merge order applies the local theme first and each preset afterward, so preset defaults overwrite the project's explicit configuration. That makes preset customization impossible for overlapping keys; merge presets first and the system theme last so local config wins.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 16
🧹 Nitpick comments (14)
packages/new-v2/system-core/src/style/css.ts (2)
18-23: 💤 Low value
CssColorFunction에 현대 CSS 컬러 함수가 누락되어 있습니다.
oklch()는 포함되어 있으나 현재 W3C 표준으로 널리 쓰이는oklab(),lch(),lab(),hwb(),color(),color-mix()가 빠져 있습니다. 점진적으로 추가할 수 있습니다.✏️ 수정 제안
export type CssColorFunction = | `rgb(${string})` | `rgba(${string})` | `hsl(${string})` | `hsla(${string})` | `oklch(${string})` + | `oklab(${string})` + | `lch(${string})` + | `lab(${string})` + | `hwb(${string})` + | `color(${string})` + | `color-mix(${string})`🤖 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 `@packages/new-v2/system-core/src/style/css.ts` around lines 18 - 23, The CssColorFunction union is missing several modern CSS color functions; update the CssColorFunction type to include template literal variants for the additional functions (e.g., `oklab(${string})`, `lch(${string})`, `lab(${string})`, `hwb(${string})`, `color(${string})`, and `color-mix(${string})`) alongside the existing entries so all common W3C color functions are covered; modify the union definition in the CssColorFunction type to add those string-template members.
38-38: 💤 Low value
NumberValue의number타입은NaN,Infinity,-Infinity를 포함합니다.
number | NumberLiteral에서number타입은 유효하지 않은 CSS 값인NaN,Infinity,-Infinity를 허용합니다. 사용 의도에 따라 정수나 유한수 범위로 제한하는 것을 고려할 수 있습니다.// 현재: NaN, Infinity 등 허용 export type NumberValue = number | NumberLiteral // 대안: 런타임 검증 없이 타입 레벨만으로는 완전히 막기 어렵지만, // 문서 주석으로 사용 의도를 명시하는 것도 방법입니다.🤖 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 `@packages/new-v2/system-core/src/style/css.ts` at line 38, NumberValue currently allows JS number including NaN/Infinity which are invalid CSS values; update the type by replacing NumberValue = number | NumberLiteral with a safer definition (e.g., introduce a branded alias FiniteNumber and use NumberValue = FiniteNumber | NumberLiteral) and/or add a clear doc comment on NumberValue/NumberLiteral stating only finite numbers are allowed; implement or call runtime checks where numeric parsing occurs to reject NaN/Infinity if you cannot fully enforce this at the type level.packages/new-v2/system-compiler/src/transform/selectors.ts (1)
58-64: ⚡ Quick win
isNestedAtRule에서@layerat-rule이 누락되어 있습니다.
@layer는 현대 CSS에서 흔히 사용되는 at-rule이지만 처리 대상에 포함되어 있지 않습니다. recipe 스타일에서@layer를 사용할 경우 at-rule로 인식되지 않아 의도치 않은 동작이 발생할 수 있습니다.✏️ 수정 제안
export function isNestedAtRule(key: string): boolean { return ( key.startsWith("@media ") || key.startsWith("@supports ") || - key.startsWith("@container ") + key.startsWith("@container ") || + key.startsWith("@layer ") ) }🤖 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 `@packages/new-v2/system-compiler/src/transform/selectors.ts` around lines 58 - 64, The isNestedAtRule function currently checks for "@media", "@supports", and "@container" but omits "@layer", causing `@layer` rules to be misclassified; update the isNestedAtRule function to also detect "@layer" (e.g., check key.startsWith("@layer") so variants like "@layer", "@layer ", or "@layer{" are caught) so recipe styles using `@layer` are recognized as nested at-rules.package.json (1)
24-24: ⚡ Quick win
@typescript/native-preview플로팅 dist-tag 사용 주의
"beta"dist-tag는 설치 시점마다 다른 빌드로 해석될 수 있어 lockfile 재생성 또는pnpm update시 CI 재현성이 저하됩니다. 이 패키지는 TypeScript 네이티브 포트의 프리뷰 빌드로, 아직 모든 기능이 구현되지 않은 테스트·실험 목적 패키지입니다. 특정 nightly 버전으로 고정하거나, 최소한 lockfile을 반드시 커밋하여 재현 가능성을 보장할 것을 권장합니다.💡 버전 고정 예시
- "@typescript/native-preview": "beta", + "@typescript/native-preview": "7.0.0-dev.20260507.1",🤖 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 `@package.json` at line 24, The dependency "@typescript/native-preview" in package.json is using a floating dist-tag "beta" which harms reproducibility; change that entry to a fixed version string (e.g., a specific nightly/version) instead of "beta" and regenerate the lockfile (pnpm-lock.yaml) then commit the updated lockfile to the repo so CI installs are deterministic; update the package.json entry named "@typescript/native-preview" and ensure you run your package manager to produce and commit the corresponding lockfile.packages/new-v2/system-cli/src/index.ts (1)
17-17: ⚡ Quick win에러 파라미터에
unknown사용은 현재 저장소 TS 규칙과 충돌합니다.Line 17은 프로젝트 규칙상
unknown회피가 필요하므로, 구체 유니온 타입(예:Error | string)으로 좁혀 선언하는 쪽이 맞습니다.As per coding guidelines "Do not use
unknown,any, or type assertions to bypass type errors; use precise types instead."🤖 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 `@packages/new-v2/system-cli/src/index.ts` at line 17, The catch handler for main() currently types the error parameter as unknown which violates repo TS rules; change the parameter type to a precise union like "Error | string" (or another appropriate specific union) in the main().catch((error: Error | string) => { ... }) callback and then narrow it inside the block (e.g., instanceof Error to access message/stack, else treat as string) before calling any logging/exit logic so you avoid using unknown/any while preserving correct error handling; update any processLogger or console usage inside this catch to use the narrowed variable.packages/new-v2/system-core/src/recipe/slotRecipe/api.ts (1)
32-34: ⚡ Quick win
TCompoundVariants의 기본 타입이 누락되어defineRecipe와 불일치합니다.
defineRecipe에서는TCompoundVariants에= undefined기본값이 있는 반면,defineSlotRecipe에서는 없습니다.compoundVariants를 생략했을 때 타입 추론 결과가 두 API 간에 다를 수 있습니다.♻️ 제안 수정
const TCompoundVariants extends | Array<SlotRecipeCompoundVariant<TSlots[number], NoInfer<TVariants>>> - | undefined = undefined, + | undefined = undefined,실제로는 아래와 같이
= undefined가 추가되어야 합니다:const TCompoundVariants extends | Array<SlotRecipeCompoundVariant<TSlots[number], NoInfer<TVariants>>> - | undefined, + | undefined = undefined,🤖 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 `@packages/new-v2/system-core/src/recipe/slotRecipe/api.ts` around lines 32 - 34, The generic TCompoundVariants in defineSlotRecipe is missing its default of = undefined, causing inconsistent type inference vs defineRecipe; update the generic declaration for TCompoundVariants in defineSlotRecipe to include the same default (= undefined) so that omitting compoundVariants yields the same inferred type as defineRecipe (ensure you update the generic signature where TCompoundVariants is declared and any related uses of compoundVariants to rely on that default).packages/new-v2/system-compiler/src/registry/keyframes.ts (1)
12-14: 💤 Low value
"keyframes."접두사가 매직 스트링으로 분산될 수 있습니다.
createKeyframesRegistry의 키 생성(keyframes.${name})과getKeyframesName의 조회 호출자(예:registry/composites.ts) 모두 같은 포맷 문자열에 의존합니다. 포맷이 변경될 경우 두 곳을 동시에 수정해야 하므로, 포맷을 상수로 추출하면 유지보수성이 향상됩니다.♻️ 제안 수정
+const KEYFRAMES_REFERENCE_PREFIX = "keyframes." as const + +export function keyframesReference(name: string): string { + return `${KEYFRAMES_REFERENCE_PREFIX}${name}` +} + export function createKeyframesRegistry( keyframes: NormalizedKeyframes, ): KeyframesRegistry { return { references: new Map( - keyframes.map(({ name }) => [`keyframes.${name}`, name]), + keyframes.map(({ name }) => [keyframesReference(name), name]), ), } }🤖 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 `@packages/new-v2/system-compiler/src/registry/keyframes.ts` around lines 12 - 14, Extract the hard-coded prefix string "keyframes." into a single exported constant (e.g., KEYFRAMES_PREFIX) and use that constant when building the references Map in createKeyframesRegistry and when forming lookup keys in getKeyframesName (and any callers such as registry/composites.ts) so both creation and lookup use the same centralized format; update references: new Map(keyframes.map(({ name }) => [ `${KEYFRAMES_PREFIX}${name}`, name ])) and replace any literal "keyframes." usages with the new constant throughout the registry code.packages/new-v2/system-compiler/src/normalize/system.test.ts (1)
125-182: 💤 Low value기본(primitive) 토큰 배열의 순서 의존성 – 유지보수 취약점
toEqual로 순서가 고정된 배열을 검증하는데, 입력 정의 순서(color가 첫 번째)와 기대 출력 순서(color가 8번째)가 다릅니다. 이는 정규화 알고리즘의 내부 처리 순서에 묵시적으로 의존하고 있음을 의미합니다. 정규화 순서가 변경되면 테스트가 이유 없이 깨지게 됩니다.
expect.arrayContaining을 사용하면 순서에 관계없이 각 토큰의 존재 여부만 검증할 수 있어 테스트가 더 견고해집니다.♻️ 제안 방향
- tokens: { - primitive: [ - { family: "spacing", path: "spacing.1", value: "0.25rem" }, - // ...순서 의존 배열 - ], + tokens: { + primitive: expect.arrayContaining([ + { family: "spacing", path: "spacing.1", value: "0.25rem" }, + { family: "color", path: "color.slate.50", value: "#f8fafc" }, + // ... 나머지 토큰들 + ]),🤖 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 `@packages/new-v2/system-compiler/src/normalize/system.test.ts` around lines 125 - 182, The test is asserting a strict order on tokens.primitive using toEqual, which makes it fragile; change the assertion to verify presence regardless of order by replacing the order-dependent toEqual check on tokens.primitive with an assertion that uses Jest's array-containing matcher (expect.arrayContaining) to assert that the actual tokens.primitive includes all expected primitive token objects (the expected primitive tokens array used in the test), so the test validates membership only and no longer depends on element order.packages/new-v2/system-cli/test/compile.test.ts (1)
26-26: 💤 Low value
path.resolve(".")을 파일 기준 경로로 교체하는 것을 고려하세요.
path.resolve(".")은 프로세스의 CWD에 의존합니다. pnpm이 항상 패키지 디렉터리에서 스크립트를 실행하므로 현재는 동작하지만, 루트에서 직접vitest를 호출하거나 CI 워크스페이스 구성이 달라지면 경로가 깨질 수 있습니다.♻️ 제안 수정
- const result = await runCompile({ - cwd: path.resolve("."), - config: "test/fixtures/basic-system.config.ts", + const result = await runCompile({ + cwd: path.resolve(import.meta.dirname, ".."), + config: "test/fixtures/basic-system.config.ts",🤖 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 `@packages/new-v2/system-cli/test/compile.test.ts` at line 26, Replace the non-deterministic cwd: path.resolve(".") with a file-relative directory reference so the test doesn't depend on process CWD; specifically, compute the test file directory using fileURLToPath(import.meta.url) and path.dirname(...) (or __dirname for CJS) and use path.resolve(...) of that value for the cwd option, and add the corresponding import of fileURLToPath from 'url' when using ESM.packages/new-v2/system-compiler/test/compiler.test.ts (1)
272-272: ⚡ Quick win
as never타입 단언을@ts-expect-error주석으로 대체해주세요.타입 단언으로 타입 검사를 우회하면 나중에 실제 타입 회귀를 숨길 수 있습니다. 테스트 파일에서 의도적인 타입 위반을 문서화할 때는
@ts-expect-error가 표준 패턴입니다.제안 패치
base: { - animation: "animation.missing" as never, + // `@ts-expect-error` runtime 에러 경로 검증을 위한 의도적 invalid reference + animation: "animation.missing", },🤖 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 `@packages/new-v2/system-compiler/test/compiler.test.ts` at line 272, Replace the type assertion "as never" on the animation property with a TypeScript suppression comment: remove the "as never" after animation: "animation.missing" and add a preceding single-line `@ts-expect-error` comment so the intentional type violation is documented by TypeScript tooling; target the test entry that sets animation: "animation.missing" (the animation property in the failing test) and ensure only that line is suppressed with `@ts-expect-error` rather than using a broad type assertion.packages/new-v2/system-core/src/style/input.ts (1)
14-33: ⚡ Quick win마진 방향별 단축키(
mt,mr,mb,ml)가 누락되어 패딩 단축키와 비대칭입니다.
pt,pr,pb,pl은 모두 정의되어 있지만, 대응하는 마진 단축키mt,mr,mb,ml은 없습니다. API 일관성 측면에서 추가하는 것이 좋습니다.♻️ 마진 단축키 추가 제안
m: StyleInputValueMap["spacing"] mx: StyleInputValueMap["spacing"] my: StyleInputValueMap["spacing"] + mt: StyleInputValueMap["spacing"] + mr: StyleInputValueMap["spacing"] + mb: StyleInputValueMap["spacing"] + ml: StyleInputValueMap["spacing"] w: StyleInputValueMap["spacing"]🤖 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 `@packages/new-v2/system-core/src/style/input.ts` around lines 14 - 33, StyleShorthandInputMap is missing the margin-direction shorthand keys (mt, mr, mb, ml) so paddings (pt, pr, pb, pl) are asymmetric; add entries mt: StyleInputValueMap["spacing"], mr: StyleInputValueMap["spacing"], mb: StyleInputValueMap["spacing"], ml: StyleInputValueMap["spacing"] to the StyleShorthandInputMap interface (placing them alongside m, mx, my) so margin direction shorthand matches padding shorthand and uses the same "spacing" type.packages/new-v2/system-compiler/src/normalize/styles.ts (1)
12-13: ⚡ Quick win
normalizeStyle반환 타입이unknown[]로 너무 느슨합니다.출력 항목의 형태(
{ scope, property, value })가 실제로는 알려져 있으므로unknown[]은 불필요하게 타입 정보를 손실시킵니다. 코딩 가이드라인에 따라 정확한 타입을 사용해야 합니다.♻️ 반환 타입 개선 제안
+type ScopeFrame = + | { kind: "selector"; value: string } + | { kind: "atRule"; name: string; params?: string } + +type StyleDeclarationRaw = { + scope: ScopeFrame[] + property: string + value: unknown +} + export function normalizeStyle(style: unknown) { - const output: unknown[] = [] + const output: StyleDeclarationRaw[] = [] const stack: Array<{ - scope: unknown[] + scope: ScopeFrame[] style: unknown }> = [As per coding guidelines, "
**/*.{ts,tsx}: Do not useunknown,any, or type assertions to bypass type errors; use precise types instead."🤖 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 `@packages/new-v2/system-compiler/src/normalize/styles.ts` around lines 12 - 13, The function normalizeStyle currently types its result as unknown[] which loses useful shape information; define a precise type (e.g., interface NormalizedStyleItem { scope: string; property: string; value: string | number | null } or the actual shapes used) and change the function signature to return NormalizedStyleItem[] and the local output variable to that type; ensure any internal narrowing/casts produce values that conform to NormalizedStyleItem (or adjust the fields/types to match real data) rather than using unknown/any, and update any call sites if needed to use the new type.packages/new-v2/system-compiler/src/normalize/recipes.ts (1)
29-54: ⚡ Quick win
compoundVariants의when필터링과defaultVariants정규화 로직이 두 브랜치에 중복됩니다.슬롯 레시피(29–54)와 일반 레시피(70–91) 브랜치의
when필터링과defaultVariants처리 로직이 완전히 동일합니다. 한쪽만 수정 시 동작이 조용히 달라질 수 있습니다.♻️ 헬퍼 추출 제안
+function normalizeWhenCondition(when: unknown): Record<string, unknown> { + return Object.fromEntries( + entriesOf(when).filter(([, value]) => value !== undefined), + ) +} + +function normalizeDefaultVariants(defaultVariants: unknown): Record<string, unknown> { + return Object.fromEntries( + entriesOf(defaultVariants).filter(([, value]) => value !== undefined), + ) +} // slotRecipe branch - return { - when: Object.fromEntries( - entriesOf(compoundVariantRecord.when).filter( - ([, value]) => value !== undefined, - ), - ), + return { + when: normalizeWhenCondition(compoundVariantRecord.when), slots: entriesOf(compoundVariantRecord.css).map(...) } - defaultVariants: Object.fromEntries( - entriesOf(recipeRecord.defaultVariants).filter( - ([, value]) => value !== undefined, - ), - ), + defaultVariants: normalizeDefaultVariants(recipeRecord.defaultVariants), // recipe branch (동일하게 적용)Also applies to: 70-91
🤖 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 `@packages/new-v2/system-compiler/src/normalize/recipes.ts` around lines 29 - 54, Duplicate logic exists for filtering compoundVariant.when and normalizing defaultVariants in the two recipe branches; extract a small helper (e.g., normalizeWhenEntries and normalizeDefaultVariants) that takes a record (use entriesOf/isRecord) and returns filtered Object.fromEntries removing undefined values, and another helper to map css slot styles using normalizeStyle for compoundVariants slots, then replace the inline logic in both branches (references: recipeRecord, compoundVariants, compoundVariantRecord, when, css, slots, defaultVariants, entriesOf, normalizeStyle, isRecord) to call these helpers so both branches share the same behavior.packages/new-v2/system-compiler/src/compile/targets/tailwind-v4.ts (1)
104-119: ⚡ Quick win
createTailwindTokenReferences가 렌더 경로에서 세 번 호출됩니다.
createThemeDeclarations(Line 194),createTextStyleUtilities(Line 224),createComponentBlocks(Line 295)에서 각각 독립적으로 호출되어 매번 전체 토큰 목록을 순회하며 동일한Map을 재생성합니다.compileTailwindV4수준에서 한 번만 생성하고 각 함수에 전달하면 됩니다.♻️ 리팩토링 제안
export function compileTailwindV4(context: CompileContext): CompileDocument { + const tailwindReferences = createTailwindTokenReferences(context) + // ... - const themeDeclarations = createThemeDeclarations(context) + const themeDeclarations = createThemeDeclarations(context, tailwindReferences) // createThemeDeclarations, createTextStyleUtilities, createComponentBlocks 시그니처에 // references: Map<string, string> 파라미터 추가🤖 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 `@packages/new-v2/system-compiler/src/compile/targets/tailwind-v4.ts` around lines 104 - 119, The token-reference Map is being rebuilt three times by createTailwindTokenReferences; instead, compute it once at the top-level compileTailwindV4 and pass the resulting Map into the callers. Modify compileTailwindV4 to call createTailwindTokenReferences(context) once and store the Map, then update createThemeDeclarations, createTextStyleUtilities, and createComponentBlocks to accept a references: Map<string,string> parameter (remove their internal calls to createTailwindTokenReferences) and use the passed Map instead.
🤖 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 @.agents/skills/ai-sdk/references/devtools.md:
- Around line 32-34: The fenced code block that contains
".devtools/generations.json" is missing a language tag and triggers markdownlint
MD040; update that block in .agents/skills/ai-sdk/references/devtools.md by
changing the opening fence from ``` to a language-tagged fence such as ```text
(or ```bash) so the snippet reads with a language specifier and the MD040
warning is resolved.
In @.agents/skills/ai-sdk/references/type-safe-agents.md:
- Around line 12-19: Add a language tag to the directory tree code fence that
begins with "lib/" so the markdown linter stops warning; change the opening
triple-backtick to specify a language (use "text") for the fenced block that
contains the lib/ agents/ tools/ listing.
In @.agents/skills/gathering-task-context/SKILL.md:
- Line 68: The fenced code block containing "switch(taskType) {" in SKILL.md
lacks a language identifier—update the opening fence to include a language tag
(e.g., ```javascript or ```typescript) so the block becomes a recognized
JavaScript/TypeScript snippet; ensure you update the specific fence that
precedes the switch(taskType) { line to satisfy markdownlint-cli2 and enable
proper syntax highlighting.
In `@packages/new-v2/system-cli/package.json`:
- Line 22: The package.json script "check-type" uses the tsgo command but the
provider package is not declared locally; add "@typescript/native-preview" to
this package's devDependencies so tsgo is available when running the
"check-type" script. Update the package's devDependencies entry in package.json
to include "@typescript/native-preview" (matching the workspace version if
desired) and run an install to ensure the binary is hoisted/available for the
system-cli package.
In `@packages/new-v2/system-cli/src/index.ts`:
- Line 5: Replace the direct JSON ESM import with Node's createRequire to load
the package.json (import { createRequire } from "module"; const require =
createRequire(import.meta.url); const packageJson = require("../package.json");)
so the CLI runs reliably under Node 22 ESM, and update the catch parameter at
the failing site from a vague/incorrect annotation to a concrete Error type
(change catch((error: unknown) => ...) to catch((error: Error) => ...) and, if
necessary, guard for non-Error values before using error.message) so the
TypeScript typing follows the project guide.
In `@packages/new-v2/system-cli/src/schema.ts`:
- Line 12: The z.custom call for the "system" schema (currently
z.custom<SystemDefinition<TokenSource>>()) provides no runtime validation;
change it to supply a predicate that at minimum checks the value is a non-null
object (e.g., val => typeof val === 'object' && val !== null) so
configFileSchema.parse() will reject non-object inputs, and consider tightening
further to validate expected SystemDefinition shape after this guard in the
SystemDefinition<TokenSource> handling.
In `@packages/new-v2/system-compiler/src/compile/targets/css.ts`:
- Around line 19-29: The cast "frame.selector as KeyframeSelector" in
keyframesToDeclarations should be removed and the source schema updated so the
type is inferred correctly: update the normalize/schema.ts entry for
frames[].selector to precisely produce KeyframeSelector (e.g., use
z.enum(["from","to"]) or a z.union/z.string().regex that maps to the
KeyframeSelector type) so
CompileContext["normalized"]["keyframes"][number]["frames"][number]["selector"]
is already KeyframeSelector; after adjusting the schema (and
regenerating/inferencing types if applicable), delete the type assertion in
keyframesToDeclarations and ensure any related type exports (KeyframeSelector)
are used consistently.
In `@packages/new-v2/system-compiler/src/compile/targets/tailwind-v4.ts`:
- Around line 133-161: The function createAnimationValue currently places the
animation-name (from getKeyframesName(context.registry.keyframes,
animation.keyframes)) at the start which can lead to mis-parsing; change the
construction so you first push duration, easing, delay, iterationCount,
direction, fillMode (using resolveTailwindValue for the value-like fields and
String(...) for iterationCount) into the values array and then append the
animation-name result last (call getKeyframesName only when appending) so the
final values.join(" ") has the name at the end.
In `@packages/new-v2/system-compiler/src/normalize/composites.ts`:
- Around line 28-45: The current isLeaf check in normalize/composites.ts treats
any presence of a record child as non-leaf, splitting styles that include nested
state/condition objects (e.g., _hover); change the logic so that a node is
considered a group only when all children are records. Concretely, replace the
isLeaf computation with the inverse of an all-record check (e.g., compute
isGroup = values.length > 0 && values.every(isRecord) and treat non-group as
leaf), keeping the same push to output (using item.path.join and item.value) and
the same children iteration via entriesOf and stack when it is a group.
In `@packages/new-v2/system-compiler/src/normalize/schema.ts`:
- Line 47: The selector regex in the Zod schema (the selector:
z.string().regex(...) entry) only allows integer percentages and rejects decimal
percentages like 33.33%; update the regex to accept optional fractional parts
(and leading dot decimals) so CSS percentages with decimals pass validation,
e.g. replace the current pattern with one that uses (?:\d+(?:\.\d+)?|\.\d+)%
such as /^(?:from|to|(?:\d+(?:\.\d+)?|\.\d+)%)$/ in the selector field of the
schema.
In `@packages/new-v2/system-compiler/src/normalize/styles.ts`:
- Around line 36-65: When handling nested keys in the selector/at-rule branches,
ensure the pushed style is actually an object to avoid passing primitives into
entriesOf; before pushing to stack in the nestedStyleKeys.selector and
nestedStyleKeys.atRule blocks, add a guard like "value is non-null object and
not an array" and if the guard fails, either skip pushing (continue) or replace
with an empty object, so entriesOf never receives a primitive; update the logic
around the stack.push calls that set style to value to validate the type and
handle non-object values safely.
In `@packages/new-v2/system-compiler/src/output/schema.ts`:
- Around line 66-70: The selector schema currently only allows integer
percentages; update the z.string().regex inside the selector union in schema.ts
to accept decimal percentages as well (e.g. change /^\d+%$/ to a regex that
permits fractional parts such as /^(\d+(\.\d+)?|\.\d+)%$/), so "12.5%" and ".5%"
are valid keyframe selectors alongside "from" and "to".
In `@packages/new-v2/system-compiler/src/registry/tokens.ts`:
- Around line 88-90: The getTokenValue function currently falls back to
returning the input path when a token reference is missing, hiding errors;
change getTokenValue (in packages/new-v2/system-compiler/src/registry/tokens.ts)
to throw a clear exception when registry.references.get(path) returns undefined
— include the missing token path and context (e.g., "Unknown token reference:
<path> in TokenRegistry") in the error message so callers fail-fast instead of
silently emitting the original string.
In `@packages/new-v2/system-compiler/src/transform/recipes.ts`:
- Around line 21-25: The exported type RecipePropertyTransformer currently
declares the second parameter as value: unknown which forces callers to
narrow/assert; change its type to the precise style value type (use
StyleDeclaration["value"]) so the public signature preserves type flow and
compiler checks; update the declaration of RecipePropertyTransformer to accept
value: StyleDeclaration["value"] and adjust any implementations of
RecipePropertyTransformer to match the new parameter type.
In `@packages/new-v2/system-compiler/src/transform/selectors.ts`:
- Around line 26-36: getCompoundClassName can produce an invalid class name when
selection yields an empty suffix and TypeScript still treats mapped values as
string|undefined; fix by applying a type-guarding filter that narrows value to
string (e.g., filter(([_, v]): v is string => v !== undefined) or equivalent)
before map so map sees string, then only append the "--" + suffix when suffix is
non-empty (if no entries after filtering, return baseClassName directly). This
addresses both the empty-suffix output and the typing issue in
getCompoundClassName.
In `@packages/new-v2/system-core/src/token/composite/animation.ts`:
- Around line 15-16: Change the generic constraint on AnimationReference from
Record<string, unknown> to the existing AnimationDefinitionMap so the type
parameter TAnimations extends AnimationDefinitionMap (use the same constraint
used by defineAnimations), update any related generic usages to match this
stricter type, and ensure imports/exports still resolve for
AnimationDefinitionMap and defineAnimations so the new constraint enforces
consistent animation definition types.
---
Nitpick comments:
In `@package.json`:
- Line 24: The dependency "@typescript/native-preview" in package.json is using
a floating dist-tag "beta" which harms reproducibility; change that entry to a
fixed version string (e.g., a specific nightly/version) instead of "beta" and
regenerate the lockfile (pnpm-lock.yaml) then commit the updated lockfile to the
repo so CI installs are deterministic; update the package.json entry named
"@typescript/native-preview" and ensure you run your package manager to produce
and commit the corresponding lockfile.
In `@packages/new-v2/system-cli/src/index.ts`:
- Line 17: The catch handler for main() currently types the error parameter as
unknown which violates repo TS rules; change the parameter type to a precise
union like "Error | string" (or another appropriate specific union) in the
main().catch((error: Error | string) => { ... }) callback and then narrow it
inside the block (e.g., instanceof Error to access message/stack, else treat as
string) before calling any logging/exit logic so you avoid using unknown/any
while preserving correct error handling; update any processLogger or console
usage inside this catch to use the narrowed variable.
In `@packages/new-v2/system-cli/test/compile.test.ts`:
- Line 26: Replace the non-deterministic cwd: path.resolve(".") with a
file-relative directory reference so the test doesn't depend on process CWD;
specifically, compute the test file directory using
fileURLToPath(import.meta.url) and path.dirname(...) (or __dirname for CJS) and
use path.resolve(...) of that value for the cwd option, and add the
corresponding import of fileURLToPath from 'url' when using ESM.
In `@packages/new-v2/system-compiler/src/compile/targets/tailwind-v4.ts`:
- Around line 104-119: The token-reference Map is being rebuilt three times by
createTailwindTokenReferences; instead, compute it once at the top-level
compileTailwindV4 and pass the resulting Map into the callers. Modify
compileTailwindV4 to call createTailwindTokenReferences(context) once and store
the Map, then update createThemeDeclarations, createTextStyleUtilities, and
createComponentBlocks to accept a references: Map<string,string> parameter
(remove their internal calls to createTailwindTokenReferences) and use the
passed Map instead.
In `@packages/new-v2/system-compiler/src/normalize/recipes.ts`:
- Around line 29-54: Duplicate logic exists for filtering compoundVariant.when
and normalizing defaultVariants in the two recipe branches; extract a small
helper (e.g., normalizeWhenEntries and normalizeDefaultVariants) that takes a
record (use entriesOf/isRecord) and returns filtered Object.fromEntries removing
undefined values, and another helper to map css slot styles using normalizeStyle
for compoundVariants slots, then replace the inline logic in both branches
(references: recipeRecord, compoundVariants, compoundVariantRecord, when, css,
slots, defaultVariants, entriesOf, normalizeStyle, isRecord) to call these
helpers so both branches share the same behavior.
In `@packages/new-v2/system-compiler/src/normalize/styles.ts`:
- Around line 12-13: The function normalizeStyle currently types its result as
unknown[] which loses useful shape information; define a precise type (e.g.,
interface NormalizedStyleItem { scope: string; property: string; value: string |
number | null } or the actual shapes used) and change the function signature to
return NormalizedStyleItem[] and the local output variable to that type; ensure
any internal narrowing/casts produce values that conform to NormalizedStyleItem
(or adjust the fields/types to match real data) rather than using unknown/any,
and update any call sites if needed to use the new type.
In `@packages/new-v2/system-compiler/src/normalize/system.test.ts`:
- Around line 125-182: The test is asserting a strict order on tokens.primitive
using toEqual, which makes it fragile; change the assertion to verify presence
regardless of order by replacing the order-dependent toEqual check on
tokens.primitive with an assertion that uses Jest's array-containing matcher
(expect.arrayContaining) to assert that the actual tokens.primitive includes all
expected primitive token objects (the expected primitive tokens array used in
the test), so the test validates membership only and no longer depends on
element order.
In `@packages/new-v2/system-compiler/src/registry/keyframes.ts`:
- Around line 12-14: Extract the hard-coded prefix string "keyframes." into a
single exported constant (e.g., KEYFRAMES_PREFIX) and use that constant when
building the references Map in createKeyframesRegistry and when forming lookup
keys in getKeyframesName (and any callers such as registry/composites.ts) so
both creation and lookup use the same centralized format; update references: new
Map(keyframes.map(({ name }) => [ `${KEYFRAMES_PREFIX}${name}`, name ])) and
replace any literal "keyframes." usages with the new constant throughout the
registry code.
In `@packages/new-v2/system-compiler/src/transform/selectors.ts`:
- Around line 58-64: The isNestedAtRule function currently checks for "@media",
"@supports", and "@container" but omits "@layer", causing `@layer` rules to be
misclassified; update the isNestedAtRule function to also detect "@layer" (e.g.,
check key.startsWith("@layer") so variants like "@layer", "@layer ", or
"@layer{" are caught) so recipe styles using `@layer` are recognized as nested
at-rules.
In `@packages/new-v2/system-compiler/test/compiler.test.ts`:
- Line 272: Replace the type assertion "as never" on the animation property with
a TypeScript suppression comment: remove the "as never" after animation:
"animation.missing" and add a preceding single-line `@ts-expect-error` comment so
the intentional type violation is documented by TypeScript tooling; target the
test entry that sets animation: "animation.missing" (the animation property in
the failing test) and ensure only that line is suppressed with `@ts-expect-error`
rather than using a broad type assertion.
In `@packages/new-v2/system-core/src/recipe/slotRecipe/api.ts`:
- Around line 32-34: The generic TCompoundVariants in defineSlotRecipe is
missing its default of = undefined, causing inconsistent type inference vs
defineRecipe; update the generic declaration for TCompoundVariants in
defineSlotRecipe to include the same default (= undefined) so that omitting
compoundVariants yields the same inferred type as defineRecipe (ensure you
update the generic signature where TCompoundVariants is declared and any related
uses of compoundVariants to rely on that default).
In `@packages/new-v2/system-core/src/style/css.ts`:
- Around line 18-23: The CssColorFunction union is missing several modern CSS
color functions; update the CssColorFunction type to include template literal
variants for the additional functions (e.g., `oklab(${string})`,
`lch(${string})`, `lab(${string})`, `hwb(${string})`, `color(${string})`, and
`color-mix(${string})`) alongside the existing entries so all common W3C color
functions are covered; modify the union definition in the CssColorFunction type
to add those string-template members.
- Line 38: NumberValue currently allows JS number including NaN/Infinity which
are invalid CSS values; update the type by replacing NumberValue = number |
NumberLiteral with a safer definition (e.g., introduce a branded alias
FiniteNumber and use NumberValue = FiniteNumber | NumberLiteral) and/or add a
clear doc comment on NumberValue/NumberLiteral stating only finite numbers are
allowed; implement or call runtime checks where numeric parsing occurs to reject
NaN/Infinity if you cannot fully enforce this at the type level.
In `@packages/new-v2/system-core/src/style/input.ts`:
- Around line 14-33: StyleShorthandInputMap is missing the margin-direction
shorthand keys (mt, mr, mb, ml) so paddings (pt, pr, pb, pl) are asymmetric; add
entries mt: StyleInputValueMap["spacing"], mr: StyleInputValueMap["spacing"],
mb: StyleInputValueMap["spacing"], ml: StyleInputValueMap["spacing"] to the
StyleShorthandInputMap interface (placing them alongside m, mx, my) so margin
direction shorthand matches padding shorthand and uses the same "spacing" type.
🪄 Autofix (Beta)
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: CHILL
Plan: Pro
Run ID: 3cfc6eea-3d09-4e75-93be-8934577dc54c
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (85)
.agents/skills/ai-sdk/SKILL.md.agents/skills/ai-sdk/references/ai-gateway.md.agents/skills/ai-sdk/references/common-errors.md.agents/skills/ai-sdk/references/devtools.md.agents/skills/ai-sdk/references/type-safe-agents.md.agents/skills/gathering-task-context/SKILL.mdpackage.jsonpackages/new-v2/system-cli/eslint.config.mjspackages/new-v2/system-cli/package.jsonpackages/new-v2/system-cli/src/command.tspackages/new-v2/system-cli/src/compile.tspackages/new-v2/system-cli/src/index.tspackages/new-v2/system-cli/src/schema.tspackages/new-v2/system-cli/test/compile.test.tspackages/new-v2/system-cli/test/fixtures/basic-system.config.tspackages/new-v2/system-cli/tsconfig.jsonpackages/new-v2/system-cli/tsdown.config.tspackages/new-v2/system-cli/vitest.config.tspackages/new-v2/system-compiler/eslint.config.mjspackages/new-v2/system-compiler/package.jsonpackages/new-v2/system-compiler/src/compile/context.tspackages/new-v2/system-compiler/src/compile/index.tspackages/new-v2/system-compiler/src/compile/options.tspackages/new-v2/system-compiler/src/compile/targets/css.tspackages/new-v2/system-compiler/src/compile/targets/tailwind-v4.tspackages/new-v2/system-compiler/src/compile/targets/types.tspackages/new-v2/system-compiler/src/compile/types.tspackages/new-v2/system-compiler/src/emit/files.tspackages/new-v2/system-compiler/src/index.tspackages/new-v2/system-compiler/src/normalize/composites.tspackages/new-v2/system-compiler/src/normalize/keyframes.tspackages/new-v2/system-compiler/src/normalize/recipes.tspackages/new-v2/system-compiler/src/normalize/schema.tspackages/new-v2/system-compiler/src/normalize/styles.tspackages/new-v2/system-compiler/src/normalize/system.test.tspackages/new-v2/system-compiler/src/normalize/system.tspackages/new-v2/system-compiler/src/normalize/theme.tspackages/new-v2/system-compiler/src/normalize/tokens.tspackages/new-v2/system-compiler/src/normalize/utils.tspackages/new-v2/system-compiler/src/output/schema.tspackages/new-v2/system-compiler/src/registry/composites.tspackages/new-v2/system-compiler/src/registry/keyframes.tspackages/new-v2/system-compiler/src/registry/tokens.tspackages/new-v2/system-compiler/src/registry/types.tspackages/new-v2/system-compiler/src/render/output.tspackages/new-v2/system-compiler/src/render/postcss.tspackages/new-v2/system-compiler/src/transform/properties.tspackages/new-v2/system-compiler/src/transform/recipes.tspackages/new-v2/system-compiler/src/transform/selectors.tspackages/new-v2/system-compiler/test/compiler.test.tspackages/new-v2/system-compiler/tsconfig.jsonpackages/new-v2/system-compiler/tsdown.config.tspackages/new-v2/system-core/eslint.config.mjspackages/new-v2/system-core/package.jsonpackages/new-v2/system-core/src/index.tspackages/new-v2/system-core/src/keyframes/api.tspackages/new-v2/system-core/src/keyframes/types.tspackages/new-v2/system-core/src/preset/api.tspackages/new-v2/system-core/src/preset/types.tspackages/new-v2/system-core/src/recipe/recipe/api.tspackages/new-v2/system-core/src/recipe/recipe/types.tspackages/new-v2/system-core/src/recipe/slotRecipe/api.tspackages/new-v2/system-core/src/recipe/slotRecipe/types.tspackages/new-v2/system-core/src/recipe/types.tspackages/new-v2/system-core/src/style/css.tspackages/new-v2/system-core/src/style/input.tspackages/new-v2/system-core/src/style/reference.tspackages/new-v2/system-core/src/style/value.tspackages/new-v2/system-core/src/system/api.tspackages/new-v2/system-core/src/system/types.tspackages/new-v2/system-core/src/token/composite/animation.tspackages/new-v2/system-core/src/token/composite/textStyle.tspackages/new-v2/system-core/src/token/primitive/api.tspackages/new-v2/system-core/src/token/primitive/types.tspackages/new-v2/system-core/src/token/semantic/api.tspackages/new-v2/system-core/src/token/semantic/types.tspackages/new-v2/system-core/src/token/types.tspackages/new-v2/system-core/src/token/utils.tspackages/new-v2/system-core/test/core.type.test.tspackages/new-v2/system-core/tsconfig.jsonpackages/new-v2/system-core/tsdown.config.tspackages/new-v2/system-core/vitest.config.tspackages/ui/tsconfig.jsonpnpm-workspace.yamltokens.json
💤 Files with no reviewable changes (1)
- tokens.json
| ``` | ||
| .devtools/generations.json | ||
| ``` |
There was a problem hiding this comment.
코드 펜스 언어를 명시해 markdownlint 경고를 제거해주세요.
Line 32 코드 블록에 언어가 없어 MD040 경고가 발생합니다. text(또는 bash)를 지정하면 됩니다.
제안 수정안
-```
+```text
.devtools/generations.json</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **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.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 32-32: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 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 @.agents/skills/ai-sdk/references/devtools.md around lines 32 - 34, The
fenced code block that contains ".devtools/generations.json" is missing a
language tag and triggers markdownlint MD040; update that block in
.agents/skills/ai-sdk/references/devtools.md by changing the opening fence from
``` to a language-tagged fence such as ```text (or ```bash) so the snippet reads
with a language specifier and the MD040 warning is resolved.
| ``` | ||
| lib/ | ||
| agents/ | ||
| my-agent.ts # Agent definition + type export | ||
| tools/ | ||
| weather-tool.ts # Individual tool definitions | ||
| calculator-tool.ts | ||
| ``` |
There was a problem hiding this comment.
디렉터리 트리 코드 블록에 언어 태그를 추가해주세요.
Line 12 코드 펜스에 언어가 없어 lint 경고가 납니다. text를 지정하는 것이 가장 무난합니다.
제안 수정안
-```
+```text
lib/
agents/
my-agent.ts # Agent definition + type export
tools/
weather-tool.ts # Individual tool definitions
calculator-tool.ts</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **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.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 12-12: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 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 @.agents/skills/ai-sdk/references/type-safe-agents.md around lines 12 - 19,
Add a language tag to the directory tree code fence that begins with "lib/" so
the markdown linter stops warning; change the opening triple-backtick to specify
a language (use "text") for the fenced block that contains the lib/ agents/
tools/ listing.
|
|
||
| Based on gathered context, classify: | ||
|
|
||
| ``` |
There was a problem hiding this comment.
코드 블록에 언어 식별자를 추가해주세요.
마크다운 모범 사례에 따라 펜스 코드 블록에는 언어 식별자를 명시해야 합니다. 이 pseudo-code의 경우 javascript 또는 typescript를 권장합니다.
🔧 제안된 수정
-```
+```javascript
switch(taskType) {Static analysis 도구(markdownlint-cli2)에서도 이 부분을 지적했습니다.
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 68-68: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 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 @.agents/skills/gathering-task-context/SKILL.md at line 68, The fenced code
block containing "switch(taskType) {" in SKILL.md lacks a language
identifier—update the opening fence to include a language tag (e.g.,
```javascript or ```typescript) so the block becomes a recognized
JavaScript/TypeScript snippet; ensure you update the specific fence that
precedes the switch(taskType) { line to satisfy markdownlint-cli2 and enable
proper syntax highlighting.
| "scripts": { | ||
| "build": "tsdown", | ||
| "lint": "eslint --max-warnings 0 --no-warn-ignored .", | ||
| "check-type": "tsgo --noEmit", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 워크스페이스 루트 package.json 및 pnpm catalog에 `@typescript/native-preview` 선언 여부 확인
rg -n "native-preview" --type jsonRepository: jongh-design-system/jds
Length of output: 125
🏁 Script executed:
#!/bin/bash
# Check the system-cli/package.json file to see devDependencies
cat -n packages/new-v2/system-cli/package.json | head -40Repository: jongh-design-system/jds
Length of output: 1279
🏁 Script executed:
#!/bin/bash
# Check the workspace root package.json for `@typescript/native-preview` declaration
cat -n package.json | grep -A2 -B2 "native-preview"Repository: jongh-design-system/jds
Length of output: 283
🏁 Script executed:
#!/bin/bash
# List the repository structure to understand monorepo setup
git ls-files | grep -E "^package\.json$|pnpm-workspace|lerna\.json" | head -20Repository: jongh-design-system/jds
Length of output: 100
🏁 Script executed:
#!/bin/bash
# Read complete devDependencies section of system-cli/package.json
sed -n '39,60p' packages/new-v2/system-cli/package.jsonRepository: jongh-design-system/jds
Length of output: 251
🏁 Script executed:
#!/bin/bash
# Check pnpm-workspace.yaml to understand workspace configuration
cat pnpm-workspace.yamlRepository: jongh-design-system/jds
Length of output: 644
tsgo 명령어를 실행할 의존성이 명시적으로 선언되지 않았습니다.
check-type 스크립트가 tsgo 명령어를 사용하는데, 이를 제공하는 @typescript/native-preview 패키지가 devDependencies에 없습니다. 워크스페이스 루트에는 선언되어 있지만, pnpm-workspace.yaml에서 hoist: false로 설정되어 있고 publicHoistPattern에도 포함되지 않아 이 패키지는 system-cli에서 접근할 수 없습니다. 따라서 이 패키지의 devDependencies에 @typescript/native-preview를 명시적으로 추가해야 합니다.
🤖 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 `@packages/new-v2/system-cli/package.json` at line 22, The package.json script
"check-type" uses the tsgo command but the provider package is not declared
locally; add "@typescript/native-preview" to this package's devDependencies so
tsgo is available when running the "check-type" script. Update the package's
devDependencies entry in package.json to include "@typescript/native-preview"
(matching the workspace version if desired) and run an install to ensure the
binary is hoisted/available for the system-cli package.
|
|
||
| import { Command } from "commander" | ||
|
|
||
| import packageJson from "../package.json" |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Node.js v22 ESM에서 package.json 같은 JSON 파일을 import할 때 import attributes (with { type: "json" } 또는 assert)가 필수인지, 그리고 CLI 엔트리포인트에서 권장되는 버전 문자열 로딩 방식은 무엇인지 확인해줘.
💡 Result:
Node.js v22 ESM에서 package.json 같은 JSON 파일을 import할 때는 import attributes가 필수입니다. 구체적으로 with { type: "json" } 구문을 사용해야 하며, 이전의 assert { type: "json" }는 v22에서 제거되었습니다[1][2][3][4][5]. 공식 예시: import packageConfig from './package.json' with { type: 'json' };[1]. CLI 엔트리포인트(예: node index.js 또는 npm start에서 실행되는 메인 모듈)에서 package.json의 version 등을 로딩하는 권장 방식은 createRequire를 사용해 CommonJS 스타일로 로드하는 것입니다. 이는 ESM 환경에서 안정적이며 경로 문제를 피할 수 있습니다[1][5][6][7]: import { createRequire } from 'node:module'; const require = createRequire(import.meta.url); const pkg = require('./package.json'); console.log(pkg.version); 이 방법은 CLI 도구에서 자신의 package.json을 로드할 때 표준으로 사용되며, global 설치나 다른 CWD에서도 올바르게 작동합니다[7]. 직접 with { type: "json" } import도 가능하지만, 상대 경로(./package.json)가 현재 모듈 위치를 기준으로 해 CLI에서 신뢰할 수 있습니다[1]. fs.readFile을 사용한 수동 로드도 대안이지만 덜 권장됩니다[8].
Citations:
- 1: https://nodejs.org/docs/latest-v22.x/api/esm.html
- 2: https://nodejs.org/api/esm.html
- 3: https://stackoverflow.com/questions/78759608/how-to-import-json-files-in-node-v22
- 4: Re-flag
assertsyntax for import attributes in Node.js 22 nodejs/node#51622 - 5: https://stackoverflow.com/questions/78876691/syntaxerror-unexpected-identifier-assert-on-json-import-in-node-v22
- 6: https://www.stefanjudis.com/snippets/how-to-import-json-files-in-es-modules-node-js/
- 7: https://stackoverflow.com/questions/76781496/node-program-module-reading-its-own-package-json-is-that-possible
- 8: https://www.codegenes.net/blog/is-there-a-way-to-get-the-version-from-the-package-json-file-in-node-js-code/
🏁 Script executed:
# 파일 내용 확인
cat -n packages/new-v2/system-cli/src/index.tsRepository: jongh-design-system/jds
Length of output: 686
🏁 Script executed:
# 프로젝트 Node 버전 확인
cat packages/new-v2/system-cli/package.json | head -20Repository: jongh-design-system/jds
Length of output: 464
🏁 Script executed:
# 프로젝트 전체 루트 package.json 확인
cat package.json | grep -A 5 '"engines"'Repository: jongh-design-system/jds
Length of output: 49
🏁 Script executed:
# tsconfig 확인 (ESM 설정)
cat packages/new-v2/system-cli/tsconfig.json 2>/dev/null || echo "tsconfig.json not found in system-cli"Repository: jongh-design-system/jds
Length of output: 214
🏁 Script executed:
# type module 확인
cd packages/new-v2/system-cli && grep -E '"type":|"module"' package.jsonRepository: jongh-design-system/jds
Length of output: 87
Node.js v22 ESM에서 JSON import에 import attributes가 필수입니다. 현재 코드는 런타임 에러가 발생할 수 있습니다.
Line 5의 import packageJson from "../package.json"은 import attributes 없이 실행되면 Node.js v22 ESM 환경에서 실패합니다. 프로젝트가 "type": "module"이고 Node >=22.0.0을 요구하므로, with { type: "json" } 구문을 추가하거나 createRequire 방식으로 변경해야 합니다. createRequire 방식이 CLI 환경에서 더 안정적입니다.
추가로 Line 17의 catch((error: unknown) 코딩 가이드를 위반합니다. 정확한 타입을 사용하세요.
수정 예시
import { Command } from "commander"
+import { createRequire } from "node:module"
-import packageJson from "../package.json"
import { createCompileCommand } from "./command.ts"
+
+const require = createRequire(import.meta.url)
+const packageJson = require("../package.json") as { version?: string }
async function main() {
const command = new Command()
.name("jds-system")
.version(packageJson.version || "0.0.0")
.addCommand(createCompileCommand())
await command.parseAsync()
}
-main().catch((error: unknown) => {
+main().catch((error) => {
console.error(error instanceof Error ? error.message : String(error))
process.exit(1)
})🤖 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 `@packages/new-v2/system-cli/src/index.ts` at line 5, Replace the direct JSON
ESM import with Node's createRequire to load the package.json (import {
createRequire } from "module"; const require = createRequire(import.meta.url);
const packageJson = require("../package.json");) so the CLI runs reliably under
Node 22 ESM, and update the catch parameter at the failing site from a
vague/incorrect annotation to a concrete Error type (change catch((error:
unknown) => ...) to catch((error: Error) => ...) and, if necessary, guard for
non-Error values before using error.message) so the TypeScript typing follows
the project guide.
| selector: z.union([ | ||
| z.literal("from"), | ||
| z.literal("to"), | ||
| z.string().regex(/^\d+%$/), | ||
| ]), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# 파일 위치 확인 및 내용 조회
find . -name "schema.ts" -path "*/system-compiler/src/output/*" | head -5Repository: jongh-design-system/jds
Length of output: 122
🏁 Script executed:
# 파일 내용 읽기
cat packages/new-v2/system-compiler/src/output/schema.ts | head -100Repository: jongh-design-system/jds
Length of output: 2905
🌐 Web query:
CSS keyframes percentage selector decimal values standard specification
💡 Result:
In CSS Animations Level 1, keyframe selectors use a grammar, where the keyframe selector can be from|to or a percentage value in the closed interval 0%–100%. The keywords from/to are equivalent to 0% and 100% respectively, and percentages outside that range are invalid and ignored. [1] About decimal (fractional) percentage values: the specification text that defines the keyframe selector constrains values to be percentages in the range 0%–100%, but (in the public syntax excerpt) does not explicitly limit the number of digits after the decimal point. Instead, it requires that the “percentage unit specifier must be used on percentage values” (i.e., you must write e.g. 33.3% not 33.3). [1] So, values like 33.3% and 33.3457% are valid as percentages in the selector (as long as they’re within 0%–100% and written with the % sign). However, any concrete “rounding” behavior (e.g., truncating to N decimal places) is an implementation detail, and the spec excerpt does not state a particular rounding precision. [1] Authoritative references: - CSS Animations Level 1 defines the keyframe selector grammar as and states that < percentage values must be written with the % unit specifier; values outside 0%–100% are invalid and ignored; from/to map to 0%/100%. [1] - MDN’s “Keyframe selectors” documentation reiterates that percentage values must include the % sign and must be within 0%–100% (and otherwise the keyframe block is ignored). [2]
Citations:
- 1: https://www.w3.org/TR/css-animations/
- 2: https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/Keyframe_selectors
키프레임 퍼센트 선택자가 소수점 값을 허용해야 합니다.
CSS Animations 표준에 따르면 소수점 퍼센트(예: 12.5%, 33.3%)는 유효한 keyframe 선택자입니다. 현재 정규식은 정수만 허용하여 이러한 유효 값들을 거절합니다.
제안 diff
- z.string().regex(/^\d+%$/),
+ z.string().regex(/^\d+(\.\d+)?%$/),🤖 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 `@packages/new-v2/system-compiler/src/output/schema.ts` around lines 66 - 70,
The selector schema currently only allows integer percentages; update the
z.string().regex inside the selector union in schema.ts to accept decimal
percentages as well (e.g. change /^\d+%$/ to a regex that permits fractional
parts such as /^(\d+(\.\d+)?|\.\d+)%$/), so "12.5%" and ".5%" are valid keyframe
selectors alongside "from" and "to".
| export function getTokenValue(registry: TokenRegistry, path: string): string { | ||
| return registry.references.get(path) ?? path | ||
| } |
There was a problem hiding this comment.
존재하지 않는 토큰 참조를 문자열로 폴백하면 오류가 숨겨집니다.
미해결 참조를 그대로 반환하면 컴파일은 성공하지만 결과 CSS가 조용히 깨질 수 있습니다. 여기서 즉시 예외를 던져 실패-빠르게 처리하는 편이 안전합니다.
제안 수정안
export function getTokenValue(registry: TokenRegistry, path: string): string {
- return registry.references.get(path) ?? path
+ const resolved = registry.references.get(path)
+ if (resolved === undefined) {
+ throw new Error(`Unknown token reference: "${path}"`)
+ }
+ return resolved
}🤖 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 `@packages/new-v2/system-compiler/src/registry/tokens.ts` around lines 88 - 90,
The getTokenValue function currently falls back to returning the input path when
a token reference is missing, hiding errors; change getTokenValue (in
packages/new-v2/system-compiler/src/registry/tokens.ts) to throw a clear
exception when registry.references.get(path) returns undefined — include the
missing token path and context (e.g., "Unknown token reference: <path> in
TokenRegistry") in the error message so callers fail-fast instead of silently
emitting the original string.
| export type RecipePropertyTransformer = ( | ||
| property: string, | ||
| value: unknown, | ||
| registry: CompilerRegistry, | ||
| ) => CssDeclaration[] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate the file and understand its structure
fd "recipes.ts" --type fRepository: jongh-design-system/jds
Length of output: 181
🏁 Script executed:
# Search for StyleDeclaration type definition
rg "type StyleDeclaration" -t ts -t tsxRepository: jongh-design-system/jds
Length of output: 95
🏁 Script executed:
# Check the context around the RecipePropertyTransformer definition
rg -A 10 -B 5 "RecipePropertyTransformer" packages/new-v2/system-compiler/src/transform/recipes.ts -t tsRepository: jongh-design-system/jds
Length of output: 1978
🏁 Script executed:
# Search for usages of RecipePropertyTransformer in the codebase
rg "RecipePropertyTransformer" -t ts -t tsx --iglob "packages/new-v2/**"Repository: jongh-design-system/jds
Length of output: 95
🏁 Script executed:
# Search for transformProperty function and how value parameter is used
rg "transformProperty|value:" packages/new-v2/system-compiler/src/transform/recipes.ts -A 3 -B 1Repository: jongh-design-system/jds
Length of output: 507
🏁 Script executed:
# Check the complete file to understand the context better
wc -l packages/new-v2/system-compiler/src/transform/recipes.tsRepository: jongh-design-system/jds
Length of output: 128
🏁 Script executed:
# Read the file to see the complete context
cat -n packages/new-v2/system-compiler/src/transform/recipes.ts | head -100Repository: jongh-design-system/jds
Length of output: 3162
🏁 Script executed:
# Check the schema definition to understand StyleDeclaration structure
rg "compilerSystemSchema\|base:" packages/new-v2/system-compiler/src/normalize/schema.ts -A 5 -B 2 | head -80Repository: jongh-design-system/jds
Length of output: 49
🏁 Script executed:
# Search for the complete schema definition related to recipes
fd "schema.ts" packages/new-v2/system-compiler/src/normalize/ -type fRepository: jongh-design-system/jds
Length of output: 238
🏁 Script executed:
# Read the schema file to understand StyleDeclaration properties
cat -n packages/new-v2/system-compiler/src/normalize/schema.ts | head -150Repository: jongh-design-system/jds
Length of output: 4630
🏁 Script executed:
# Check the transformProperty function to see how it uses the value parameter
cat -n packages/new-v2/system-compiler/src/transform/properties.ts | head -50Repository: jongh-design-system/jds
Length of output: 1806
🏁 Script executed:
# Read more of the transformProperty function
cat -n packages/new-v2/system-compiler/src/transform/properties.ts | tail -n +49 | head -80Repository: jongh-design-system/jds
Length of output: 1313
RecipePropertyTransformer의 value: unknown은 타입 안정성 원칙과 충돌합니다.
공개 시그니처에서 unknown을 사용하면 실제 타입이 string | number임에도 불구하고 호출부에서 불필요한 타입 좁히기나 단언이 필요해집니다. StyleDeclaration["value"]로 정확한 타입을 지정하면 타입 흐름을 유지하고 컴파일러의 타입 검사 효과를 극대화할 수 있습니다.
제안 diff
export type RecipePropertyTransformer = (
property: string,
- value: unknown,
+ value: StyleDeclaration["value"],
registry: CompilerRegistry,
) => CssDeclaration[]코딩 가이드라인에 따라 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 `@packages/new-v2/system-compiler/src/transform/recipes.ts` around lines 21 -
25, The exported type RecipePropertyTransformer currently declares the second
parameter as value: unknown which forces callers to narrow/assert; change its
type to the precise style value type (use StyleDeclaration["value"]) so the
public signature preserves type flow and compiler checks; update the declaration
of RecipePropertyTransformer to accept value: StyleDeclaration["value"] and
adjust any implementations of RecipePropertyTransformer to match the new
parameter type.
| export function getCompoundClassName( | ||
| baseClassName: string, | ||
| selection: Record<string, string | undefined>, | ||
| ): string { | ||
| const suffix = Object.entries(selection) | ||
| .filter(([, value]) => value !== undefined) | ||
| .map(([name, value]) => `${name}_${value}`) | ||
| .join("-") | ||
|
|
||
| return `${baseClassName}--${suffix}` | ||
| } |
There was a problem hiding this comment.
getCompoundClassName에서 빈 suffix로 인해 잘못된 클래스명이 생성될 수 있습니다.
selection이 빈 객체이거나 모든 값이 undefined인 경우, suffix는 빈 문자열이 되어 반환값이 "${baseClassName}--"이 됩니다. 이는 유효하지 않은 CSS 클래스명입니다.
또한, .filter() 이후 .map()에서 TypeScript가 value를 여전히 string | undefined로 추론합니다. 타입 가드를 사용한 filter로 개선할 수 있습니다.
🐛 수정 제안
export function getCompoundClassName(
baseClassName: string,
selection: Record<string, string | undefined>,
): string {
const suffix = Object.entries(selection)
- .filter(([, value]) => value !== undefined)
- .map(([name, value]) => `${name}_${value}`)
+ .filter((entry): entry is [string, string] => entry[1] !== undefined)
+ .map(([name, value]) => `${name}_${value}`)
.join("-")
+ if (!suffix) {
+ return baseClassName
+ }
+
return `${baseClassName}--${suffix}`
}🤖 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 `@packages/new-v2/system-compiler/src/transform/selectors.ts` around lines 26 -
36, getCompoundClassName can produce an invalid class name when selection yields
an empty suffix and TypeScript still treats mapped values as string|undefined;
fix by applying a type-guarding filter that narrows value to string (e.g.,
filter(([_, v]): v is string => v !== undefined) or equivalent) before map so
map sees string, then only append the "--" + suffix when suffix is non-empty (if
no entries after filtering, return baseClassName directly). This addresses both
the empty-suffix output and the typing issue in getCompoundClassName.
| export type AnimationReference<TAnimations extends Record<string, unknown>> = | ||
| `animation.${keyof TAnimations & string}` |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "animation.ts" -type f | head -20Repository: jongh-design-system/jds
Length of output: 130
🏁 Script executed:
cat -n packages/new-v2/system-core/src/token/composite/animation.ts | head -30Repository: jongh-design-system/jds
Length of output: 854
🏁 Script executed:
rg "AnimationDefinitionMap" --type ts --type tsxRepository: jongh-design-system/jds
Length of output: 95
🏁 Script executed:
rg "AnimationDefinitionMap" --type tsRepository: jongh-design-system/jds
Length of output: 606
🏁 Script executed:
rg "AnimationReference" --type ts -A 2 -B 2Repository: jongh-design-system/jds
Length of output: 1701
🏁 Script executed:
cat -n packages/new-v2/system-core/test/core.type.test.ts | grep -A 10 "AnimationReference"Repository: jongh-design-system/jds
Length of output: 764
🏁 Script executed:
grep -r "AnimationReference" --type ts -B 3 -A 3Repository: jongh-design-system/jds
Length of output: 185
AnimationReference 제네릭 제약의 unknown을 AnimationDefinitionMap으로 변경하세요.
현재 Record<string, unknown> 제약은 타입 안전성 가이드라인을 위반합니다. AnimationDefinitionMap은 이미 파일에 정의되어 있으며, defineAnimations 함수도 동일한 제약을 사용 중입니다. 이 변경은 타입 일관성을 높이고 더 정확한 타입 검증을 제공합니다.
제안 diff
-export type AnimationReference<TAnimations extends Record<string, unknown>> =
+export type AnimationReference<TAnimations extends AnimationDefinitionMap> =
`animation.${keyof TAnimations & 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.
| export type AnimationReference<TAnimations extends Record<string, unknown>> = | |
| `animation.${keyof TAnimations & string}` | |
| export type AnimationReference<TAnimations extends AnimationDefinitionMap> = | |
| `animation.${keyof TAnimations & string}` |
🤖 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 `@packages/new-v2/system-core/src/token/composite/animation.ts` around lines 15
- 16, Change the generic constraint on AnimationReference from Record<string,
unknown> to the existing AnimationDefinitionMap so the type parameter
TAnimations extends AnimationDefinitionMap (use the same constraint used by
defineAnimations), update any related generic usages to match this stricter
type, and ensure imports/exports still resolve for AnimationDefinitionMap and
defineAnimations so the new constraint enforces consistent animation definition
types.
요약
new-v2구현을 추가했습니다.아직 검증 중인 구현이며, npm 배포는 진행하지 않았습니다.
이번 변경은 type-safe API로 시스템 정의를 작성하고, 그 정의를 CSS 파일로 생성하는 흐름을 제공합니다.
system-core: 시스템 정의를 작성하기 위한 type-safe APIsystem-compiler:system-core에서 만든 시스템 정의를 CSS 출력 구조로 변환하는 로직system-cli: config 파일을 읽고 compiler를 실행해 CSS 파일을 생성하는 CLI설계
system-coresystem-core는 시스템 정의를 TypeScript 코드로 작성하기 위한 type-safe API를 제공합니다.주요 API:
definePrimitiveTokensdefineSemanticTokensdefineTextStylesdefineAnimationsdefineKeyframesdefineSlotRecipedefineRecipedefinePresetdefineSystem타입 정책은 시스템 구조와 참조 흐름을 잡는 쪽에 맞췄습니다. primitive token, semantic token, textStyle, animation, keyframes, recipe, slot recipe의 입력 형태를 타입으로 제한하고, 작성한 값의 literal type이 유지되도록 구성했습니다.
style 값은 CSS에서 유효한 raw value와 token reference를 함께 받을 수 있게 열어두었습니다. 예를 들어
color는 CSS color 값과color.*참조를 받고, spacing 계열 속성은 CSS length 값과spacing.*참조를 받습니다. 여기서 실제 token 존재 여부를 전부 타입 단계에서 강하게 묶지는 않습니다. config 작성 단계에서 불필요하게 복잡한 조건부 타입을 늘리는 대신, 속성별 값 범위와 참조 문자열의 방향을 잡는 데 집중했습니다.system-compilersystem-compiler는defineSystem으로 만든 시스템 정의를 CSS 출력 구조로 변환합니다.처리 단계:
normalize: 입력된 시스템 정의를 스키마 기준으로 정리registry: token, keyframes, composite 참조를 조회할 수 있는 구조 생성compile: target에 맞는 CSS 출력 구조 생성render: CSS node를 문자열로 변환emitFiles: layer별 CSS 파일 목록 생성현재 compiler target은 두 가지입니다.
css: 기본 CSS 변수, keyframes, recipe class 출력tailwind-v4: Tailwind v4의@theme,@utility, cascade layer에 맞춘 출력system-clisystem-cli는 config 파일을 읽고 compiler를 실행합니다.처리 단계:
compileSystem실행emitFiles결과를 실제 파일로 저장실행 흐름
기타 변경
packages/new-v2/*workspace 등록tsdown기반 ESM only 번들 설정 추가>=22.0.0packages/ui의 Vite env 타입 포함 설정 추가tokens.json제거Summary by CodeRabbit
릴리스 노트
새로운 기능
문서
기반 시설