@almadar/extensions 2.0.0 → 2.0.2
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/dist/index.d.ts +213 -0
- package/package.json +3 -3
- package/dist/sexpr.injection.json +0 -74
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtual Document — The TypeScript Wrapper Trick
|
|
3
|
+
*
|
|
4
|
+
* Wraps .orb JSON content inside a TypeScript file that imports
|
|
5
|
+
* OrbitalSchema from @almadar/core. This lets the TypeScript
|
|
6
|
+
* language server validate the entire .orb structure for free.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Number of lines the prefix adds before .orb content begins.
|
|
12
|
+
* Used to offset diagnostics back to original .orb line numbers.
|
|
13
|
+
*
|
|
14
|
+
* The prefix is exactly 2 lines:
|
|
15
|
+
* Line 1: import type { OrbitalSchema } from '@almadar/core';
|
|
16
|
+
* Line 2: const _orbital = ... (the .orb content starts on THIS line)
|
|
17
|
+
*
|
|
18
|
+
* So .orb line 1 corresponds to virtual .ts line 2.
|
|
19
|
+
*/
|
|
20
|
+
declare const WRAPPER_LINE_OFFSET = 1;
|
|
21
|
+
/**
|
|
22
|
+
* Number of characters on the prefix line before .orb content begins.
|
|
23
|
+
* `const _orbital = ` is 18 characters.
|
|
24
|
+
*/
|
|
25
|
+
declare const WRAPPER_COL_OFFSET = 18;
|
|
26
|
+
/**
|
|
27
|
+
* Wrap raw .orb JSON content into a virtual TypeScript file.
|
|
28
|
+
*
|
|
29
|
+
* @param orbContent - The raw JSON string from the .orb file
|
|
30
|
+
* @returns The complete TypeScript source that tsserver can validate
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* const orbJson = fs.readFileSync('app.orb', 'utf-8');
|
|
35
|
+
* const tsContent = wrapOrbContent(orbJson);
|
|
36
|
+
* // tsContent is now a valid .ts file that TypeScript can check
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare function wrapOrbContent(orbContent: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Extract the original .orb content from a wrapped virtual TypeScript file.
|
|
42
|
+
*
|
|
43
|
+
* @param virtualContent - The virtual .ts file content
|
|
44
|
+
* @returns The original .orb JSON string, or null if not a valid wrapper
|
|
45
|
+
*/
|
|
46
|
+
declare function unwrapOrbContent(virtualContent: string): string | null;
|
|
47
|
+
/**
|
|
48
|
+
* Generate the virtual .ts filename for a given .orb file path.
|
|
49
|
+
*
|
|
50
|
+
* @param orbFilePath - Absolute path to the .orb file
|
|
51
|
+
* @returns The virtual .ts file path (same directory, `.orb.ts` extension)
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* getVirtualPath('/projects/app.orb')
|
|
56
|
+
* // → '/projects/app.orb.ts'
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
declare function getVirtualPath(orbFilePath: string): string;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Diagnostic Mapper
|
|
63
|
+
*
|
|
64
|
+
* Maps TypeScript diagnostics from the virtual .ts file back to
|
|
65
|
+
* the original .orb file positions, adjusting for the wrapper prefix.
|
|
66
|
+
*
|
|
67
|
+
* @packageDocumentation
|
|
68
|
+
*/
|
|
69
|
+
/**
|
|
70
|
+
* A position in a text document (0-indexed line and character).
|
|
71
|
+
*/
|
|
72
|
+
interface Position {
|
|
73
|
+
/** 0-indexed line number */
|
|
74
|
+
line: number;
|
|
75
|
+
/** 0-indexed character offset within the line */
|
|
76
|
+
character: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* A range in a text document.
|
|
80
|
+
*/
|
|
81
|
+
interface Range {
|
|
82
|
+
start: Position;
|
|
83
|
+
end: Position;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Severity levels matching both VSCode and Zed conventions.
|
|
87
|
+
*/
|
|
88
|
+
type DiagnosticSeverity = 'error' | 'warning' | 'info' | 'hint';
|
|
89
|
+
/**
|
|
90
|
+
* An editor-agnostic diagnostic — the universal unit that
|
|
91
|
+
* VSCode and Zed extensions translate into their native format.
|
|
92
|
+
*/
|
|
93
|
+
interface OrbDiagnostic {
|
|
94
|
+
/** Human-readable error message */
|
|
95
|
+
message: string;
|
|
96
|
+
/** Location in the .orb file (already adjusted from virtual .ts) */
|
|
97
|
+
range: Range;
|
|
98
|
+
/** Severity level */
|
|
99
|
+
severity: DiagnosticSeverity;
|
|
100
|
+
/** TypeScript error code (e.g. 2322, 2353) for filtering */
|
|
101
|
+
code?: number;
|
|
102
|
+
/** Source identifier */
|
|
103
|
+
source: 'almadar-ts';
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Raw TypeScript diagnostic (minimal shape matching ts.Diagnostic).
|
|
107
|
+
* Extensions should map their TS server output to this shape.
|
|
108
|
+
*/
|
|
109
|
+
interface TsDiagnostic {
|
|
110
|
+
/** 0-indexed line in the virtual .ts file */
|
|
111
|
+
line: number;
|
|
112
|
+
/** 0-indexed character in the virtual .ts file */
|
|
113
|
+
character: number;
|
|
114
|
+
/** End line (optional, defaults to same as line) */
|
|
115
|
+
endLine?: number;
|
|
116
|
+
/** End character (optional) */
|
|
117
|
+
endCharacter?: number;
|
|
118
|
+
/** Error message text */
|
|
119
|
+
messageText: string;
|
|
120
|
+
/** TS error code */
|
|
121
|
+
code?: number;
|
|
122
|
+
/** 1 = error, 2 = warning, 3 = info, 4 = hint */
|
|
123
|
+
category?: number;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Map a virtual .ts file position back to the original .orb position.
|
|
127
|
+
*
|
|
128
|
+
* @param virtualLine - 0-indexed line in the virtual .ts file
|
|
129
|
+
* @param virtualChar - 0-indexed character in the virtual .ts file
|
|
130
|
+
* @returns Adjusted position in the .orb file
|
|
131
|
+
*/
|
|
132
|
+
declare function mapPositionToOrb(virtualLine: number, virtualChar: number): Position;
|
|
133
|
+
/**
|
|
134
|
+
* Map a single TypeScript diagnostic to an OrbDiagnostic.
|
|
135
|
+
*
|
|
136
|
+
* @param tsDiag - The raw TypeScript diagnostic
|
|
137
|
+
* @returns An editor-agnostic diagnostic with adjusted positions
|
|
138
|
+
*/
|
|
139
|
+
declare function mapDiagnostic(tsDiag: TsDiagnostic): OrbDiagnostic;
|
|
140
|
+
/**
|
|
141
|
+
* Map an array of TypeScript diagnostics to OrbDiagnostics.
|
|
142
|
+
* Filters out diagnostics that fall within the wrapper prefix.
|
|
143
|
+
*
|
|
144
|
+
* @param diagnostics - Array of raw TypeScript diagnostics
|
|
145
|
+
* @returns Array of editor-agnostic diagnostics
|
|
146
|
+
*/
|
|
147
|
+
declare function mapDiagnostics(diagnostics: TsDiagnostic[]): OrbDiagnostic[];
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* S-Expression Grammar Generator
|
|
151
|
+
*
|
|
152
|
+
* Generates a TextMate injection grammar for S-expression syntax
|
|
153
|
+
* highlighting inside .orb files. The grammar is derived from
|
|
154
|
+
* @almadar/operators — the single source of truth for all operator names.
|
|
155
|
+
*
|
|
156
|
+
* This means new operators automatically get highlighting when
|
|
157
|
+
* the package is rebuilt. No manual grammar maintenance.
|
|
158
|
+
*
|
|
159
|
+
* @packageDocumentation
|
|
160
|
+
*/
|
|
161
|
+
/**
|
|
162
|
+
* TextMate grammar rule
|
|
163
|
+
*/
|
|
164
|
+
interface TmRule {
|
|
165
|
+
name: string;
|
|
166
|
+
match: string;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* TextMate injection grammar structure
|
|
170
|
+
*/
|
|
171
|
+
interface TmInjectionGrammar {
|
|
172
|
+
scopeName: string;
|
|
173
|
+
injectionSelector: string;
|
|
174
|
+
patterns: TmRule[];
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Generate a TextMate injection grammar for S-expression highlighting.
|
|
178
|
+
*
|
|
179
|
+
* The grammar injects into `.orb` files (JSON scope) and highlights:
|
|
180
|
+
* - **Operators** by category (arithmetic, effect, control, etc.)
|
|
181
|
+
* - **Bindings** (`@entity.field`, `@payload.value`)
|
|
182
|
+
* - **Events** (UPPER_CASE_NAMES)
|
|
183
|
+
*
|
|
184
|
+
* @returns A complete TextMate injection grammar object
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```ts
|
|
188
|
+
* import { generateSExprGrammar } from '@almadar/extensions';
|
|
189
|
+
* import { writeFileSync } from 'fs';
|
|
190
|
+
*
|
|
191
|
+
* const grammar = generateSExprGrammar();
|
|
192
|
+
* writeFileSync('sexpr.injection.json', JSON.stringify(grammar, null, 2));
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
declare function generateSExprGrammar(): TmInjectionGrammar;
|
|
196
|
+
/**
|
|
197
|
+
* Serialize the grammar to a formatted JSON string.
|
|
198
|
+
* Ready to be written to `sexpr.injection.json`.
|
|
199
|
+
*/
|
|
200
|
+
declare function generateSExprGrammarJson(): string;
|
|
201
|
+
/**
|
|
202
|
+
* Get a flat list of all operator names from the registry.
|
|
203
|
+
* Useful for editor extensions that need the operator list without
|
|
204
|
+
* importing @almadar/operators directly.
|
|
205
|
+
*/
|
|
206
|
+
declare function getOperatorNames(): string[];
|
|
207
|
+
/**
|
|
208
|
+
* Get operators grouped by category.
|
|
209
|
+
* Useful for autocomplete that groups suggestions by category.
|
|
210
|
+
*/
|
|
211
|
+
declare function getOperatorsByCategory(): Record<string, string[]>;
|
|
212
|
+
|
|
213
|
+
export { type DiagnosticSeverity, type OrbDiagnostic, type Position, type Range, type TmInjectionGrammar, type TsDiagnostic, WRAPPER_COL_OFFSET, WRAPPER_LINE_OFFSET, generateSExprGrammar, generateSExprGrammarJson, getOperatorNames, getOperatorsByCategory, getVirtualPath, mapDiagnostic, mapDiagnostics, mapPositionToOrb, unwrapOrbContent, wrapOrbContent };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@almadar/extensions",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "Editor extension utilities for .orb files — virtual document wrapper and S-expression grammar generator",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"tsup": "^8.0.0",
|
|
27
27
|
"typescript": "^5.4.0",
|
|
28
|
-
"
|
|
28
|
+
"@types/node": "^22.0.0"
|
|
29
29
|
},
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
],
|
|
44
44
|
"homepage": "https://github.com/almadar-io/almadar#readme",
|
|
45
45
|
"scripts": {
|
|
46
|
-
"build": "tsup && pnpm run generate-grammar && pnpm run build:editors",
|
|
46
|
+
"build": "tsup && pnpm run generate-grammar && pnpm run build:editors || true",
|
|
47
47
|
"build:core": "tsup && pnpm run generate-grammar",
|
|
48
48
|
"build:watch": "tsup --watch",
|
|
49
49
|
"build:editors": "pnpm run build:lsp && pnpm run build:vscode && pnpm run build:zed",
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"scopeName": "source.orb.sexpr-injection",
|
|
3
|
-
"injectionSelector": "L:source.orb -comment",
|
|
4
|
-
"patterns": [
|
|
5
|
-
{
|
|
6
|
-
"name": "keyword.operator.arithmetic.sexpr",
|
|
7
|
-
"match": "(?<=\")(floor|round|clamp|ceil|abs|min|max|\\+|-|\\*|/|%)(?=\")"
|
|
8
|
-
},
|
|
9
|
-
{
|
|
10
|
-
"name": "keyword.operator.comparison.sexpr",
|
|
11
|
-
"match": "(?<=\")(!=|<=|>=|=|<|>)(?=\")"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"name": "keyword.operator.logical.sexpr",
|
|
15
|
-
"match": "(?<=\")(and|not|or|if)(?=\")"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"name": "keyword.control.sexpr",
|
|
19
|
-
"match": "(?<=\")(when|let|do|fn)(?=\")"
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
"name": "keyword.other.effect.sexpr",
|
|
23
|
-
"match": "(?<=\")(call-service|render-ui|navigate|persist|despawn|notify|spawn|emit|set)(?=\")"
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"name": "support.function.collection.sexpr",
|
|
27
|
-
"match": "(?<=\")(includes|contains|average|filter|concat|count|first|empty|find|last|map|sum|nth)(?=\")"
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
"name": "support.function.math.sexpr",
|
|
31
|
-
"match": "(?<=\")(math/randomInt|math/default|math/random|math/clamp|math/floor|math/round|math/ceil|math/sqrt|math/sign|math/lerp|math/abs|math/min|math/max|math/pow|math/mod|math/map)(?=\")"
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"name": "support.function.string.sexpr",
|
|
35
|
-
"match": "(?<=\")(str/startsWith|str/replaceAll|str/capitalize|str/includes|str/endsWith|str/template|str/truncate|str/replace|str/reverse|str/default|str/concat|str/repeat|str/upper|str/lower|str/slice|str/split|str/trim|str/join|str/len)(?=\")"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"name": "support.function.array.sexpr",
|
|
39
|
-
"match": "(?<=\")(array/partition|array/findIndex|array/includes|array/dropLast|array/takeLast|array/reverse|array/flatten|array/groupBy|array/prepend|array/shuffle|array/indexOf|array/filter|array/reduce|array/concat|array/unique|array/append|array/insert|array/remove|array/reject|array/repeat|array/every|array/first|array/slice|array/range|array/find|array/some|array/last|array/sort|array/take|array/drop|array/len|array/map|array/nth|array/sum|array/avg|array/min|array/max|array/zip)(?=\")"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"name": "support.function.object.sexpr",
|
|
43
|
-
"match": "(?<=\")(object/entries|object/values|object/equals|object/filter|object/merge|object/clone|object/keys|object/pick|object/omit|object/get|object/set|object/has)(?=\")"
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"name": "support.function.time.sexpr",
|
|
47
|
-
"match": "(?<=\")(time/subtract|time/isBefore|time/isFuture|time/isAfter|time/weekday|time/format|time/isPast|time/minute|time/today|time/parse|time/month|time/diff|time/year|time/hour|time/now|time/add|time/day)(?=\")"
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"name": "support.function.validate.sexpr",
|
|
51
|
-
"match": "(?<=\")(validate/minLength|validate/maxLength|validate/required|validate/pattern|validate/length|validate/equals|validate/email|validate/phone|validate/range|validate/oneOf|validate/check|validate/uuid|validate/url|validate/min|validate/max)(?=\")"
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"name": "support.function.format.sexpr",
|
|
55
|
-
"match": "(?<=\")(format/currency|format/percent|format/ordinal|format/number|format/plural|format/bytes|format/phone|format/list)(?=\")"
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
"name": "support.function.async.sexpr",
|
|
59
|
-
"match": "(?<=\")(async/debounce|async/throttle|async/sequence|async/timeout|async/delay|async/retry|async/race|async/all)(?=\")"
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
"name": "variable.other.binding.sexpr",
|
|
63
|
-
"match": "(?<=\")@(entity|payload|context|config)\\.[a-zA-Z_][a-zA-Z0-9_.]*(?=\")"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
"name": "constant.other.event.sexpr",
|
|
67
|
-
"match": "(?<=\")[A-Z][A-Z0-9_]{2,}(?=\")"
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
"name": "entity.name.tag.slot.sexpr",
|
|
71
|
-
"match": "(?<=\")(main|sidebar|modal|drawer|overlay|center|toast|hud-top|hud-bottom|floating|system)(?=\")"
|
|
72
|
-
}
|
|
73
|
-
]
|
|
74
|
-
}
|