Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

zjy2414
Copy link

@zjy2414 zjy2414 commented Sep 2, 2025

feat: introduce react-to-dsl plugin

English | 简体中文

PR

PR Checklist

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)
  • Built its own designer, fully self-validated

PR Type

  • Feature
  • Bugfix
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other...

Background and solution

What is the current behavior?

项目缺少从 React 源码到 Tiny Engine DSL 的转换能力。

What is the new behavior?

新增包 @opentiny/tiny-engine-react-to-dsl,提供从 React 代码到 TinyEngine DSL(IAppSchema)的转换能力,聚焦“单文件源 -> 单个 Page/Block schema”。核心能力如下:

  • 解析 JSX/TSX 为 children 树;对 JS 表达式以 { type: 'JSExpression', value } 形式保留。
  • 从函数组件体内提取函数声明/箭头函数,填充为 page.methods;类组件提取生命周期方法与类方法。
  • 识别最常见的 arr.map(x => <JSX />) 列表渲染,转换为子节点的 loop 表达式。
  • 规范化 props.style:对象转为 CSS 字符串。
  • 组件名映射(如 Form -> TinyFormInput -> TinyInput 等),并包含图标特殊映射(DatabaseOutlined -> Icon 且附加 name: 'IconPanelMini')。
  • 支持注入外部 CSS 内容(例如来自同目录 .css 文件),写入 page.css
  • TypeScript 类型定义齐全(见 types.ts),并提供 Vitest 单测与集成用例输出(会生成 test/testcases/**/output/app.schema.jsonpage.schema.json)。

简要 API:

  • transformReactToDsl(code: string, options?: { filename?: string; isBlock?: boolean; css?: string | string[] }): IAppSchema

Docs

  • 新增 README.md,包含简介、特性、API、组件映射、快速开始与测试说明。

