@zenithbuild/language 0.5.0-beta.2.20 → 0.6.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.6.0] - 2026-02-28
9
+
10
+ ### Added
11
+
12
+ - Grammar: canonical primitives (ref, signal, state, zenOn, zenMount, zenWindow, zenDocument)
13
+ - Grammar: `on:event` with handler expression highlighted as TypeScript
14
+ - Grammar: legacy `@click` / `onclick` scoped as legacy
15
+ - Snippets for canonical primitives (consistent ctx.cleanup style)
16
+ - `zenith.strictDomLints` setting contribution
17
+
8
18
  ## [0.5.0-beta.2.19] - 2026-02-04
9
19
 
10
20
  ### ✨ Features
@@ -0,0 +1,26 @@
1
+ # @zenithbuild/language v0.6.0
2
+
3
+ ## Summary
4
+
5
+ - Grammar highlights canonical primitives (zenMount, zenWindow, zenDocument, zenOn, zenResize, collectRefs, signal, ref)
6
+ - `on:event` canonical; `@click` and `onclick` scoped as legacy
7
+ - Snippets for state, signal, ref, zenMount, zenOn, zenResize, collectRefs, on:click
8
+ - `zenith.strictDomLints` setting added
9
+
10
+ ## Breaking Changes
11
+
12
+ None.
13
+
14
+ ## Key Changes
15
+
16
+ - **Grammar:** `on:click={handler}` highlighted as canonical; `{handler}` as TypeScript identifier
17
+ - **Grammar:** Legacy `@click` and `onclick` use `meta.attribute.event.legacy.zenith` scope
18
+ - **Snippets:** state toggle, signal counter, ref dom, zenMount cleanup, zenEffect, zenWindow, zenOn keydown escape, zenResize viewport, collectRefs, on:click
19
+ - **Config:** `zenith.strictDomLints` (boolean, default false)
20
+ - **Embedded:** `source.ts.embedded.zenith` mapped to TypeScript for expression highlighting
21
+
22
+ ## Verification Checklist
23
+
24
+ - [ ] `on:click={handler}` highlights `handler` as TS identifier
25
+ - [ ] `@click` and `onclick` use legacy scope (different color if theme supports it)
26
+ - [ ] Snippets expand correctly; no querySelector/addEventListener patterns
package/package.json CHANGED
@@ -1,161 +1,174 @@
1
1
  {
2
- "name": "@zenithbuild/language",
3
- "displayName": "Zenith Language Support",
4
- "description": "Syntax highlighting, IntelliSense, and editor support for Zenith Framework (.zen files)",
5
- "version": "0.5.0-beta.2.20",
6
- "publisher": "ZenithBuild",
7
- "engines": {
8
- "vscode": "^1.80.0"
9
- },
10
- "main": "./out/extension.js",
11
- "activationEvents": [
12
- "onLanguage:zenith",
13
- "onCommand:zenith.runContractPack",
14
- "onCommand:zenith.runLegacyTests",
15
- "onCommand:zenith.build",
16
- "onCommand:zenith.restartServer"
2
+ "name": "@zenithbuild/language",
3
+ "displayName": "Zenith Language Support",
4
+ "description": "Syntax highlighting, IntelliSense, and editor support for Zenith Framework (.zen files)",
5
+ "version": "0.6.1",
6
+ "publisher": "ZenithBuild",
7
+ "engines": {
8
+ "vscode": "^1.80.0"
9
+ },
10
+ "main": "./out/extension.js",
11
+ "activationEvents": [
12
+ "onLanguage:zenith",
13
+ "onCommand:zenith.runContractPack",
14
+ "onCommand:zenith.runLegacyTests",
15
+ "onCommand:zenith.build",
16
+ "onCommand:zenith.restartServer"
17
+ ],
18
+ "scripts": {
19
+ "test": "node --test test/grammar-snippets.spec.js",
20
+ "build:server": "cd ../zenith-language-server && bun run build",
21
+ "compile": "bun x esbuild src/extension.ts --bundle --outfile=out/extension.js --external:vscode --external:vscode-languageclient/node --format=cjs --platform=node && cp ../zenith-language-server/dist/server.js out/server.js",
22
+ "watch": "bun run compile -- --watch",
23
+ "build:markplace": "bun run build:marketplace",
24
+ "build:marketplace": "bun run build:server && bun run compile && node scripts/build.js marketplace",
25
+ "build:openvsx": "bun run build:server && bun run compile && node scripts/build.js openvsx",
26
+ "build:all": "bun run build:server && bun run compile && node scripts/build.js all",
27
+ "release": "bun run scripts/release.ts",
28
+ "release:dry": "bun run scripts/release.ts --dry-run",
29
+ "release:patch": "bun run scripts/release.ts --bump=patch",
30
+ "release:minor": "bun run scripts/release.ts --bump=minor",
31
+ "release:major": "bun run scripts/release.ts --bump=major",
32
+ "build": "tsc"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^20.0.0",
36
+ "@types/vscode": "^1.80.0",
37
+ "esbuild": "^0.19.0",
38
+ "typescript": "^5.0.0"
39
+ },
40
+ "categories": [
41
+ "Programming Languages"
42
+ ],
43
+ "icon": "assets/logo.png",
44
+ "keywords": [
45
+ "zenith",
46
+ "zen",
47
+ "syntax",
48
+ "highlighting",
49
+ "intellisense",
50
+ "framework"
51
+ ],
52
+ "contributes": {
53
+ "languages": [
54
+ {
55
+ "id": "zenith",
56
+ "aliases": [
57
+ "Zenith",
58
+ "zenith"
59
+ ],
60
+ "extensions": [
61
+ ".zen",
62
+ ".zen.html",
63
+ ".zenx"
64
+ ],
65
+ "configuration": "./language-configuration.json"
66
+ }
17
67
  ],
18
- "scripts": {
19
- "build:server": "cd ../zenith-language-server && bun run build",
20
- "compile": "bun x esbuild src/extension.ts --bundle --outfile=out/extension.js --external:vscode --external:vscode-languageclient/node --format=cjs --platform=node && cp ../zenith-language-server/dist/server.js out/server.js",
21
- "watch": "bun run compile -- --watch",
22
- "build:markplace": "bun run build:marketplace",
23
- "build:marketplace": "bun run build:server && bun run compile && node scripts/build.js marketplace",
24
- "build:openvsx": "bun run build:server && bun run compile && node scripts/build.js openvsx",
25
- "build:all": "bun run build:server && bun run compile && node scripts/build.js all",
26
- "release": "bun run scripts/release.ts",
27
- "release:dry": "bun run scripts/release.ts --dry-run",
28
- "release:patch": "bun run scripts/release.ts --bump=patch",
29
- "release:minor": "bun run scripts/release.ts --bump=minor",
30
- "release:major": "bun run scripts/release.ts --bump=major",
31
- "build": "tsc"
32
- },
33
- "devDependencies": {
34
- "@types/node": "^20.0.0",
35
- "@types/vscode": "^1.80.0",
36
- "esbuild": "^0.19.0",
37
- "typescript": "^5.0.0"
38
- },
39
- "categories": [
40
- "Programming Languages"
68
+ "snippets": [
69
+ {
70
+ "language": "zenith",
71
+ "path": "./snippets/zenith.code-snippets"
72
+ }
41
73
  ],
42
- "icon": "assets/logo.png",
43
- "keywords": [
44
- "zenith",
45
- "zen",
46
- "syntax",
47
- "highlighting",
48
- "intellisense",
49
- "framework"
74
+ "grammars": [
75
+ {
76
+ "language": "zenith",
77
+ "scopeName": "text.html.zenith",
78
+ "path": "./syntaxes/zenith.tmLanguage.json",
79
+ "embeddedLanguages": {
80
+ "source.js": "javascript",
81
+ "source.ts": "typescript",
82
+ "source.ts.embedded.zenith": "typescript",
83
+ "source.css": "css",
84
+ "text.html.basic": "html",
85
+ "meta.embedded.block.javascript": "javascript",
86
+ "meta.embedded.block.typescript": "typescript",
87
+ "meta.embedded.block.css": "css"
88
+ }
89
+ }
50
90
  ],
51
- "contributes": {
52
- "languages": [
53
- {
54
- "id": "zenith",
55
- "aliases": [
56
- "Zenith",
57
- "zenith"
58
- ],
59
- "extensions": [
60
- ".zen",
61
- ".zen.html",
62
- ".zenx"
63
- ],
64
- "configuration": "./language-configuration.json"
65
- }
66
- ],
67
- "grammars": [
68
- {
69
- "language": "zenith",
70
- "scopeName": "text.html.zenith",
71
- "path": "./syntaxes/zenith.tmLanguage.json",
72
- "embeddedLanguages": {
73
- "source.js": "javascript",
74
- "source.ts": "typescript",
75
- "source.css": "css",
76
- "text.html.basic": "html",
77
- "meta.embedded.block.javascript": "javascript",
78
- "meta.embedded.block.typescript": "typescript",
79
- "meta.embedded.block.css": "css"
80
- }
81
- }
82
- ],
83
- "configurationDefaults": {
84
- "[zenith]": {
85
- "editor.formatOnSave": true,
86
- "editor.wordBasedSuggestions": "off",
87
- "editor.suggest.insertMode": "replace",
88
- "editor.semanticHighlighting.enabled": true,
89
- "editor.quickSuggestions": {
90
- "other": true,
91
- "comments": false,
92
- "strings": true
93
- },
94
- "editor.autoClosingBrackets": "always"
95
- },
96
- "emmet.includeLanguages": {
97
- "zenith": "html"
98
- },
99
- "emmet.syntaxProfiles": {
100
- "zenith": "html"
101
- }
91
+ "configurationDefaults": {
92
+ "[zenith]": {
93
+ "editor.formatOnSave": true,
94
+ "editor.wordBasedSuggestions": "off",
95
+ "editor.suggest.insertMode": "replace",
96
+ "editor.semanticHighlighting.enabled": true,
97
+ "editor.quickSuggestions": {
98
+ "other": true,
99
+ "comments": false,
100
+ "strings": true
102
101
  },
103
- "commands": [
104
- {
105
- "command": "zenith.runContractPack",
106
- "title": "Zenith: Run Contract Pack",
107
- "category": "Zenith"
108
- },
109
- {
110
- "command": "zenith.runLegacyTests",
111
- "title": "Zenith: Run Legacy Tests",
112
- "category": "Zenith"
113
- },
114
- {
115
- "command": "zenith.build",
116
- "title": "Zenith: Build",
117
- "category": "Zenith"
118
- },
119
- {
120
- "command": "zenith.restartServer",
121
- "title": "Zenith: Restart Server",
122
- "category": "Zenith"
123
- }
124
- ],
125
- "configuration": {
126
- "type": "object",
127
- "title": "Zenith",
128
- "properties": {
129
- "zenith.componentScripts": {
130
- "type": "string",
131
- "enum": [
132
- "forbid",
133
- "allow"
134
- ],
135
- "default": "forbid",
136
- "description": "Component script contract mode. 'forbid' enforces structural-only components; 'allow' disables this diagnostic."
137
- },
138
- "zenith.languageServer.path": {
139
- "type": "string",
140
- "default": "",
141
- "description": "Optional absolute or workspace-relative path to a custom Zenith language server entry file."
142
- }
143
- }
144
- }
145
- },
146
- "repository": {
147
- "type": "git",
148
- "url": "https://github.com/zenithbuild/zenith"
149
- },
150
- "homepage": "https://github.com/zenithbuild/zenith#readme",
151
- "bugs": {
152
- "url": "https://github.com/zenithbuild/zenith/issues"
153
- },
154
- "publishConfig": {
155
- "access": "public"
102
+ "editor.autoClosingBrackets": "always"
103
+ },
104
+ "emmet.includeLanguages": {
105
+ "zenith": "html"
106
+ },
107
+ "emmet.syntaxProfiles": {
108
+ "zenith": "html"
109
+ }
156
110
  },
157
- "license": "MIT",
158
- "dependencies": {
159
- "vscode-languageclient": "^9.0.1"
111
+ "commands": [
112
+ {
113
+ "command": "zenith.runContractPack",
114
+ "title": "Zenith: Run Contract Pack",
115
+ "category": "Zenith"
116
+ },
117
+ {
118
+ "command": "zenith.runLegacyTests",
119
+ "title": "Zenith: Run Legacy Tests",
120
+ "category": "Zenith"
121
+ },
122
+ {
123
+ "command": "zenith.build",
124
+ "title": "Zenith: Build",
125
+ "category": "Zenith"
126
+ },
127
+ {
128
+ "command": "zenith.restartServer",
129
+ "title": "Zenith: Restart Server",
130
+ "category": "Zenith"
131
+ }
132
+ ],
133
+ "configuration": {
134
+ "type": "object",
135
+ "title": "Zenith",
136
+ "properties": {
137
+ "zenith.componentScripts": {
138
+ "type": "string",
139
+ "enum": [
140
+ "forbid",
141
+ "allow"
142
+ ],
143
+ "default": "forbid",
144
+ "description": "Component script contract mode. 'forbid' enforces structural-only components; 'allow' disables this diagnostic."
145
+ },
146
+ "zenith.strictDomLints": {
147
+ "type": "boolean",
148
+ "default": false,
149
+ "description": "When true, ZEN-DOM-* lints (querySelector, addEventListener, etc.) are reported as errors instead of warnings."
150
+ },
151
+ "zenith.languageServer.path": {
152
+ "type": "string",
153
+ "default": "",
154
+ "description": "Optional absolute or workspace-relative path to a custom Zenith language server entry file."
155
+ }
156
+ }
160
157
  }
158
+ },
159
+ "repository": {
160
+ "type": "git",
161
+ "url": "https://github.com/zenithbuild/zenith"
162
+ },
163
+ "homepage": "https://github.com/zenithbuild/zenith#readme",
164
+ "bugs": {
165
+ "url": "https://github.com/zenithbuild/zenith/issues"
166
+ },
167
+ "publishConfig": {
168
+ "access": "public"
169
+ },
170
+ "license": "MIT",
171
+ "dependencies": {
172
+ "vscode-languageclient": "^9.0.1"
173
+ }
161
174
  }
@@ -0,0 +1,94 @@
1
+ {
2
+ "State Toggle": {
3
+ "prefix": "state toggle",
4
+ "body": [
5
+ "state ${1:open} = false",
6
+ "function toggle${1/(.*)/${1:/capitalize}/}() { ${1:open} = !${1:open} }",
7
+ "$0"
8
+ ],
9
+ "description": "State variable with toggle function"
10
+ },
11
+ "Signal Counter": {
12
+ "prefix": "signal counter",
13
+ "body": [
14
+ "const ${1:count} = signal(${2:0})",
15
+ "$0"
16
+ ],
17
+ "description": "Signal with get/set"
18
+ },
19
+ "Ref DOM": {
20
+ "prefix": "ref dom",
21
+ "body": [
22
+ "const ${1:el} = ref<${2:HTMLElement}>()",
23
+ "$0"
24
+ ],
25
+ "description": "Ref for DOM node"
26
+ },
27
+ "zenMount Cleanup": {
28
+ "prefix": "zenMount cleanup",
29
+ "body": [
30
+ "zenMount((ctx) => {",
31
+ "\t$0",
32
+ "\tctx.cleanup(${1:disposer})",
33
+ "})"
34
+ ],
35
+ "description": "zenMount with ctx.cleanup for disposers"
36
+ },
37
+ "zenEffect Pattern": {
38
+ "prefix": "zenEffect pattern",
39
+ "body": [
40
+ "zenEffect(() => {",
41
+ "\t$0",
42
+ "})"
43
+ ],
44
+ "description": "Reactive effect"
45
+ },
46
+ "zenWindow": {
47
+ "prefix": "zenWindow",
48
+ "body": [
49
+ "const win = zenWindow()",
50
+ "if (!win) return",
51
+ "$0"
52
+ ],
53
+ "description": "SSR-safe window access"
54
+ },
55
+ "zenOn Keydown Escape": {
56
+ "prefix": "zenOn keydown escape",
57
+ "body": [
58
+ "const doc = zenDocument()",
59
+ "if (!doc) return",
60
+ "const offKey = zenOn(doc, 'keydown', (e) => {",
61
+ "\tif (e.key === 'Escape') ${1:closeMenu}()",
62
+ "})",
63
+ "ctx.cleanup(offKey)",
64
+ "$0"
65
+ ],
66
+ "description": "zenOn keydown with Escape handler (use inside zenMount)"
67
+ },
68
+ "zenResize Viewport": {
69
+ "prefix": "zenResize viewport",
70
+ "body": [
71
+ "const off = zenResize(({ w, h }) => {",
72
+ "\t$0",
73
+ "})",
74
+ "ctx.cleanup(off)"
75
+ ],
76
+ "description": "zenResize with ctx.cleanup (use inside zenMount)"
77
+ },
78
+ "collectRefs Links": {
79
+ "prefix": "collectRefs links",
80
+ "body": [
81
+ "const nodes = collectRefs(${1:refA}, ${2:refB}, ${3:refC})",
82
+ "$0"
83
+ ],
84
+ "description": "Collect multiple refs into node list"
85
+ },
86
+ "on:click Handler": {
87
+ "prefix": "on:click",
88
+ "body": [
89
+ "on:click={${1:handler}}",
90
+ "$0"
91
+ ],
92
+ "description": "Canonical event binding"
93
+ }
94
+ }
@@ -102,6 +102,12 @@
102
102
  {
103
103
  "include": "#lifecycle-hooks"
104
104
  },
105
+ {
106
+ "include": "#platform-primitives"
107
+ },
108
+ {
109
+ "include": "#support-functions"
110
+ },
105
111
  {
106
112
  "include": "#zenith-imports"
107
113
  },
@@ -182,9 +188,17 @@
182
188
  }
183
189
  },
184
190
  "lifecycle-hooks": {
185
- "match": "\\b(zenOnMount|zenOnDestroy|zenOnUpdate|zenEffect|onMount|onDestroy|onUpdate|useRoute|useRouter)\\b",
191
+ "match": "\\b(zenMount|zenOnMount|zenOnDestroy|zenOnUpdate|zenEffect|onMount|onDestroy|onUpdate|useRoute|useRouter)\\b",
186
192
  "name": "support.function.lifecycle.zenith"
187
193
  },
194
+ "platform-primitives": {
195
+ "match": "\\b(zenWindow|zenDocument|zenOn|zenResize|collectRefs)\\b",
196
+ "name": "support.function.platform.zenith"
197
+ },
198
+ "support-functions": {
199
+ "match": "\\b(signal|ref)\\s*(<|\\()",
200
+ "name": "support.function.zenith"
201
+ },
188
202
  "zenith-imports": {
189
203
  "match": "(['\"])(zenith(?:/[a-zA-Z-]+)?|zenith:[a-zA-Z-]+)\\1",
190
204
  "captures": {
@@ -342,6 +356,9 @@
342
356
  {
343
357
  "include": "#attribute-directive"
344
358
  },
359
+ {
360
+ "include": "#attribute-on-event"
361
+ },
345
362
  {
346
363
  "include": "#attribute-at-event"
347
364
  },
@@ -419,6 +436,33 @@
419
436
  }
420
437
  ]
421
438
  },
439
+ "attribute-on-event": {
440
+ "begin": "(on:[a-zA-Z][a-zA-Z0-9_-]*)\\s*(=)\\s*(\\{)",
441
+ "beginCaptures": {
442
+ "1": {
443
+ "name": "entity.other.attribute-name.event.canonical.zenith"
444
+ },
445
+ "2": {
446
+ "name": "punctuation.separator.key-value.html.zenith"
447
+ },
448
+ "3": {
449
+ "name": "punctuation.section.embedded.begin.zenith"
450
+ }
451
+ },
452
+ "end": "(\\})",
453
+ "endCaptures": {
454
+ "1": {
455
+ "name": "punctuation.section.embedded.end.zenith"
456
+ }
457
+ },
458
+ "name": "meta.attribute.event.canonical.zenith",
459
+ "contentName": "source.ts.embedded.zenith",
460
+ "patterns": [
461
+ {
462
+ "include": "source.ts"
463
+ }
464
+ ]
465
+ },
422
466
  "attribute-at-event": {
423
467
  "begin": "(@)([a-zA-Z][a-zA-Z0-9]*)\\s*(=)\\s*(\\{)",
424
468
  "beginCaptures": {
@@ -441,7 +485,7 @@
441
485
  "name": "punctuation.section.embedded.end.zenith"
442
486
  }
443
487
  },
444
- "name": "meta.attribute.event.zenith",
488
+ "name": "meta.attribute.event.legacy.zenith",
445
489
  "contentName": "source.ts.embedded.zenith",
446
490
  "patterns": [
447
491
  {
@@ -575,7 +619,7 @@
575
619
  "name": "punctuation.section.embedded.end.zenith"
576
620
  }
577
621
  },
578
- "name": "meta.attribute.event-handler.zenith",
622
+ "name": "meta.attribute.event-handler.legacy.zenith",
579
623
  "contentName": "source.ts.embedded.zenith",
580
624
  "patterns": [
581
625
  {
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Acceptance tests: grammar and snippets contain expected tokens/prefixes.
3
+ * No VS Code required. Runs in CI.
4
+ */
5
+ const test = require('node:test');
6
+ const assert = require('node:assert/strict');
7
+ const fs = require('node:fs');
8
+ const path = require('node:path');
9
+
10
+ const ROOT = path.resolve(__dirname, '..');
11
+
12
+ const CANONICAL_PRIMITIVES = [
13
+ 'state',
14
+ 'signal',
15
+ 'ref',
16
+ 'zenMount',
17
+ 'zenWindow',
18
+ 'zenDocument',
19
+ 'zenOn',
20
+ 'zenResize',
21
+ 'collectRefs'
22
+ ];
23
+
24
+ const SNIPPET_PREFIXES = [
25
+ 'zenOn',
26
+ 'zenResize',
27
+ 'zenWindow',
28
+ 'zenMount',
29
+ 'ref',
30
+ 'state',
31
+ 'signal',
32
+ 'on:click',
33
+ 'collectRefs'
34
+ ];
35
+
36
+ test('grammar includes canonical primitives', () => {
37
+ const grammarPath = path.join(ROOT, 'syntaxes', 'zenith.tmLanguage.json');
38
+ const grammar = JSON.parse(fs.readFileSync(grammarPath, 'utf8'));
39
+
40
+ const repo = grammar.repository || {};
41
+ const grammarStr = JSON.stringify(grammar);
42
+
43
+ for (const prim of CANONICAL_PRIMITIVES) {
44
+ assert.ok(
45
+ grammarStr.includes(prim),
46
+ `Grammar should include "${prim}"`
47
+ );
48
+ }
49
+
50
+ assert.ok(grammar.scopeName === 'text.html.zenith', 'Scope should be text.html.zenith');
51
+ assert.ok(grammar.fileTypes?.includes('zen'), 'File types should include .zen');
52
+ });
53
+
54
+ test('snippets include expected prefixes', () => {
55
+ const snippetsPath = path.join(ROOT, 'snippets', 'zenith.code-snippets');
56
+ const snippets = JSON.parse(fs.readFileSync(snippetsPath, 'utf8'));
57
+ const snippetStr = JSON.stringify(snippets);
58
+
59
+ for (const prefix of SNIPPET_PREFIXES) {
60
+ assert.ok(
61
+ snippetStr.includes(prefix),
62
+ `Snippets should include "${prefix}"`
63
+ );
64
+ }
65
+ });
66
+
67
+ test('package.json contributes single grammar for zenith', () => {
68
+ const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
69
+ const grammars = pkg.contributes?.grammars || [];
70
+ const zenithGrammars = grammars.filter((g) => g.language === 'zenith');
71
+ assert.equal(zenithGrammars.length, 1, 'Exactly one grammar for zenith');
72
+ assert.equal(zenithGrammars[0]?.scopeName, 'text.html.zenith');
73
+ });