vscode-constela 0.1.3
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/.vscodeignore +21 -0
- package/CHANGELOG.md +61 -0
- package/LICENSE +21 -0
- package/README.md +118 -0
- package/icons/constela-dark.svg +4 -0
- package/icons/constela-icon.png +0 -0
- package/icons/constela-light.svg +4 -0
- package/language-configuration.json +27 -0
- package/package.json +106 -0
- package/schemas/program.schema.json +161 -0
- package/scripts/build.mjs +78 -0
- package/src/extension.ts +55 -0
- package/syntaxes/constela.tmLanguage.json +296 -0
- package/tsconfig.json +20 -0
package/.vscodeignore
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Source files (bundled into dist/)
|
|
2
|
+
src/
|
|
3
|
+
scripts/
|
|
4
|
+
*.ts
|
|
5
|
+
tsconfig.json
|
|
6
|
+
|
|
7
|
+
# Development files
|
|
8
|
+
node_modules/
|
|
9
|
+
.gitignore
|
|
10
|
+
*.map
|
|
11
|
+
|
|
12
|
+
# Test files
|
|
13
|
+
**/*.test.ts
|
|
14
|
+
**/__tests__/
|
|
15
|
+
|
|
16
|
+
# Editor/IDE
|
|
17
|
+
.vscode/
|
|
18
|
+
.idea/
|
|
19
|
+
|
|
20
|
+
# Build artifacts not needed
|
|
21
|
+
*.tsbuildinfo
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the Constela extension will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.3] - 2025-01-24
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Corrected homepage URL to https://constela.dev/
|
|
13
|
+
- Corrected repository URLs in package metadata
|
|
14
|
+
|
|
15
|
+
## [0.1.1] - 2025-01-24
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- README documentation for Marketplace
|
|
20
|
+
- CHANGELOG for version history
|
|
21
|
+
|
|
22
|
+
## [0.1.0] - 2025-01-24
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **Syntax Highlighting** - TextMate grammar for Constela DSL keywords
|
|
27
|
+
- Expression types (`lit`, `state`, `var`, `bin`, `not`, `cond`, `get`, `concat`, etc.)
|
|
28
|
+
- Action steps (`set`, `update`, `fetch`, `navigate`, `delay`, `interval`, etc.)
|
|
29
|
+
- View nodes (`element`, `text`, `if`, `each`, `component`, `slot`, etc.)
|
|
30
|
+
- Top-level sections (`state`, `actions`, `view`, `components`, `route`, etc.)
|
|
31
|
+
|
|
32
|
+
- **Language Server** - Full LSP implementation
|
|
33
|
+
- Real-time validation using Constela compiler
|
|
34
|
+
- JSON parse error detection
|
|
35
|
+
- Semantic error reporting with suggestions
|
|
36
|
+
|
|
37
|
+
- **Auto-completion**
|
|
38
|
+
- Expression type completions
|
|
39
|
+
- Action step completions
|
|
40
|
+
- View node completions
|
|
41
|
+
- State field name completions
|
|
42
|
+
- Action name completions
|
|
43
|
+
- Component name completions
|
|
44
|
+
|
|
45
|
+
- **Hover Documentation**
|
|
46
|
+
- Expression type signatures and descriptions
|
|
47
|
+
- Action step usage documentation
|
|
48
|
+
- View node structure information
|
|
49
|
+
|
|
50
|
+
- **Go to Definition**
|
|
51
|
+
- Navigate to state field definitions
|
|
52
|
+
- Navigate to action definitions
|
|
53
|
+
- Navigate to component definitions
|
|
54
|
+
|
|
55
|
+
- **JSON Schema Validation**
|
|
56
|
+
- Basic schema validation for `.constela.json` files
|
|
57
|
+
|
|
58
|
+
### Technical
|
|
59
|
+
|
|
60
|
+
- Bundled language server with all dependencies (no external npm packages required)
|
|
61
|
+
- Self-contained `.vsix` package (~160 KB)
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Constela
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Constela for Visual Studio Code
|
|
2
|
+
|
|
3
|
+
Language support for [Constela](https://constela.dev) - a constrained UI DSL that compiles to minimal runtime JavaScript.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### Syntax Highlighting
|
|
8
|
+
|
|
9
|
+
Full syntax highlighting for `.constela.json` files with semantic coloring for:
|
|
10
|
+
|
|
11
|
+
- Expression types (`lit`, `state`, `var`, `bin`, `cond`, etc.)
|
|
12
|
+
- Action steps (`set`, `fetch`, `navigate`, `delay`, etc.)
|
|
13
|
+
- View nodes (`element`, `text`, `if`, `each`, `component`, etc.)
|
|
14
|
+
- State definitions, actions, components, and more
|
|
15
|
+
|
|
16
|
+
### IntelliSense
|
|
17
|
+
|
|
18
|
+
Smart auto-completion for:
|
|
19
|
+
|
|
20
|
+
- **Expression types** - Complete list of available expressions
|
|
21
|
+
- **Action steps** - All action types with descriptions
|
|
22
|
+
- **View nodes** - Element, text, conditional, loop nodes
|
|
23
|
+
- **State references** - Your defined state fields
|
|
24
|
+
- **Action references** - Your defined actions
|
|
25
|
+
- **Component references** - Your defined components
|
|
26
|
+
|
|
27
|
+
### Real-time Validation
|
|
28
|
+
|
|
29
|
+
Errors are displayed as you type, powered by the Constela compiler:
|
|
30
|
+
|
|
31
|
+
- JSON syntax errors
|
|
32
|
+
- Missing required fields
|
|
33
|
+
- Invalid references (undefined state, actions, components)
|
|
34
|
+
- Type mismatches
|
|
35
|
+
|
|
36
|
+
### Hover Information
|
|
37
|
+
|
|
38
|
+
Hover over keywords to see documentation:
|
|
39
|
+
|
|
40
|
+
- Expression signatures and descriptions
|
|
41
|
+
- Action step usage examples
|
|
42
|
+
- View node structure
|
|
43
|
+
|
|
44
|
+
### Go to Definition
|
|
45
|
+
|
|
46
|
+
Navigate to definitions with `Ctrl+Click` (or `Cmd+Click` on macOS):
|
|
47
|
+
|
|
48
|
+
- Jump to state field definitions
|
|
49
|
+
- Jump to action definitions
|
|
50
|
+
- Jump to component definitions
|
|
51
|
+
|
|
52
|
+
## Requirements
|
|
53
|
+
|
|
54
|
+
- Visual Studio Code 1.85.0 or higher
|
|
55
|
+
|
|
56
|
+
## Extension Settings
|
|
57
|
+
|
|
58
|
+
This extension contributes the following settings:
|
|
59
|
+
|
|
60
|
+
- `constela.trace.server`: Traces communication between VS Code and the language server (`off`, `messages`, `verbose`)
|
|
61
|
+
- `constela.validation.enable`: Enable/disable validation of Constela files
|
|
62
|
+
|
|
63
|
+
## File Association
|
|
64
|
+
|
|
65
|
+
The extension automatically activates for files matching:
|
|
66
|
+
|
|
67
|
+
- `*.constela.json`
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
1. Create a new file with `.constela.json` extension
|
|
72
|
+
2. Start with the basic structure:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"version": "1.0",
|
|
77
|
+
"state": {
|
|
78
|
+
"count": { "type": "number", "initial": 0 }
|
|
79
|
+
},
|
|
80
|
+
"actions": [
|
|
81
|
+
{
|
|
82
|
+
"name": "increment",
|
|
83
|
+
"steps": [
|
|
84
|
+
{ "do": "update", "name": "count", "with": "increment" }
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"view": {
|
|
89
|
+
"node": "element",
|
|
90
|
+
"tag": "button",
|
|
91
|
+
"props": {
|
|
92
|
+
"onClick": { "action": "increment" }
|
|
93
|
+
},
|
|
94
|
+
"children": [
|
|
95
|
+
{
|
|
96
|
+
"node": "text",
|
|
97
|
+
"content": { "expr": "state", "name": "count" }
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
3. Enjoy syntax highlighting, auto-completion, and validation!
|
|
105
|
+
|
|
106
|
+
## Learn More
|
|
107
|
+
|
|
108
|
+
- [Constela Website](https://constela.dev/)
|
|
109
|
+
- [GitHub Repository](https://github.com/yuuichieguchi/constela)
|
|
110
|
+
- [Examples](https://github.com/yuuichieguchi/constela/tree/main/examples)
|
|
111
|
+
|
|
112
|
+
## Issues
|
|
113
|
+
|
|
114
|
+
Found a bug or have a feature request? Please open an issue on [GitHub](https://github.com/yuuichieguchi/constela/issues).
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
MIT
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
|
2
|
+
<rect x="4" y="4" width="24" height="24" rx="4" fill="#1a1a1a" stroke="#333" stroke-width="1"/>
|
|
3
|
+
<text x="16" y="21" text-anchor="middle" font-family="monospace" font-size="14" font-weight="bold" fill="#4fc3f7">C</text>
|
|
4
|
+
</svg>
|
|
Binary file
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
|
2
|
+
<rect x="4" y="4" width="24" height="24" rx="4" fill="#f0f0f0" stroke="#ccc" stroke-width="1"/>
|
|
3
|
+
<text x="16" y="21" text-anchor="middle" font-family="monospace" font-size="14" font-weight="bold" fill="#0288d1">C</text>
|
|
4
|
+
</svg>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"comments": {},
|
|
3
|
+
"brackets": [
|
|
4
|
+
["{", "}"],
|
|
5
|
+
["[", "]"]
|
|
6
|
+
],
|
|
7
|
+
"autoClosingPairs": [
|
|
8
|
+
{ "open": "{", "close": "}" },
|
|
9
|
+
{ "open": "[", "close": "]" },
|
|
10
|
+
{ "open": "\"", "close": "\"" }
|
|
11
|
+
],
|
|
12
|
+
"surroundingPairs": [
|
|
13
|
+
{ "open": "{", "close": "}" },
|
|
14
|
+
{ "open": "[", "close": "]" },
|
|
15
|
+
{ "open": "\"", "close": "\"" }
|
|
16
|
+
],
|
|
17
|
+
"folding": {
|
|
18
|
+
"markers": {
|
|
19
|
+
"start": "^\\s*\\{",
|
|
20
|
+
"end": "^\\s*\\}"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"indentationRules": {
|
|
24
|
+
"increaseIndentPattern": "^.*\\{[^}]*$",
|
|
25
|
+
"decreaseIndentPattern": "^\\s*\\}"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vscode-constela",
|
|
3
|
+
"displayName": "Constela",
|
|
4
|
+
"description": "Language support for Constela DSL - syntax highlighting, auto-completion, and error checking",
|
|
5
|
+
"version": "0.1.3",
|
|
6
|
+
"publisher": "constela",
|
|
7
|
+
"icon": "icons/constela-icon.png",
|
|
8
|
+
"engines": {
|
|
9
|
+
"vscode": "^1.85.0"
|
|
10
|
+
},
|
|
11
|
+
"categories": [
|
|
12
|
+
"Programming Languages",
|
|
13
|
+
"Linters"
|
|
14
|
+
],
|
|
15
|
+
"keywords": [
|
|
16
|
+
"constela",
|
|
17
|
+
"dsl",
|
|
18
|
+
"ui",
|
|
19
|
+
"json"
|
|
20
|
+
],
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/yuuichieguchi/constela"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://constela.dev/",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/yuuichieguchi/constela/issues"
|
|
28
|
+
},
|
|
29
|
+
"main": "./dist/extension.js",
|
|
30
|
+
"activationEvents": [
|
|
31
|
+
"onLanguage:constela",
|
|
32
|
+
"workspaceContains:**/*.constela.json"
|
|
33
|
+
],
|
|
34
|
+
"contributes": {
|
|
35
|
+
"languages": [
|
|
36
|
+
{
|
|
37
|
+
"id": "constela",
|
|
38
|
+
"aliases": [
|
|
39
|
+
"Constela",
|
|
40
|
+
"constela"
|
|
41
|
+
],
|
|
42
|
+
"extensions": [
|
|
43
|
+
".constela.json"
|
|
44
|
+
],
|
|
45
|
+
"configuration": "./language-configuration.json",
|
|
46
|
+
"icon": {
|
|
47
|
+
"light": "./icons/constela-light.svg",
|
|
48
|
+
"dark": "./icons/constela-dark.svg"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"grammars": [
|
|
53
|
+
{
|
|
54
|
+
"language": "constela",
|
|
55
|
+
"scopeName": "source.constela",
|
|
56
|
+
"path": "./syntaxes/constela.tmLanguage.json"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"configuration": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"title": "Constela",
|
|
62
|
+
"properties": {
|
|
63
|
+
"constela.trace.server": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"enum": [
|
|
66
|
+
"off",
|
|
67
|
+
"messages",
|
|
68
|
+
"verbose"
|
|
69
|
+
],
|
|
70
|
+
"default": "off",
|
|
71
|
+
"description": "Traces the communication between VS Code and the Constela language server."
|
|
72
|
+
},
|
|
73
|
+
"constela.validation.enable": {
|
|
74
|
+
"type": "boolean",
|
|
75
|
+
"default": true,
|
|
76
|
+
"description": "Enable/disable validation of Constela files."
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"jsonValidation": [
|
|
81
|
+
{
|
|
82
|
+
"fileMatch": "*.constela.json",
|
|
83
|
+
"url": "./schemas/program.schema.json"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
"dependencies": {},
|
|
88
|
+
"devDependencies": {
|
|
89
|
+
"@types/node": "^20.10.0",
|
|
90
|
+
"@types/vscode": "^1.85.0",
|
|
91
|
+
"@vscode/vsce": "^2.22.0",
|
|
92
|
+
"esbuild": "^0.24.0",
|
|
93
|
+
"tsup": "^8.0.0",
|
|
94
|
+
"typescript": "^5.3.0",
|
|
95
|
+
"vscode-languageclient": "^9.0.1",
|
|
96
|
+
"@constela/language-server": "0.1.1"
|
|
97
|
+
},
|
|
98
|
+
"license": "MIT",
|
|
99
|
+
"scripts": {
|
|
100
|
+
"vscode:prepublish": "pnpm run build",
|
|
101
|
+
"build": "node scripts/build.mjs",
|
|
102
|
+
"watch": "tsup src/extension.ts --format cjs --external vscode --watch",
|
|
103
|
+
"package": "vsce package --no-dependencies",
|
|
104
|
+
"type-check": "tsc --noEmit"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://constela.dev/schemas/program.schema.json",
|
|
4
|
+
"title": "Constela Program",
|
|
5
|
+
"description": "Schema for Constela DSL programs",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["version", "view"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"version": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"const": "1.0",
|
|
12
|
+
"description": "Constela version"
|
|
13
|
+
},
|
|
14
|
+
"state": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"description": "State fields",
|
|
17
|
+
"additionalProperties": {
|
|
18
|
+
"$ref": "#/definitions/stateField"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"actions": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"description": "Action definitions",
|
|
24
|
+
"items": {
|
|
25
|
+
"$ref": "#/definitions/actionDef"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"view": {
|
|
29
|
+
"$ref": "#/definitions/viewNode",
|
|
30
|
+
"description": "Root view node"
|
|
31
|
+
},
|
|
32
|
+
"components": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"description": "Component definitions",
|
|
35
|
+
"additionalProperties": {
|
|
36
|
+
"$ref": "#/definitions/componentDef"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"route": {
|
|
40
|
+
"$ref": "#/definitions/routeDef",
|
|
41
|
+
"description": "Route definition"
|
|
42
|
+
},
|
|
43
|
+
"imports": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"description": "External module imports",
|
|
46
|
+
"additionalProperties": {
|
|
47
|
+
"type": "string"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"data": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"description": "Build-time data sources",
|
|
53
|
+
"additionalProperties": {
|
|
54
|
+
"$ref": "#/definitions/dataSource"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"styles": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"description": "Style presets",
|
|
60
|
+
"additionalProperties": {
|
|
61
|
+
"$ref": "#/definitions/stylePreset"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"lifecycle": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"description": "Lifecycle hooks",
|
|
67
|
+
"properties": {
|
|
68
|
+
"onMount": { "type": "string" },
|
|
69
|
+
"onUnmount": { "type": "string" },
|
|
70
|
+
"onRouteEnter": { "type": "string" },
|
|
71
|
+
"onRouteLeave": { "type": "string" }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"definitions": {
|
|
76
|
+
"stateField": {
|
|
77
|
+
"oneOf": [
|
|
78
|
+
{ "type": "object", "properties": { "type": { "const": "number" }, "initial": { "type": "number" } }, "required": ["type"] },
|
|
79
|
+
{ "type": "object", "properties": { "type": { "const": "string" }, "initial": { "type": "string" } }, "required": ["type"] },
|
|
80
|
+
{ "type": "object", "properties": { "type": { "const": "boolean" }, "initial": { "type": "boolean" } }, "required": ["type"] },
|
|
81
|
+
{ "type": "object", "properties": { "type": { "const": "list" }, "initial": { "type": "array" } }, "required": ["type"] },
|
|
82
|
+
{ "type": "object", "properties": { "type": { "const": "object" }, "initial": { "type": "object" } }, "required": ["type"] }
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
"actionDef": {
|
|
86
|
+
"type": "object",
|
|
87
|
+
"required": ["name", "steps"],
|
|
88
|
+
"properties": {
|
|
89
|
+
"name": { "type": "string" },
|
|
90
|
+
"params": { "type": "array", "items": { "type": "string" } },
|
|
91
|
+
"steps": { "type": "array", "items": { "$ref": "#/definitions/actionStep" } }
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"actionStep": {
|
|
95
|
+
"type": "object",
|
|
96
|
+
"required": ["do"],
|
|
97
|
+
"properties": {
|
|
98
|
+
"do": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"enum": ["set", "update", "setPath", "fetch", "navigate", "storage", "clipboard", "delay", "interval", "clearTimer", "focus", "dom", "if", "call", "import", "subscribe", "dispose", "send", "close"]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"viewNode": {
|
|
105
|
+
"type": "object",
|
|
106
|
+
"required": ["node"],
|
|
107
|
+
"properties": {
|
|
108
|
+
"node": {
|
|
109
|
+
"type": "string",
|
|
110
|
+
"enum": ["element", "text", "if", "each", "component", "slot", "markdown", "code", "portal"]
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
"componentDef": {
|
|
115
|
+
"type": "object",
|
|
116
|
+
"required": ["view"],
|
|
117
|
+
"properties": {
|
|
118
|
+
"params": { "type": "array", "items": { "type": "string" } },
|
|
119
|
+
"state": { "type": "object" },
|
|
120
|
+
"actions": { "type": "array" },
|
|
121
|
+
"view": { "$ref": "#/definitions/viewNode" }
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"routeDef": {
|
|
125
|
+
"type": "object",
|
|
126
|
+
"properties": {
|
|
127
|
+
"pattern": { "type": "string" },
|
|
128
|
+
"params": { "type": "array", "items": { "type": "string" } },
|
|
129
|
+
"layout": { "type": "string" },
|
|
130
|
+
"title": { "type": "string" }
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"dataSource": {
|
|
134
|
+
"type": "object",
|
|
135
|
+
"required": ["type"],
|
|
136
|
+
"properties": {
|
|
137
|
+
"type": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"enum": ["glob", "file", "api", "mdx", "yaml", "csv"]
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
"stylePreset": {
|
|
144
|
+
"type": "object",
|
|
145
|
+
"properties": {
|
|
146
|
+
"base": { "type": "object" },
|
|
147
|
+
"variants": { "type": "object" }
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
"expr": {
|
|
151
|
+
"type": "object",
|
|
152
|
+
"required": ["expr"],
|
|
153
|
+
"properties": {
|
|
154
|
+
"expr": {
|
|
155
|
+
"type": "string",
|
|
156
|
+
"enum": ["lit", "state", "var", "bin", "not", "cond", "get", "concat", "route", "import", "data", "ref", "index", "style", "param", "validity"]
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build script for vscode-constela extension
|
|
4
|
+
*
|
|
5
|
+
* This script:
|
|
6
|
+
* 1. Runs codegen to generate completion/hover data from AST types
|
|
7
|
+
* 2. Bundles the language server with all dependencies
|
|
8
|
+
* 3. Bundles the extension client with all dependencies
|
|
9
|
+
*
|
|
10
|
+
* All code is bundled into self-contained files so the .vsix works standalone.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import * as esbuild from 'esbuild';
|
|
14
|
+
import { mkdirSync, rmSync, existsSync } from 'fs';
|
|
15
|
+
import { dirname, join } from 'path';
|
|
16
|
+
import { fileURLToPath } from 'url';
|
|
17
|
+
import { execSync } from 'child_process';
|
|
18
|
+
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const rootDir = join(__dirname, '..');
|
|
21
|
+
const packagesDir = join(rootDir, '..');
|
|
22
|
+
const distDir = join(rootDir, 'dist');
|
|
23
|
+
|
|
24
|
+
// Paths to language server source
|
|
25
|
+
const languageServerDir = join(rootDir, '..', 'constela-language-server');
|
|
26
|
+
const languageServerEntry = join(languageServerDir, 'src', 'index.ts');
|
|
27
|
+
|
|
28
|
+
console.log('🔨 Building Constela VSCode Extension...\n');
|
|
29
|
+
|
|
30
|
+
// Step 1: Run codegen to generate completion/hover data
|
|
31
|
+
console.log('1. Running codegen...');
|
|
32
|
+
execSync('pnpm --filter @constela/codegen generate', {
|
|
33
|
+
cwd: packagesDir,
|
|
34
|
+
stdio: 'inherit',
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Step 2: Clean dist directory
|
|
38
|
+
console.log('2. Cleaning dist directory...');
|
|
39
|
+
if (existsSync(distDir)) {
|
|
40
|
+
rmSync(distDir, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
mkdirSync(distDir, { recursive: true });
|
|
43
|
+
|
|
44
|
+
// Step 3: Bundle the language server with all dependencies
|
|
45
|
+
console.log('3. Bundling language server...');
|
|
46
|
+
await esbuild.build({
|
|
47
|
+
entryPoints: [languageServerEntry],
|
|
48
|
+
bundle: true,
|
|
49
|
+
outfile: join(distDir, 'server', 'index.js'),
|
|
50
|
+
format: 'cjs',
|
|
51
|
+
platform: 'node',
|
|
52
|
+
target: 'node20',
|
|
53
|
+
sourcemap: false,
|
|
54
|
+
minify: true,
|
|
55
|
+
external: [],
|
|
56
|
+
// Ensure all workspace dependencies are bundled
|
|
57
|
+
packages: 'bundle',
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Step 4: Bundle the extension client
|
|
61
|
+
console.log('4. Bundling extension client...');
|
|
62
|
+
await esbuild.build({
|
|
63
|
+
entryPoints: [join(rootDir, 'src', 'extension.ts')],
|
|
64
|
+
bundle: true,
|
|
65
|
+
outfile: join(distDir, 'extension.js'),
|
|
66
|
+
format: 'cjs',
|
|
67
|
+
platform: 'node',
|
|
68
|
+
target: 'node20',
|
|
69
|
+
sourcemap: false,
|
|
70
|
+
minify: true,
|
|
71
|
+
external: ['vscode'],
|
|
72
|
+
// Ensure all dependencies are bundled
|
|
73
|
+
packages: 'bundle',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
console.log('\n✅ Build complete!');
|
|
77
|
+
console.log(` Extension: ${join(distDir, 'extension.js')}`);
|
|
78
|
+
console.log(` Server: ${join(distDir, 'server', 'index.js')}`);
|
package/src/extension.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { workspace, ExtensionContext, window } from 'vscode';
|
|
3
|
+
import {
|
|
4
|
+
LanguageClient,
|
|
5
|
+
LanguageClientOptions,
|
|
6
|
+
ServerOptions,
|
|
7
|
+
TransportKind,
|
|
8
|
+
} from 'vscode-languageclient/node';
|
|
9
|
+
|
|
10
|
+
let client: LanguageClient | undefined;
|
|
11
|
+
|
|
12
|
+
export function activate(context: ExtensionContext): void {
|
|
13
|
+
// Server is bundled inside the extension's dist/server directory
|
|
14
|
+
const serverModule = context.asAbsolutePath(
|
|
15
|
+
path.join('dist', 'server', 'index.js')
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] };
|
|
19
|
+
|
|
20
|
+
const serverOptions: ServerOptions = {
|
|
21
|
+
run: { module: serverModule, transport: TransportKind.ipc },
|
|
22
|
+
debug: {
|
|
23
|
+
module: serverModule,
|
|
24
|
+
transport: TransportKind.ipc,
|
|
25
|
+
options: debugOptions,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const clientOptions: LanguageClientOptions = {
|
|
30
|
+
documentSelector: [
|
|
31
|
+
{ scheme: 'file', language: 'constela' },
|
|
32
|
+
{ scheme: 'file', pattern: '**/*.constela.json' },
|
|
33
|
+
],
|
|
34
|
+
synchronize: {
|
|
35
|
+
fileEvents: workspace.createFileSystemWatcher('**/*.constela.json'),
|
|
36
|
+
},
|
|
37
|
+
outputChannel: window.createOutputChannel('Constela'),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
client = new LanguageClient(
|
|
41
|
+
'constelaLanguageServer',
|
|
42
|
+
'Constela Language Server',
|
|
43
|
+
serverOptions,
|
|
44
|
+
clientOptions
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
client.start();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function deactivate(): Thenable<void> | undefined {
|
|
51
|
+
if (!client) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
return client.stop();
|
|
55
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
|
|
3
|
+
"name": "Constela",
|
|
4
|
+
"scopeName": "source.constela",
|
|
5
|
+
"patterns": [
|
|
6
|
+
{
|
|
7
|
+
"include": "#value"
|
|
8
|
+
}
|
|
9
|
+
],
|
|
10
|
+
"repository": {
|
|
11
|
+
"value": {
|
|
12
|
+
"patterns": [
|
|
13
|
+
{
|
|
14
|
+
"include": "#string"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"include": "#number"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"include": "#constant"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"include": "#object"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"include": "#array"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"object": {
|
|
31
|
+
"begin": "\\{",
|
|
32
|
+
"end": "\\}",
|
|
33
|
+
"beginCaptures": {
|
|
34
|
+
"0": {
|
|
35
|
+
"name": "punctuation.definition.object.begin.constela"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"endCaptures": {
|
|
39
|
+
"0": {
|
|
40
|
+
"name": "punctuation.definition.object.end.constela"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"patterns": [
|
|
44
|
+
{
|
|
45
|
+
"include": "#object-member"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"include": "#value"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"object-member": {
|
|
53
|
+
"patterns": [
|
|
54
|
+
{
|
|
55
|
+
"include": "#version-key"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"include": "#expr-key"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"include": "#do-key"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"include": "#node-key"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"include": "#state-key"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"include": "#actions-key"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"include": "#view-key"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"include": "#components-key"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"include": "#route-key"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"include": "#imports-key"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"include": "#data-key"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"include": "#styles-key"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"include": "#lifecycle-key"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"include": "#property-key"
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
"version-key": {
|
|
99
|
+
"match": "\"(version)\"\\s*:",
|
|
100
|
+
"captures": {
|
|
101
|
+
"1": {
|
|
102
|
+
"name": "keyword.control.constela"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"expr-key": {
|
|
107
|
+
"match": "\"(expr)\"\\s*:\\s*\"(bin|call|concat|cond|data|get|import|index|lambda|lit|not|param|ref|route|state|style|validity|var)\"",
|
|
108
|
+
"captures": {
|
|
109
|
+
"1": {
|
|
110
|
+
"name": "keyword.control.constela"
|
|
111
|
+
},
|
|
112
|
+
"2": {
|
|
113
|
+
"name": "entity.name.type.constela"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"do-key": {
|
|
118
|
+
"match": "\"(do)\"\\s*:\\s*\"(call|clearTimer|clipboard|close|delay|dispose|dom|fetch|focus|if|import|interval|navigate|send|set|setPath|storage|subscribe|update)\"",
|
|
119
|
+
"captures": {
|
|
120
|
+
"1": {
|
|
121
|
+
"name": "keyword.control.constela"
|
|
122
|
+
},
|
|
123
|
+
"2": {
|
|
124
|
+
"name": "entity.name.function.constela"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"node-key": {
|
|
129
|
+
"match": "\"(kind)\"\\s*:\\s*\"(code|component|each|element|if|markdown|portal|slot|text)\"",
|
|
130
|
+
"captures": {
|
|
131
|
+
"1": {
|
|
132
|
+
"name": "keyword.control.constela"
|
|
133
|
+
},
|
|
134
|
+
"2": {
|
|
135
|
+
"name": "entity.name.tag.constela"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"state-key": {
|
|
140
|
+
"match": "\"(state)\"\\s*:",
|
|
141
|
+
"captures": {
|
|
142
|
+
"1": {
|
|
143
|
+
"name": "storage.type.constela"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"actions-key": {
|
|
148
|
+
"match": "\"(actions)\"\\s*:",
|
|
149
|
+
"captures": {
|
|
150
|
+
"1": {
|
|
151
|
+
"name": "storage.type.constela"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"view-key": {
|
|
156
|
+
"match": "\"(view)\"\\s*:",
|
|
157
|
+
"captures": {
|
|
158
|
+
"1": {
|
|
159
|
+
"name": "storage.type.constela"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"components-key": {
|
|
164
|
+
"match": "\"(components)\"\\s*:",
|
|
165
|
+
"captures": {
|
|
166
|
+
"1": {
|
|
167
|
+
"name": "storage.type.constela"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"route-key": {
|
|
172
|
+
"match": "\"(route)\"\\s*:",
|
|
173
|
+
"captures": {
|
|
174
|
+
"1": {
|
|
175
|
+
"name": "storage.type.constela"
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"imports-key": {
|
|
180
|
+
"match": "\"(imports)\"\\s*:",
|
|
181
|
+
"captures": {
|
|
182
|
+
"1": {
|
|
183
|
+
"name": "storage.type.constela"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
"data-key": {
|
|
188
|
+
"match": "\"(data)\"\\s*:",
|
|
189
|
+
"captures": {
|
|
190
|
+
"1": {
|
|
191
|
+
"name": "storage.type.constela"
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"styles-key": {
|
|
196
|
+
"match": "\"(styles)\"\\s*:",
|
|
197
|
+
"captures": {
|
|
198
|
+
"1": {
|
|
199
|
+
"name": "storage.type.constela"
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
"lifecycle-key": {
|
|
204
|
+
"match": "\"(lifecycle|onMount|onUnmount|onRouteEnter|onRouteLeave)\"\\s*:",
|
|
205
|
+
"captures": {
|
|
206
|
+
"1": {
|
|
207
|
+
"name": "support.function.constela"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
"property-key": {
|
|
212
|
+
"patterns": [
|
|
213
|
+
{
|
|
214
|
+
"match": "\"(name|value|op|left|right|if|then|else|cond|base|path|parts|part|items|as|template|tag|props|children|on|ref|content|language|target|method|url|body|headers|result|onSuccess|onError|action|key|steps|ms|timerId|subscriptionId|connectionId|from|with|args|params|pattern|layout|title)\"\\s*:",
|
|
215
|
+
"captures": {
|
|
216
|
+
"1": {
|
|
217
|
+
"name": "variable.other.property.constela"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"match": "\"([a-zA-Z_][a-zA-Z0-9_]*)\"\\s*:",
|
|
223
|
+
"captures": {
|
|
224
|
+
"1": {
|
|
225
|
+
"name": "variable.other.member.constela"
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
},
|
|
231
|
+
"array": {
|
|
232
|
+
"begin": "\\[",
|
|
233
|
+
"end": "\\]",
|
|
234
|
+
"beginCaptures": {
|
|
235
|
+
"0": {
|
|
236
|
+
"name": "punctuation.definition.array.begin.constela"
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
"endCaptures": {
|
|
240
|
+
"0": {
|
|
241
|
+
"name": "punctuation.definition.array.end.constela"
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
"patterns": [
|
|
245
|
+
{
|
|
246
|
+
"include": "#value"
|
|
247
|
+
}
|
|
248
|
+
]
|
|
249
|
+
},
|
|
250
|
+
"string": {
|
|
251
|
+
"patterns": [
|
|
252
|
+
{
|
|
253
|
+
"name": "string.quoted.double.constela",
|
|
254
|
+
"begin": "\"",
|
|
255
|
+
"end": "\"",
|
|
256
|
+
"beginCaptures": {
|
|
257
|
+
"0": {
|
|
258
|
+
"name": "punctuation.definition.string.begin.constela"
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
"endCaptures": {
|
|
262
|
+
"0": {
|
|
263
|
+
"name": "punctuation.definition.string.end.constela"
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
"patterns": [
|
|
267
|
+
{
|
|
268
|
+
"name": "constant.character.escape.constela",
|
|
269
|
+
"match": "\\\\."
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
},
|
|
275
|
+
"number": {
|
|
276
|
+
"name": "constant.numeric.constela",
|
|
277
|
+
"match": "-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?"
|
|
278
|
+
},
|
|
279
|
+
"constant": {
|
|
280
|
+
"patterns": [
|
|
281
|
+
{
|
|
282
|
+
"name": "constant.language.boolean.true.constela",
|
|
283
|
+
"match": "\\btrue\\b"
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"name": "constant.language.boolean.false.constela",
|
|
287
|
+
"match": "\\bfalse\\b"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
"name": "constant.language.null.constela",
|
|
291
|
+
"match": "\\bnull\\b"
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"outDir": "./dist",
|
|
12
|
+
"rootDir": "./src",
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"noUncheckedIndexedAccess": true,
|
|
16
|
+
"noImplicitOverride": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|