Tests

  • 单测:basic.test.ts
  • 集成用例:test/testcases/**,会从 input/ 读取 .jsx/.tsx 与 .css,输出转换结果至 output/
  • 当前状态:本地验证通过(Vitest)

Does this PR introduce a breaking change?

  • Yes
  • No

Summary by CodeRabbit

  • New Features

    • New React→TinyEngine DSL transformer package: converts JSX/TSX into Page/Block schemas with component mappings, state/methods/lifecycles extraction, loop handling, style normalization, CSS injection, and a public transform API.
    • Small ID utility exposed for generated schema items.
  • Documentation

    • Added comprehensive README with installation, usage examples, API and build/test instructions.
  • Tests

    • Added unit and integration tests covering transformation, data binding, lifecycle handling and mappings.
  • Chores

    • Added package manifest, build/test configs, TypeScript config and ignore rules.

Copy link
Contributor

coderabbitai bot commented Sep 2, 2025

Walkthrough

Adds a new package packages/react-to-dsl that provides a Babel-based transformer (TypeScript) to convert React JSX/TSX into a TinyEngine DSL IAppSchema, with package scaffolding, build/test config, types, utilities, component mappings, tests, and several JSX/CSS testcases.

Changes

Cohort / File(s) Summary
Package docs & config
packages/react-to-dsl/README.md, packages/react-to-dsl/package.json, packages/react-to-dsl/tsconfig.json, packages/react-to-dsl/vite.config.ts, packages/react-to-dsl/.gitignore
New package manifest, README, TypeScript and Vite configs, and .gitignore (ignores output).
Public API index
packages/react-to-dsl/src/index.ts
Re-exports types and exposes transformReactToDsl.
Core types
packages/react-to-dsl/src/types.ts
Adds DSL type definitions (JSExpression, IFuncType, IPageSchema, IAppSchema, etc.).
Component map constants
packages/react-to-dsl/src/constants.ts
Adds defaultComponentMap mapping React names to Tiny DSL equivalents.
Utilities
packages/react-to-dsl/src/utils.ts
Adds genId8() — 8-character id generator.
Transformer implementation
packages/react-to-dsl/src/transform.ts
Adds transformReactToDsl(code, options) — Babel parse/traverse to build IAppSchema (JSX → ISchemaChildrenItem, props, loops, style normalization, state/methods/lifecycles extraction, CSS injection, component mapping).
Unit test (basic)
packages/react-to-dsl/test/basic/basic.test.ts
Adds Vitest unit verifying simple JSX→DSL conversion and className preservation.
Integration test runner
packages/react-to-dsl/test/testcases/index.test.js
Adds testcase discovery runner that feeds input files/CSS to transformer and writes outputs per case with validations.
Testcases: Normal form/table
packages/react-to-dsl/test/testcases/001_normal/input/FormTable.jsx, packages/react-to-dsl/test/testcases/001_normal/input/FormTable.css
Adds complex FormTable JSX sample and CSS used by integration tests.
Testcases: Data binding
packages/react-to-dsl/test/testcases/002_data-binding/input/DataBindingDemo.jsx
Adds controlled inputs/checkbox sample component.
Testcases: Create VM wizard
packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx, packages/react-to-dsl/test/testcases/003_createVM/input/createVm.css
Adds multi-step CreateVm sample and stylesheet.
Testcases: Lifecycle (class)
packages/react-to-dsl/test/testcases/004_lifecycle/input/lifecycle.jsx
Adds class component sample with lifecycle methods and click handler.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor Caller
    participant TR as transformReactToDsl
    participant BP as Babel Parser
    participant TV as AST Traversal
    participant NB as Node Builder
    participant CM as Component Mapper
    participant SB as Schema Builder

    Caller->>TR: transformReactToDsl(code, { filename, css, isBlock })
    TR->>BP: parse(code)
    BP-->>TR: AST
    TR->>TV: traverse(AST) 
    TV-->>TR: roots, hooks, methods, lifecycles
    TR->>NB: buildNodeFromJSX(rootJSX)
    NB-->>TR: ISchemaChildrenItem tree
    TR->>CM: apply defaultComponentMap & special icon handling
    CM-->>TR: normalized nodes (props/styles adjusted)
    TR->>SB: assemble IAppSchema (page/block, state, methods, lifeCycles, css, meta)
    SB-->>TR: IAppSchema
    TR-->>Caller: IAppSchema
    note over TR,TV: defensive parsing for loops/expressions and extraction errors
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks (3 passed)

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly and accurately summarizes the primary change — introducing a react-to-dsl plugin/package to the repo; it is concise, uses the conventional "feat:" prefix, and directly reflects the added package and supporting files.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

I nibble code and hop with cheer,
JSX turns to schema near.
Loops become nodes, styles sing true,
Methods tucked and lifecycles too.
Hooray—DSL blooms from React's view! 🐇✨

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41700e8 and 4a9bc32.

📒 Files selected for processing (1)
  • packages/react-to-dsl/.gitignore (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/react-to-dsl/.gitignore
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added enhancement New feature or request ospp ospp labels Sep 2, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

🧹 Nitpick comments (27)
packages/react-to-dsl/.gitignore (1)

1-2: Anchor ignores to package root and add trailing newline.

Minor hygiene; also consider ignoring build artifacts here.

Apply:

-output
-result
+/output
+/result
+dist/
+coverage/
packages/react-to-dsl/tsconfig.json (1)

3-13: Align TS 5 bundler resolution with explicit ESM semantics.

Consider enabling verbatimModuleSyntax to prevent TS from rewriting imports/exports.

   "compilerOptions": {
     "skipLibCheck": true,
-    "strict": true
+    "strict": true,
+    "verbatimModuleSyntax": true
   },
packages/react-to-dsl/src/utils.ts (1)

1-13: Prefer nanoid for collision-resistance and easier testability.

Math.random is fine for demos, but nanoid is standard, faster, and mockable in tests. You already externalize "nanoid" in the build.

-// Local 8-char id generator: digits + lowercase letters only
-const _ID_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'
-function genId8(): string {
-  let id = ''
-  for (let i = 0; i < 8; i++) {
-    // Use Math.random for simplicity; sufficient for schema ids
-    const idx = Math.floor(Math.random() * _ID_ALPHABET.length)
-    id += _ID_ALPHABET.charAt(idx)
-  }
-  return id
-}
+import { customAlphabet } from 'nanoid'
+// 36-char alphabet, fixed length 8
+const genId8: () => string = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 8)
 
 export { genId8 }

If determinism is needed for golden outputs, make the ID generator injectable via transform options and default to genId8.

packages/react-to-dsl/test/testcases/001_normal/input/FormTable.css (2)

19-25: Prefer flex-start over start for broader Flexbox compatibility

justify-content: start can behave differently across engines. flex-start is safer for Flexbox containers.

Apply:

-  justify-content: start;
+  justify-content: flex-start;

10-15: Minor: simplify padding shorthand

padding: 20px 20px can be padding: 20px.

-  padding: 20px 20px;
+  padding: 20px;
packages/react-to-dsl/src/constants.ts (1)

1-15: Consider allowing user-supplied component map overrides

Expose an option (e.g., options.componentMap) merged over defaultComponentMap so consumers can customize without forking.

packages/react-to-dsl/README.md (2)

100-129: Document how to override component mappings and icon rules

Add a short section showing options.componentMap usage and how special icon mappings can be extended.


20-35: Call out TypeScript types delivery

README promises types; ensure package.json exposes "types" and build emits .d.ts. Add a note or “Build outputs” section so consumers know typings are included.

I can draft the vite + vite-plugin-dts config snippet if helpful.

packages/react-to-dsl/package.json (1)

44-47: Peer deps likely unnecessary

Library parses strings; it doesn’t require react/react-dom at runtime. Consider removing peerDependencies to avoid needless install warnings.

packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx (1)

78-86: Don’t pass children via “children” prop

Use JSX children for readability and to satisfy linters.

Examples:

- <Typography.Text
-   children="温馨提示:页面左上角切换区域"
-   style={{ color: '#8a8e99', fontSize: '12px' }}
- ></Typography.Text>
+ <Typography.Text style={{ color: '#8a8e99', fontSize: '12px' }}>
+   温馨提示:页面左上角切换区域
+ </Typography.Text>

- <Typography.Text children="当前规格" style={{ width: '150px', display: 'inline-block' }} />
+ <Typography.Text style={{ width: '150px', display: 'inline-block' }}>当前规格</Typography.Text>

Apply similarly to the other instances in this file.

Also applies to: 216-224, 433-452, 220-223

packages/react-to-dsl/src/index.ts (1)

1-2: Re-export TransformOptions for a complete public API surface

Consumers need the options type without deep imports. Add a type re-export.

 export * from './types'
-export { transformReactToDsl } from './transform'
+export { transformReactToDsl } from './transform'
+export type { TransformOptions } from './transform'
packages/react-to-dsl/test/testcases/index.test.js (4)

8-14: Stabilize testcase discovery order

Sort directories to ensure deterministic run order and stable output diffs across platforms.

 function getTestCaseDirs(rootDir) {
   return fs
     .readdirSync(rootDir, { withFileTypes: true })
     .filter((d) => d.isDirectory())
-    .map((d) => d.name)
+    .map((d) => d.name)
     .filter((name) => name !== 'output' && !name.startsWith('.'))
+    .sort()
 }

57-60: Make the discovery test assert at least one testcase (or skip gracefully)

This catches path issues early.

-  it(`should discover at least 1 testcase`, () => {
-    expect(Array.isArray(caseNames)).toBe(true)
-    // 允许为空,但给出提示;如果后续补充用例即可被自动识别
-  })
+  it(`should discover at least 1 testcase`, () => {
+    expect(Array.isArray(caseNames)).toBe(true)
+    expect(caseNames.length).toBeGreaterThan(0)
+  })

75-78: Strengthen schema assertions

Also assert there is at least one page to guard against empty outputs.

   // 基本校验
   expect(appSchema).toBeTruthy()
   expect(Array.isArray(appSchema.pageSchema)).toBe(true)
+  expect(appSchema.pageSchema.length).toBeGreaterThan(0)

79-81: Gate filesystem outputs behind an env flag to keep CI clean

Avoid writing artifacts unless explicitly requested.

   // 输出到 output/<caseName>
-  writeOutputs(casesRoot, caseName, appSchema)
+  if (process.env.WRITE_OUTPUT === '1') {
+    writeOutputs(casesRoot, caseName, appSchema)
+  }
packages/react-to-dsl/test/basic/basic.test.ts (1)

11-22: Add a small invariant on fileName for extra safety

This protects the filename normalization behavior.

     const dsl = transformReactToDsl(code, { filename: 'App.tsx' })
     expect(dsl.pageSchema.length).toBe(1)
     const pageOrFolder = dsl.pageSchema[0]
     if ((pageOrFolder as any).componentName === 'Folder') {
       throw new Error('unexpected Folder in pageSchema')
     }
     const page = pageOrFolder as any
+    expect(page.fileName).toBe('App')
     expect(page.children.length).toBe(1)
     expect(page.children[0].componentName).toBe('div')
     // props.className should be preserved
     expect(page.children[0].props.className).toBe('box')
packages/react-to-dsl/test/testcases/002_data-binding/input/DataBindingDemo.jsx (2)

17-17: Use object style to exercise “style object → CSS string” normalization

A string style bypasses the normalization path. Using an object better validates the feature.

-        <div style="padding: 20px;">
+        <div style={{ padding: '20px' }}>

12-12: Remove unused local utils

Not used; trimming avoids noise in fixture processing.

-  const utils = {}
+  // (removed) unused
packages/react-to-dsl/test/testcases/004_lifecycle/input/lifecycle.jsx (2)

38-38: Use object style to test style normalization path

Same rationale: drive the object→CSS conversion logic.

-          <div style="padding: 20px;">
+          <div style={{ padding: '20px' }}>

33-33: Remove unused utils inside render

Unreferenced; safe to drop.

-    const utils = {}
+    // (removed) unused
packages/react-to-dsl/test/testcases/001_normal/input/FormTable.jsx (2)

188-188: Redundant conditional rendering

The condition false ? <TinyIconHelpCircle></TinyIconHelpCircle> : null is always false and could be simplified.

This code can be removed entirely since it never renders:

-        {false ? <TinyIconHelpCircle></TinyIconHelpCircle> : null}

98-98: Unused variable declaration

The utils object is declared but never used in the component.

-  const utils = {}
packages/react-to-dsl/src/transform.ts (3)

36-41: Consider improving computed property key handling

The computed property key handling generates code without validation. Consider adding safety checks or documentation about limitations.

          const k = prop.computed
-            ? generate(prop.key).code
+            ? generate(prop.key).code // Note: Complex computed keys may not be preserved correctly
            : prop.key.type === 'Identifier'
            ? prop.key.name
            : String((prop.key as any).value)

189-195: Improve CSS conversion robustness

The styleObjToCss function should handle edge cases like numeric values and units.

function styleObjToCss(obj: Record<string, any> | string | undefined): any {
  if (!obj || typeof obj === 'string') return obj
  const toKebab = (s: string) => s.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())
  return Object.entries(obj)
-    .map(([k, v]) => `${toKebab(k)}: ${v}`)
+    .map(([k, v]) => {
+      // Handle numeric values that need units
+      const value = typeof v === 'number' && !['opacity', 'zIndex', 'fontWeight'].includes(k) 
+        ? `${v}px` 
+        : v
+      return `${toKebab(k)}: ${value}`
+    })
    .join('; ')
}

344-353: Consider supporting modern React lifecycle methods

The lifecycle method list doesn't include newer React lifecycle methods like getDerivedStateFromProps and getSnapshotBeforeUpdate.

      const lifecycleNames = new Set([
        'constructor',
        'componentDidMount',
        'componentWillUnmount',
        'componentDidUpdate',
        'componentDidCatch',
        'shouldComponentUpdate',
        'getSnapshotBeforeUpdate',
-        'componentWillReceiveProps'
+        'componentWillReceiveProps',
+        'getDerivedStateFromProps',
+        'getDerivedStateFromError'
      ])
packages/react-to-dsl/src/types.ts (2)

71-71: Consider using a more specific type for content

The content field in IUtilsItem is typed as object, which provides minimal type safety. Consider using a more specific type or union type.

export interface IUtilsItem {
  name: string
  type: 'npm' | 'function'
-  content: object
+  content: Record<string, any> | { package: string; version: string } | IFuncType
}

49-49: Nested Record type may be confusing

The lifeCycles type uses nested Records which might be confusing. Consider simplifying or adding documentation.

  lifeCycles: {
-    [key: string]: Record<string, IFuncType>
+    [lifecycleName: string]: Record<string, IFuncType>  // lifecycle name -> method implementations
  }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 108919d and e8cc174.

📒 Files selected for processing (18)
  • packages/react-to-dsl/.gitignore (1 hunks)
  • packages/react-to-dsl/README.md (1 hunks)
  • packages/react-to-dsl/package.json (1 hunks)
  • packages/react-to-dsl/src/constants.ts (1 hunks)
  • packages/react-to-dsl/src/index.ts (1 hunks)
  • packages/react-to-dsl/src/transform.ts (1 hunks)
  • packages/react-to-dsl/src/types.ts (1 hunks)
  • packages/react-to-dsl/src/utils.ts (1 hunks)
  • packages/react-to-dsl/test/basic/basic.test.ts (1 hunks)
  • packages/react-to-dsl/test/testcases/001_normal/input/FormTable.css (1 hunks)
  • packages/react-to-dsl/test/testcases/001_normal/input/FormTable.jsx (1 hunks)
  • packages/react-to-dsl/test/testcases/002_data-binding/input/DataBindingDemo.jsx (1 hunks)
  • packages/react-to-dsl/test/testcases/003_createVM/input/createVm.css (1 hunks)
  • packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx (1 hunks)
  • packages/react-to-dsl/test/testcases/004_lifecycle/input/lifecycle.jsx (1 hunks)
  • packages/react-to-dsl/test/testcases/index.test.js (1 hunks)
  • packages/react-to-dsl/tsconfig.json (1 hunks)
  • packages/react-to-dsl/vite.config.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-01-14T08:42:18.574Z
Learnt from: gene9831
PR: opentiny/tiny-engine#1038
File: packages/plugins/block/index.js:24-24
Timestamp: 2025-01-14T08:42:18.574Z
Learning: In the tiny-engine project, breaking changes are documented in the changelog rather than in JSDoc comments or separate migration guides.

Applied to files:

  • packages/react-to-dsl/README.md
📚 Learning: 2024-10-09T01:47:35.507Z
Learnt from: chilingling
PR: opentiny/tiny-engine#583
File: packages/build/vite-config/index.js:1-1
Timestamp: 2024-10-09T01:47:35.507Z
Learning: The `getDefaultConfig` function inside `packages/build/vite-config/src/default-config.js` is intended to remain and be called internally. Ensure no references to this function exist outside of this file.

Applied to files:

  • packages/react-to-dsl/vite.config.ts
📚 Learning: 2024-09-30T07:51:10.036Z
Learnt from: chilingling
PR: opentiny/tiny-engine#837
File: packages/vue-generator/src/plugins/genDependenciesPlugin.js:66-66
Timestamp: 2024-09-30T07:51:10.036Z
Learning: In the `tiny-engine` project, `opentiny/tiny-engine-dsl-vue` refers to the current package itself, and importing types from it may cause circular dependencies.

Applied to files:

  • packages/react-to-dsl/package.json
🧬 Code graph analysis (4)
packages/react-to-dsl/src/transform.ts (3)
packages/react-to-dsl/src/types.ts (3)
  • ISchemaChildrenItem (26-33)
  • IAppSchema (93-105)
  • IPageSchema (44-66)
packages/react-to-dsl/src/utils.ts (1)
  • genId8 (13-13)
packages/react-to-dsl/src/constants.ts (1)
  • defaultComponentMap (1-15)
packages/react-to-dsl/test/testcases/002_data-binding/input/DataBindingDemo.jsx (1)
packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx (2)
  • state (7-24)
  • utils (26-26)
packages/react-to-dsl/test/testcases/index.test.js (1)
packages/react-to-dsl/src/transform.ts (1)
  • transformReactToDsl (223-406)
packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx (1)
packages/react-to-dsl/test/testcases/002_data-binding/input/DataBindingDemo.jsx (2)
  • state (6-10)
  • utils (12-12)
🪛 Biome (2.1.2)
packages/react-to-dsl/test/testcases/001_normal/input/FormTable.jsx

[error] 107-107: This variable is used before its declaration.

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 198-198: Unexpected constant condition.

(lint/correctness/noConstantCondition)

packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx

[error] 80-80: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 84-84: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 136-137: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 148-148: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 162-162: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 228-229: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 235-235: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 360-360: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 436-436: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 446-446: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 449-450: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 452-453: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 460-460: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 464-464: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 471-471: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🔇 Additional comments (13)
packages/react-to-dsl/test/testcases/003_createVM/input/createVm.css (1)

1-4: LGTM for test fixture CSS.

Clear, minimal, and appropriate for the case input.

packages/react-to-dsl/src/constants.ts (1)

1-15: Verify several component mappings (possible mismatches)

  • Steps -> TinyTimeLine: confirm this is intended (Steps vs Timeline semantics).
  • Radio.Group -> TinyButtonGroup: verify; many ecosystems use RadioGroup.
  • Typography.Text -> Text: ensure the target is correct in Tiny DSL.

I can adjust the map once you confirm the desired targets.

packages/react-to-dsl/package.json (1)

29-43: Align Babel package versions to avoid AST incompatibilities

parser/traverse/generator are ~7.23.2 while core/types are 7.28.x. Keep all Babel 7 packages on the same minor for safety.

I proposed pinning core/types to ^7.23.2, but aligning all to a single modern 7.x is fine—pick one and standardize.

packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx (3)

245-251: Form props look non-antd (likely Tiny-style)

labelCol="80px", layout={false}, label-position, label-width aren’t antd props. If this file is only a transform fixture, fine; otherwise these won’t function in real antd.

Also applies to: 307-313


184-214: Table props appear non-antd

editConfig, options, auto-resize aren’t antd Table props. Confirm intent (fixture vs runnable example).


351-352: Icon usage matches special-case mapping—good

DatabaseOutlined and PlusOutlined presence should exercise your icon mapping logic.

Also applies to: 389-389

packages/react-to-dsl/test/testcases/002_data-binding/input/DataBindingDemo.jsx (1)

18-33: Confirm alias mapping for Antd components

You’re using aliased tags (AntdInput/AntdCheckbox). Verify the component-mapping logic handles aliases; otherwise these won’t remap to TinyInput/TinyCheckbox.

Would you like me to add a focused test to assert the mapped componentName values for aliased imports?

packages/react-to-dsl/test/testcases/004_lifecycle/input/lifecycle.jsx (1)

11-29: Verify lifecycle and class-field extraction into schema

Ensure these methods land in page.lifeCycles and page.methods respectively:

  • componentDidMount/WillUnmount/DidUpdate/DidCatch → lifeCycles
  • handleClick (class field arrow) → methods

If helpful, I can add assertions in the integration test to check for these keys in the emitted schema.

packages/react-to-dsl/src/transform.ts (4)

15-65: Good: Comprehensive AST expression handling

The astExprToValue function handles various AST node types effectively, with proper fallback to JSExpression for complex expressions.


137-158: Well-implemented map pattern recognition

The code effectively recognizes and converts common arr.map() patterns to loop expressions in the DSL. This is a key feature for React-to-DSL transformation.


302-304: Good error handling strategy

Silently catching errors during state extraction prevents partial failures from breaking the entire transformation. This resilient approach is appropriate for a transformer tool.


388-392: Error handling for component mapping

Good practice to wrap the component mapping in a try-catch block to prevent mapping errors from breaking the transformation.

packages/react-to-dsl/src/types.ts (1)

1-105: Well-structured type definitions

The type definitions provide a comprehensive and well-organized schema for the DSL structure. The interfaces are properly typed with clear naming conventions.

Comment on lines +1 to +48
{
"name": "@opentiny/tiny-engine-react-to-dsl",
"version": "0.1.0",
"description": "Transform React source code (JSX/TSX) to TinyEngine DSL schema.",
"publishConfig": {
"access": "public"
},
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"files": [
"dist"
],
"scripts": {
"build": "vite build",
"test": "vitest run"
},
"repository": {
"type": "git",
"url": "https://github.com/opentiny/tiny-engine",
"directory": "packages/react-to-dsl"
},
"bugs": {
"url": "https://github.com/opentiny/tiny-engine/issues"
},
"author": "OpenTiny Team",
"license": "MIT",
"homepage": "https://opentiny.design/tiny-engine",
"dependencies": {
"@babel/generator": "~7.23.2",
"@babel/parser": "~7.23.2",
"@babel/traverse": "~7.23.2",
"nanoid": "^5.0.7"
},
"devDependencies": {
"@babel/core": "^7.28.2",
"@babel/types": "^7.28.2",
"@types/babel__generator": "^7.27.0",
"@types/babel__traverse": "^7.28.0",
"typescript": "~5.4.5",
"vite": "^5.4.2",
"vitest": "^1.6.0"
},
"peerDependencies": {
"react": ">=17",
"react-dom": ">=17"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Publish typings and modern exports

Type consumers won’t see your .d.ts without a types field/exports. Also consider shipping README/LICENSE.

Apply:

 {
   "name": "@opentiny/tiny-engine-react-to-dsl",
   "version": "0.1.0",
   "description": "Transform React source code (JSX/TSX) to TinyEngine DSL schema.",
   "publishConfig": {
     "access": "public"
   },
   "type": "module",
   "main": "dist/index.js",
   "module": "dist/index.js",
+  "types": "dist/index.d.ts",
+  "exports": {
+    ".": {
+      "types": "./dist/index.d.ts",
+      "import": "./dist/index.js",
+      "default": "./dist/index.js"
+    }
+  },
   "files": [
-    "dist"
+    "dist",
+    "README.md",
+    "LICENSE"
   ],
   "scripts": {
     "build": "vite build",
     "test": "vitest run"
   },
@@
   "devDependencies": {
-    "@babel/core": "^7.28.2",
-    "@babel/types": "^7.28.2",
+    "@babel/core": "^7.23.2",
+    "@babel/types": "^7.23.2",
     "@types/babel__generator": "^7.27.0",
     "@types/babel__traverse": "^7.28.0",
+    "vite-plugin-dts": "^3.6.0",
     "typescript": "~5.4.5",
     "vite": "^5.4.2",
     "vitest": "^1.6.0"
   },
+  "engines": {
+    "node": ">=18"
+  }
 }

Note: use vite-plugin-dts in vite.config.ts to emit declarations.

📝 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.

Suggested change
{
"name": "@opentiny/tiny-engine-react-to-dsl",
"version": "0.1.0",
"description": "Transform React source code (JSX/TSX) to TinyEngine DSL schema.",
"publishConfig": {
"access": "public"
},
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"files": [
"dist"
],
"scripts": {
"build": "vite build",
"test": "vitest run"
},
"repository": {
"type": "git",
"url": "https://github.com/opentiny/tiny-engine",
"directory": "packages/react-to-dsl"
},
"bugs": {
"url": "https://github.com/opentiny/tiny-engine/issues"
},
"author": "OpenTiny Team",
"license": "MIT",
"homepage": "https://opentiny.design/tiny-engine",
"dependencies": {
"@babel/generator": "~7.23.2",
"@babel/parser": "~7.23.2",
"@babel/traverse": "~7.23.2",
"nanoid": "^5.0.7"
},
"devDependencies": {
"@babel/core": "^7.28.2",
"@babel/types": "^7.28.2",
"@types/babel__generator": "^7.27.0",
"@types/babel__traverse": "^7.28.0",
"typescript": "~5.4.5",
"vite": "^5.4.2",
"vitest": "^1.6.0"
},
"peerDependencies": {
"react": ">=17",
"react-dom": ">=17"
}
}
{
"name": "@opentiny/tiny-engine-react-to-dsl",
"version": "0.1.0",
"description": "Transform React source code (JSX/TSX) to TinyEngine DSL schema.",
"publishConfig": {
"access": "public"
},
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
}
},
"files": [
"dist",
"README.md",
"LICENSE"
],
"scripts": {
"build": "vite build",
"test": "vitest run"
},
"repository": {
"type": "git",
"url": "https://github.com/opentiny/tiny-engine",
"directory": "packages/react-to-dsl"
},
"bugs": {
"url": "https://github.com/opentiny/tiny-engine/issues"
},
"author": "OpenTiny Team",
"license": "MIT",
"homepage": "https://opentiny.design/tiny-engine",
"dependencies": {
"@babel/generator": "~7.23.2",
"@babel/parser": "~7.23.2",
"@babel/traverse": "~7.23.2",
"nanoid": "^5.0.7"
},
"devDependencies": {
"@babel/core": "^7.23.2",
"@babel/types": "^7.23.2",
"@types/babel__generator": "^7.27.0",
"@types/babel__traverse": "^7.28.0",
"vite-plugin-dts": "^3.6.0",
"typescript": "~5.4.5",
"vite": "^5.4.2",
"vitest": "^1.6.0"
},
"peerDependencies": {
"react": ">=17",
"react-dom": ">=17"
},
"engines": {
"node": ">=18"
}
}
🤖 Prompt for AI Agents
In packages/react-to-dsl/package.json lines 1-48, the package is missing a
"types" entry and proper "exports" entries so consumers won't get emitted .d.ts
files, and README/LICENSE are not shipped; update package.json to add a "types"
field pointing to the emitted declaration file (e.g. dist/index.d.ts) and add an
"exports" map that exposes the ESM/CJS entry and the types entry for the package
root, add README.md and LICENSE files to the package root and ensure they are
included in the published files (or remove "files" restriction), and update
vite.config.ts to use vite-plugin-dts to emit declarations during build (enable
declaration output to dist). Ensure package.json version/peerDependencies remain
correct and run the build to verify dist/*.d.ts exists before publishing.


const FormTable = (props = {}) => {
const [state, setState] = React.useState({
IconPlusSquare: this.utils.IconPlusSquare(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: Invalid this.utils reference in functional component

The code references this.utils.IconPlusSquare() within a functional component's state initialization. Functional components don't have a this context. This will cause a runtime error.

-    IconPlusSquare: this.utils.IconPlusSquare(),
+    IconPlusSquare: null, // TODO: Initialize appropriately
📝 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.

Suggested change
IconPlusSquare: this.utils.IconPlusSquare(),
IconPlusSquare: null, // TODO: Initialize appropriately
🤖 Prompt for AI Agents
In packages/react-to-dsl/test/testcases/001_normal/input/FormTable.jsx around
line 10, the state init incorrectly calls this.utils.IconPlusSquare() inside a
functional component (no this); replace the reference with a valid value by
either importing the utils module and calling utils.IconPlusSquare(), using a
locally defined utils variable, or accessing it from props (e.g.,
props.utils.IconPlusSquare()) so the call does not rely on this.

filter: {
layout: 'input,enum,default,extends,base',
inputFilter: {
component: this.utils.Numeric,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: this.utils.Numeric reference in functional component

The code attempts to access this.utils.Numeric inside a functional component, which will fail at runtime.

-            component: this.utils.Numeric,
+            component: null, // TODO: Import and use Numeric component properly
📝 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.

Suggested change
component: this.utils.Numeric,
// before (invalid in a functional component):
component: null, // TODO: Import and use Numeric component properly
🤖 Prompt for AI Agents
In packages/react-to-dsl/test/testcases/001_normal/input/FormTable.jsx around
line 41, the code uses this.utils.Numeric inside a functional component which
will throw because functional components have no this; replace the reference by
either importing Numeric directly from the utils module or by accessing it via
props/context (e.g., props.utils.Numeric or the appropriate context hook) and
update the component to use that imported or passed-in Numeric component instead
of this.utils.Numeric.

{ id: '7', name: 'KBG物业有限公司', city: '赤壁', employees: 400, boole: false },
{ id: '8', name: '深圳市福德宝网络技术有限公司', boole: true, city: '厦门', employees: 540 }
],
status: this.statusData,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: Invalid this.statusData reference

The code assigns this.statusData to the state object, but statusData is defined as a local function, not a class method.

-    status: this.statusData,
+    status: statusData(),
📝 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.

Suggested change
status: this.statusData,
status: statusData(),
🤖 Prompt for AI Agents
In packages/react-to-dsl/test/testcases/001_normal/input/FormTable.jsx around
line 90, the code assigns this.statusData to state but statusData is a locally
defined function (not a class instance method); fix by either calling the local
function (status: statusData()) to assign its return value, or move/convert the
function into a class method and reference it as this.statusData()
consistently—update the code to one of these two approaches so the reference is
valid.

buttons: [
{ type: 'primary', text: '主要操作' },
{ type: 'success', text: '成功操作' },
{ type: 'danger', text: t('operation.danger') }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: t function used before declaration

The t function from useTranslation is referenced in the initial state before it's declared on line 100.

Move the useTranslation hook call before the state initialization:

const FormTable = (props = {}) => {
+  const { t } = useTranslation()
  const [state, setState] = React.useState({
    // ... state initialization
-      { type: 'danger', text: t('operation.danger') }
+      { type: 'danger', text: t('operation.danger') }
    ]
  })
  
  const utils = {}
  
-  const { t } = useTranslation()
📝 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.

Suggested change
{ type: 'danger', text: t('operation.danger') }
const FormTable = (props = {}) => {
// Move hook above state so `t` is available in the initializer
const { t } = useTranslation()
const [state, setState] = React.useState({
// ... state initialization
{ type: 'danger', text: t('operation.danger') }
]
})
const utils = {}
// (Removed the duplicate `const { t } = useTranslation()` here)
// ...rest of component...
}
🤖 Prompt for AI Agents
In packages/react-to-dsl/test/testcases/001_normal/input/FormTable.jsx around
line 94, the t function from useTranslation is being referenced in the
component's initial state before useTranslation is called; move the
useTranslation() hook call to precede the state initialization so t is defined
when building the initial state (i.e., call const { t } = useTranslation() above
where state/defaults are declared), then keep the rest of the state and usage
unchanged.

Comment on lines +349 to +387
{state.dataDisk.map((item) => (
<div style={{ marginTop: '12px', display: 'flex' }}>
<DatabaseOutlined style={{ marginRight: '10px', width: '16px', height: '16px' }}></DatabaseOutlined>
<Select
value={state.formData.diskType}
onChange={(e) => setState((prev) => ({ ...prev, formData: { ...prev.formData, diskType: e } }))}
placeholder="请选择"
options={[
{ value: '1', label: '黄金糕' },
{ value: '2', label: '双皮奶' }
]}
style={{ width: '200px', marginRight: '10px' }}
></Select>
<Input
placeholder="请输入"
value={state.inputValues.dataDiskSize}
onChange={(e) =>
setState((prev) => ({
...prev,
inputValues: { ...prev.inputValues, dataDiskSize: e.target.value }
}))
}
style={{ width: '120px', marginRight: '10px' }}
></Input>
<Typography.Text
label="GiB
IOPS上限600,IOPS突发上限5,000"
style={{ color: '#575d6c', fontSize: '12px', marginRight: '10px' }}
></Typography.Text>
<Input
placeholder="请输入"
value={state.inputValues.diskLabel}
onChange={(e) =>
setState((prev) => ({ ...prev, inputValues: { ...prev.inputValues, diskLabel: e.target.value } }))
}
style={{ width: '120px' }}
></Input>
</div>
))}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add keys to elements rendered in a list

Missing key on the mapped

. React warns; also useful if you later render this in a playground.

- {state.dataDisk.map((item) => (
-   <div style={{ marginTop: '12px', display: 'flex' }}>
+ {state.dataDisk.map((item, idx) => (
+   <div key={item ?? idx} style={{ marginTop: '12px', display: 'flex' }}>
      ...
   </div>
 ))}
📝 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.

Suggested change
{state.dataDisk.map((item) => (
<div style={{ marginTop: '12px', display: 'flex' }}>
<DatabaseOutlined style={{ marginRight: '10px', width: '16px', height: '16px' }}></DatabaseOutlined>
<Select
value={state.formData.diskType}
onChange={(e) => setState((prev) => ({ ...prev, formData: { ...prev.formData, diskType: e } }))}
placeholder="请选择"
options={[
{ value: '1', label: '黄金糕' },
{ value: '2', label: '双皮奶' }
]}
style={{ width: '200px', marginRight: '10px' }}
></Select>
<Input
placeholder="请输入"
value={state.inputValues.dataDiskSize}
onChange={(e) =>
setState((prev) => ({
...prev,
inputValues: { ...prev.inputValues, dataDiskSize: e.target.value }
}))
}
style={{ width: '120px', marginRight: '10px' }}
></Input>
<Typography.Text
label="GiB
IOPS上限600,IOPS突发上限5,000"
style={{ color: '#575d6c', fontSize: '12px', marginRight: '10px' }}
></Typography.Text>
<Input
placeholder="请输入"
value={state.inputValues.diskLabel}
onChange={(e) =>
setState((prev) => ({ ...prev, inputValues: { ...prev.inputValues, diskLabel: e.target.value } }))
}
style={{ width: '120px' }}
></Input>
</div>
))}
{state.dataDisk.map((item, idx) => (
<div key={item ?? idx} style={{ marginTop: '12px', display: 'flex' }}>
<DatabaseOutlined style={{ marginRight: '10px', width: '16px', height: '16px' }}></DatabaseOutlined>
<Select
value={state.formData.diskType}
onChange={(e) => setState((prev) => ({ ...prev, formData: { ...prev.formData, diskType: e } }))}
placeholder="请选择"
options={[
{ value: '1', label: '黄金糕' },
{ value: '2', label: '双皮奶' }
]}
style={{ width: '200px', marginRight: '10px' }}
></Select>
<Input
placeholder="请输入"
value={state.inputValues.dataDiskSize}
onChange={(e) =>
setState((prev) => ({
...prev,
inputValues: { ...prev.inputValues, dataDiskSize: e.target.value }
}))
}
style={{ width: '120px', marginRight: '10px' }}
></Input>
<Typography.Text
label="GiB
IOPS上限600,IOPS突发上限5,000"
style={{ color: '#575d6c', fontSize: '12px', marginRight: '10px' }}
></Typography.Text>
<Input
placeholder="请输入"
value={state.inputValues.diskLabel}
onChange={(e) =>
setState((prev) => ({ ...prev, inputValues: { ...prev.inputValues, diskLabel: e.target.value } }))
}
style={{ width: '120px' }}
></Input>
</div>
))}
🧰 Tools
🪛 Biome (2.1.2)

[error] 360-360: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

🤖 Prompt for AI Agents
In packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx around
lines 349 to 387, the mapped <div> inside state.dataDisk.map is missing a React
key; add a key prop to the top-level element in the map (e.g., key={item.id} if
dataDisk items have a unique id, otherwise key={index} as a last resort) to
remove React warnings and ensure stable identity when rendering the list.

Comment on lines +3 to +13
"compilerOptions": {
"composite": false,
"declaration": false,
"emitDeclarationOnly": false,
"module": "ESNext",
"moduleResolution": "bundler",
"target": "ES2020",
"lib": ["ES2020"],
"skipLibCheck": true,
"strict": true
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Ensure consumers get TypeScript types.

Right now declaration emit is disabled. Either add vite-plugin-dts (preferred; see vite.config.ts comment) or enable declaration emit to publish .d.ts with the package.

If you prefer tsc-based emit, update:

   "compilerOptions": {
-    "declaration": false,
-    "emitDeclarationOnly": false,
+    "declaration": true,
+    "emitDeclarationOnly": true,
+    "declarationDir": "./dist/types",
     "module": "ESNext",

And set "types" in package.json to "dist/types/index.d.ts".


🏁 Script executed:

#!/bin/bash
# List contents of the react-to-dsl package
echo "=== packages/react-to-dsl/ ==="
ls -R packages/react-to-dsl

# Display tsconfig.json to confirm declaration settings
echo
echo "=== packages/react-to-dsl/tsconfig.json ==="
sed -n '1,200p' packages/react-to-dsl/tsconfig.json

# Locate and inspect Vite config for vite-plugin-dts usage
echo
echo "=== Finding vite.config.ts ==="
find packages/react-to-dsl -type f -name 'vite.config.ts'
if [ -f packages/react-to-dsl/vite.config.ts ]; then
  echo
  echo "=== packages/react-to-dsl/vite.config.ts ==="
  sed -n '1,200p' packages/react-to-dsl/vite.config.ts
fi

# Check package.json for a "types" entry
echo
echo "=== packages/react-to-dsl/package.json ==="
sed -n '1,200p' packages/react-to-dsl/package.json

Length of output: 3710


🏁 Script executed:

#!/bin/bash
# Display root tsconfig.json to check for global declaration settings
echo "=== Root tsconfig.json ==="
sed -n '1,200p' tsconfig.json

echo
echo "=== Declaration flags in root tsconfig.json ==="
grep -R '"declaration"' -n tsconfig.json || echo "no declaration flags found"

Length of output: 418


Enable declaration output for TypeScript consumers
Your package currently doesn’t emit any .d.ts files, so downstream TS projects won’t receive type definitions. Configure either vite-plugin-dts or TSC-based emit:

In packages/react-to-dsl/tsconfig.json update:

   "compilerOptions": {
-    "declaration": false,
-    "emitDeclarationOnly": false,
+    "declaration": true,
+    "emitDeclarationOnly": true,
+    "declarationDir": "./dist/types",
     "module": "ESNext",

And in packages/react-to-dsl/package.json add:

  "types": "dist/types/index.d.ts",
🤖 Prompt for AI Agents
In packages/react-to-dsl/tsconfig.json (lines 3-13) the project currently
disables declaration output; enable TypeScript declaration generation by setting
"declaration": true and adding a "declarationDir": "dist/types" (and optionally
"declarationMap": true) so .d.ts files are emitted to dist/types; either run a
separate tsc pass with --emitDeclarationOnly during your build or configure
vite-plugin-dts to emit declarations into that folder. Also update
packages/react-to-dsl/package.json to include "types": "dist/types/index.d.ts"
so downstream consumers pick up the bundled types.

@@ -0,0 +1,23 @@
import { defineConfig } from 'vite'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add DTS generation to ship types.

Generate .d.ts via vite-plugin-dts so consumers get the declared API.

 import { defineConfig } from 'vite'
+import dts from 'vite-plugin-dts'
 import path from 'node:path'
📝 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.

Suggested change
import { defineConfig } from 'vite'
import { defineConfig } from 'vite'
import dts from 'vite-plugin-dts'
import path from 'node:path'
🤖 Prompt for AI Agents
In packages/react-to-dsl/vite.config.ts around line 1, the project doesn’t
generate .d.ts files for consumers; install and import vite-plugin-dts and add
it to the Vite plugins list (e.g., import dts from 'vite-plugin-dts' and include
dts({ insertTypesEntry: true }) in defineConfig plugins), ensure your build
config exposes the library entry (build.lib.entry) so the plugin can emit
declarations into dist (or configure outputDir), and confirm tsconfig has
declaration enabled or let the plugin generate declarations — this will produce
.d.ts files alongside the build for consumers.

Comment on lines +4 to +23
export default defineConfig({
publicDir: false,
resolve: {},
base: './',
define: {
'import.meta': 'import.meta'
},
build: {
sourcemap: true,
lib: {
entry: path.resolve(__dirname, './src/index.ts'),
name: 'reactToDsl',
fileName: () => 'index.js',
formats: ['es']
},
rollupOptions: {
external: [/^@babel.*/, 'react', 'react-dom', 'nanoid']
}
}
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Wire up vite-plugin-dts and drop the unnecessary import.meta define.

