@jay-framework/jay-stack-cli 0.18.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -93,6 +93,8 @@ Errors:
93
93
  1 error(s) found, 7 file(s) valid.
94
94
  ```
95
95
 
96
+ Plugins can provide custom validators that run as part of `jay-stack validate`. Plugin findings include a suggestion field with fix instructions. See the plugin [validation.md](../plugin/validation.md) guide.
97
+
96
98
  Always run validate after creating or editing jay-html and contract files.
97
99
 
98
100
  ## jay-stack params
@@ -34,7 +34,7 @@ A plugin provides headless components (data + interactions, no UI) that project
34
34
  | [plugin-routes.md](plugin-routes.md) | Plugin-provided pages: routes, jay-html templates, page components |
35
35
  | [seo-guide.md](seo-guide.md) | SEO head tags: title, meta, OG, canonical via phaseOutput |
36
36
  | [commands-guide.md](commands-guide.md) | makeCliCommand, .jay-command files, CONSOLE_CONTEXT, jay-stack run |
37
- | [validation.md](validation.md) | jay-stack validate-plugin usage |
37
+ | [validation.md](validation.md) | jay-stack validate-plugin, writing custom jay-html validators |
38
38
  | [dev-server-service.md](dev-server-service.md) | Dev server service API: routes, params, freeze management |
39
39
  | `../references/<plugin>/` | Plugin reference data |
40
40
 
@@ -190,6 +190,21 @@ name: product-search
190
190
  description: Product listing with filters, sorting, and pagination. Use for search results and category pages.
191
191
  ```
192
192
 
193
+ ## Tag Metadata
194
+
195
+ Tags can carry a `meta` field — a free-form key-value map for plugin validators. The framework ignores `meta`; only validators read it.
196
+
197
+ ```yaml
198
+ - tag: heroImage
199
+ type: data
200
+ dataType: string
201
+ meta:
202
+ vendor: wix-image
203
+ defaultTransform: w_800,h_400,q_80
204
+ ```
205
+
206
+ Use `meta` to attach semantic meaning that goes beyond the data type — e.g., marking a `string` tag as a URL that requires specific formatting. See [validation.md](validation.md) for writing validators that consume `meta`.
207
+
193
208
  ## Validation Rules
194
209
 
195
210
  - Tag names must be unique at each level
@@ -61,6 +61,11 @@ commands:
61
61
  - name: sync-catalog
62
62
  command: commands/sync-catalog.jay-command
63
63
 
64
+ validators:
65
+ - name: media-optimization
66
+ handler: ./validators/media-validator
67
+ description: Ensures media URLs use resize parameters
68
+
64
69
  setup:
65
70
  handler: setup-handler
66
71
  references: references-handler
@@ -185,6 +190,14 @@ Plugin routes are served by the dev server alongside project routes. If a projec
185
190
 
186
191
  Commands are CLI operations run via `jay-stack run`. Use `makeCliCommand()` to create handlers with service injection. See [commands-guide.md](commands-guide.md).
187
192
 
193
+ ### Validator Entry Fields
194
+
195
+ - `name` — Validator name (shown in validation output as `plugin-name/validator-name`)
196
+ - `handler` — Relative path to the validator module (must export a `validate` function)
197
+ - `description` — (optional) What this validator checks
198
+
199
+ Validators run during `jay-stack validate` against every parsed jay-html file. The handler module exports a `validate` function that receives a `JayHtmlValidationContext` and returns an array of findings. See [validation.md](validation.md) for implementation details.
200
+
188
201
  ### Setup Fields
189
202
 
190
203
  - `handler` — Setup handler for `jay-stack setup` (handles config, credentials)
@@ -210,6 +223,8 @@ my-plugin/
210
223
  │ │ └── upload-public.jay-command
211
224
  │ ├── webhooks/
212
225
  │ │ └── on-product-change.ts
226
+ │ ├── validators/
227
+ │ │ └── media-validator.ts
213
228
  │ ├── components/
214
229
  │ │ ├── product-page.ts
215
230
  │ │ └── product-search.ts
@@ -99,3 +99,93 @@ component: ./lib/components/product-page.ts
99
99
  # Right
100
100
  component: productPage
