Skip to content

feat: add vue to dsl#1785

Open
xuanlid wants to merge 5 commits intoopentiny:developfrom
xuanlid:feat/vue-to-dsl
Open

feat: add vue to dsl#1785
xuanlid wants to merge 5 commits intoopentiny:developfrom
xuanlid:feat/vue-to-dsl

Conversation

@xuanlid
Copy link
Contributor

@xuanlid xuanlid commented Mar 13, 2026

English | 简体中文

PR

PR Checklist

Please check if your PR fulfills the following requirements:

  • 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

What kind of change does this PR introduce?

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

Background and solution

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features
    • Upload toolbar: import Vue files, project directories, or ZIPs into the designer with duplicate-page overwrite flow.
    • Vue-to-DSL converter: auto-convert imported projects into editable pages/components; CLI available for standalone conversions.
  • User Experience
    • New overwrite confirmation dialog for handling duplicate page names.
  • Tests
    • End-to-end and unit tests added to validate conversion and import flows.
  • Documentation
    • New README and usage docs for the Vue-to-DSL tooling.

@github-actions github-actions bot added the enhancement New feature or request label Mar 13, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 13, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4ff8cd99-b4ac-4e0b-9d53-80f4d75464d4

📥 Commits

Reviewing files that changed from the base of the PR and between f2955e7 and bbefc01.

📒 Files selected for processing (1)
  • packages/toolbars/upload/vite.config.ts

Walkthrough

Adds a new Upload toolbar (UI, metadata, registry integration) and a new Vue-to-DSL package with parsers, generator, CLI, tests, and app-level conversion features; integrates the toolbar into design-core, layout, aliases, and TypeScript paths.

Changes

Cohort / File(s) Summary
Upload Toolbar UI & Assets
packages/toolbars/upload/src/Main.vue, packages/toolbars/upload/src/OverwriteDialog.vue, packages/toolbars/upload/src/styles/vars.less
New Vue components and styles implementing upload UI, duplicate-overwrite dialog, and CSS variables.
Upload Toolbar Module & Build
packages/toolbars/upload/index.ts, packages/toolbars/upload/meta.js, packages/toolbars/upload/package.json, packages/toolbars/upload/vite.config.ts, packages/toolbars/upload/src/http.ts
Toolbar entry, metadata, package manifest, Vite build config, and small HTTP helper (fetchPageList).
Design-Core Integration
packages/design-core/package.json, packages/design-core/re-export.js, packages/design-core/registry.js
Adds package dependency, re-exports Upload, and includes Upload in the toolbars registry guarded by feature flag.
Layout & Constants
packages/layout/src/defaultLayout.js, packages/register/src/constants.ts, tsconfig.app.json
Inserts Upload into toolbar layout, adds META_APP.Upload constant, and adds TypeScript path alias.
Dev Alias
packages/build/vite-config/src/vite-plugins/devAliasPlugin.js
Adds dev alias entries for @opentiny/tiny-engine-toolbar-upload and @opentiny/tiny-engine-vue-to-dsl.
Vue-to-DSL Core Library
packages/vue-to-dsl/src/converter.ts, packages/vue-to-dsl/src/generator/index.ts, packages/vue-to-dsl/src/index.ts, packages/vue-to-dsl/src/index.d.ts, packages/vue-to-dsl/src/constants.ts
New conversion engine, schema generator, types, exports, constants for default component maps and registry data.
Parsers & Utilities
packages/vue-to-dsl/src/parser/index.ts, packages/vue-to-dsl/src/parsers/templateParser.ts, packages/vue-to-dsl/src/parsers/scriptParser.ts, packages/vue-to-dsl/src/parsers/styleParser.ts, packages/vue-to-dsl/src/parsers/index.ts, packages/vue-to-dsl/src/types/index.js
Template/script/style parsers and helpers to extract AST, props, state, methods, lifecycle hooks, and CSS rules.
CLI, Build & Config
packages/vue-to-dsl/cli.ts, packages/vue-to-dsl/package.json, packages/vue-to-dsl/vite.config.js, packages/vue-to-dsl/vite.config.cli.mjs, packages/vue-to-dsl/tsconfig.json
Adds CLI entry, package manifest, Vite build configs (library and CLI), and TypeScript project config.
Tests & Fixtures
packages/vue-to-dsl/test/**, packages/vue-to-dsl/test/full/input/appdemo01/**, packages/vue-to-dsl/test/testcases/**
Extensive tests, full app fixtures, expected schema artifacts, and unit cases validating conversion paths and outputs.
Misc docs & config
packages/vue-to-dsl/README.md, packages/vue-to-dsl/.gitignore, tsconfig.app.json
Documentation and ignore rules for the new package; TypeScript path mapping updated.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UploadUI as Upload Toolbar (Main.vue)
    participant FileInput as File Handler
    participant Converter as VueToDslConverter
    participant MetaAPI as Backend API (Pages)
    participant Designer as App State / Canvas

    User->>UploadUI: open upload menu / choose option
    UploadUI->>FileInput: trigger file/directory/zip input
    FileInput->>Converter: convertFromFile / convertAppFromZip
    activate Converter
    Converter->>Converter: parse SFCs (template/script/style)
    Converter->>Converter: generate DSL schema / app schema
    Converter-->>FileInput: return ConvertResult (schema, deps)
    deactivate Converter
    FileInput->>MetaAPI: fetchPageList(appId)
    MetaAPI-->>FileInput: existing pages list
    alt duplicates detected
        FileInput->>UploadUI: prompt OverwriteDialog
        User->>UploadUI: select overwrite choices
    end
    FileInput->>MetaAPI: create/update pages
    MetaAPI-->>FileInput: success
    FileInput->>Designer: update canvas / switch to imported page
    Designer-->>User: show success notification
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I hopped through files with cheer,
I bundled Vue and DSL near,
Uploads land and schemas bloom,
Designers wake in canvas room,
A tiny rabbit celebrates new gear.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add vue to dsl' is concise and directly reflects the main objective of the changeset: introducing Vue-to-DSL conversion capabilities.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

CodeRabbit can suggest fixes for GitHub Check annotations.

Configure the reviews.tools.github-checks setting to adjust the time to wait for GitHub Checks to complete.

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

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (27)
packages/vue-to-dsl/test/full/input/appdemo01/src/views/createVm.vue-437-442 (1)

437-442: ⚠️ Potential issue | 🟡 Minor

Scoped styles targeting body will have no effect.

The <style scoped> directive only applies styles to elements within this component's template. The body element is outside the component scope, so these styles will not be applied.

Consider removing or using unscoped style

If these styles are needed globally, either:

  • Remove scoped attribute, or
  • Move body styles to a global stylesheet, or
  • Apply styles to the component's root <div> instead
-<style scoped>
-body {
-  background-color: `#eef0f5`;
-  margin-bottom: 80px;
-}
+<style scoped>
+/* Component-specific styles if needed */
 </style>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/src/views/createVm.vue` around
lines 437 - 442, The scoped <style> block in createVm.vue targets the global
body element which is outside the component scope, so the body rules won’t
apply; fix by either removing the scoped attribute from the <style> tag to make
the body rules global, moving the body styles into a global stylesheet, or
change the selector to target the component root element (e.g., the top-level
<div> in this component) so the styles take effect within the scoped CSS.
packages/vue-to-dsl/test/full/input/appdemo01/src/views/createVm.vue-26-32 (1)

26-32: ⚠️ Potential issue | 🟡 Minor

Duplicate and conflicting form props.

The <tiny-form> components specify both camelCase and kebab-case versions of the same props with different values:

  • labelWidth="80px" vs label-width="150px"
  • labelPosition="top" vs label-position="left " (also has trailing space)

Only one value will apply. This pattern repeats throughout the file (lines 83-89, 197-203, 255-261, 339-345).

Proposed fix (apply to all form instances)
       <tiny-form
-        labelWidth="80px"
-        labelPosition="top"
         :inline="false"
-        label-position="left "
-        label-width="150px"
+        label-position="left"
+        label-width="150px"
         style="border-radius: 0px"
       >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/src/views/createVm.vue` around
