feat(genui-sdk-vue): add code generation capabilities#121
Conversation
…tionality in SchemaCardRenderer
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a Vue SFC code-generation pipeline and UI export: new code-generator modules (template, state, event, utils, constants, validator), integrates an export button into SchemaCardRenderer to download generated Changes
Sequence DiagramsequenceDiagram
participant User
participant Renderer as SchemaCardRenderer.vue
participant Generator as code-generator
participant StateGen as state-generator
participant TemplateGen as template-generator
participant Validator as vue-sfc-validator
participant Browser
User->>Renderer: Click Export button
Renderer->>Generator: generateCode(pageInfo, componentsMap)
Generator->>Generator: sanitize & dedupe componentsMap
Generator->>StateGen: traverseState(schema.state)
StateGen-->>Generator: transformed state (expressions/functions/slots handled)
Generator->>TemplateGen: generateTemplate(schema, state)
TemplateGen-->>Generator: template string
Generator->>Validator: validateByCompile(filename, code)
Validator-->>Generator: errors[]
Generator-->>Renderer: { panelName, panelValue, errors }
Renderer->>Browser: downloadTextFile(panelValue, filename)
Browser-->>User: .vue file downloaded
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (7)
packages/frameworks/vue/src/renderer/SchemaCardRenderer.vue (2)
197-200: Consider using i18n for the button label.The label "导出源码" is hardcoded in Chinese. For consistency with the rest of the component (which uses
t()for translations, e.g., line 54), consider adding this string to the i18n resources.♻️ Proposed i18n usage
<div class="schema-export-button" `@click.stop.prevent`="generateCode"> <TinyIconDownload class="schema-export-icon" /> - <span class="schema-export-label">导出源码</span> + <span class="schema-export-label">{{ t('renderer.exportSource') }}</span> </div>Add the corresponding translation key to your i18n resources.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/renderer/SchemaCardRenderer.vue` around lines 197 - 200, The button label "导出源码" is hardcoded; replace it with a translation call (e.g., use t('schema.exportSource') or t('schema.exportCodeLabel') where the template currently renders the span inside the div with class "schema-export-button" and keep the click handler generateCode and TinyIconDownload unchanged), and add the same key with Chinese and other locale values to your i18n resource files so the component (which already uses t()) will render the localized label.
132-144: UnusedprettierOptsvariable.
prettierOptsis destructured from the generator result but never used. Either remove it or apply formatting with it.♻️ Remove unused variable
const generateCode = async () => { - const { panelValue: code, panelName: fileName, errors, prettierOpts } = generateVueCode({ + const { panelValue: code, panelName: fileName, errors } = generateVueCode({ pageInfo: { schema: displaySchema.value }, componentsMap, });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/renderer/SchemaCardRenderer.vue` around lines 132 - 144, The destructured prettierOpts from generateVueCode in generateCode is unused; either remove prettierOpts from the destructuring or apply it to format the generated code before saving (e.g., call prettier.format(code, prettierOpts) or an existing format helper) and pass the formatted result to downloadTextFile; update the generateCode function to use the chosen approach and keep references to generateVueCode, prettierOpts, code, and downloadTextFile consistent.packages/frameworks/vue/src/renderer/code-generator/template-generator.ts (3)
1-1: Unused import:capitalize.
capitalizeis imported from@vue/sharedbut is not used anywhere in this file. Consider removing it to keep imports clean.♻️ Suggested fix
-import { capitalize, hyphenate } from '@vue/shared'; +import { hyphenate } from '@vue/shared';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/renderer/code-generator/template-generator.ts` at line 1, The import list in template-generator.ts includes an unused symbol `capitalize` from `@vue/shared`; remove `capitalize` from the import so the statement only imports `hyphenate` (and run linter/formatting to ensure imports are updated). Locate the import statement that reads `import { capitalize, hyphenate } from '@vue/shared'` and delete `capitalize` while keeping `hyphenate`.
211-214: VOID_ELEMENTS list may be incomplete.The HTML specification defines more void elements than listed here (e.g.,
area,base,col,embed,meta,param,source,track,wbr). If these elements appear in schemas, they won't be self-closed properly. Consider expanding the list or extracting it as a shared constant.♻️ Suggested expanded list
- const VOID_ELEMENTS = ['img', 'input', 'br', 'hr', 'link']; + const VOID_ELEMENTS = [ + 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', + 'link', 'meta', 'param', 'source', 'track', 'wbr' + ];🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/renderer/code-generator/template-generator.ts` around lines 211 - 214, The VOID_ELEMENTS array used in template-generator.ts is incomplete (currently only ['img','input','br','hr','link']) which causes some HTML void tags to not be self-closed; update VOID_ELEMENTS to include the full set of HTML void elements (e.g., area, base, col, embed, meta, param, source, track, wbr, etc.) or extract it into a shared constant used by the generator, and ensure the existing branch that checks VOID_ELEMENTS.includes(component) and calls result.push(' />') continues to apply to the expanded/shared list.
248-250: Duplicate VOID_ELEMENTS constant.The
VOID_ELEMENTSarray is duplicated here and at line 212. Consider extracting it to a shared constant to maintain consistency and avoid divergence.♻️ Suggested refactor
Add at the top of the file:
const VOID_ELEMENTS = [ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr' ];Then remove the inline definitions at lines 212 and 249.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/renderer/code-generator/template-generator.ts` around lines 248 - 250, There is a duplicated VOID_ELEMENTS array in template-generator.ts; extract a single shared constant named VOID_ELEMENTS at the top of the file (as suggested) and remove the inline array definitions around the checks that reference VOID_ELEMENTS (the blocks that check if (VOID_ELEMENTS.includes(component)) near where component is resolved); update all references in this file to use the single top-level VOID_ELEMENTS constant so both locations (previously at line ~212 and ~249) use the same shared symbol.packages/frameworks/vue/src/renderer/code-generator/code-generator.ts (2)
28-30: Simplify single-element array.
importsFromVueis an array with one element that is immediately joined. This can be simplified to a direct string.♻️ Suggested simplification
- const importsFromVue = ['import * as vue from "vue"']; - - imports.push(importsFromVue.join('\n')); + imports.push('import * as vue from "vue"');🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/renderer/code-generator/code-generator.ts` around lines 28 - 30, The variable importsFromVue is an unnecessary single-element array that’s immediately joined; replace it with a direct string and push that string into imports instead. Locate the declaration/imports push in code-generator.ts (the importsFromVue variable and the subsequent imports.push(importsFromVue.join('\n')) call) and change it to push the literal string 'import * as vue from "vue"' (or assign a const importFromVueString = 'import * as vue from "vue"' and push that) to remove the redundant array and join.
148-157:prettierOptsis defined but formatting is not applied.The prettier options are returned in the panel object but the code is never actually formatted. If formatting is intended to happen downstream, this is fine. Otherwise, consider either applying Prettier here or removing the unused options.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/renderer/code-generator/code-generator.ts` around lines 148 - 157, prettierOpts is declared but never used, so either format the generated code with Prettier using those options or remove the unused config; update the code in code-generator.ts to call Prettier.format(generatedCode, prettierOpts) (or the equivalent async API) and assign the formatted result into the property you return on the panel object (the same field where unformatted code is currently set), ensuring you import/require Prettier where needed, or delete prettierOpts and its return from the panel if formatting is handled downstream.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/frameworks/vue/src/renderer/code-generator/code-generator.ts`:
- Around line 144-145: The current deep copy using
JSON.parse(JSON.stringify(originSchema)) in code-generator.ts (creating const
schema) strips function values; replace it with a cloning approach that
preserves functions (e.g., use structuredClone(originSchema) if available or a
deep-clone utility such as lodash.cloneDeep or a project deepClone helper) so
schema retains function expressions; update the creation of schema to use that
cloning method and ensure any imports (e.g., cloneDeep) are added where used.
- Around line 74-89: The Function branch in the properties loop accesses
defaultValue.value without a null check which can throw; update the Function
handling in code-generator.ts (inside the properties.forEach/content.forEach
where propType is computed) to guard defaultValue (e.g., use defaultValue?.value
or check defaultValue != null) and fall back to a safe default (such as
undefined or an empty function expression) before assigning propValue and
pushing into propsArr so missing schema data won't cause a TypeError.
In `@packages/frameworks/vue/src/renderer/code-generator/event-binding.ts`:
- Around line 17-23: Remove the unused helper function toPascalCase: locate the
function declaration named toPascalCase in event-binding.ts and delete it
(including its JSDoc comment) since it's not exported or referenced anywhere;
ensure no other code depends on it and run tests/lint to confirm no remaining
references.
- Around line 5-6: Remove the unused and duplicate regex exports thisBindRe and
thisPropsBindRe from event-binding.ts; delete both exported constants (they both
equal /this\.(props\.)?/g) and ensure no other module imports them (replace or
consolidate any inline uses in template-generator.ts to reference a single
in-file literal or a new shared constant if desired). Also run a quick
project-wide search for thisBindRe and thisPropsBindRe to confirm there are no
remaining references before committing.
In `@packages/frameworks/vue/src/renderer/code-generator/state-generator.ts`:
- Around line 51-56: The code that handles [JS_FUNCTION] unconditionally
destructures getFunctionInfo(value) which can return null; update the
[JS_FUNCTION] handler to guard the getFunctionInfo result (call
getFunctionInfo(value) into a local like info), check for null/undefined and
return the original value (or a safe fallback string) early if parsing failed,
otherwise destructure info to obtain type, params, body and build inlineFunc as
before; ensure you still reference start and end when returning the
reconstructed string.
In `@packages/frameworks/vue/src/renderer/code-generator/template-generator.ts`:
- Line 244: The call handleBinding(props, attrsArr, description, {}) wrongly
passes an empty state object so temp variables from handleLiteralBinding are
written to a throwaway object; replace the {} with the actual binding state
object used by this generator (e.g., the existing `state` or `bindingState`
variable used elsewhere in this module) or create/preserve a persistent
bindingState before the call and pass that so temporary bindings like those
created by handleLiteralBinding are stored and referenced correctly in the
generated JSX.
- Around line 77-87: The handleSlotBinding function can emit strings like
"#[object Object]" when name is falsy and item is an object; update
handleSlotBinding to compute a safe name fallback (e.g., const slotName = name
|| (typeof item === 'string' ? item : 'default')) and use slotName for all
generated strings so you never interpolate the raw object; keep the same params
logic but reference slotName when building `#${...}` for the array and string
branches to ensure valid template output.
- Around line 89-107: handleEventBinding currently returns an empty string for
non-JSExpression items which gets pushed into attrsArr and creates spurious
empty attributes; change the function (handleEventBinding) to return a falsy
value (e.g., null or undefined) instead of '' when no binding is produced
(change the eventBinding default and final return), and ensure the caller that
builds attrsArr filters falsy values before pushing (or only pushes when
handleEventBinding returns a truthy string) so attrsArr never contains empty
strings.
- Around line 140-147: The code clears the shared description.internalTypes
inside the canotBind branch causing global side effects; instead of mutating
description.internalTypes, create and use a local Set for this binding (e.g.,
const localInternalTypes = new Set(description.internalTypes) or new Set()) when
preparing the temporary state binding in the canotBind block, and leave
description.internalTypes untouched; keep the rest of the logic that computes
valueKey (avoidDuplicateString), assigns state[valueKey] = item, and pushes
attrsArr.push(`:${key}="state.${valueKey}"`) unchanged.
In `@packages/frameworks/vue/src/renderer/code-generator/vue-sfc-validator.ts`:
- Around line 107-122: The locateErrorMessage function currently assumes
loc.start.line exists within originalSource lines causing errorLineCode to be
undefined when line is out of bounds; update locateErrorMessage to validate and
clamp the line index (derived from loc.start.line) against
originalSource.split(/\r?\n/) length (or bail out and return the original
message if line is invalid), only compute scopeCode and call generateCodeFrame
when errorLineCode is defined, and ensure column is also clamped within the
errorLineCode length; reference locateErrorMessage, originalSource, error,
loc.start, and generateCodeFrame when making the change.
- Around line 60-71: The code uses descriptor.template without guarding for
null; add a null/undefined check before calling compileTemplate so we only
access template.content when descriptor.template exists (e.g., if
(descriptor.template) ...), or early-return/skip validation when template is
missing; update the block around the compileTemplate call (referencing
descriptor, template, scoped and the compileTemplate invocation that produces
templateResult) to avoid calling template.content when template is null.
---
Nitpick comments:
In `@packages/frameworks/vue/src/renderer/code-generator/code-generator.ts`:
- Around line 28-30: The variable importsFromVue is an unnecessary
single-element array that’s immediately joined; replace it with a direct string
and push that string into imports instead. Locate the declaration/imports push
in code-generator.ts (the importsFromVue variable and the subsequent
imports.push(importsFromVue.join('\n')) call) and change it to push the literal
string 'import * as vue from "vue"' (or assign a const importFromVueString =
'import * as vue from "vue"' and push that) to remove the redundant array and
join.
- Around line 148-157: prettierOpts is declared but never used, so either format
the generated code with Prettier using those options or remove the unused
config; update the code in code-generator.ts to call
Prettier.format(generatedCode, prettierOpts) (or the equivalent async API) and
assign the formatted result into the property you return on the panel object
(the same field where unformatted code is currently set), ensuring you
import/require Prettier where needed, or delete prettierOpts and its return from
the panel if formatting is handled downstream.
In `@packages/frameworks/vue/src/renderer/code-generator/template-generator.ts`:
- Line 1: The import list in template-generator.ts includes an unused symbol
`capitalize` from `@vue/shared`; remove `capitalize` from the import so the
statement only imports `hyphenate` (and run linter/formatting to ensure imports
are updated). Locate the import statement that reads `import { capitalize,
hyphenate } from '@vue/shared'` and delete `capitalize` while keeping
`hyphenate`.
- Around line 211-214: The VOID_ELEMENTS array used in template-generator.ts is
incomplete (currently only ['img','input','br','hr','link']) which causes some
HTML void tags to not be self-closed; update VOID_ELEMENTS to include the full
set of HTML void elements (e.g., area, base, col, embed, meta, param, source,
track, wbr, etc.) or extract it into a shared constant used by the generator,
and ensure the existing branch that checks VOID_ELEMENTS.includes(component) and
calls result.push(' />') continues to apply to the expanded/shared list.
- Around line 248-250: There is a duplicated VOID_ELEMENTS array in
template-generator.ts; extract a single shared constant named VOID_ELEMENTS at
the top of the file (as suggested) and remove the inline array definitions
around the checks that reference VOID_ELEMENTS (the blocks that check if
(VOID_ELEMENTS.includes(component)) near where component is resolved); update
all references in this file to use the single top-level VOID_ELEMENTS constant
so both locations (previously at line ~212 and ~249) use the same shared symbol.
In `@packages/frameworks/vue/src/renderer/SchemaCardRenderer.vue`:
- Around line 197-200: The button label "导出源码" is hardcoded; replace it with a
translation call (e.g., use t('schema.exportSource') or
t('schema.exportCodeLabel') where the template currently renders the span inside
the div with class "schema-export-button" and keep the click handler
generateCode and TinyIconDownload unchanged), and add the same key with Chinese
and other locale values to your i18n resource files so the component (which
already uses t()) will render the localized label.
- Around line 132-144: The destructured prettierOpts from generateVueCode in
generateCode is unused; either remove prettierOpts from the destructuring or
apply it to format the generated code before saving (e.g., call
prettier.format(code, prettierOpts) or an existing format helper) and pass the
formatted result to downloadTextFile; update the generateCode function to use
the chosen approach and keep references to generateVueCode, prettierOpts, code,
and downloadTextFile consistent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 80a81b08-01e6-4bb5-98aa-d3a88e5ee06c
📒 Files selected for processing (10)
packages/frameworks/vue/package.jsonpackages/frameworks/vue/src/renderer/SchemaCardRenderer.vuepackages/frameworks/vue/src/renderer/code-generator/code-generator.tspackages/frameworks/vue/src/renderer/code-generator/constants.tspackages/frameworks/vue/src/renderer/code-generator/event-binding.tspackages/frameworks/vue/src/renderer/code-generator/index.tspackages/frameworks/vue/src/renderer/code-generator/state-generator.tspackages/frameworks/vue/src/renderer/code-generator/template-generator.tspackages/frameworks/vue/src/renderer/code-generator/types.tspackages/frameworks/vue/src/renderer/code-generator/vue-sfc-validator.ts
…ications for various architectures
…improve state traversal for JS_SLOT
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/frameworks/vue/src/renderer/code-generator/code-generator.ts`:
- Around line 109-126: The generated <script setup> block in code-generator.ts
doesn't include a lang attribute when JSX is required (description.hasJSX is set
by state-generator.ts for slot content); update the template generation (the
multi-line string building the <template>...<script setup> block) to
conditionally emit <script setup lang="jsx"> (or the appropriate JSX/TSX variant
if your description indicates) when description.hasJSX is true, otherwise emit
the plain <script setup>; locate the code that constructs the string
(references: description.hasJSX, imports, propsArr, emitsArr, iconStatement,
reactiveStatement, methodsArr) and inject the conditional lang attribute into
the opening script tag.
In `@packages/frameworks/vue/src/renderer/code-generator/state-generator.ts`:
- Around line 106-117: The array branch in traverseState skips calling
transformType for array entries, letting raw protocol nodes leak into the
reactive initializer; update the Array.isArray branch in traverseState so that
for each element you first call transformType(element, /*prop=*/ undefined,
description, rootState) (or use the element's index as the prop string) and then
call traverseState(element, description, rootState) so built-in protocol nodes
inside arrays are transformed before recursion; keep using the existing
traverseState and transformType symbols and preserve rootState propagation.
- Around line 78-84: The current JS_SLOT generator concatenates children with
.join('') producing empty or invalid multi-root bodies; change the
implementation in JS_SLOT to map items via generateJSXTemplate into an array
(e.g., slotNodes), then: if slotNodes.length === 0 return the string 'null'; if
slotNodes.length === 1 use slotNodes[0]; otherwise wrap them as an array string
like `[${slotNodes.join(',')}]`; finally build the return using params (e.g., ({
${params.join(',')} }, h) => <body>) so start/end and the JS_SLOT function
produce a valid single-root or array root render body.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2676d20d-4e84-4267-b4e9-f700e12c711b
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
packages/frameworks/vue/src/renderer/code-generator/code-generator.tspackages/frameworks/vue/src/renderer/code-generator/event-binding.tspackages/frameworks/vue/src/renderer/code-generator/state-generator.tspackages/frameworks/vue/src/renderer/code-generator/template-generator.tspackages/frameworks/vue/src/renderer/code-generator/vue-sfc-validator.ts
✅ Files skipped from review due to trivial changes (1)
- packages/frameworks/vue/src/renderer/code-generator/template-generator.ts
…templates, event binding, and state management
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (4)
packages/frameworks/vue/src/code-generator/state-generator.ts (2)
109-110:⚠️ Potential issue | 🟠 MajorTransform protocol nodes inside arrays before recursing.
Line 110 only descends into each array element. If an element itself is a built-in protocol node,
transformTypenever runs for that entry, so the raw{ type, ... }object leaks into the generatedreactive(...)initializer.🛠️ Suggested fix
if (Array.isArray(current)) { - current.forEach((prop) => traverseState(prop, description, rootState)); + current.forEach((_, index) => { + transformType(current, index, description, rootState); + traverseState(current[index], description, rootState); + }); } else if (typeof current === 'object') {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/code-generator/state-generator.ts` around lines 109 - 110, Array elements that are protocol nodes aren't being transformed before recursion: update the Array branch in traverseState so each element is passed through transformType (e.g., let transformed = transformType(prop, description, rootState) or assign back to prop) before calling traverseState on it; specifically, in the current.forEach callback call transformType(prop, description, rootState) and use its result when recursing to ensure protocol nodes inside arrays are converted prior to generating the reactive initializer.
78-84:⚠️ Potential issue | 🟠 MajorGenerate a valid JSX body for empty and multi-node slots.
Line 81 concatenates every slot child into one string. That leaves
({ row }, h) =>with no body whenvalueis empty, and emits adjacent roots like<A /><B />when there are multiple children. Both forms are invalid once unwrapped into the generated slot render function.🛠️ Suggested fix
[JS_SLOT]: ({ value = [], params = ['row'] }, description, rootState) => { description.hasJSX = true; - const slotValues = value.map((item) => generateJSXTemplate(item, description, rootState)).join(''); + const slotNodes = value.map((item) => generateJSXTemplate(item, description, rootState)); + const slotBody = + slotNodes.length === 0 ? 'null' : slotNodes.length === 1 ? slotNodes[0] : `[${slotNodes.join(',')}]`; // 默认解构参数 row,因为jsx slot 必须有第二个参数 h - return `${start}({ ${params.join(',')} }, h) => ${slotValues}${end}`; + return `${start}({ ${params.join(',')} }, h) => ${slotBody}${end}`; },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/code-generator/state-generator.ts` around lines 78 - 84, The current JS_SLOT generator builds slotValues by concatenating children which yields an empty body when value is empty and adjacent roots when there are multiple children; change it to: compute children via generateJSXTemplate for each item, then if value.length === 0 set the body to "null", if value.length === 1 use the single child string, otherwise wrap the joined children in a JSX fragment (e.g. `<>${joined}</>`) so the returned string from JS_SLOT (the `${start}({ ${params.join(',')} }, h) => ${body}${end}` expression) is always a valid JSX function body; keep the existing description.hasJSX flag and use the same symbols (JS_SLOT, generateJSXTemplate, slotValues/start/end/params) when implementing.packages/frameworks/vue/src/code-generator/code-generator.ts (2)
24-57:⚠️ Potential issue | 🔴 CriticalDeclare the helper symbols that generated code can reference.
Lines 24-57 only import Vue and component dependencies, and Lines 117-124 never declare any runtime helpers.
generateTemplate(...)andtraverseState(...)can still emitt(...),utils.*, andbridge.*, so schemas using i18n orJS_RESOURCEcurrently download a component with unresolved identifiers.Also applies to: 68-69, 117-124
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/code-generator/code-generator.ts` around lines 24 - 57, The generated code currently only imports Vue and component packages in generateImports, but does not declare runtime helper symbols (e.g., t, utils.*, bridge.*), so code emitted by generateTemplate and traverseState can contain unresolved identifiers; update generateImports to also declare and export or return helper bindings for these symbols (t, utils, bridge and any subhelpers used by generateTemplate/traverseState) so they are always defined for generated SFCs—ensure the helpers are derived from vue (or appropriate runtime modules) or stubbed consistently with how generateTemplate/traverseState expect them to be referenced and include them alongside the existing imports in the returned structure.
114-114:⚠️ Potential issue | 🟠 MajorSwitch the script block to JSX mode when slot code is emitted.
JS_SLOTgenerates arrow functions whose bodies come fromgenerateJSXTemplate(...). With the current plain<script setup>, Vue parses that block as standard JS, so any slot render function containing<Comp />fails duringcompileScript. Emitlang="jsx"wheneverdescription.hasJSXis set.🛠️ Suggested fix
-<script setup> +<script setup${description.hasJSX ? ' lang="jsx"' : ''}>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/code-generator/code-generator.ts` at line 114, The script block is currently emitted as plain JavaScript which breaks when JS_SLOT generates arrow functions using generateJSXTemplate(...) that contain JSX; update the emitter that writes the <script setup> block to emit lang="jsx" whenever description.hasJSX is true so Vue treats the block as JSX. Locate the code that outputs the <script setup> tag (where JS_SLOT and generateJSXTemplate are used) and conditionally add the lang="jsx" attribute based on description.hasJSX.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/frameworks/vue/src/code-generator/template-generator.ts`:
- Around line 100-103: The generated eventBinding currently calls
`${eventHandler}(eventArgs, ${extendParams})` which passes all emitted args as
one array; change it to spread emitted args so handlers receive positional args
by generating a call like `(...eventArgs) => ${eventHandler}(...eventArgs,
${extendParams})` (use the same `item.params`, `eventKey`, `eventHandler`, and
`eventBinding` variables) so emitted args are forwarded positionally and
additional params follow.
- Around line 32-74: handleBinding currently emits Vue template directives
(":prop", "@event", "v-model", "#slot") and is reused when generating JSX,
producing invalid output; split responsibilities by creating a JSX-specific
binding path and switching callers based on output format/state. Add a new
function (e.g., handleJSXBinding) that mirrors handleBinding's intent but emits
JSX-appropriate syntax (convert `:key="expr"` -> `key={expr}`,
`@event="handler"` -> `onEvent={handler}` using camelCase event names, translate
`v-model` into value + onInput/onChange pair or appropriate controlled prop, and
convert slot bindings into prop/children-compatible JSX patterns), keep existing
handleBinding as handleTemplateBinding for Vue directives, and update usages
such as generateJSXTemplate/generateJSX (and any callers referenced by
state-generator) to call handleJSXBinding when state indicates JSX output; reuse
helper functions like handleEventBinding/handleLiteralBinding by extracting
JSExpression-to-JSX-expression conversion logic so both binding handlers can
share parsing logic but emit different syntaxes.
---
Duplicate comments:
In `@packages/frameworks/vue/src/code-generator/code-generator.ts`:
- Around line 24-57: The generated code currently only imports Vue and component
packages in generateImports, but does not declare runtime helper symbols (e.g.,
t, utils.*, bridge.*), so code emitted by generateTemplate and traverseState can
contain unresolved identifiers; update generateImports to also declare and
export or return helper bindings for these symbols (t, utils, bridge and any
subhelpers used by generateTemplate/traverseState) so they are always defined
for generated SFCs—ensure the helpers are derived from vue (or appropriate
runtime modules) or stubbed consistently with how generateTemplate/traverseState
expect them to be referenced and include them alongside the existing imports in
the returned structure.
- Line 114: The script block is currently emitted as plain JavaScript which
breaks when JS_SLOT generates arrow functions using generateJSXTemplate(...)
that contain JSX; update the emitter that writes the <script setup> block to
emit lang="jsx" whenever description.hasJSX is true so Vue treats the block as
JSX. Locate the code that outputs the <script setup> tag (where JS_SLOT and
generateJSXTemplate are used) and conditionally add the lang="jsx" attribute
based on description.hasJSX.
In `@packages/frameworks/vue/src/code-generator/state-generator.ts`:
- Around line 109-110: Array elements that are protocol nodes aren't being
transformed before recursion: update the Array branch in traverseState so each
element is passed through transformType (e.g., let transformed =
transformType(prop, description, rootState) or assign back to prop) before
calling traverseState on it; specifically, in the current.forEach callback call
transformType(prop, description, rootState) and use its result when recursing to
ensure protocol nodes inside arrays are converted prior to generating the
reactive initializer.
- Around line 78-84: The current JS_SLOT generator builds slotValues by
concatenating children which yields an empty body when value is empty and
adjacent roots when there are multiple children; change it to: compute children
via generateJSXTemplate for each item, then if value.length === 0 set the body
to "null", if value.length === 1 use the single child string, otherwise wrap the
joined children in a JSX fragment (e.g. `<>${joined}</>`) so the returned string
from JS_SLOT (the `${start}({ ${params.join(',')} }, h) => ${body}${end}`
expression) is always a valid JSX function body; keep the existing
description.hasJSX flag and use the same symbols (JS_SLOT, generateJSXTemplate,
slotValues/start/end/params) when implementing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ab6f9385-d864-40e6-b81f-2a63fdbdcefb
📒 Files selected for processing (10)
packages/frameworks/vue/src/code-generator/code-generator.tspackages/frameworks/vue/src/code-generator/constants.tspackages/frameworks/vue/src/code-generator/event-binding.tspackages/frameworks/vue/src/code-generator/index.tspackages/frameworks/vue/src/code-generator/state-generator.tspackages/frameworks/vue/src/code-generator/template-generator.tspackages/frameworks/vue/src/code-generator/types.tspackages/frameworks/vue/src/code-generator/vue-sfc-validator.tspackages/frameworks/vue/src/renderer/SchemaCardRenderer.vueprojects/tiny-schema-renderer
✅ Files skipped from review due to trivial changes (2)
- packages/frameworks/vue/src/code-generator/index.ts
- packages/frameworks/vue/src/code-generator/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/frameworks/vue/src/renderer/SchemaCardRenderer.vue
…y functions for better code generation
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/frameworks/vue/src/code-generator/state-generator.ts (1)
79-86:⚠️ Potential issue | 🟠 MajorGenerate valid render bodies for empty and multi-node slots.
Line 82 joins slot children with
.join(''), which produces invalid output in two cases:
- Empty slots: Arrow function body is empty (
({ row }, h) =>), which is a syntax error.- Multiple nodes: Adjacent JSX elements are concatenated (
<A/><B/>) without array wrapping, which violates Vue render function requirements.Vue render functions require either a single root or an explicit array.
🐛 Proposed fix
[JS_SLOT]: ({ value = [], params = ['row'] }: { value?: any[]; params?: string[] }, description: ICodegenDescription, rootState: Record<string, any>) => { description.hasJSX = true; - const slotValues = value.map((item) => generateJSXTemplate(item, description, rootState)).join(''); + const slotItems = value.map((item) => generateJSXTemplate(item, description, rootState)); + const slotBody = + slotItems.length === 0 + ? 'null' + : slotItems.length === 1 + ? slotItems[0] + : `[${slotItems.join(', ')}]`; // 默认解构参数 row,因为jsx slot 必须有第二个参数 h - return `${start}({ ${params.join(',')} }, h) => ${slotValues}${end}`; + return `${start}({ ${params.join(',')} }, h) => ${slotBody}${end}`; },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/code-generator/state-generator.ts` around lines 79 - 86, The JS_SLOT handler builds slotValues with value.map(...).join('') which yields invalid render bodies for empty or multi-node slots; update the JS_SLOT implementation (referencing JS_SLOT, generateJSXTemplate, params, start, end, and slotValues) to first map into an array of node strings, then: if the array is empty return a render null body (`... => null`), if it has one item return that single node as before, and if it has multiple items return an explicit array (`... => [node1, node2, ...]`) so Vue's render function always receives a valid single root or array. Ensure description.hasJSX remains set to true.
🧹 Nitpick comments (1)
packages/frameworks/vue/src/code-generator/event-binding.ts (1)
7-13: Consider adding a guard for empty string inlowerFirst.While
lowerFirstis currently always called with a non-empty string (guaranteed byisOnUpdaterequiringonUpdate:\w+), it will throw aTypeErrorif passed an empty string sincestr[0]would beundefined.For defensive coding, a simple guard could prevent potential future issues if the function is reused elsewhere.
🛡️ Optional: Add empty-string guard
/** 字符串首字符转小写。 */ -const lowerFirst = (str: string) => str[0].toLowerCase() + str.slice(1) +const lowerFirst = (str: string) => (str ? str[0].toLowerCase() + str.slice(1) : '')🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/code-generator/event-binding.ts` around lines 7 - 13, The helper lowerFirst currently does str[0].toLowerCase() + str.slice(1) and will throw on an empty string; update lowerFirst to guard for empty input (e.g., return str if !str or str.length === 0) so callers like isOnUpdate / other consumers are safe if an empty string is ever passed; keep the function name lowerFirst and ensure behavior for non-empty strings remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/frameworks/vue/src/code-generator/state-generator.ts`:
- Around line 119-120: The array branch in traverseState fails to transform
protocol nodes because it only recurses into elements and never calls
transformType; update the Array.isArray(current) branch in traverseState to call
transformType for each element (e.g., invoke transformType(prop, description,
rootState) or replace current[i] with the transformed result) before/after
recursing so protocol objects inside arrays are unwrapped into their JS
expression form and do not leak into the reactive(...) initializer.
---
Duplicate comments:
In `@packages/frameworks/vue/src/code-generator/state-generator.ts`:
- Around line 79-86: The JS_SLOT handler builds slotValues with
value.map(...).join('') which yields invalid render bodies for empty or
multi-node slots; update the JS_SLOT implementation (referencing JS_SLOT,
generateJSXTemplate, params, start, end, and slotValues) to first map into an
array of node strings, then: if the array is empty return a render null body
(`... => null`), if it has one item return that single node as before, and if it
has multiple items return an explicit array (`... => [node1, node2, ...]`) so
Vue's render function always receives a valid single root or array. Ensure
description.hasJSX remains set to true.
---
Nitpick comments:
In `@packages/frameworks/vue/src/code-generator/event-binding.ts`:
- Around line 7-13: The helper lowerFirst currently does str[0].toLowerCase() +
str.slice(1) and will throw on an empty string; update lowerFirst to guard for
empty input (e.g., return str if !str or str.length === 0) so callers like
isOnUpdate / other consumers are safe if an empty string is ever passed; keep
the function name lowerFirst and ensure behavior for non-empty strings remains
unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 132e7118-47d4-4328-81e1-d030eaf69e29
📒 Files selected for processing (7)
packages/frameworks/vue/src/code-generator/code-generator.tspackages/frameworks/vue/src/code-generator/event-binding.tspackages/frameworks/vue/src/code-generator/state-generator.tspackages/frameworks/vue/src/code-generator/template-generator.tspackages/frameworks/vue/src/code-generator/types.tspackages/frameworks/vue/src/code-generator/utils.tspackages/frameworks/vue/src/code-generator/vue-sfc-validator.ts
✅ Files skipped from review due to trivial changes (2)
- packages/frameworks/vue/src/code-generator/utils.ts
- packages/frameworks/vue/src/code-generator/types.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/frameworks/vue/src/code-generator/vue-sfc-validator.ts
- packages/frameworks/vue/src/code-generator/code-generator.ts
- packages/frameworks/vue/src/code-generator/template-generator.ts
…nce code generation options
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (2)
packages/frameworks/vue/src/code-generator/code-generator.ts (2)
94-96:⚠️ Potential issue | 🟠 MajorPreserve JSX mode when slot generation marks it.
traverseState(...)is where slot state can flag JSX usage, but Line 113 always emits a plain<script setup>. Vue SFCs use thelangattribute to opt into non-default script syntaxes, and Vue documents JSX / TSX as a separate authoring mode, so this needs verification before slot-based exports ship. (vuejs.org)🛠️ Proposed fix
-<script setup> +<script setup${description.hasJSX ? ' lang="jsx"' : ''}> ${imports.join('\n')}In Vue 3 SFCs, should a `<script setup>` block that contains JSX be emitted with `lang="jsx"` / `lang="tsx"` for the SFC parser to handle it correctly?Also applies to: 113-125
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/code-generator/code-generator.ts` around lines 94 - 96, traverseState(...) can mark that generated slot code requires JSX/TSX, but the code that emits the <script setup> block (where reactiveStatement and slot exports are written) always outputs a plain <script setup>; update the emitter to detect the JSX/TSX flag set by traverseState (e.g., a boolean like state.isJSX or state.jsxMode) and, when present, emit the script tag with the appropriate lang attribute ("jsx" or "tsx" depending on whether TypeScript mode is in use) so the SFC parser handles JSX correctly; ensure the decision uses the same state object inspected by traverseState and propagate that flag into the script emitter that writes the reactiveStatement and slot export code.
62-68:⚠️ Potential issue | 🔴 CriticalEmit the runtime helpers recorded in
description.After
generateTemplate(...)andtraverseState(...), this file only consumescomponentSetandiconComponents. The collected resource/i18n metadata never becomes imports or setup bindings here, so schemas that emitt(...),utils.*, orbridge.*references will download as uncompilable SFCs. Please materialize those helpers in<script setup>or report them througherrorsinstead of returning a clean panel.Also applies to: 70-71, 94-125
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/frameworks/vue/src/code-generator/code-generator.ts` around lines 62 - 68, The code never materializes the runtime helpers recorded in the local description object (description.jsResource, description.stateAccessor, i18n/t references) after generateTemplate(...) and traverseState(...), so update the generator (after calls to generateTemplate and traverseState in code-generator.ts) to 1) inspect description.jsResource.utils and description.jsResource.bridge and emit corresponding import lines and setup bindings into the <script setup> output (or add them to the script's top-level bindings), 2) convert any entries in description.stateAccessor and description.iconComponents into usable bindings or imports in the generated script, and 3) if a required runtime helper (e.g. t(...), utils.*, bridge.*) cannot be resolved, push a descriptive error into the errors array instead of returning a clean panel; reference the description variable, generateTemplate, traverseState, description.jsResource, description.stateAccessor, and description.iconComponents when making these changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/frameworks/vue/src/code-generator/code-generator.ts`:
- Line 61: The schema's lifeCycles object is destructured into lifeCycles but
never emitted into the generated <script setup> and the errors array remains
hard-coded to [], so mounted/unmounted logic is dropped silently; update the
code-generator to either include lifeCycles content into the emitted script
(e.g., incorporate lifeCycles entries into the generated lifecycle hooks within
the script output where script generation is assembled) or, if lifecycles are
intentionally unsupported, push a descriptive validation error into errors (and
remove the hard-coded []). Specifically, modify the code surrounding the
lifeCycles destructuring and the script generation routines (references:
lifeCycles, errors, and the script-generation function that builds the <script
setup>) to serialize lifecycle hook bodies into the output or add an explicit
error entry explaining lifecycles are unsupported.
- Around line 127-129: The Prettier browser formatting for Vue SFCs is missing
the PostCSS plugin; update formatWithPrettierCode to import the PostCSS plugin
(postcss) used by Prettier's css parser and pass it via the plugins option to
prettier.format so embedded <style> blocks are formatted correctly;
specifically, add the postcss plugin import at the top of code-generator.ts and
include it in the plugins array passed into formatWithPrettierCode's call to
prettier.format (alongside any existing plugins and the parser: "vue"/"css"
selection).
In `@packages/frameworks/vue/src/renderer/SchemaCardRenderer.vue`:
- Around line 193-201: The export control is a non-focusable <div> revealed only
on :hover, making it inaccessible to keyboard and touch users; update the
element with class "schema-export-button" in SchemaCardRenderer.vue to be an
actual interactive element (change to a <button> or add tabindex="0" and
role="button"), add keyboard handlers to invoke generateCode on Enter/Space,
include an accessible label via aria-label or visible text, ensure the reveal
styles are triggered on :focus/:focus-visible (and not only :hover) so
keyboard/touch users can access it, and apply the same changes to the similar
export block around lines 229-289 so both export controls are keyboard/touch
accessible.
- Around line 82-116: generateComponentsMap currently builds componentsMap only
from rendererConfig.materialsList so custom components passed in via
props.customComponents aren’t included and exports can miss imports; update the
logic that computes componentsMap (the call sites for generateComponentsMap and
the variable componentsMap) to merge in caller-supplied import metadata
(props.customComponents or a newly exposed prop) into the deduped map so entries
from props override/augment rendererConfig entries, and add a validation step
before export that checks every component referenced in props.customComponents
and the schema resolves to an entry in the merged map and throws/blocks the
export (or surfaces an error) if any component name cannot be resolved.
---
Duplicate comments:
In `@packages/frameworks/vue/src/code-generator/code-generator.ts`:
- Around line 94-96: traverseState(...) can mark that generated slot code
requires JSX/TSX, but the code that emits the <script setup> block (where
reactiveStatement and slot exports are written) always outputs a plain <script
setup>; update the emitter to detect the JSX/TSX flag set by traverseState
(e.g., a boolean like state.isJSX or state.jsxMode) and, when present, emit the
script tag with the appropriate lang attribute ("jsx" or "tsx" depending on
whether TypeScript mode is in use) so the SFC parser handles JSX correctly;
ensure the decision uses the same state object inspected by traverseState and
propagate that flag into the script emitter that writes the reactiveStatement
and slot export code.
- Around line 62-68: The code never materializes the runtime helpers recorded in
the local description object (description.jsResource, description.stateAccessor,
i18n/t references) after generateTemplate(...) and traverseState(...), so update
the generator (after calls to generateTemplate and traverseState in
code-generator.ts) to 1) inspect description.jsResource.utils and
description.jsResource.bridge and emit corresponding import lines and setup
bindings into the <script setup> output (or add them to the script's top-level
bindings), 2) convert any entries in description.stateAccessor and
description.iconComponents into usable bindings or imports in the generated
script, and 3) if a required runtime helper (e.g. t(...), utils.*, bridge.*)
cannot be resolved, push a descriptive error into the errors array instead of
returning a clean panel; reference the description variable, generateTemplate,
traverseState, description.jsResource, description.stateAccessor, and
description.iconComponents when making these changes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c0a1dfcd-dcbe-4d98-b768-92dc42513426
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (4)
packages/frameworks/vue/package.jsonpackages/frameworks/vue/src/code-generator/code-generator.tspackages/frameworks/vue/src/code-generator/types.tspackages/frameworks/vue/src/renderer/SchemaCardRenderer.vue
✅ Files skipped from review due to trivial changes (1)
- packages/frameworks/vue/src/code-generator/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/frameworks/vue/package.json
… handling in Vue SFC validation
…utility functions for improved script setup
…code generator options for improved clarity and functionality
…streamline the codebase
…by removing unnecessary generics and unused types
…ature in GenuiChat component
… reactive and computed
…update dependencies
…d remove unused packages
…ion in package.json
…r VitePress, Angular, and other packages
…etup generation in Vue
…rity in Vue code generation files
…y using computed properties
…on token and updating related components
- Updated dependencies in pnpm-lock.yaml, including postcss and sass versions. - Added new dependencies for Vue framework: @vue/compiler-sfc, @vue/shared, and prettier. - Removed unused dependency '@opentiny/tiny-engine-builtin-component' from package.json.
…map generation - Replaced IRendererConfig with IMaterialsMeta and updated related logic in getComponentsMap. - Enhanced type definitions for materialsList and componentsMapCache. - Simplified the useExportVueCode hook to utilize materialsMeta by default.
…etupMethods - Updated the method generation logic in buildScriptSetupMethods to support async functions and improved parameter handling. - Introduced a new function info extraction to streamline the creation of method definitions, enhancing code readability and maintainability.
Summary by CodeRabbit
New Features
Chores