101
101
  ```
102
+
103
+ ## Plugin Validators
104
+
105
+ Plugins can provide custom jay-html validation rules that run during `jay-stack validate`. Declare validators in `plugin.yaml`:
106
+
107
+ ```yaml
108
+ validators:
109
+ - name: media-optimization
110
+ handler: ./validators/media-validator
111
+ description: Ensures media URLs use resize parameters
112
+ ```
113
+
114
+ ### Writing a Validator
115
+
116
+ The handler module exports a `validate` function:
117
+
118
+ ```typescript
119
+ import type { JayHtmlValidatorFn, JayHtmlValidationFinding } from '@jay-framework/compiler-shared';
120
+
121
+ export const validate: JayHtmlValidatorFn = (ctx) => {
122
+ const findings: JayHtmlValidationFinding[] = [];
123
+
124
+ // ctx.body — parsed DOM tree (HTMLElement from node-html-parser)
125
+ // ctx.filePath — relative path to the jay-html file
126
+ // ctx.contract — page contract (if any), with tags including meta
127
+ // ctx.headlessImports — headless components used in this file
128
+ // ctx.projectRoot — absolute project root path
129
+
130
+ return findings;
131
+ };
132
+ ```
133
+
134
+ Each finding has:
135
+
136
+ - `severity` — `'error'` (fails validation) or `'warning'`
137
+ - `message` — what's wrong
138
+ - `suggestion` — how to fix it (shown to agents and developers)
139
+ - `element` — (optional) which element
140
+ - `attribute` — (optional) which attribute
141
+
142
+ ### Validator Utilities
143
+
144
+ - **`parseTemplateParts(value)`** — split `"{url}/v1/fit/w_300/file.jpg"` into binding and static parts (import from `@jay-framework/compiler-jay-html`)
145
+ - **`walkElements(root, ctx, visitor)`** — depth-first traversal tracking data scope through `forEach` and `<jay:component>` boundaries (import from `@jay-framework/compiler-shared`)
146
+ - **`resolveBinding(path, scope)`** — resolve a binding path to its contract tag (including `meta`) (import from `@jay-framework/compiler-shared`)
147
+
148
+ ### Contract Tag `meta`
149
+
150
+ Contract tags can carry a `meta` field — arbitrary key-value metadata that validators read:
151
+
152
+ ```yaml
153
+ tags:
154
+ - tag: imageUrl
155
+ type: data
156
+ dataType: string
157
+ meta:
158
+ vendor: wix-image
159
+ defaultTransform: w_300,h_200,q_80
160
+ ```
161
+
162
+ Validators use `resolveBinding` to find the tag and inspect `meta`:
163
+
164
+ ```typescript
165
+ import { walkElements, resolveBinding } from '@jay-framework/compiler-shared';
166
+ import { parseTemplateParts } from '@jay-framework/compiler-jay-html';
167
+
168
+ export const validate: JayHtmlValidatorFn = (ctx) => {
169
+ const findings: JayHtmlValidationFinding[] = [];
170
+
171
+ walkElements(ctx.body, ctx, (el, scope) => {
172
+ if (el.rawTagName !== 'img') return;
173
+ const src = el.getAttribute('src');
174
+ if (!src) return;
175
+
176
+ for (const part of parseTemplateParts(src)) {
177
+ if (part.kind !== 'binding') continue;
178
+ const resolved = resolveBinding(part.value, scope);
179
+ if (resolved.tag?.meta?.vendor !== 'wix-image') continue;
180
+
181
+ findings.push({
182
+ severity: 'warning',
183
+ message: `Image binding {${part.value}} may need resize parameters`,
184
+ suggestion: 'Add /v1/fit/w_{WIDTH},h_{HEIGHT},q_80/file.jpg after the binding',
185
+ });
186
+ }
187
+ });
188
+
189
+ return findings;
190
+ };
191
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/jay-stack-cli",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -24,15 +24,15 @@
24
24
  "test:watch": "vitest"
25
25
  },
26
26
  "dependencies": {
27
- "@jay-framework/compiler-jay-html": "^0.18.0",
28
- "@jay-framework/compiler-shared": "^0.18.0",
29
- "@jay-framework/dev-server": "^0.18.0",
30
- "@jay-framework/editor-server": "^0.18.0",
31
- "@jay-framework/fullstack-component": "^0.18.0",
32
- "@jay-framework/logger": "^0.18.0",
33
- "@jay-framework/plugin-validator": "^0.18.0",
34
- "@jay-framework/production-server": "^0.18.0",
35
- "@jay-framework/stack-server-runtime": "^0.18.0",
27
+ "@jay-framework/compiler-jay-html": "^0.18.1",
28
+ "@jay-framework/compiler-shared": "^0.18.1",
29
+ "@jay-framework/dev-server": "^0.18.1",
30
+ "@jay-framework/editor-server": "^0.18.1",
31
+ "@jay-framework/fullstack-component": "^0.18.1",
32
+ "@jay-framework/logger": "^0.18.1",
33
+ "@jay-framework/plugin-validator": "^0.18.1",
34
+ "@jay-framework/production-server": "^0.18.1",
35
+ "@jay-framework/stack-server-runtime": "^0.18.1",
36
36
  "chalk": "^4.1.2",
37
37
  "commander": "^14.0.0",
38
38
  "express": "^5.0.1",
@@ -43,7 +43,7 @@
43
43
  "yaml": "^2.3.4"
44
44
  },
45
45
  "devDependencies": {
46
- "@jay-framework/dev-environment": "^0.18.0",
46
+ "@jay-framework/dev-environment": "^0.18.1",
47
47
  "@types/express": "^5.0.2",
48
48
  "@types/node": "^22.15.21",
49
49
  "nodemon": "^3.0.3",