lines 26 - 32, The tiny-form components use duplicate/conflicting prop names
(camelCase vs kebab-case) with different values — e.g., labelWidth="80px" vs
label-width="150px" and labelPosition="top" vs label-position="left " (note
trailing space) — causing one to be ignored; pick a single canonical prop format
per component (prefer kebab-case in templates) and remove the duplicate
camelCase attributes, normalize values (remove trailing spaces) and ensure
consistency across all <tiny-form> instances (including the other occurrences of
the same component) so each form only declares label-width and label-position
with the intended values.
packages/vue-to-dsl/test/full/input/appdemo01/src/views/createVm.vue-404-405 (1)

404-405: ⚠️ Potential issue | 🟡 Minor

Remove unnecessary imports of defineProps and defineEmits.

In Vue 3's <script setup>, defineProps and defineEmits are compiler macros that are automatically available without importing. These imports should be removed.

Proposed fix
 import * as vue from 'vue'
-import { defineProps, defineEmits } from 'vue'
 import { I18nInjectionKey } from 'vue-i18n'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/src/views/createVm.vue` around
lines 404 - 405, Remove the explicit import of the compiler macros: delete the
named import "defineProps" and "defineEmits" from the import statement that
currently reads "import { defineProps, defineEmits } from 'vue'" (keep the
existing "import * as vue from 'vue'" if other vue symbols are used) so the
script relies on the built-in <script setup> compiler macros defineProps and
defineEmits instead of importing them.
packages/vue-to-dsl/README.md-49-52 (1)

49-52: ⚠️ Potential issue | 🟡 Minor

Fix invalid Vue API usage in quick-start snippet.

Line 50 uses vue.reactive(...) but vue is not defined, and the reactive function is not imported. This sample won't run as written. Replace with a direct import and usage of reactive:

Proposed fix
-import { ref } from 'vue'
-const state = vue.reactive({
+import { reactive } from 'vue'
+const state = reactive({
   title: 'Hello TinyEngine'
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/README.md` around lines 49 - 52, The quick-start snippet
incorrectly calls vue.reactive without defining `vue` and doesn't import
`reactive`; change the import to include reactive (e.g., import { ref, reactive
} from 'vue') and update the state initialization to call `reactive(...)`
directly (replace `vue.reactive` with `reactive` in the `state` assignment) so
the example uses the correct Vue API; also remove unused imports if needed.
packages/vue-to-dsl/cli.ts-56-62 (1)

56-62: ⚠️ Potential issue | 🟡 Minor

Invalid --format value is silently ignored.

When an invalid format value is provided (not 'json' or 'js'), the code silently falls through without warning the user. Consider adding a warning or error message.

🔧 Suggested fix
     case '--format':
     case '-f':
       if (value === 'json' || value === 'js') {
         format = value
+      } else if (value) {
+        console.warn(`⚠️  无效的格式: ${value},将使用默认格式 json`)
       }
       i += 2
       break
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/cli.ts` around lines 56 - 62, The --format handling
silently ignores invalid values: in the switch case for '--format' / '-f' where
'value' is checked and 'format' is set, add explicit validation that if value is
not 'json' or 'js' you emit a clear error/warning (e.g., console.error or
process.stderr.write) and exit with non-zero status or fallback to a known
default; update the branch that currently just advances 'i' so that invalid
values produce the message and terminate (or set default and inform user) rather
than being ignored — reference the 'format' variable, the 'value' variable, and
the '--format'/'-f' switch case to locate the change.
packages/vue-to-dsl/test/testcases/002_createVM/expected/schema.json-117-132 (1)

117-132: ⚠️ Potential issue | 🟡 Minor

Expected schema contains propagated data bug: [object Event].

This schema correctly mirrors the input file, but it also captures the corrupted background-color: [object Event] style value. Once the input file is fixed, this expected schema should also be updated.

🔧 Fix needed after input is corrected
                     "componentName": "span",
                     "props": {
-                        "style": "background-color: [object Event]; color: `#8a8e99`; font-size: 12px"
+                        "style": "color: `#8a8e99`; font-size: 12px"
                     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/testcases/002_createVM/expected/schema.json` around
lines 117 - 132, The expected schema has a corrupted style value
"background-color: [object Event]" for the span component (id "sfcukuue") —
update the schema to match the corrected input by replacing the bad
background-color token in the props.style for the span (componentName "span", id
"sfcukuue") with the proper CSS value from the fixed source (or remove the
background-color entry if the fixed input omits it), and ensure the expected
file no longer captures event objects in style strings.
packages/vue-to-dsl/test/testcases/002_createVM/input/component.vue-49-51 (1)

49-51: ⚠️ Potential issue | 🟡 Minor

Invalid style value: [object Event] suggests serialization bug.

The style attribute contains background-color: [object Event]; which is the string representation of an incorrectly serialized JavaScript Event object. This appears to be corrupted test data that should be corrected.

🔧 Suggested fix
-          <span style="background-color: [object Event]; color: `#8a8e99`; font-size: 12px"
+          <span style="color: `#8a8e99`; font-size: 12px"

Or if a background color was intended:

-          <span style="background-color: [object Event]; color: `#8a8e99`; font-size: 12px"
+          <span style="background-color: transparent; color: `#8a8e99`; font-size: 12px"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/testcases/002_createVM/input/component.vue` around
lines 49 - 51, The span element with inline style containing "background-color:
[object Event]" is corrupted by a serialized Event object; locate the span (the
<span ...> 温馨提示:页面左上角切换区域 </span>) and either remove the invalid
background-color entry from its style attribute or replace "[object Event]" with
a valid CSS color value (e.g., a hex, rgb, or named color) or bind a proper
reactive color variable instead; ensure the style string is a plain CSS value
(not an Event) so the inline style becomes valid.
packages/vue-to-dsl/src/parser/index.ts-43-46 (1)

43-46: ⚠️ Potential issue | 🟡 Minor

Missing error handling for file read failures.

parseVueFile can throw if the file doesn't exist or is unreadable, but there's no try-catch or error propagation. Callers won't receive a consistent error structure like parseSFC parsing errors.

🛡️ Suggested error handling
 export async function parseVueFile(filePath: string): Promise<any> {
+  try {
     const content = await fs.readFile(filePath, 'utf-8')
     return parseSFC(content)
+  } catch (error: any) {
+    console.warn(`Failed to read Vue file: ${filePath}`, error.message)
+    return { error: error.message }
+  }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/parser/index.ts` around lines 43 - 46, parseVueFile
currently reads files without handling read errors, so add a try-catch around
the fs.readFile + parseSFC call in the parseVueFile function; on error,
normalize and rethrow a consistent parsing error (matching parseSFC's error
shape) that includes the original error message and context (e.g., filePath) so
callers always receive a predictable error object. Ensure you reference
parseVueFile and parseSFC when implementing the catch and rethrow logic.
packages/vue-to-dsl/src/generator/index.ts-122-135 (1)

122-135: ⚠️ Potential issue | 🟡 Minor

Dead code in sanitizeSchemaStrings - array check after array return.

Line 126 returns early for arrays, but line 128 still checks Array.isArray(obj) in the ternary. This branch will never be reached for arrays, making [] : dead code.

