@almadar/extensions 1.0.13
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/LICENSE +72 -0
- package/dist/index.d.ts +213 -0
- package/dist/index.js +143 -0
- package/dist/index.js.map +1 -0
- package/dist/sexpr.injection.json +74 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Parameters
|
|
4
|
+
|
|
5
|
+
Licensor: Almadar FZE
|
|
6
|
+
Licensed Work: KFlow Builder / Almadar
|
|
7
|
+
The Licensed Work is (c) 2025-2026 Almadar FZE.
|
|
8
|
+
Additional Use Grant: You may make production use of the Licensed Work for
|
|
9
|
+
non-commercial purposes and for internal evaluation.
|
|
10
|
+
Production use for commercial purposes requires a
|
|
11
|
+
commercial license from the Licensor.
|
|
12
|
+
Change Date: 2030-02-01
|
|
13
|
+
Change License: Apache License, Version 2.0
|
|
14
|
+
|
|
15
|
+
Terms
|
|
16
|
+
|
|
17
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
18
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
19
|
+
Licensor may make an Additional Use Grant, above, permitting limited
|
|
20
|
+
production use.
|
|
21
|
+
|
|
22
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
23
|
+
available distribution of a specific version of the Licensed Work under this
|
|
24
|
+
License, whichever comes first, the Licensor hereby grants you rights under
|
|
25
|
+
the terms of the Change License, and the rights granted in the paragraph
|
|
26
|
+
above terminate.
|
|
27
|
+
|
|
28
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
29
|
+
currently in effect as described in this License, you must purchase a
|
|
30
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
31
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
32
|
+
|
|
33
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
34
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
35
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
36
|
+
for each version of the Licensed Work released by Licensor.
|
|
37
|
+
|
|
38
|
+
You must conspicuously display this License on each original or modified copy
|
|
39
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
40
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
41
|
+
License apply to your use of that work.
|
|
42
|
+
|
|
43
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
44
|
+
terminate your rights under this License for the current and all other
|
|
45
|
+
versions of the Licensed Work.
|
|
46
|
+
|
|
47
|
+
This License does not grant you any right in any trademark or logo of
|
|
48
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
49
|
+
Licensor as expressly required by this License).
|
|
50
|
+
|
|
51
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
52
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
53
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
54
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
55
|
+
TITLE.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
|
|
60
|
+
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
61
|
+
|
|
62
|
+
ADDITIONAL TERMS:
|
|
63
|
+
|
|
64
|
+
Documentation (builder/packages/website/docs/) is licensed under CC BY 4.0.
|
|
65
|
+
|
|
66
|
+
TRADEMARKS:
|
|
67
|
+
|
|
68
|
+
"Orbital", "KFlow", "Almadar", and the Almadar logo are trademarks of
|
|
69
|
+
Almadar FZE. You may not use these trademarks without prior written
|
|
70
|
+
permission from Almadar FZE.
|
|
71
|
+
|
|
72
|
+
For licensing inquiries: licensing@almadar.io
|
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/dist/index.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { OPERATOR_NAMES, OPERATORS } from '@almadar/operators';
|
|
2
|
+
|
|
3
|
+
// src/virtual-document.ts
|
|
4
|
+
var TS_PREFIX = `import type { OrbitalSchema } from '@almadar/core';
|
|
5
|
+
const _orbital = `;
|
|
6
|
+
var TS_SUFFIX = ` satisfies OrbitalSchema;
|
|
7
|
+
`;
|
|
8
|
+
var WRAPPER_LINE_OFFSET = 1;
|
|
9
|
+
var WRAPPER_COL_OFFSET = 18;
|
|
10
|
+
function wrapOrbContent(orbContent) {
|
|
11
|
+
return TS_PREFIX + orbContent + TS_SUFFIX;
|
|
12
|
+
}
|
|
13
|
+
function unwrapOrbContent(virtualContent) {
|
|
14
|
+
if (!virtualContent.startsWith(TS_PREFIX)) return null;
|
|
15
|
+
if (!virtualContent.endsWith(TS_SUFFIX)) return null;
|
|
16
|
+
return virtualContent.slice(
|
|
17
|
+
TS_PREFIX.length,
|
|
18
|
+
virtualContent.length - TS_SUFFIX.length
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function getVirtualPath(orbFilePath) {
|
|
22
|
+
return orbFilePath + ".ts";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/diagnostic-mapper.ts
|
|
26
|
+
function mapPositionToOrb(virtualLine, virtualChar) {
|
|
27
|
+
const orbLine = virtualLine - WRAPPER_LINE_OFFSET;
|
|
28
|
+
const orbChar = orbLine === 0 ? Math.max(0, virtualChar - WRAPPER_COL_OFFSET) : virtualChar;
|
|
29
|
+
return {
|
|
30
|
+
line: Math.max(0, orbLine),
|
|
31
|
+
character: Math.max(0, orbChar)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function mapDiagnostic(tsDiag) {
|
|
35
|
+
const start = mapPositionToOrb(tsDiag.line, tsDiag.character);
|
|
36
|
+
const end = mapPositionToOrb(
|
|
37
|
+
tsDiag.endLine ?? tsDiag.line,
|
|
38
|
+
tsDiag.endCharacter ?? tsDiag.character + 1
|
|
39
|
+
);
|
|
40
|
+
const severityMap = {
|
|
41
|
+
1: "error",
|
|
42
|
+
2: "warning",
|
|
43
|
+
3: "info",
|
|
44
|
+
4: "hint"
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
message: cleanTsMessage(tsDiag.messageText),
|
|
48
|
+
range: { start, end },
|
|
49
|
+
severity: severityMap[tsDiag.category ?? 1] ?? "error",
|
|
50
|
+
code: tsDiag.code,
|
|
51
|
+
source: "almadar-ts"
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function mapDiagnostics(diagnostics) {
|
|
55
|
+
return diagnostics.filter((d) => d.line >= WRAPPER_LINE_OFFSET).map(mapDiagnostic);
|
|
56
|
+
}
|
|
57
|
+
function cleanTsMessage(message) {
|
|
58
|
+
return message.replace(/_orbital/g, ".orb file").replace(/Type '([^']+)'/g, "Value '$1'");
|
|
59
|
+
}
|
|
60
|
+
var CATEGORY_SCOPES = {
|
|
61
|
+
// Core language
|
|
62
|
+
arithmetic: "keyword.operator.arithmetic.sexpr",
|
|
63
|
+
comparison: "keyword.operator.comparison.sexpr",
|
|
64
|
+
logic: "keyword.operator.logical.sexpr",
|
|
65
|
+
control: "keyword.control.sexpr",
|
|
66
|
+
effect: "keyword.other.effect.sexpr",
|
|
67
|
+
collection: "support.function.collection.sexpr",
|
|
68
|
+
// Standard library
|
|
69
|
+
"std-math": "support.function.math.sexpr",
|
|
70
|
+
"std-str": "support.function.string.sexpr",
|
|
71
|
+
"std-array": "support.function.array.sexpr",
|
|
72
|
+
"std-object": "support.function.object.sexpr",
|
|
73
|
+
"std-time": "support.function.time.sexpr",
|
|
74
|
+
"std-validate": "support.function.validate.sexpr",
|
|
75
|
+
"std-format": "support.function.format.sexpr",
|
|
76
|
+
"std-async": "support.function.async.sexpr",
|
|
77
|
+
"std-nn": "support.function.nn.sexpr",
|
|
78
|
+
"std-tensor": "support.function.tensor.sexpr",
|
|
79
|
+
"std-train": "support.function.train.sexpr"
|
|
80
|
+
};
|
|
81
|
+
function escapeRegex(str) {
|
|
82
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
83
|
+
}
|
|
84
|
+
function groupOperatorsByScope() {
|
|
85
|
+
const groups = /* @__PURE__ */ new Map();
|
|
86
|
+
for (const name of OPERATOR_NAMES) {
|
|
87
|
+
const meta = OPERATORS[name];
|
|
88
|
+
const category = meta?.category ?? "effect";
|
|
89
|
+
const scope = CATEGORY_SCOPES[category] ?? "keyword.other.sexpr";
|
|
90
|
+
if (!groups.has(scope)) groups.set(scope, []);
|
|
91
|
+
groups.get(scope).push(name);
|
|
92
|
+
}
|
|
93
|
+
return groups;
|
|
94
|
+
}
|
|
95
|
+
function generateSExprGrammar() {
|
|
96
|
+
const patterns = [];
|
|
97
|
+
const groups = groupOperatorsByScope();
|
|
98
|
+
for (const [scope, names] of groups) {
|
|
99
|
+
const sorted = [...names].sort((a, b) => b.length - a.length);
|
|
100
|
+
const alternation = sorted.map(escapeRegex).join("|");
|
|
101
|
+
patterns.push({
|
|
102
|
+
name: scope,
|
|
103
|
+
match: `(?<=")(${alternation})(?=")`
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
patterns.push({
|
|
107
|
+
name: "variable.other.binding.sexpr",
|
|
108
|
+
match: '(?<=")@(entity|payload|context|config)\\.[a-zA-Z_][a-zA-Z0-9_.]*(?=")'
|
|
109
|
+
});
|
|
110
|
+
patterns.push({
|
|
111
|
+
name: "constant.other.event.sexpr",
|
|
112
|
+
match: '(?<=")[A-Z][A-Z0-9_]{2,}(?=")'
|
|
113
|
+
});
|
|
114
|
+
patterns.push({
|
|
115
|
+
name: "entity.name.tag.slot.sexpr",
|
|
116
|
+
match: '(?<=")(main|sidebar|modal|drawer|overlay|center|toast|hud-top|hud-bottom|floating|system)(?=")'
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
scopeName: "source.orb.sexpr-injection",
|
|
120
|
+
injectionSelector: "L:source.orb -comment",
|
|
121
|
+
patterns
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function generateSExprGrammarJson() {
|
|
125
|
+
return JSON.stringify(generateSExprGrammar(), null, 2);
|
|
126
|
+
}
|
|
127
|
+
function getOperatorNames() {
|
|
128
|
+
return [...OPERATOR_NAMES];
|
|
129
|
+
}
|
|
130
|
+
function getOperatorsByCategory() {
|
|
131
|
+
const result = {};
|
|
132
|
+
for (const name of OPERATOR_NAMES) {
|
|
133
|
+
const meta = OPERATORS[name];
|
|
134
|
+
const category = meta?.category ?? "unknown";
|
|
135
|
+
if (!result[category]) result[category] = [];
|
|
136
|
+
result[category].push(name);
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export { WRAPPER_COL_OFFSET, WRAPPER_LINE_OFFSET, generateSExprGrammar, generateSExprGrammarJson, getOperatorNames, getOperatorsByCategory, getVirtualPath, mapDiagnostic, mapDiagnostics, mapPositionToOrb, unwrapOrbContent, wrapOrbContent };
|
|
142
|
+
//# sourceMappingURL=index.js.map
|
|
143
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/virtual-document.ts","../src/diagnostic-mapper.ts","../src/sexpr-grammar.ts"],"names":[],"mappings":";;;AAmBA,IAAM,SAAA,GACF,CAAA;AAAA,iBAAA,CAAA;AAMJ,IAAM,SAAA,GAAY,CAAA;AAAA,CAAA;AAYX,IAAM,mBAAA,GAAsB;AAM5B,IAAM,kBAAA,GAAqB;AAmB3B,SAAS,eAAe,UAAA,EAA4B;AACvD,EAAA,OAAO,YAAY,UAAA,GAAa,SAAA;AACpC;AAQO,SAAS,iBAAiB,cAAA,EAAuC;AACpE,EAAA,IAAI,CAAC,cAAA,CAAe,UAAA,CAAW,SAAS,GAAG,OAAO,IAAA;AAClD,EAAA,IAAI,CAAC,cAAA,CAAe,QAAA,CAAS,SAAS,GAAG,OAAO,IAAA;AAEhD,EAAA,OAAO,cAAA,CAAe,KAAA;AAAA,IAClB,SAAA,CAAU,MAAA;AAAA,IACV,cAAA,CAAe,SAAS,SAAA,CAAU;AAAA,GACtC;AACJ;AAcO,SAAS,eAAe,WAAA,EAA6B;AACxD,EAAA,OAAO,WAAA,GAAc,KAAA;AACzB;;;ACVO,SAAS,gBAAA,CACZ,aACA,WAAA,EACQ;AACR,EAAA,MAAM,UAAU,WAAA,GAAc,mBAAA;AAG9B,EAAA,MAAM,OAAA,GACF,YAAY,CAAA,GAAI,IAAA,CAAK,IAAI,CAAA,EAAG,WAAA,GAAc,kBAAkB,CAAA,GAAI,WAAA;AAEpE,EAAA,OAAO;AAAA,IACH,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,CAAA;AAAA,IACzB,SAAA,EAAW,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO;AAAA,GAClC;AACJ;AAQO,SAAS,cAAc,MAAA,EAAqC;AAC/D,EAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,MAAA,CAAO,IAAA,EAAM,OAAO,SAAS,CAAA;AAC5D,EAAA,MAAM,GAAA,GAAM,gBAAA;AAAA,IACR,MAAA,CAAO,WAAW,MAAA,CAAO,IAAA;AAAA,IACzB,MAAA,CAAO,YAAA,IAAgB,MAAA,CAAO,SAAA,GAAY;AAAA,GAC9C;AAEA,EAAA,MAAM,WAAA,GAAkD;AAAA,IACpD,CAAA,EAAG,OAAA;AAAA,IACH,CAAA,EAAG,SAAA;AAAA,IACH,CAAA,EAAG,MAAA;AAAA,IACH,CAAA,EAAG;AAAA,GACP;AAEA,EAAA,OAAO;AAAA,IACH,OAAA,EAAS,cAAA,CAAe,MAAA,CAAO,WAAW,CAAA;AAAA,IAC1C,KAAA,EAAO,EAAE,KAAA,EAAO,GAAA,EAAI;AAAA,IACpB,QAAA,EAAU,WAAA,CAAY,MAAA,CAAO,QAAA,IAAY,CAAC,CAAA,IAAK,OAAA;AAAA,IAC/C,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,MAAA,EAAQ;AAAA,GACZ;AACJ;AASO,SAAS,eAAe,WAAA,EAA8C;AACzE,EAAA,OAAO,WAAA,CACF,OAAO,CAAC,CAAA,KAAM,EAAE,IAAA,IAAQ,mBAAmB,CAAA,CAC3C,GAAA,CAAI,aAAa,CAAA;AAC1B;AAYA,SAAS,eAAe,OAAA,EAAyB;AAC7C,EAAA,OAAO,QACF,OAAA,CAAQ,WAAA,EAAa,WAAW,CAAA,CAChC,OAAA,CAAQ,mBAAmB,YAAc,CAAA;AAClD;AC/GA,IAAM,eAAA,GAA0C;AAAA;AAAA,EAE5C,UAAA,EAAY,mCAAA;AAAA,EACZ,UAAA,EAAY,mCAAA;AAAA,EACZ,KAAA,EAAO,gCAAA;AAAA,EACP,OAAA,EAAS,uBAAA;AAAA,EACT,MAAA,EAAQ,4BAAA;AAAA,EACR,UAAA,EAAY,mCAAA;AAAA;AAAA,EAGZ,UAAA,EAAY,6BAAA;AAAA,EACZ,SAAA,EAAW,+BAAA;AAAA,EACX,WAAA,EAAa,8BAAA;AAAA,EACb,YAAA,EAAc,+BAAA;AAAA,EACd,UAAA,EAAY,6BAAA;AAAA,EACZ,cAAA,EAAgB,iCAAA;AAAA,EAChB,YAAA,EAAc,+BAAA;AAAA,EACd,WAAA,EAAa,8BAAA;AAAA,EACb,QAAA,EAAU,2BAAA;AAAA,EACV,YAAA,EAAc,+BAAA;AAAA,EACd,WAAA,EAAa;AACjB,CAAA;AASA,SAAS,YAAY,GAAA,EAAqB;AACtC,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,qBAAA,EAAuB,MAAM,CAAA;AACpD;AAKA,SAAS,qBAAA,GAA+C;AACpD,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAsB;AAEzC,EAAA,KAAA,MAAW,QAAQ,cAAA,EAAgB;AAC/B,IAAA,MAAM,IAAA,GAAiC,UAAU,IAAI,CAAA;AACrD,IAAA,MAAM,QAAA,GAAW,MAAM,QAAA,IAAY,QAAA;AACnC,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,QAAQ,CAAA,IAAK,qBAAA;AAE3C,IAAA,IAAI,CAAC,OAAO,GAAA,CAAI,KAAK,GAAG,MAAA,CAAO,GAAA,CAAI,KAAA,EAAO,EAAE,CAAA;AAC5C,IAAA,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA,CAAG,IAAA,CAAK,IAAI,CAAA;AAAA,EAChC;AAEA,EAAA,OAAO,MAAA;AACX;AAqBO,SAAS,oBAAA,GAA2C;AACvD,EAAA,MAAM,WAAqB,EAAC;AAG5B,EAAA,MAAM,SAAS,qBAAA,EAAsB;AACrC,EAAA,KAAA,MAAW,CAAC,KAAA,EAAO,KAAK,CAAA,IAAK,MAAA,EAAQ;AAEjC,IAAA,MAAM,MAAA,GAAS,CAAC,GAAG,KAAK,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,MAAA,GAAS,CAAA,CAAE,MAAM,CAAA;AAC5D,IAAA,MAAM,cAAc,MAAA,CAAO,GAAA,CAAI,WAAW,CAAA,CAAE,KAAK,GAAG,CAAA;AAEpD,IAAA,QAAA,CAAS,IAAA,CAAK;AAAA,MACV,IAAA,EAAM,KAAA;AAAA,MACN,KAAA,EAAO,UAAU,WAAW,CAAA,MAAA;AAAA,KAC/B,CAAA;AAAA,EACL;AAGA,EAAA,QAAA,CAAS,IAAA,CAAK;AAAA,IACV,IAAA,EAAM,8BAAA;AAAA,IACN,KAAA,EAAO;AAAA,GACV,CAAA;AAGD,EAAA,QAAA,CAAS,IAAA,CAAK;AAAA,IACV,IAAA,EAAM,4BAAA;AAAA,IACN,KAAA,EAAO;AAAA,GACV,CAAA;AAGD,EAAA,QAAA,CAAS,IAAA,CAAK;AAAA,IACV,IAAA,EAAM,4BAAA;AAAA,IACN,KAAA,EAAO;AAAA,GACV,CAAA;AAED,EAAA,OAAO;AAAA,IACH,SAAA,EAAW,4BAAA;AAAA,IACX,iBAAA,EAAmB,uBAAA;AAAA,IACnB;AAAA,GACJ;AACJ;AAMO,SAAS,wBAAA,GAAmC;AAC/C,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,oBAAA,EAAqB,EAAG,MAAM,CAAC,CAAA;AACzD;AAOO,SAAS,gBAAA,GAA6B;AACzC,EAAA,OAAO,CAAC,GAAG,cAAc,CAAA;AAC7B;AAMO,SAAS,sBAAA,GAAmD;AAC/D,EAAA,MAAM,SAAmC,EAAC;AAE1C,EAAA,KAAA,MAAW,QAAQ,cAAA,EAAgB;AAC/B,IAAA,MAAM,IAAA,GAAiC,UAAU,IAAI,CAAA;AACrD,IAAA,MAAM,QAAA,GAAW,MAAM,QAAA,IAAY,SAAA;AACnC,IAAA,IAAI,CAAC,MAAA,CAAO,QAAQ,GAAG,MAAA,CAAO,QAAQ,IAAI,EAAC;AAC3C,IAAA,MAAA,CAAO,QAAQ,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAAA,EAC9B;AAEA,EAAA,OAAO,MAAA;AACX","file":"index.js","sourcesContent":["/**\n * Virtual Document — The TypeScript Wrapper Trick\n *\n * Wraps .orb JSON content inside a TypeScript file that imports\n * OrbitalSchema from @almadar/core. This lets the TypeScript\n * language server validate the entire .orb structure for free.\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * The TypeScript prefix prepended to .orb content.\n * Line 1: import type\n * Line 2: const declaration with `satisfies` for best error messages\n */\nconst TS_PREFIX =\n `import type { OrbitalSchema } from '@almadar/core';\\n` +\n `const _orbital = `;\n\n/**\n * The TypeScript suffix appended after .orb content.\n */\nconst TS_SUFFIX = ` satisfies OrbitalSchema;\\n`;\n\n/**\n * Number of lines the prefix adds before .orb content begins.\n * Used to offset diagnostics back to original .orb line numbers.\n *\n * The prefix is exactly 2 lines:\n * Line 1: import type { OrbitalSchema } from '@almadar/core';\n * Line 2: const _orbital = ... (the .orb content starts on THIS line)\n *\n * So .orb line 1 corresponds to virtual .ts line 2.\n */\nexport const WRAPPER_LINE_OFFSET = 1;\n\n/**\n * Number of characters on the prefix line before .orb content begins.\n * `const _orbital = ` is 18 characters.\n */\nexport const WRAPPER_COL_OFFSET = 18;\n\n// ============================================================================\n// Core API\n// ============================================================================\n\n/**\n * Wrap raw .orb JSON content into a virtual TypeScript file.\n *\n * @param orbContent - The raw JSON string from the .orb file\n * @returns The complete TypeScript source that tsserver can validate\n *\n * @example\n * ```ts\n * const orbJson = fs.readFileSync('app.orb', 'utf-8');\n * const tsContent = wrapOrbContent(orbJson);\n * // tsContent is now a valid .ts file that TypeScript can check\n * ```\n */\nexport function wrapOrbContent(orbContent: string): string {\n return TS_PREFIX + orbContent + TS_SUFFIX;\n}\n\n/**\n * Extract the original .orb content from a wrapped virtual TypeScript file.\n *\n * @param virtualContent - The virtual .ts file content\n * @returns The original .orb JSON string, or null if not a valid wrapper\n */\nexport function unwrapOrbContent(virtualContent: string): string | null {\n if (!virtualContent.startsWith(TS_PREFIX)) return null;\n if (!virtualContent.endsWith(TS_SUFFIX)) return null;\n\n return virtualContent.slice(\n TS_PREFIX.length,\n virtualContent.length - TS_SUFFIX.length,\n );\n}\n\n/**\n * Generate the virtual .ts filename for a given .orb file path.\n *\n * @param orbFilePath - Absolute path to the .orb file\n * @returns The virtual .ts file path (same directory, `.orb.ts` extension)\n *\n * @example\n * ```ts\n * getVirtualPath('/projects/app.orb')\n * // → '/projects/app.orb.ts'\n * ```\n */\nexport function getVirtualPath(orbFilePath: string): string {\n return orbFilePath + '.ts';\n}\n","/**\n * Diagnostic Mapper\n *\n * Maps TypeScript diagnostics from the virtual .ts file back to\n * the original .orb file positions, adjusting for the wrapper prefix.\n *\n * @packageDocumentation\n */\n\nimport { WRAPPER_LINE_OFFSET, WRAPPER_COL_OFFSET } from './virtual-document.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A position in a text document (0-indexed line and character).\n */\nexport interface Position {\n /** 0-indexed line number */\n line: number;\n /** 0-indexed character offset within the line */\n character: number;\n}\n\n/**\n * A range in a text document.\n */\nexport interface Range {\n start: Position;\n end: Position;\n}\n\n/**\n * Severity levels matching both VSCode and Zed conventions.\n */\nexport type DiagnosticSeverity = 'error' | 'warning' | 'info' | 'hint';\n\n/**\n * An editor-agnostic diagnostic — the universal unit that\n * VSCode and Zed extensions translate into their native format.\n */\nexport interface OrbDiagnostic {\n /** Human-readable error message */\n message: string;\n /** Location in the .orb file (already adjusted from virtual .ts) */\n range: Range;\n /** Severity level */\n severity: DiagnosticSeverity;\n /** TypeScript error code (e.g. 2322, 2353) for filtering */\n code?: number;\n /** Source identifier */\n source: 'almadar-ts';\n}\n\n/**\n * Raw TypeScript diagnostic (minimal shape matching ts.Diagnostic).\n * Extensions should map their TS server output to this shape.\n */\nexport interface TsDiagnostic {\n /** 0-indexed line in the virtual .ts file */\n line: number;\n /** 0-indexed character in the virtual .ts file */\n character: number;\n /** End line (optional, defaults to same as line) */\n endLine?: number;\n /** End character (optional) */\n endCharacter?: number;\n /** Error message text */\n messageText: string;\n /** TS error code */\n code?: number;\n /** 1 = error, 2 = warning, 3 = info, 4 = hint */\n category?: number;\n}\n\n// ============================================================================\n// Core API\n// ============================================================================\n\n/**\n * Map a virtual .ts file position back to the original .orb position.\n *\n * @param virtualLine - 0-indexed line in the virtual .ts file\n * @param virtualChar - 0-indexed character in the virtual .ts file\n * @returns Adjusted position in the .orb file\n */\nexport function mapPositionToOrb(\n virtualLine: number,\n virtualChar: number,\n): Position {\n const orbLine = virtualLine - WRAPPER_LINE_OFFSET;\n\n // If on the same line as the wrapper prefix, adjust column\n const orbChar =\n orbLine === 0 ? Math.max(0, virtualChar - WRAPPER_COL_OFFSET) : virtualChar;\n\n return {\n line: Math.max(0, orbLine),\n character: Math.max(0, orbChar),\n };\n}\n\n/**\n * Map a single TypeScript diagnostic to an OrbDiagnostic.\n *\n * @param tsDiag - The raw TypeScript diagnostic\n * @returns An editor-agnostic diagnostic with adjusted positions\n */\nexport function mapDiagnostic(tsDiag: TsDiagnostic): OrbDiagnostic {\n const start = mapPositionToOrb(tsDiag.line, tsDiag.character);\n const end = mapPositionToOrb(\n tsDiag.endLine ?? tsDiag.line,\n tsDiag.endCharacter ?? tsDiag.character + 1,\n );\n\n const severityMap: Record<number, DiagnosticSeverity> = {\n 1: 'error',\n 2: 'warning',\n 3: 'info',\n 4: 'hint',\n };\n\n return {\n message: cleanTsMessage(tsDiag.messageText),\n range: { start, end },\n severity: severityMap[tsDiag.category ?? 1] ?? 'error',\n code: tsDiag.code,\n source: 'almadar-ts',\n };\n}\n\n/**\n * Map an array of TypeScript diagnostics to OrbDiagnostics.\n * Filters out diagnostics that fall within the wrapper prefix.\n *\n * @param diagnostics - Array of raw TypeScript diagnostics\n * @returns Array of editor-agnostic diagnostics\n */\nexport function mapDiagnostics(diagnostics: TsDiagnostic[]): OrbDiagnostic[] {\n return diagnostics\n .filter((d) => d.line >= WRAPPER_LINE_OFFSET)\n .map(mapDiagnostic);\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Clean up TypeScript error messages for .orb context.\n *\n * - Removes references to `_orbital` variable name\n * - Replaces `OrbitalSchema` with `.orb schema` for clarity\n */\nfunction cleanTsMessage(message: string): string {\n return message\n .replace(/_orbital/g, '.orb file')\n .replace(/Type '([^']+)'/g, 'Value \\'$1\\'');\n}\n","/**\n * S-Expression Grammar Generator\n *\n * Generates a TextMate injection grammar for S-expression syntax\n * highlighting inside .orb files. The grammar is derived from\n * @almadar/operators — the single source of truth for all operator names.\n *\n * This means new operators automatically get highlighting when\n * the package is rebuilt. No manual grammar maintenance.\n *\n * @packageDocumentation\n */\n\nimport {\n OPERATOR_NAMES,\n OPERATORS,\n type OperatorMeta,\n type OperatorCategory,\n} from '@almadar/operators';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * TextMate grammar rule\n */\ninterface TmRule {\n name: string;\n match: string;\n}\n\n/**\n * TextMate injection grammar structure\n */\nexport interface TmInjectionGrammar {\n scopeName: string;\n injectionSelector: string;\n patterns: TmRule[];\n}\n\n// ============================================================================\n// Category → Scope Mapping\n// ============================================================================\n\n/**\n * Maps operator categories to TextMate scopes for semantic coloring.\n */\nconst CATEGORY_SCOPES: Record<string, string> = {\n // Core language\n arithmetic: 'keyword.operator.arithmetic.sexpr',\n comparison: 'keyword.operator.comparison.sexpr',\n logic: 'keyword.operator.logical.sexpr',\n control: 'keyword.control.sexpr',\n effect: 'keyword.other.effect.sexpr',\n collection: 'support.function.collection.sexpr',\n\n // Standard library\n 'std-math': 'support.function.math.sexpr',\n 'std-str': 'support.function.string.sexpr',\n 'std-array': 'support.function.array.sexpr',\n 'std-object': 'support.function.object.sexpr',\n 'std-time': 'support.function.time.sexpr',\n 'std-validate': 'support.function.validate.sexpr',\n 'std-format': 'support.function.format.sexpr',\n 'std-async': 'support.function.async.sexpr',\n 'std-nn': 'support.function.nn.sexpr',\n 'std-tensor': 'support.function.tensor.sexpr',\n 'std-train': 'support.function.train.sexpr',\n};\n\n// ============================================================================\n// Grammar Generation\n// ============================================================================\n\n/**\n * Escape a string for use in a TextMate regex pattern.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Group operator names by their TextMate scope.\n */\nfunction groupOperatorsByScope(): Map<string, string[]> {\n const groups = new Map<string, string[]>();\n\n for (const name of OPERATOR_NAMES) {\n const meta: OperatorMeta | undefined = OPERATORS[name];\n const category = meta?.category ?? 'effect';\n const scope = CATEGORY_SCOPES[category] ?? 'keyword.other.sexpr';\n\n if (!groups.has(scope)) groups.set(scope, []);\n groups.get(scope)!.push(name);\n }\n\n return groups;\n}\n\n/**\n * Generate a TextMate injection grammar for S-expression highlighting.\n *\n * The grammar injects into `.orb` files (JSON scope) and highlights:\n * - **Operators** by category (arithmetic, effect, control, etc.)\n * - **Bindings** (`@entity.field`, `@payload.value`)\n * - **Events** (UPPER_CASE_NAMES)\n *\n * @returns A complete TextMate injection grammar object\n *\n * @example\n * ```ts\n * import { generateSExprGrammar } from '@almadar/extensions';\n * import { writeFileSync } from 'fs';\n *\n * const grammar = generateSExprGrammar();\n * writeFileSync('sexpr.injection.json', JSON.stringify(grammar, null, 2));\n * ```\n */\nexport function generateSExprGrammar(): TmInjectionGrammar {\n const patterns: TmRule[] = [];\n\n // 1. Operator keywords grouped by category/scope\n const groups = groupOperatorsByScope();\n for (const [scope, names] of groups) {\n // Sort by length descending so longer operators match first\n const sorted = [...names].sort((a, b) => b.length - a.length);\n const alternation = sorted.map(escapeRegex).join('|');\n\n patterns.push({\n name: scope,\n match: `(?<=\")(${alternation})(?=\")`,\n });\n }\n\n // 2. Bindings: @entity.field, @payload.value, @context.key\n patterns.push({\n name: 'variable.other.binding.sexpr',\n match: '(?<=\")@(entity|payload|context|config)\\\\.[a-zA-Z_][a-zA-Z0-9_.]*(?=\")',\n });\n\n // 3. Events: UPPER_CASE identifiers (e.g. SELECT_UNIT, ATTACK)\n patterns.push({\n name: 'constant.other.event.sexpr',\n match: '(?<=\")[A-Z][A-Z0-9_]{2,}(?=\")',\n });\n\n // 4. UI Slots: main, sidebar, modal, etc.\n patterns.push({\n name: 'entity.name.tag.slot.sexpr',\n match: '(?<=\")(main|sidebar|modal|drawer|overlay|center|toast|hud-top|hud-bottom|floating|system)(?=\")',\n });\n\n return {\n scopeName: 'source.orb.sexpr-injection',\n injectionSelector: 'L:source.orb -comment',\n patterns,\n };\n}\n\n/**\n * Serialize the grammar to a formatted JSON string.\n * Ready to be written to `sexpr.injection.json`.\n */\nexport function generateSExprGrammarJson(): string {\n return JSON.stringify(generateSExprGrammar(), null, 2);\n}\n\n/**\n * Get a flat list of all operator names from the registry.\n * Useful for editor extensions that need the operator list without\n * importing @almadar/operators directly.\n */\nexport function getOperatorNames(): string[] {\n return [...OPERATOR_NAMES];\n}\n\n/**\n * Get operators grouped by category.\n * Useful for autocomplete that groups suggestions by category.\n */\nexport function getOperatorsByCategory(): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n\n for (const name of OPERATOR_NAMES) {\n const meta: OperatorMeta | undefined = OPERATORS[name];\n const category = meta?.category ?? 'unknown';\n if (!result[category]) result[category] = [];\n result[category].push(name);\n }\n\n return result;\n}\n"]}
|
|
@@ -0,0 +1,74 @@
|
|
|
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
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@almadar/extensions",
|
|
3
|
+
"version": "1.0.13",
|
|
4
|
+
"description": "Editor extension utilities for .orb files — virtual document wrapper and S-expression grammar generator",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@almadar/core": "1.0.13",
|
|
23
|
+
"@almadar/operators": "1.0.13"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"tsup": "^8.0.0",
|
|
27
|
+
"typescript": "^5.4.0"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://github.com/almadar-io/almadar.git",
|
|
32
|
+
"directory": "packages/almadar-extensions"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"keywords": [
|
|
36
|
+
"almadar",
|
|
37
|
+
"orbital",
|
|
38
|
+
"editor",
|
|
39
|
+
"extensions",
|
|
40
|
+
"vscode",
|
|
41
|
+
"zed"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup && pnpm run generate-grammar && pnpm run build:editors",
|
|
45
|
+
"build:core": "tsup && pnpm run generate-grammar",
|
|
46
|
+
"build:watch": "tsup --watch",
|
|
47
|
+
"build:editors": "pnpm run build:lsp && pnpm run build:vscode && pnpm run build:zed",
|
|
48
|
+
"build:vscode": "cd editors/vscode && npm install --ignore-scripts 2>/dev/null; node esbuild.js && cp ../../dist/sexpr.injection.json syntaxes/sexpr.injection.json",
|
|
49
|
+
"build:zed": "mkdir -p editors/zed/syntaxes && cp dist/sexpr.injection.json editors/zed/syntaxes/sexpr.injection.json",
|
|
50
|
+
"build:lsp": "cd lsp && npm install --ignore-scripts 2>/dev/null; npx tsup",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"generate-grammar": "tsx scripts/build-grammars.ts"
|
|
53
|
+
}
|
|
54
|
+
}
|