The manual import.meta define is typically unnecessary for lib mode; types emission is the missing piece.

 export default defineConfig({
   publicDir: false,
   resolve: {},
   base: './',
-  define: {
-    'import.meta': 'import.meta'
-  },
+  plugins: [dts({ insertTypesEntry: true, outDir: 'dist' })],
   build: {
     sourcemap: true,
     lib: {
       entry: path.resolve(__dirname, './src/index.ts'),
       name: 'reactToDsl',
       fileName: () => 'index.js',
       formats: ['es']
     },
     rollupOptions: {
       external: [/^@babel.*/, 'react', 'react-dom', 'nanoid']
     }
   }
 })

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/react-to-dsl/vite.config.ts around lines 4 to 23, remove the manual
define entry for 'import.meta' and wire up vite-plugin-dts: import the plugin at
the top, add a plugins array to defineConfig that includes dts() (configure
insertTypesEntry: true or emitDeclarationOnly as needed for your package), and
keep the existing build.lib and rollupOptions; this will enable type declaration
emission for the library and remove the unnecessary import.meta define.

Comment on lines +19 to +21
rollupOptions: {
external: [/^@babel.*/, 'react', 'react-dom', 'nanoid']
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify externals are declared as deps/peers.

Externalizing @babel/*, react, react-dom, and nanoid requires they be present in dependencies or peerDependencies of packages/react-to-dsl/package.json.

Run:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
python - <<'PY'
import json, pathlib
p = pathlib.Path('packages/react-to-dsl/package.json')
d = json.loads(p.read_text())
deps = set((d.get('dependencies') or {}).keys()) | set((d.get('peerDependencies') or {}).keys())
need = {'@babel/parser','@babel/traverse','@babel/generator','@babel/types','react','react-dom','nanoid'}
print('types field:', d.get('types'))
print('declared deps/peers:', sorted(deps))
print('missing externals (declare as deps/peers):', sorted(need - deps))
PY

Length of output: 218


Declare missing external @babel/types in package.json
The rollup externals include @babel/types, but it’s not listed under dependencies or peerDependencies in packages/react-to-dsl/package.json—add it to prevent unresolved-module errors.

🤖 Prompt for AI Agents
In packages/react-to-dsl/vite.config.ts around lines 19–21 the rollup externals
reference @babel/types but packages/react-to-dsl/package.json does not declare
it; add "@babel/types" to that package.json (either dependencies or
peerDependencies as appropriate for how the package is consumed), run your
package manager to update the lockfile/hoisting, and publish or link the change
so Rollup/Vite no longer throws unresolved-module errors.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx (2)

286-287: Typography.Text: remove unsupported “label” prop; use children instead (duplicate of earlier review).

AntD Typography.Text doesn’t have a label prop, so text won’t render. Inline the text as children.

-                <Typography.Text label="请注意操作系统的语言类型。" style={{ color: '#e37d29' }}></Typography.Text>
+                <Typography.Text style={{ color: '#e37d29' }}>请注意操作系统的语言类型。</Typography.Text>
-                <Typography.Text
-                  label="GiB   
-IOPS上限240,IOPS突发上限5,000"
-                  style={{ color: '#575d6c', fontSize: '12px' }}
-                ></Typography.Text>
+                <Typography.Text style={{ color: '#575d6c', fontSize: '12px' }}>
+                  GiB <br />
+                  IOPS上限240,IOPS突发上限5,000
+                </Typography.Text>
-                  <Typography.Text
-                    label="GiB   
-IOPS上限600,IOPS突发上限5,000"
-                    style={{ color: '#575d6c', fontSize: '12px', marginRight: '10px' }}
-                  ></Typography.Text>
+                  <Typography.Text style={{ color: '#575d6c', fontSize: '12px', marginRight: '10px' }}>
+                    GiB <br />
+                    IOPS上限600,IOPS突发上限5,000
+                  </Typography.Text>
-              <div style={{ display: 'flex', marginTop: '12px', borderRadius: '0px' }}>
-                <Typography.Text
-                  label="增加一块数据盘"
-                  style={{ fontSize: '12px', borderRadius: '0px', marginRight: '10px' }}
-                ></Typography.Text>
-                <Typography.Text
-                  label="您还可以挂载 21 块磁盘(云硬盘)"
-                  style={{ color: '#8a8e99', fontSize: '12px' }}
-                ></Typography.Text>
-              </div>
+              <div style={{ display: 'flex', marginTop: '12px', borderRadius: '0px' }}>
+                <Typography.Text style={{ fontSize: '12px', borderRadius: '0px', marginRight: '10px' }}>
+                  增加一块数据盘
+                </Typography.Text>
+                <Typography.Text style={{ color: '#8a8e99', fontSize: '12px' }}>
+                  您还可以挂载 21 块磁盘(云硬盘)
+                </Typography.Text>
+              </div>

Also applies to: 333-337, 374-377, 389-397


349-387: Add React keys to list items (duplicate of earlier review).

Missing key on the mapped div will trigger React warnings.

-              {state.dataDisk.map((item) => (
-                <div style={{ marginTop: '12px', display: 'flex' }}>
+              {state.dataDisk.map((item, idx) => (
+                <div key={item ?? idx} style={{ marginTop: '12px', display: 'flex' }}>
🧹 Nitpick comments (6)
packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx (4)

78-86: Avoid using the “children” prop; place text as JSX children.

Biome flags these; prefer <Typography.Text>内容</Typography.Text>. Apply pattern across the file.

-              <Typography.Text
-                children="温馨提示:页面左上角切换区域"
-                style={{ color: '#8a8e99', fontSize: '12px' }}
-              ></Typography.Text>
+              <Typography.Text style={{ color: '#8a8e99', fontSize: '12px' }}>
+                温馨提示:页面左上角切换区域
+              </Typography.Text>

-                  <Typography.Text children="vCPUs" style={{ width: '80px' }}></Typography.Text>
+                  <Typography.Text style={{ width: '80px' }}>vCPUs</Typography.Text>

-                  <Typography.Text children="规格名称" style={{ width: '120px' }}></Typography.Text>
+                  <Typography.Text style={{ width: '120px' }}>规格名称</Typography.Text>

-                  <Typography.Text
-                    children="当前规格"
-                    style={{ width: '150px', display: 'inline-block' }}
-                  ></Typography.Text>
+                  <Typography.Text style={{ width: '150px', display: 'inline-block' }}>
+                    当前规格
+                  </Typography.Text>

-                  <Typography.Text children="配置费用" style={{ fontSize: '12px' }}></Typography.Text>
+                  <Typography.Text style={{ fontSize: '12px' }}>配置费用</Typography.Text>

-                  <Typography.Text children="/小时" style={{ fontSize: '12px' }}></Typography.Text>
+                  <Typography.Text style={{ fontSize: '12px' }}>/小时</Typography.Text>

Also applies to: 132-146, 156-166, 216-224, 431-451


245-249: Form props don’t match AntD API; verify intent.

Props like layout={false}, labelCol="80px", label-position, label-width aren’t valid in antd Form. If this is purely a parser fixture, okay; otherwise replace with supported props (e.g., layout="horizontal", labelCol={{ span: 6 }}) or drop unsupported ones.

Also applies to: 306-312, 341-347


26-26: Remove unused variable.

utils is declared but never used.

-  const utils = {}

419-457: Col span should be numbers, not strings.

Use span={16}, span={6}, etc., to match AntD prop types and avoid warnings.

-            <Col span="16">
+            <Col span={16}>
...
-                <Col span="6">
+                <Col span={6}>
...
-                <Col span="7">
+                <Col span={7}>
...
-            <Col
-              span="8"
+            <Col
+              span={8}
packages/react-to-dsl/test/testcases/index.test.js (2)

8-14: Make discovery deterministic by sorting directories and files.

Stabilizes CI and output.

 function getTestCaseDirs(rootDir) {
   return fs
     .readdirSync(rootDir, { withFileTypes: true })
     .filter((d) => d.isDirectory())
     .map((d) => d.name)
-    .filter((name) => name !== 'output' && !name.startsWith('.'))
+    .filter((name) => name !== 'output' && !name.startsWith('.'))
+    .sort()
 }

 function findInputSource(caseDir) {
   const inputDir = path.join(caseDir, 'input')
   if (!fs.existsSync(inputDir)) return null
-  const files = fs.readdirSync(inputDir)
+  const files = fs.readdirSync(inputDir).sort()
   const src = files.find((f) => /\.(jsx|tsx)$/.test(f))
   return src ? path.join(inputDir, src) : null
 }

 function readAllCss(caseDir) {
   const inputDir = path.join(caseDir, 'input')
   if (!fs.existsSync(inputDir)) return ''
-  const files = fs.readdirSync(inputDir)
-  const cssFiles = files.filter((f) => f.endsWith('.css'))
+  const files = fs.readdirSync(inputDir).sort()
+  const cssFiles = files.filter((f) => f.endsWith('.css'))
   const contents = cssFiles.map((f) => fs.readFileSync(path.join(inputDir, f), 'utf-8'))
   return contents.join('\n')
 }

Also applies to: 36-42, 45-52


176-178: Gate filesystem outputs behind an env flag to keep CI/worktrees clean.

Prevents test runs from modifying the repo unless explicitly enabled.

-      // 输出到 output/<caseName>
-      writeOutputs(casesRoot, caseName, appSchema)
+      // 输出到 output/<caseName>(仅在显式开启时)
+      if (process.env.WRITE_DSL_OUTPUT === '1') {
+        writeOutputs(casesRoot, caseName, appSchema)
+      }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8cc174 and 41700e8.

📒 Files selected for processing (4)
  • packages/react-to-dsl/README.md (1 hunks)
  • packages/react-to-dsl/src/constants.ts (1 hunks)
  • packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx (1 hunks)
  • packages/react-to-dsl/test/testcases/index.test.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/react-to-dsl/README.md
  • packages/react-to-dsl/src/constants.ts
🧰 Additional context used
🧬 Code graph analysis (2)
packages/react-to-dsl/test/testcases/index.test.js (1)
packages/react-to-dsl/src/transform.ts (1)
  • transformReactToDsl (223-406)
packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx (1)
packages/react-to-dsl/test/testcases/002_data-binding/input/DataBindingDemo.jsx (2)
  • state (6-10)
  • utils (12-12)
🪛 Biome (2.1.2)
packages/react-to-dsl/test/testcases/003_createVM/input/createVm.jsx

[error] 80-80: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 84-84: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 136-137: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 148-148: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 162-162: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 228-229: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 235-235: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 360-360: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 435-435: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 445-445: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 448-449: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 451-452: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 459-459: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 463-463: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 470-470: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个result你看看能不能换个名字。

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK,gitignore这里应该不需要result了,我删掉吧。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request ospp ospp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.