🔧 Fix dead code
 function sanitizeSchemaStrings(obj: any): any {
   if (obj === null || obj === undefined) return obj
   if (typeof obj === 'string') return obj
   if (Array.isArray(obj)) return obj.map((v) => sanitizeSchemaStrings(v))
   if (typeof obj === 'object') {
-    const out: any = Array.isArray(obj) ? [] : {}
+    const out: Record<string, any> = {}
     Object.keys(obj).forEach((k) => {
       out[k] = sanitizeSchemaStrings(obj[k])
     })
     return out
   }
   return obj
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/generator/index.ts` around lines 122 - 135,
sanitizeSchemaStrings contains dead code: it returns early for arrays
(Array.isArray(obj) => obj.map(...)) but later still uses Array.isArray(obj)
when creating out, which is never reached for arrays. Fix by making the object
branch consistent: either remove the early-array return and let the object
branch handle arrays by setting const out: any = Array.isArray(obj) ? [] : {}
and iterating keys, or keep the early-array return and change the object branch
to always initialize out as {} (const out: any = {}), then recursively sanitize
object properties. Update the function sanitizeSchemaStrings accordingly.
packages/vue-to-dsl/src/generator/index.ts-168-179 (1)

168-179: ⚠️ Potential issue | 🟡 Minor

generateAppSchema mutates input pageSchemas array.

The function modifies ps.meta.router directly on the input objects (lines 174-176), which can cause unexpected side effects for callers who don't expect their input to be mutated.

🛡️ Avoid mutation by working on copies
 export function generateAppSchema(pageSchemas: any[], options: any = {}) {
-  // Ensure all pages have a router path without leading slash
-  if (pageSchemas && Array.isArray(pageSchemas)) {
-    for (const ps of pageSchemas) {
-      if (ps && ps.meta && ps.meta.router && typeof ps.meta.router === 'string') {
-        // Remove leading slash from router path
-        if (ps.meta.router.startsWith('/')) {
-          ps.meta.router = ps.meta.router.slice(1)
-        }
-      }
-    }
-  }
+  // Normalize router paths without mutating input
+  const normalizedPageSchemas = (pageSchemas || []).map((ps) => {
+    if (ps?.meta?.router && typeof ps.meta.router === 'string' && ps.meta.router.startsWith('/')) {
+      return { ...ps, meta: { ...ps.meta, router: ps.meta.router.slice(1) } }
+    }
+    return ps
+  })

   return {
     // ... rest of return
-    pageSchema: pageSchemas || [],
+    pageSchema: normalizedPageSchemas,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/generator/index.ts` around lines 168 - 179,
generateAppSchema currently mutates the caller's pageSchemas by assigning to
ps.meta.router; instead, create and operate on a shallow/deep copy of the input
(e.g., clone each page schema or map to a new array) before trimming leading
slashes so original objects are not modified. Locate generateAppSchema and
replace the in-place loop over pageSchemas with logic that builds a new array
(or clones individual ps objects and their meta) and adjusts meta.router on the
copies; ensure any return or further processing uses the new copied array rather
than mutating the original pageSchemas.
packages/vue-to-dsl/src/constants.ts-1-16 (1)

1-16: ⚠️ Potential issue | 🟡 Minor

Add missing TinyGridItem entry to defaultComponentsMap.

defaultComponentMap includes 'tiny-grid-item': 'TinyGridItem' for template tag parsing, but defaultComponentsMap lacks the corresponding component metadata. This will cause schema generation to fail when TinyGridItem is used in templates, as the output won't include the necessary import information.

Add the entry following the TinyGrid pattern
  { componentName: 'TinyGrid', package: '@opentiny/vue', exportName: 'Grid', destructuring: true, version: '3.24.0' },
+  { componentName: 'TinyGridItem', package: '@opentiny/vue', exportName: 'GridItem', destructuring: true, version: '3.24.0' },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/constants.ts` around lines 1 - 16,
defaultComponentsMap is missing the metadata entry for TinyGridItem which breaks
schema generation when 'tiny-grid-item' is parsed; add a new entry for
"TinyGridItem" to defaultComponentsMap using the same structure as the existing
TinyGrid entry (same keys: importName/component name and import/source metadata
used for TinyGrid) so that the tag 'tiny-grid-item' (mapped by
defaultComponentMap) has matching component metadata for imports and schema
generation.
packages/vue-to-dsl/src/constants.ts-197-203 (1)

197-203: ⚠️ Potential issue | 🟡 Minor

Update TinyDropdown version to match other components.

TinyDropdown is versioned at 0.1.20, significantly older than all adjacent components in this file (which use 3.24.0) and the current latest version (3.29.0). This appears to be a mistake rather than an intentional variant—update to 3.24.0 to align with the rest of the codebase.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/constants.ts` around lines 197 - 203, Update the
TinyDropdown entry so its version matches the other components: find the object
with componentName 'TinyDropdown' (package '@opentiny/vue', exportName
'Dropdown') and change its version field from '0.1.20' to '3.24.0' to align with
adjacent component versions.
packages/vue-to-dsl/src/index.ts-1-1 (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Remove unnecessary .d.ts import.

The import './index.d.ts' statement serves no functional purpose. TypeScript declaration files are ambient declarations that are automatically available when the package is used; they don't need to be explicitly imported. The index.d.ts file provides module augmentations for the package namespace, while the actual public API is provided by the re-exports on lines 3-7. This import pattern is unconventional and doesn't appear elsewhere in the codebase. Remove line 1 entirely.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/index.ts` at line 1, Remove the unnecessary explicit
import of the declaration file by deleting the line `import './index.d.ts'` from
the top of the module; keep the existing re-exports (the public API exports)
intact (the subsequent export lines in this file) and run the TypeScript
build/typecheck to confirm nothing else depends on that explicit import.
packages/vue-to-dsl/test/full/input/appdemo01/src/views/LifeCyclePage.vue-30-31 (1)

30-31: ⚠️ Potential issue | 🟡 Minor

State missing properties used in template.

The template references state.activeUsers and state.systemLoad, but the reactive state is initialized as an empty object. If this fixture is meant to be runnable, add the missing properties.

Proposed fix
-const state = vue.reactive({})
+const state = vue.reactive({ activeUsers: 0, systemLoad: 0 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/src/views/LifeCyclePage.vue`
around lines 30 - 31, The reactive state is initialized empty but the template
expects state.activeUsers and state.systemLoad; update the vue.reactive call
that constructs state (the symbol "state") to include those properties (e.g.,
provide sensible initial values for "activeUsers" and "systemLoad") so that
wrap({ state }) receives a state object containing state.activeUsers and
state.systemLoad used by the template.
packages/vue-to-dsl/test/full/input/appdemo01/src/views/LifeCyclePage.vue-12-12 (1)

12-12: ⚠️ Potential issue | 🟡 Minor

Template references undefined method refreshData.

The button's @click handler references refreshData, but only handleClick is defined in the script. This mismatch will cause a runtime error if the component is executed.

Proposed fix: Either rename the method or the handler
-      <tiny-button type="success" `@click`="refreshData">刷新数据</tiny-button>
+      <tiny-button type="success" `@click`="handleClick">刷新数据</tiny-button>

Or rename the method:

-const handleClick = wrap(function handleClick() {
+const refreshData = wrap(function refreshData() {
   console.log('Button clicked')
 })

-wrap({ handleClick })
+wrap({ refreshData })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/src/views/LifeCyclePage.vue` at
line 12, The template uses a tiny-button with `@click`="refreshData" but the
script only defines handleClick, causing a missing method runtime error; either
rename the template handler to `@click`="handleClick" or add a refreshData method
in the component that delegates to handleClick (e.g., create a refreshData
method that calls this.handleClick) so the template and script method names
match (referencing tiny-button, refreshData, and handleClick).
packages/vue-to-dsl/test/full/input/appdemo01/src/http/index.js-19-24 (1)

19-24: ⚠️ Potential issue | 🟡 Minor

Error interceptor swallows errors silently.

The error handler doesn't return a rejected promise or re-throw, causing all HTTP errors to be silently swallowed. Additionally, error.response may be undefined for network errors, leading to a potential null reference on line 21.

Proposed fix
-  http.interceptors.response.use(dataHandler, (error) => {
-    const response = error.response
-    if (response.status === 403 && response.headers && response.headers['x-login-url']) {
-      // TODO 处理无权限时,重新登录再发送请求
-    }
-  })
+  http.interceptors.response.use(dataHandler, (error) => {
+    const response = error.response
+    if (response?.status === 403 && response.headers?.['x-login-url']) {
+      // TODO 处理无权限时,重新登录再发送请求
+    }
+    return Promise.reject(error)
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/src/http/index.js` around lines
19 - 24, The response error interceptor (http.interceptors.response.use)
currently assumes error.response exists and never re-throws or returns a
rejected promise, which swallows errors and can NPE on network failures; fix by
guarding access to error.response (e.g., check if error && error.response before
reading status/headers), handle the 403/x-login-url flow inside that guard, and
in all other cases (or after your login-handling flow if you don't retry) return
Promise.reject(error) (or re-throw) so callers receive the error; reference the
existing dataHandler and the anonymous error handler passed to
http.interceptors.response.use to locate where to add these checks and the final
Promise.reject(error).
packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/dataSource.js-36-38 (1)

36-38: ⚠️ Potential issue | 🟡 Minor

Returning undefined silently may cause unexpected behavior.

When shouldFetch() returns false, the function returns undefined without any indication. Callers may not handle this case properly.

Consider returning the current data or a specific value
   if (!shouldFetch()) {
-    return
+    return dataSource.data // or return a specific sentinel value
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/dataSource.js`
around lines 36 - 38, The early return when shouldFetch() is false silently
yields undefined; update the function in dataSource.js that contains the
shouldFetch() guard to return an explicit, documented value (e.g., the current
cached data, null, or an empty array/Promise depending on the function's
contract) instead of undefined so callers get a predictable result; adjust
callers or JSDoc/type annotations if needed to reflect the chosen return value
and ensure consistency with functions that consume this function.
packages/vue-to-dsl/vite.config.js-36-40 (1)

36-40: ⚠️ Potential issue | 🟡 Minor

Remove unused and incorrectly configured alias.

The alias '@': '/src' uses an absolute filesystem path that won't resolve correctly. However, since the @ alias is not used anywhere in the source code, this dead configuration can be safely removed.

If the alias is intended for use, replace it with a proper project-relative path:

Corrected alias configuration
+import { fileURLToPath, URL } from 'node:url'
 import { defineConfig } from 'vite'
 
 export default defineConfig({
   // ...
   resolve: {
     alias: {
-      '@': '/src'
+      '@': fileURLToPath(new URL('./src', import.meta.url))
     }
   }
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/vite.config.js` around lines 36 - 40, Remove the
dead/incorrect alias entry in the Vite config: delete the '@': '/src' key from
the resolve.alias object in vite.config.js since it uses an absolute filesystem
path and is not used; if you actually need an '@' alias, set it to a proper
project-relative path (e.g., use path.resolve(__dirname, 'src') or a relative
'./src') and ensure imports use '@' so the alias is necessary.
packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/lowcode.js-30-33 (1)

30-33: ⚠️ Potential issue | 🟡 Minor

Potential runtime error if callback is not provided.

The setState function calls callback.apply(global) without checking if callback is defined. If called without a callback argument, this will throw a TypeError.

🛡️ Proposed defensive check
   const setState = (newState, callback) => {
     Object.assign(global.state, newState)
-    nextTick(() => callback.apply(global))
+    nextTick(() => callback?.apply(global))
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/lowcode.js`
around lines 30 - 33, The setState function currently calls
callback.apply(global) unguarded which will throw if callback is undefined;
update setState (referencing setState, global.state and nextTick) to defensively
handle an optional callback by either checking typeof callback === 'function'
before calling or defaulting callback to a no-op, and invoke it with the proper
this (global) inside nextTick only when it's a function.
packages/vue-to-dsl/test/full/input/appdemo01/src/http/axios.js-37-39 (1)

37-39: ⚠️ Potential issue | 🟡 Minor

Error handler assumes error.response exists.

The catch block directly accesses error.response.status and error.response.data. For network errors or timeouts, error.response may be undefined, causing a TypeError.

🛡️ Proposed defensive error handling
               .catch((error) => {
-                resolve([error.response.status, error.response.data])
+                if (error.response) {
+                  resolve([error.response.status, error.response.data])
+                } else {
+                  resolve([0, { message: error.message || 'Network Error' }])
+                }
               })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/src/http/axios.js` around lines
37 - 39, The catch block in the axios wrapper currently assumes error.response
exists and will throw if a network error or timeout occurs; update the catch
handler (the .catch((error) => { ... }) in axios.js) to defensively read
error.response using optional chaining or existence checks and fall back to
sensible defaults (e.g., status 0 or null and data set to error.message or
error.request info) before resolving so network/timeouts don't cause a
TypeError. Ensure the resolved tuple uses error.response?.status and
error.response?.data fallback values and include error.message when response is
absent.
packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/dataSource.json-628-631 (1)

628-631: ⚠️ Potential issue | 🟡 Minor

Typo in function name: dataHanlder should be dataHandler.

The root-level dataHandler function (line 630) has a typo: "function dataHanlder(res)" should be "function dataHandler(res)". If this is intentional test data to verify the converter handles misspellings, consider adding a comment indicating this is deliberate.

✏️ Fix the typo
   "dataHandler": {
     "type": "JSFunction",
-    "value": "function dataHanlder(res){\n return res;\n}"
+    "value": "function dataHandler(res){\n return res;\n}"
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/dataSource.json`
around lines 628 - 631, The JSON object under the "dataHandler" property
contains a JSFunction string with a misspelled function name ("function
dataHanlder(res)"); update the function declaration inside the "value" string to
use the correct name "function dataHandler(res)" so the exported function name
matches the property key (or, if the misspelling is intentional for a test, add
a clear comment in the test data indicating that it's deliberate); look for the
"dataHandler" property and its "value" string to make this change.
packages/vue-to-dsl/src/index.d.ts-58-62 (1)

58-62: ⚠️ Potential issue | 🟡 Minor

Type mismatch: ImportInfo.specifiers should be an array of objects, not strings.

In the implementation (converter.ts lines 75-76 and templateParser.ts lines 134-152), specifiers is used as { local: string, imported?: string }[], not string[].

🐛 Proposed fix
 export interface ImportInfo {
   source: string
-  specifiers: string[]
+  specifiers: Array<{ local: string; imported?: string }>
   default?: string
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/index.d.ts` around lines 58 - 62, Update the
ImportInfo interface so specifiers matches its actual usage: change specifiers
from string[] to an array of objects with shape { local: string; imported?:
string } (used by converter.ts and templateParser.ts), ensuring the declaration
in index.d.ts reflects this composite type for ImportInfo so callers like the
functions in converter.ts and templateParser.ts can access specifier.local and
specifier.imported correctly.
packages/vue-to-dsl/src/parsers/templateParser.ts-272-274 (1)

272-274: ⚠️ Potential issue | 🟡 Minor

Fix invalid empty character class [^] in regex patterns.

The regex uses [^] which is flagged as an empty negated character class. While some JS engines interpret this as "match any character," it's non-standard. Use [\s\S] for cross-platform compatibility and clarity.

🐛 Proposed fix
           const match =
-            exp.match(/^[^]*?(?:\)|\S)\s+(?:in|of)\s+([^]+)$/) || exp.match(/^(?:[^]+?)\s+(?:in|of)\s+([^]+)$/)
+            exp.match(/^[\s\S]*?(?:\)|\S)\s+(?:in|of)\s+([\s\S]+)$/) || exp.match(/^(?:[\s\S]+?)\s+(?:in|of)\s+([\s\S]+)$/)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/parsers/templateParser.ts` around lines 272 - 274,
Replace the non-standard empty negated class `[^]` with the cross-platform
`[\s\S]` in the regexes used to parse the iteration source in templateParser.ts
(the expressions that produce `match` from `exp.match(...)`), so update both
occurrences in the `match` assignment to use `[\s\S]` instead of `[^]`; keep the
rest of the pattern and then keep `const src = (match ? match[1] : exp).trim()`
as-is so the captured group behavior remains unchanged.
packages/vue-to-dsl/src/converter.ts-116-119 (1)

116-119: ⚠️ Potential issue | 🟡 Minor

Avoid mutating this.options during conversion.

Setting this.options.fileName during convertFromString makes the converter stateful and unsafe for concurrent conversions. Pass the fileName through the options parameter to generateSchema instead.

🐛 Proposed fix
-      // Set fileName in options for schema generation
-      if (fileName) {
-        this.options.fileName = fileName.replace(/\.vue$/i, '')
-      }
-
-      const schema = await generateSchema(templateSchema, scriptSchema, styleSchema, this.options as any)
+      const schemaOptions = {
+        ...this.options,
+        fileName: fileName ? fileName.replace(/\.vue$/i, '') : this.options.fileName
+      }
+      const schema = await generateSchema(templateSchema, scriptSchema, styleSchema, schemaOptions as any)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/converter.ts` around lines 116 - 119, The converter
currently mutates instance state by setting this.options.fileName inside
convertFromString; instead, avoid changing this.options and pass the sanitized
fileName through the local options when calling generateSchema. In
convertFromString, compute a fileName value (e.g. strip the .vue suffix) and
merge it into the options object you pass to generateSchema (rather than
assigning to this.options.fileName) so convertFromString and generateSchema
receive the fileName without making the converter stateful.
packages/vue-to-dsl/src/parsers/templateParser.ts-278-279 (1)

278-279: ⚠️ Potential issue | 🟡 Minor

v-show directive value should use JSExpression wrapper for consistency.

Other directives like v-model, v-on, and v-bind wrap their values in { type: 'JSExpression', value: ... }, but v-show stores the raw expression string. This inconsistency may cause issues in downstream processing.

🐛 Proposed fix
       case 'show':
-        schema.props['v-show'] = prop.exp ? prop.exp.content : 'true'
+        schema.props['v-show'] = {
+          type: 'JSExpression',
+          value: ensureThisPrefix(prop.exp ? prop.exp.content : 'true', loopVariable)
+        }
         break
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/parsers/templateParser.ts` around lines 278 - 279,
The v-show handling in templateParser.ts stores the raw expression string into
schema.props['v-show'] instead of the consistent JSExpression wrapper used by
v-model/v-on/v-bind; change the assignment in the case 'show' branch so
schema.props['v-show'] is set to an object { type: 'JSExpression', value:
prop.exp ? prop.exp.content : 'true' } (using the same prop.exp and fallback
logic currently present) so downstream consumers receive a JSExpression for
v-show just like other directives.
packages/vue-to-dsl/src/parsers/templateParser.ts-10-16 (1)

10-16: ⚠️ Potential issue | 🟡 Minor

Potential ReDoS vulnerability with user-controlled regex input.

The loopVariable is extracted from user-provided Vue template content. While the regex pattern itself is simple, building regexes from user input is a security concern. Consider sanitizing the loop variable or using a safer approach.

🛡️ Proposed fix to escape special regex characters
+function escapeRegExp(str: string): string {
+  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+}
+
 function ensureThisPrefix(exp: string, loopVariable?: string) {
   const v = String(exp || '').trim()
   if (!v) return v
   if (v.startsWith('this.')) return v

   // If we're inside a loop and the expression starts with the loop variable, don't prefix
   if (loopVariable) {
     // Check if expression starts with the loop variable name
-    const loopVarPattern = new RegExp(`^${loopVariable}(?:\\.|\\[|$)`)
+    const loopVarPattern = new RegExp(`^${escapeRegExp(loopVariable)}(?:\\.|\\[|$)`)
     if (loopVarPattern.test(v)) {
       return v
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/parsers/templateParser.ts` around lines 10 - 16, The
regex construction using loopVariable in templateParser.ts (loopVarPattern) can
be abused; instead escape regex metacharacters in loopVariable before building
loopVarPattern or avoid regex entirely by checking v.startsWith(loopVariable)
and then ensuring the following character (if any) is '.' '[' or end-of-string;
update the logic in the block that references loopVariable and loopVarPattern to
use a safe escaped value (via a utility like escapeRegex) or a pure string-check
approach so user-controlled template names cannot inject regex patterns.
packages/vue-to-dsl/src/converter.ts-796-809 (1)

796-809: ⚠️ Potential issue | 🟡 Minor

Potential ReDoS vulnerability in gitignore pattern regex conversion.

The conversion of gitignore patterns to regex using .* for ** can cause catastrophic backtracking when malicious patterns are combined with specific input paths. Since gitignore content is loaded from user-uploaded files, this is exploitable. Consider using the ignore npm package, which safely implements the gitignore specification.

🛡️ Suggested safer approach
+import ignore from 'ignore'
+
     const createGitignoreFilter = (gitignoreContent: string) => {
-      const lines = gitignoreContent
-        .split('\n')
-        .map((l) => l.trim())
-        .filter((l) => l && !l.startsWith('#'))
-      const patterns = lines.map((line) => {
-        // ... regex conversion
-      })
-      return (path: string) => { ... }
+      const ig = ignore().add(gitignoreContent)
+      return (path: string) => !ig.ignores(path)
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/src/converter.ts` around lines 796 - 809, The current
conversion in converter.ts builds regexes by replacing gitignore tokens into
strings (see the pattern -> regexString replacements and the returned RegExp
using `.*` for `**`), which is vulnerable to ReDoS; replace this custom
conversion by delegating gitignore parsing/matching to a safe, well-tested
library (e.g., the `ignore` npm package) instead of building RegExp from
`regexString` — update the code path that maps `pattern` to `{ regex, isNegative
}` to use the `ignore` matcher API (or equivalent safe matcher) to produce match
results, remove the manual `.replace()` conversions around `regexString`, and
ensure directory handling (the branch checking `regexString.endsWith('/')`) is
handled by the library's semantics.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7783fb69-a1c0-4463-81fe-b359a8d9c2d0

📥 Commits

Reviewing files that changed from the base of the PR and between 3474daa and f2955e7.

⛔ Files ignored due to path filters (2)
  • packages/vue-to-dsl/test/full/input/appdemo01.zip is excluded by !**/*.zip
  • packages/vue-to-dsl/test/full/input/appdemo01/public/favicon.ico is excluded by !**/*.ico
📒 Files selected for processing (78)
  • packages/build/vite-config/src/vite-plugins/devAliasPlugin.js
  • packages/design-core/package.json
  • packages/design-core/re-export.js
  • packages/design-core/registry.js
  • packages/layout/src/defaultLayout.js
  • packages/register/src/constants.ts
  • packages/toolbars/upload/index.ts
  • packages/toolbars/upload/meta.js
  • packages/toolbars/upload/package.json
  • packages/toolbars/upload/src/Main.vue
  • packages/toolbars/upload/src/OverwriteDialog.vue
  • packages/toolbars/upload/src/http.ts
  • packages/toolbars/upload/src/styles/vars.less
  • packages/vue-to-dsl/.gitignore
  • packages/vue-to-dsl/README.md
  • packages/vue-to-dsl/cli.ts
  • packages/vue-to-dsl/package.json
  • packages/vue-to-dsl/src/constants.ts
  • packages/vue-to-dsl/src/converter.ts
  • packages/vue-to-dsl/src/generator/index.ts
  • packages/vue-to-dsl/src/index.d.ts
  • packages/vue-to-dsl/src/index.ts
  • packages/vue-to-dsl/src/parser/index.ts
  • packages/vue-to-dsl/src/parsers/index.ts
  • packages/vue-to-dsl/src/parsers/scriptParser.ts
  • packages/vue-to-dsl/src/parsers/styleParser.ts
  • packages/vue-to-dsl/src/parsers/templateParser.ts
  • packages/vue-to-dsl/src/shims.d.ts
  • packages/vue-to-dsl/src/types.ts
  • packages/vue-to-dsl/src/types/index.js
  • packages/vue-to-dsl/test/full/expected/schema.from-zip.json
  • packages/vue-to-dsl/test/full/expected/schema.json
  • packages/vue-to-dsl/test/full/index.test.js
  • packages/vue-to-dsl/test/full/input/appdemo01/.gitignore
  • packages/vue-to-dsl/test/full/input/appdemo01/README.md
  • packages/vue-to-dsl/test/full/input/appdemo01/index.html
  • packages/vue-to-dsl/test/full/input/appdemo01/package.json
  • packages/vue-to-dsl/test/full/input/appdemo01/src/App.vue
  • packages/vue-to-dsl/test/full/input/appdemo01/src/http/axios.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/http/config.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/http/index.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/i18n/en_US.json
  • packages/vue-to-dsl/test/full/input/appdemo01/src/i18n/index.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/i18n/locale.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/i18n/zh_CN.json
  • packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/bridge.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/dataSource.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/dataSource.json
  • packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/lowcode.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/lowcodeConfig/store.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/main.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/router/index.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/stores/index.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/stores/testState.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/utils.js
  • packages/vue-to-dsl/test/full/input/appdemo01/src/views/DemoPage.vue
  • packages/vue-to-dsl/test/full/input/appdemo01/src/views/LifeCyclePage.vue
  • packages/vue-to-dsl/test/full/input/appdemo01/src/views/UntitledA.vue
  • packages/vue-to-dsl/test/full/input/appdemo01/src/views/createVm.vue
  • packages/vue-to-dsl/test/full/input/appdemo01/vite.config.js
  • packages/vue-to-dsl/test/sfc/converter.test.js
  • packages/vue-to-dsl/test/testcases/001_simple/expected/schema.json
  • packages/vue-to-dsl/test/testcases/001_simple/input/component.vue
  • packages/vue-to-dsl/test/testcases/002_createVM/expected/schema.json
  • packages/vue-to-dsl/test/testcases/002_createVM/input/component.vue
  • packages/vue-to-dsl/test/testcases/003_login/expected/schema.json
  • packages/vue-to-dsl/test/testcases/003_login/input/component.vue
  • packages/vue-to-dsl/test/testcases/004_dashboard/expected/schema.json
  • packages/vue-to-dsl/test/testcases/004_dashboard/input/component.vue
  • packages/vue-to-dsl/test/testcases/005_survey/expected/schema.json
  • packages/vue-to-dsl/test/testcases/005_survey/input/component.vue
  • packages/vue-to-dsl/test/testcases/006_lifecycle/expected/schema.json
  • packages/vue-to-dsl/test/testcases/006_lifecycle/input/component.vue
  • packages/vue-to-dsl/test/testcases/index.test.js
  • packages/vue-to-dsl/tsconfig.json
  • packages/vue-to-dsl/vite.config.cli.mjs
  • packages/vue-to-dsl/vite.config.js
  • tsconfig.app.json

Comment on lines +124 to +175
const processAppSchema = async (appSchema: any) => {
// 将 appSchema 应用到全局
const { appSchemaState } = useResource()
// 1) 全局元数据(i18n/utils/dataSource/globalState/componentsMap)
const i18n = appSchema?.i18n || {}
const locales = Object.keys(i18n).length
? Object.keys(i18n).map((key) => ({ lang: key, label: key }))
: [
{ lang: 'zh_CN', label: 'zh_CN' },
{ lang: 'en_US', label: 'en_US' }
]
appSchemaState.langs = {
locales,
messages: i18n
}
appSchemaState.utils = appSchema?.utils || []
appSchemaState.dataSource = appSchema?.dataSource?.list || []
appSchemaState.globalState = appSchema?.globalState || []
appSchemaState.componentsMap = appSchema?.componentsMap || appSchemaState.componentsMap

// 同步刷新 i18n 到画布/设计器
const { id, type } = getMetaApi(META_SERVICE.GlobalService).getBaseInfo()
await useTranslate().initI18n({ host: id, hostType: type, init: true })

// 2) 创建静态页面(批量)并刷新页面树
const pages = Array.isArray(appSchema?.pageSchema) ? appSchema.pageSchema : []
// 将应用级 schema 归一化并持久化,便于 Http 拦截器统一返回
try {
const componentsTree = pages.map((ps: any) => ({
name: ps?.meta?.name || ps?.fileName || 'Page',
meta: { ...(ps?.meta || {}), isPage: true },
page_content: ps
}))
if (!componentsTree.some((p: any) => p?.meta?.isHome) && componentsTree[0]) {
componentsTree[0].meta.isHome = true
}
const normalizedAppData = {
...appSchema,
componentsTree,
pageSchema: pages,
meta: {
...(appSchema.meta || {}),
globalState: (appSchema.meta && appSchema.meta.globalState) || appSchema.globalState || []
}
}
localStorage.setItem('TE_LOCAL_APPSCHEMA', JSON.stringify(normalizedAppData))
} catch (e) {
// ignore persistence errors
}
const appId = getMetaApi(META_SERVICE.GlobalService).getBaseInfo().id
// 保存 appId 供覆盖选择确认/取消时使用
state.appId = appId
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 | 🟠 Major

Delay app-schema side effects until overwrite is confirmed.

Lines 125-170 commit appSchemaState, reinitialize i18n, and persist TE_LOCAL_APPSCHEMA before the duplicate-page branch at Lines 218-223 can still abort the import. If the user cancels the overwrite dialog, the UI says nothing was imported, but those global mutations have already been applied.

Also applies to: 218-223

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/toolbars/upload/src/Main.vue` around lines 124 - 175, The code
currently applies global side effects (mutating appSchemaState, calling
useTranslate().initI18n, writing TE_LOCAL_APPSCHEMA to localStorage, and setting
state.appId) inside processAppSchema before the overwrite confirmation may
abort; instead, make processAppSchema only produce/stage the normalizedAppData,
componentsTree, locales, and appId (e.g., return an object or set a transient
pendingAppSchema/pendingAppMeta field) and do NOT call useTranslate().initI18n,
mutate appSchemaState, write localStorage, or set state.appId there; then, in
the overwrite-confirmation handler (the duplicate-page/overwrite branch), when
the user confirms, apply the staged changes by assigning to appSchemaState,
calling useTranslate().initI18n, persisting TE_LOCAL_APPSCHEMA, and setting
state.appId; if the user cancels, discard the staged data so no global mutations
occur.

Comment on lines +195 to +243
try {
const existingList: any[] = await fetchPageList(appId)
const mapByName = new Map<string, any>()
existingList?.forEach?.((p: any) => {
if (p?.name) mapByName.set(String(p.name), p)
})

const getRawName = (ps: any) => (ps?.meta?.name || ps?.fileName || 'Page') as string
const pagesToUpdate: Array<{ ps: any; existing: any; name: string }> = []
const pagesToCreate: any[] = []
const duplicateNames: string[] = []

for (const ps of pages) {
const rawName = getRawName(ps)
const existing = mapByName.get(rawName)
if (existing) {
pagesToUpdate.push({ ps, existing, name: rawName })
duplicateNames.push(rawName)
} else {
pagesToCreate.push(ps)
}
}

if (duplicateNames.length) {
// 打开覆盖选择对话框并缓存数据,等待用户选择
state.duplicatePages = pagesToUpdate
state.toCreatePages = pagesToCreate
state.pendingImportedPages = pages
state.showOverwriteDialog = true
} else {
// 无重名,直接创建
await Promise.allSettled(
pagesToCreate.map((ps: any) =>
getMetaApi(META_SERVICE.Http).post('/app-center/api/pages/create', buildCreateParams(ps))
)
)
const { pageSettingState } = usePage()
await pageSettingState.updateTreeData?.()
}
} catch (e) {
// 若校验失败,则回退为原始创建逻辑
await Promise.allSettled(
pages.map((ps: any) =>
getMetaApi(META_SERVICE.Http).post('/app-center/api/pages/create', buildCreateParams(ps))
)
)
const { pageSettingState } = usePage()
await pageSettingState.updateTreeData?.()
}
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

Don't retry batch creates from this broad fallback.

This try wraps duplicate lookup, page creation, and tree refresh together. If updateTreeData() fails after some /pages/create calls already succeeded, the catch posts every page again, which retries a non-idempotent write and can duplicate data.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/toolbars/upload/src/Main.vue` around lines 195 - 243, The catch is
currently retrying all page creates on any error (including updateTreeData),
causing duplicate non-idempotent writes; refactor so that only the
duplicate-detection and create requests are inside the try and do NOT re-post
pages in the catch. Specifically, in the block around fetchPageList, mapByName,
pagesToUpdate/pagesToCreate and the Promise.allSettled that calls
getMetaApi(...).post('/app-center/api/pages/create', buildCreateParams(ps)),
remove the fallback that re-iterates pages in the catch; instead handle errors
by setting state (state.showOverwriteDialog/state.pendingImportedPages) or
logging the error and either rethrowing or returning early. Also isolate
pageSettingState.updateTreeData() into its own try/catch so failures to refresh
the tree do not trigger re-creating pages. Ensure references: fetchPageList,
buildCreateParams, getMetaApi(...).post('/app-center/api/pages/create', ...),
usePage()/pageSettingState.updateTreeData, and state. Do not change API call
semantics—only stop retrying creates from the broad catch and handle
updateTreeData errors separately.

Comment on lines +267 to +268
const rawName = (result?.schema?.meta?.name || file.name).replace(/\.(vue|jsx|tsx)$/i, '')
const safeRoute = `${rawName.replace(/\s+/g, '-').toLowerCase()}`
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 | 🟠 Major

Normalize the single-file fallback route with a leading slash.

Line 268 builds foo-bar, while the app import path uses /${...}. Single-file imports without meta.router end up with a different route shape and can break routing/lookups that expect a leading slash.

Suggested fix
-      const safeRoute = `${rawName.replace(/\s+/g, '-').toLowerCase()}`
+      const safeRoute = `/${rawName.replace(/\s+/g, '-').toLowerCase()}`

Also applies to: 293-296, 312-315

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/toolbars/upload/src/Main.vue` around lines 267 - 268, The fallback
route normalization currently produces values like "foo-bar" (const rawName /
const safeRoute) whereas consumers expect a leading slash; update the safeRoute
construction in the single-file fallback branches (the places using rawName →
safeRoute around the rawName.replace(...) calls and the other similar blocks at
the other two occurrences) to prepend a slash, e.g. build the route as `"/" +
rawName.replace(/\s+/g, '-').toLowerCase()` (or template `/${...}`) so all
fallback routes consistently include a leading "/" before returning/using them.

Comment on lines +273 to +328
try {
const existingList: any[] = await fetchPageList(appId)
const existing = existingList?.find?.((p: any) => String(p?.name) === rawName)

// 将待导入的 schema 作为 ps(与 zip 流程保持一致的数据形态)
const ps: any = {
...result.schema,
meta: { ...(result?.schema?.meta || {}), name: rawName },
fileName
}

if (existing) {
// 重名:弹出覆盖对话框
state.appId = appId
state.duplicatePages = [{ ps, existing, name: rawName }]
state.toCreatePages = []
state.pendingImportedPages = [ps]
state.showOverwriteDialog = true
} else {
// 不重名:直接创建
const createParams: any = {
name: rawName,
route: result?.schema?.meta?.router || safeRoute,
group: 'staticPages',
parentId: '0',
isPage: true,
app: appId,
page_content: {
...result.schema,
fileName
}
}
await getMetaApi(META_SERVICE.Http).post('/app-center/api/pages/create', createParams)
const { pageSettingState } = usePage()
await pageSettingState.updateTreeData?.()
useNotify({ type: 'success', title: '导入成功', message: `已创建新页面:${rawName}` })
}
} catch (e: any) {
// 兜底:如果列表获取失败,按原逻辑创建
const createParams: any = {
name: rawName,
route: result?.schema?.meta?.router || safeRoute,
group: 'staticPages',
parentId: '0',
isPage: true,
app: appId,
page_content: {
...result.schema,
fileName
}
}
await getMetaApi(META_SERVICE.Http).post('/app-center/api/pages/create', createParams)
const { pageSettingState } = usePage()
await pageSettingState.updateTreeData?.()
useNotify({ type: 'success', title: '导入成功', message: `已创建新页面:${rawName}` })
}
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

Scope the single-file fallback to fetchPageList() only.

This catch retries /pages/create on any error in the block, not just page-list lookup failures. A successful create followed by an updateTreeData() failure will send the same create request a second time.

Comment on lines +411 to +428
if (requests.length) {
await Promise.allSettled(requests)
}
const hasOps = requests.length > 0
if (hasOps) {
await pageSettingState.updateTreeData?.()
// 用户选择后进行渲染
const pages = state.pendingImportedPages
const chosen = pages.find((p: any) => p?.meta?.isHome) || pages[0]
if (chosen) {
await switchToPageByName(chosen?.meta?.name || chosen?.fileName)
useNotify({
type: 'success',
title: '导入成功',
message: `已创建/覆盖页面并加载:${chosen?.meta?.name || '页面'}`
})
} else {
useNotify({ type: 'success', title: '导入成功', message: `已更新全局配置(未检测到页面)` })
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 | 🟠 Major

Derive success from settled results, not requests.length.

After Promise.allSettled(requests), hasOps only means work was attempted. A fully rejected overwrite/create batch still refreshes the tree, switches pages, and shows “导入成功”.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/toolbars/upload/src/Main.vue` around lines 411 - 428, After awaiting
Promise.allSettled(requests) don't use requests.length to decide success;
instead capture the settled results (from Promise.allSettled) and compute
whether any operation fulfilled (e.g., results.some(r => r.status ===
'fulfilled')) and only when there is at least one fulfilled result call
pageSettingState.updateTreeData, select a page via switchToPageByName and call
useNotify with the "导入成功" message; if all settled results are rejected, avoid
refreshing/switching and call useNotify (or other error handling) to surface the
failure and optionally log the aggregate rejection reasons; update the block
that defines hasOps to use the settled results status and handle partial success
vs total failure accordingly, referencing requests, Promise.allSettled,
pageSettingState.updateTreeData, switchToPageByName, useNotify, and
state.pendingImportedPages.

Comment on lines +49 to +51
<span style="background-color: [object Event]; color: #8a8e99; font-size: 12px"
>温馨提示:页面左上角切换区域</span
>
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 CSS value: [object Event] is not a valid background-color.

This appears to be a JavaScript object accidentally serialized into the style attribute. This will cause a CSS parsing error and the background-color property will be ignored.

Proposed fix
-          <span style="background-color: [object Event]; color: `#8a8e99`; font-size: 12px"
+          <span style="color: `#8a8e99`; font-size: 12px"

Or specify the intended color value.

📝 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
<span style="background-color: [object Event]; color: #8a8e99; font-size: 12px"
>温馨提示:页面左上角切换区域</span
>
<span style="color: `#8a8e99`; font-size: 12px"
>温馨提示:页面左上角切换区域</span
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/src/views/createVm.vue` around
lines 49 - 51, The inline style on the span rendering "温馨提示:页面左上角切换区域" contains
an invalid background-color value "[object Event]" (likely an accidentally
serialized event object); locate that span in createVm.vue and replace the
background-color token with a valid CSS color (e.g., a hex, rgb(), or named
color) or remove the inline style and move styling into a class/CSS rule (update
the className or stylesheet accordingly) so the background-color is a proper CSS
value.

style="border-radius: 0px"
>
<tiny-form-item label="数据盘" style="border-radius: 0px">
<div v-for="() in state.dataDisk" style="margin-top: 12px; display: flex">
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 v-for syntax: empty loop variable.

v-for="() in state.dataDisk" is invalid Vue syntax. The directive requires at least one iteration variable.

Proposed fix
-          <div v-for="() in state.dataDisk" style="margin-top: 12px; display: flex">
+          <div v-for="(_, index) in state.dataDisk" :key="index" style="margin-top: 12px; display: flex">

Note: A :key binding should also be added for list rendering stability.

📝 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
<div v-for="() in state.dataDisk" style="margin-top: 12px; display: flex">
<div v-for="(_, index) in state.dataDisk" :key="index" style="margin-top: 12px; display: flex">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/src/views/createVm.vue` at line
292, The v-for on the div is using an empty loop variable ("v-for=\"() in
state.dataDisk\"") which is invalid; change it to provide iteration variables
(for example v-for="(disk, index) in state.dataDisk") and add a stable :key (for
example :key="disk.id || index"); also update any references inside the loop
that assumed a specific name to use the new variable (disk or index) where
needed.

@@ -0,0 +1,24 @@
import { defineConfig } from 'vite'
import path from 'path'
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check current vite config patterns in the repo for __dirname vs import.meta.url usage.
# Expected: confirm whether this file is an outlier and standardize accordingly.
fd '^vite\.config\.(js|ts|mjs|cjs)$' -x rg -n "__dirname|fileURLToPath|new URL\(" {}

Repository: opentiny/tiny-engine

Length of output: 4711


🏁 Script executed:

cat -n packages/vue-to-dsl/test/full/input/appdemo01/vite.config.js

Repository: opentiny/tiny-engine

Length of output: 707


🏁 Script executed:

# Check if this is a CommonJS or ESM file, and verify directory structure
file packages/vue-to-dsl/test/full/input/appdemo01/vite.config.js
head -20 packages/vue-to-dsl/test/full/input/appdemo01/vite.config.js

Repository: opentiny/tiny-engine

Length of output: 554


🏁 Script executed:

# Check if there are similar test/demo vite.config files and how they handle this
fd 'vite\.config' packages/vue-to-dsl/test -x head -15 {}

Repository: opentiny/tiny-engine

Length of output: 399


🏁 Script executed:

# Check the build configuration for this package to understand how it's compiled
cat -n packages/vue-to-dsl/package.json | head -50

Repository: opentiny/tiny-engine

Length of output: 1821


🏁 Script executed:

# Search for references to this vite.config.js file
rg "appdemo01" packages/vue-to-dsl/test --type js --type ts -A 2 -B 2

Repository: opentiny/tiny-engine

Length of output: 1566


🏁 Script executed:

# Check the test directory structure to understand what this fixture is used for
find packages/vue-to-dsl/test/full/input/appdemo01 -type f | head -20

Repository: opentiny/tiny-engine

Length of output: 1373


🏁 Script executed:

# Check if there's a test that imports or uses this vite config
rg "vite\.config" packages/vue-to-dsl/test --type js --type ts -B 3 -A 3

Repository: opentiny/tiny-engine

Length of output: 46


🏁 Script executed:

# Check if __dirname is declared anywhere in the file or imported
cat -n packages/vue-to-dsl/test/full/input/appdemo01/vite.config.js

Repository: opentiny/tiny-engine

Length of output: 707


🏁 Script executed:

# Verify the package.json type setting
grep -A 5 '"type"' packages/vue-to-dsl/package.json

Repository: opentiny/tiny-engine

Length of output: 445


🏁 Script executed:

# Check if there are other test fixture vite configs and how they handle __dirname
find packages -path "*/test/*" -name "vite.config.*" -exec grep -l "__dirname\|fileURLToPath" {} \;

Repository: opentiny/tiny-engine

Length of output: 296


🏁 Script executed:

# Check the other test fixture vite configs to see how they handle __dirname
for file in packages/vue-generator/test/testcases/element-plus-case/expected/appdemo01/vite.config.js packages/vue-generator/test/testcases/generator/expected/appdemo01/vite.config.js; do
  echo "=== $file ==="
  cat -n "$file"
  echo ""
done

Repository: opentiny/tiny-engine

Length of output: 1541


🏁 Script executed:

# Check vue-generator package.json to see if it also has "type": "module"
grep -A 2 '"type"' packages/vue-generator/package.json

Repository: opentiny/tiny-engine

Length of output: 286


Fix ESM-safe path resolution in Vite config.

In an ESM context (package.json declares "type": "module"), __dirname is not available and causes a ReferenceError at runtime. Use the ESM-safe pattern instead:

♻️ Proposed refactor
 import { defineConfig } from 'vite'
 import path from 'path'
+import { fileURLToPath } from 'url'
 import vue from '@vitejs/plugin-vue'
 import vueJsx from '@vitejs/plugin-vue-jsx'
 
+const __dirname = new URL('.', import.meta.url).pathname
+
 export default defineConfig({
   resolve: {
     alias: {
-      '@': path.resolve(__dirname, 'src')
+      '@': fileURLToPath(new URL('./src', import.meta.url))
     }
   },

Also applies to: 9-9

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/vite.config.js` at line 2,
Replace any use of the CommonJS __dirname in the Vite config with the ESM-safe
pattern: import { fileURLToPath } from 'url' and derive __dirname via const
__dirname = path.dirname(fileURLToPath(import.meta.url)); update any
path.resolve/joins that reference __dirname accordingly (look for occurrences of
__dirname in this file and lines around the import path statement) so the config
runs under "type":"module" without ReferenceError.

Comment on lines +13 to +15
define: {
'process.env': { ...process.env }
},
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify whether this app actually depends on process.env in source files.
# Expected: no required `process.env` usages in client code, or usages can be migrated to import.meta.env.
rg -n "process\.env|import\.meta\.env" \
  packages/vue-to-dsl/test/full/input/appdemo01/src \
  -g "*.js" -g "*.ts" -g "*.vue"

Repository: opentiny/tiny-engine

Length of output: 194


Remove the unnecessary and overly permissive process.env injection.

The define block exposes all build-time environment variables to the client bundle, creating a security risk. The codebase already follows Vite best practices by using import.meta.env.VITE_APP_MOCK (found in src/lowcodeConfig/dataSource.js), making this injection redundant. Delete the define block entirely.

🔧 Proposed fix
 export default defineConfig({
@@
-  define: {
-    'process.env': { ...process.env }
-  },
   build: {
📝 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
define: {
'process.env': { ...process.env }
},
export default defineConfig({
build: {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/test/full/input/appdemo01/vite.config.js` around lines 13
- 15, Remove the overly permissive define block that injects process.env into
the client bundle; specifically delete the define: { 'process.env': {
...process.env } } entry in vite.config.js (remove references to define and
process.env in that file) since the codebase uses import.meta.env.VITE_APP_MOCK
in src/lowcodeConfig/dataSource.js and this injection is redundant and a
security risk.

export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'cli.ts'),
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C2 '\b__dirname\b' packages/vue-to-dsl/vite.config.cli.mjs
rg -n -C2 'fileURLToPath\s*\(\s*import\.meta\.url\s*\)' packages/vue-to-dsl/vite.config.cli.mjs

Repository: opentiny/tiny-engine

Length of output: 203


🏁 Script executed:

#!/bin/bash
# Read the full vite.config.cli.mjs file to understand context
cat -n packages/vue-to-dsl/vite.config.cli.mjs

# Check for any build configuration that might compile this file
fd -t f 'vite.config' packages/vue-to-dsl/ 2>/dev/null | head -20

# Look for any config compilation or preprocessing
rg -n 'vite.config.cli' . --max-count=10

Repository: opentiny/tiny-engine

Length of output: 1182


🏁 Script executed:

#!/bin/bash
# Check if there are any test files or build logs
fd -t f 'package.json' packages/vue-to-dsl/ -exec grep -l 'build:cli' {} \;

# Look for any CI/test configuration
fd -t f '.github' | head -5

# Search for any Node.js config that might inject globals
rg -n 'NODE_OPTIONS\|--require\|register' . --max-count=10

# Check if __dirname errors are mentioned in issues
rg -i '__dirname.*undefined\|ReferenceError.*__dirname' . 2>/dev/null | head -5

Repository: opentiny/tiny-engine

Length of output: 267


🏁 Script executed:

#!/bin/bash
# Check package.json in vue-to-dsl
cat packages/vue-to-dsl/package.json

# Look for CI configuration
find .github -name '*.yml' -o -name '*.yaml' 2>/dev/null | head -5

# Check for any test runs or workflows
fd -t f '\.yml$|\.yaml$' .github 2>/dev/null | head -10

Repository: opentiny/tiny-engine

Length of output: 2045


🏁 Script executed:

#!/bin/bash
# Check the release workflow to see if build:cli is executed
cat .github/workflows/Release.yml | head -100

# Also check if there are any other workflows
fd -t f '\.yml$' .github/workflows | xargs head -50

Repository: opentiny/tiny-engine

Length of output: 8944


Use ESM-safe dirname resolution in Vite config.

__dirname is undefined in ESM modules. Line 8 will cause a ReferenceError when running vite build --config vite.config.cli.mjs.

Fix
 import { defineConfig } from 'vite'
 import path from 'node:path'
+import { fileURLToPath } from 'node:url'
+
+const __filename = fileURLToPath(import.meta.url)
+const __dirname = path.dirname(__filename)

 // 专用于打包 CLI 入口 cli.ts,输出为 dist/cli.js(CJS)
 export default defineConfig({
📝 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
entry: path.resolve(__dirname, 'cli.ts'),
import { defineConfig } from 'vite'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
// 专用于打包 CLI 入口 cli.ts,输出为 dist/cli.js(CJS)
export default defineConfig({
entry: path.resolve(__dirname, 'cli.ts'),
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vue-to-dsl/vite.config.cli.mjs` at line 8, Replace the ESM-unsafe
use of __dirname in the Vite config entry (the line using
path.resolve(__dirname, 'cli.ts')) with an ESM-safe dirname computed from
import.meta.url; add an import reference to fileURLToPath from 'url' and compute
const __dirname = path.dirname(fileURLToPath(import.meta.url)) at the top of the
module, then use that __dirname in path.resolve for the entry so the config
works under ESM.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants