-
Notifications
You must be signed in to change notification settings - Fork 475
feat: suport mockserver file as database and add dsl-genenrator skill #1792
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 23 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
a9f6985
fix: Automatically serialize `page_content` to JSON string to resolve…
hexqi 6acc71e
feat: Implement a pluggable store abstraction with a new file-based s…
hexqi bf0be96
fix: Resolve P0 issues in store adapter implementation
hexqi b9ce9d3
feat: Implement file-based data storage for mock server entities and …
hexqi 5f2ce0a
fix(mockServer): filter nedb metadata in export-db-to-file
hexqi 8ee2d7a
chore: add base file data and dev:file cmd
hexqi c5eed6b
feat: add dsl generator skill
hexqi e382cb3
fix: windows start error
hexqi 0b02ba8
Merge remote-tracking branch 'hexqi/develop' into feat/file-as-database
hexqi 0a4b25a
Merge remote-tracking branch 'origin/develop' into feat/file-as-database
hexqi 641be77
chore: move skill from .claude to .agents directory
hexqi 3570654
fix: review
hexqi 7d01778
fix: add deep equality check and update query matching
hexqi 2b2a78b
fix: skill symlink
hexqi b59add3
docs: add guide for using Skill to generate pages
hexqi 278aa63
fix: docs
hexqi 0ba0b14
docs: update
hexqi 4b260f9
chore: replace tracked symlink with per-platform link script
hexqi 6eddb99
fix: update check script
hexqi 42baf46
refactor: update python script to nodejs mjs
hexqi e39da95
fix: docs
hexqi cee2ccb
feat: update skill component props and event binding rules
hexqi d5c287c
fix: review
hexqi e0b935e
fix: review
hexqi 1832605
fix(FileStore): add case sensitivity detection for file operations
hexqi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| --- | ||
| name: tinyengine-dsl-generator | ||
| description: Use when creating or modifying TinyEngine low-code applications - generating page, block, or app DSL (JSON schemas), converting designs/screenshots to DSL, or debugging generated TinyEngine JSON. | ||
| --- | ||
|
|
||
| # TinyEngine DSL Generator | ||
|
|
||
| Generate conformant DSL (JSON) for the TinyEngine low-code platform: **pages**, **blocks**, and **apps**. This file is a router — load the reference files on demand for detail instead of reading everything up front. | ||
|
|
||
| ## Quick Reference | ||
|
|
||
| | Task | Do | | ||
| | ------------------ | ----------------------------------------------------- | | ||
| | Generate page DSL | Describe components, layout, interactions → §Workflow | | ||
| | Generate block DSL | Describe reusable functionality + configurable props | | ||
| | Generate app DSL | Describe multi-page structure + shared componentsMap | | ||
| | From screenshot | Describe layout → map to components (§Design-to-DSL) | | ||
| | Lookup a component | `node scripts/query_components.mjs props <Name>` | | ||
| | Validate output | `bash scripts/validate_all.sh <file>` (required) | | ||
|
|
||
| ## Workflow | ||
|
|
||
| 1. **Understand the goal** — Page (components / state / methods / lifeCycles), Block (reusable, exposes a props `schema`), or App (pages + `componentsMap` + `meta`). | ||
| 2. **Gather requirements** — name / route / title; component hierarchy; state; event handlers; data sources. Blocks additionally: exposed props, emitted events. Apps additionally: all pages, shared `componentsMap`. | ||
| 3. **Load only the reference you need:** | ||
|
|
||
| | Need | File | | ||
| | ----------------------------------------------------------- | ---------------------------------------------------------- | | ||
| | Schema structure, TS interfaces, reserved names, prop types | [protocol.md](references/protocol.md) | | ||
| | Component props/events, or a component not listed here | [components.md](references/components.md) · `query_components.mjs` | | ||
| | List page / form page / layout / interaction templates | [patterns.md](references/patterns.md) | | ||
|
|
||
| ⚠️ **Before generating any page with interactions**, read the event-binding section of [protocol.md](references/protocol.md). Event handlers are the #1 error source; the compact Critical Rules table below is a reminder, not a substitute for the full ❌/✅ example. | ||
|
|
||
| 4. **Generate** — follow the Page skeleton + property types below. Full Page/Block/Component interfaces are in protocol.md. | ||
| 5. **Validate** (required) — see §Validate. | ||
| 6. **Run the checklist** before handing off — see §Pre-Generation Checklist. | ||
|
|
||
| ### Page skeleton (anchor) | ||
|
|
||
| ```json | ||
| { | ||
| "componentName": "Page", | ||
| "fileName": "PageName", | ||
| "meta": { "id": 1, "title": "...", "router": "...", "creator": "...", "isHome": false, "parentId": "0", "rootElement": "div", "group": "staticPages" }, | ||
| "state": {}, | ||
| "methods": {}, | ||
| "lifeCycles": {}, | ||
| "children": [] | ||
| } | ||
| ``` | ||
|
|
||
| ### Property value types | ||
|
|
||
| - **Literal**: `"text"`, `123`, `true` | ||
| - **JSExpression**: `{"type":"JSExpression","value":"this.state.count"}` — bindings, conditions, **event handlers** | ||
| - **JSFunction**: `{"type":"JSFunction","value":"function(){}"}` — **only** inside `methods` / `lifeCycles` | ||
| - **i18n**: `{"type":"i18n","key":"app.title"}` | ||
| - **JSResource**: `{"type":"JSResource","value":"this.utils.format()"}` | ||
|
|
||
| ### Referencing a block | ||
|
|
||
| ```json | ||
| { "componentName": "BlockFileName", "componentType": "block", "id": "block-001", "props": { "title": "value" } } | ||
| ``` | ||
|
|
||
| Inside the block: read `this.props.xxx`, emit via `this.emit('eventName', data)`. | ||
|
|
||
| ## Critical Rules (common pitfalls) | ||
|
|
||
| These cause silent failures. Full ❌/✅ JSON examples live in [protocol.md](references/protocol.md); the checklist below enforces them. | ||
|
|
||
| | Rule | ❌ Wrong | ✅ Right | | ||
| | ------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- | | ||
| | **Event bindings** | `"onClick":{"type":"JSFunction",...}`; or `JSExpression.value` = `"function…"` | `"onClick":{"type":"JSExpression","value":"this.handleX"}` — put the body in `methods` as `JSFunction` | | ||
| | **Method params** | `function(filter){...}` | `function(event, filter){...}`; binding `"params":["'all'"]` → call `handleX(event,'all')` | | ||
| | **Lifecycle name** | `"mounted":{...}` | `"onMounted":{"type":"JSFunction","value":"function onMounted(){...}"}` | | ||
| | **Two-way binding**| `modelValue` with **no** `model` | `"model":true` (v-model) or `"model":{"prop":"x"}` (v-model:x) | | ||
| | **Page editable** | `"occupier": {...}` | `"occupier": null` | | ||
| | **CSS class** | `props.class` | `props.className` | | ||
|
|
||
| ### Event bindings — the full pattern (highest-frequency error) | ||
|
|
||
| The function body lives in `methods` (`JSFunction`); the event only **references** it (`JSExpression`). `event` is always the first arg; `params` append after. | ||
|
|
||
| ```json | ||
| "methods": { | ||
| "handleDelete": { | ||
| "type": "JSFunction", | ||
| "value": "function(event, id) { this.state.list = this.state.list.filter(x => x.id !== id); }" | ||
| } | ||
| }, | ||
| "children": [{ | ||
| "componentName": "TinyButton", | ||
| "props": { | ||
| "text": "删除", | ||
| "onClick": { "type": "JSExpression", "value": "this.handleDelete", "params": ["123"] } | ||
| } | ||
| }] | ||
| ``` | ||
|
|
||
| The binding above calls `handleDelete(event, 123)`. ❌ Never put a `JSFunction` on an event, and never put a `function(){}` body inside a `JSExpression.value` — both silently break the handler. | ||
|
|
||
| **Memory aid:** `JSExpression` = reference (`this.fn`) · `JSFunction` = definition (`function(){}`). Events use references; methods use definitions. | ||
|
|
||
| ## Validate (required) | ||
|
|
||
| ```bash | ||
| bash .agents/skills/tinyengine-dsl-generator/scripts/validate_all.sh <output-file> | ||
| ``` | ||
|
|
||
| `validate_all.sh` chains three checks — do **not** rely on `validate_dsl.mjs` alone (it misses event-binding errors). Fix and re-run until all three pass; never hand off unvalidated output. | ||
|
|
||
| | Stage | Script | Catches | | ||
| | -------------- | ------------------------ | ------------------------------------------------------------------------------- | | ||
| | Structure | validate_dsl.mjs | Required fields, Page/Block `componentName`, meta, `class` vs `className`, app/page id types | | ||
| | Event bindings | check_event_bindings.mjs | `JSFunction` on an event, or a function body in `JSExpression.value` | | ||
| | CSS | check_css.mjs | Malformed `css` strings | | ||
|
|
||
| ## Pre-Generation Checklist | ||
|
|
||
| - [ ] Event bindings use `JSExpression`; no `value` starts with `"function"`; function bodies live in `methods` / `lifeCycles` | ||
| - [ ] Event methods take `event` as the first parameter; `params` append after it | ||
| - [ ] Lifecycle names start with `on` (`onMounted`, …); `setup` is the only exception | ||
| - [ ] `modelValue` declares `model` (`true` for standard v-model) | ||
| - [ ] `occupier` is `null` | ||
| - [ ] All `id`s are unique; CSS classes use `className`, not `class` | ||
| - [ ] **App schema** `id` and `meta.appId` are integers (`918`, not `"918"`) — apps.js persists `meta.appId` as string internally, keep the DSL integer | ||
| - [ ] **Page** `app` reference is a string (`"918"`, not `918`) — pages.js queries with `appId.toString()`; a numeric `app` won't be found by `list()`. Page's own `id` is a NanoID string assigned by the server | ||
|
|
||
| ## Component lookup | ||
|
|
||
| Don't load `bundle.json` (≈1 MB) by hand. Query it: | ||
|
|
||
| ```bash | ||
| node scripts/query_components.mjs list # all components | ||
| node scripts/query_components.mjs props TinyButton # one component's props (fuzzy match) | ||
| node scripts/query_components.mjs cat 表单 # components in a category | ||
| node scripts/query_components.mjs search 表格 # full-text search | ||
| ``` | ||
|
|
||
| ## File output | ||
|
|
||
| - **Apps** → `mockServer/data/apps/<app-name>.json` | ||
| - **Pages** → `mockServer/data/pages/<PageName>.json` | ||
| - **Blocks** → `mockServer/data/blocks/<BlockName>.json` | ||
|
|
||
| Pages and blocks are saved with an **outer wrapper** around the DSL: page files wrap the Page DSL in `page_content` (plus `name`, `id`, `app`, `route`, `tenant`, `parentId`, `group`, `isPage`, `isHome`); block files wrap the Block DSL in `content` (plus `id`, `label`, `framework`, `path`, `public`, `is_published`). The validators auto-unwrap both, so you can validate either the wrapper or the inner DSL directly. | ||
|
|
||
| ## Design-to-DSL | ||
|
|
||
| From a description or screenshot: identify layout regions → map visuals to components → extract interactions → define state + handlers → apply `className` / `style`. | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| | Problem | Check | | ||
| | ----------------- | ---------------------------------------------------------------------- | | ||
| | Input not working | `modelValue` declares `model` (`true` for standard v-model) | | ||
| | Event not firing | `JSExpression` (not `JSFunction`); method exists in `methods` | | ||
| | Page not editable | `occupier` is `null` | | ||
| | Wrong params | first param is always `event`; `params` append after | | ||
|
|
||
| ## Resources | ||
|
|
||
| - [protocol.md](references/protocol.md) — schema spec, TS interfaces, reserved names, property types, slots, full ❌/✅ examples | ||
| - [components.md](references/components.md) — component catalog (props/events); supplement with `query_components.mjs` | ||
| - [patterns.md](references/patterns.md) — list/form page, layout, interaction templates | ||
| - `scripts/` — `validate_all.sh` (run this), `validate_dsl.mjs`, `check_event_bindings.mjs`, `check_css.mjs`, `validate_page.mjs`, `query_components.mjs` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.