tjs-lang 0.2.0
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/CONTEXT.md +594 -0
- package/LICENSE +190 -0
- package/README.md +220 -0
- package/bin/benchmarks.ts +351 -0
- package/bin/dev.ts +205 -0
- package/bin/docs.js +170 -0
- package/bin/install-cursor.sh +71 -0
- package/bin/install-vscode.sh +71 -0
- package/bin/select-local-models.d.ts +1 -0
- package/bin/select-local-models.js +28 -0
- package/bin/select-local-models.ts +31 -0
- package/demo/autocomplete.test.ts +232 -0
- package/demo/docs.json +186 -0
- package/demo/examples.test.ts +598 -0
- package/demo/index.html +91 -0
- package/demo/src/autocomplete.ts +482 -0
- package/demo/src/capabilities.ts +859 -0
- package/demo/src/demo-nav.ts +2097 -0
- package/demo/src/examples.test.ts +161 -0
- package/demo/src/examples.ts +476 -0
- package/demo/src/imports.test.ts +196 -0
- package/demo/src/imports.ts +421 -0
- package/demo/src/index.ts +639 -0
- package/demo/src/module-store.ts +635 -0
- package/demo/src/module-sw.ts +132 -0
- package/demo/src/playground.ts +949 -0
- package/demo/src/service-host.ts +389 -0
- package/demo/src/settings.ts +440 -0
- package/demo/src/style.ts +280 -0
- package/demo/src/tjs-playground.ts +1605 -0
- package/demo/src/ts-examples.ts +478 -0
- package/demo/src/ts-playground.ts +1092 -0
- package/demo/static/favicon.svg +30 -0
- package/demo/static/photo-1.jpg +0 -0
- package/demo/static/photo-2.jpg +0 -0
- package/demo/static/texts/ai-history.txt +9 -0
- package/demo/static/texts/coffee-origins.txt +9 -0
- package/demo/static/texts/renewable-energy.txt +9 -0
- package/dist/index.js +256 -0
- package/dist/index.js.map +37 -0
- package/dist/tjs-batteries.js +4 -0
- package/dist/tjs-batteries.js.map +15 -0
- package/dist/tjs-full.js +256 -0
- package/dist/tjs-full.js.map +37 -0
- package/dist/tjs-transpiler.js +220 -0
- package/dist/tjs-transpiler.js.map +21 -0
- package/dist/tjs-vm.js +4 -0
- package/dist/tjs-vm.js.map +14 -0
- package/docs/CNAME +1 -0
- package/docs/favicon.svg +30 -0
- package/docs/index.html +91 -0
- package/docs/index.js +10468 -0
- package/docs/index.js.map +92 -0
- package/docs/photo-1.jpg +0 -0
- package/docs/photo-1.webp +0 -0
- package/docs/photo-2.jpg +0 -0
- package/docs/photo-2.webp +0 -0
- package/docs/texts/ai-history.txt +9 -0
- package/docs/texts/coffee-origins.txt +9 -0
- package/docs/texts/renewable-energy.txt +9 -0
- package/docs/tjs-lang.svg +31 -0
- package/docs/tosijs-agent.svg +31 -0
- package/editors/README.md +325 -0
- package/editors/ace/ajs-mode.js +328 -0
- package/editors/ace/ajs-mode.ts +269 -0
- package/editors/ajs-syntax.ts +212 -0
- package/editors/build-grammars.ts +510 -0
- package/editors/codemirror/ajs-language.js +287 -0
- package/editors/codemirror/ajs-language.ts +1447 -0
- package/editors/codemirror/autocomplete.test.ts +531 -0
- package/editors/codemirror/component.ts +404 -0
- package/editors/monaco/ajs-monarch.js +243 -0
- package/editors/monaco/ajs-monarch.ts +225 -0
- package/editors/tjs-syntax.ts +115 -0
- package/editors/vscode/language-configuration.json +37 -0
- package/editors/vscode/package.json +65 -0
- package/editors/vscode/syntaxes/ajs-injection.tmLanguage.json +107 -0
- package/editors/vscode/syntaxes/ajs.tmLanguage.json +252 -0
- package/editors/vscode/syntaxes/tjs.tmLanguage.json +333 -0
- package/package.json +83 -0
- package/src/cli/commands/check.ts +41 -0
- package/src/cli/commands/convert.ts +133 -0
- package/src/cli/commands/emit.ts +260 -0
- package/src/cli/commands/run.ts +68 -0
- package/src/cli/commands/test.ts +194 -0
- package/src/cli/commands/types.ts +20 -0
- package/src/cli/create-app.ts +236 -0
- package/src/cli/playground.ts +250 -0
- package/src/cli/tjs.ts +166 -0
- package/src/cli/tjsx.ts +160 -0
- package/tjs-lang.svg +31 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeMirror 6 Language Support for AsyncJS (ES Module)
|
|
3
|
+
*
|
|
4
|
+
* Usage with CDN:
|
|
5
|
+
* ```html
|
|
6
|
+
* <script type="module">
|
|
7
|
+
* import { EditorView, basicSetup } from 'https://esm.sh/codemirror'
|
|
8
|
+
* import { EditorState } from 'https://esm.sh/@codemirror/state'
|
|
9
|
+
* import { javascript } from 'https://esm.sh/@codemirror/lang-javascript'
|
|
10
|
+
*
|
|
11
|
+
* // Inline the forbidden keyword highlighter
|
|
12
|
+
* const FORBIDDEN = new Set(['new', 'class', 'async', 'await', 'var', 'this', 'super', 'extends', 'implements', 'interface', 'type', 'yield', 'import', 'export', 'require'])
|
|
13
|
+
*
|
|
14
|
+
* // ... see full example below
|
|
15
|
+
* </script>
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* For a complete working example, see the ajsExtension function below.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { EditorView, Decoration, ViewPlugin } from '@codemirror/view'
|
|
22
|
+
import { RangeSetBuilder } from '@codemirror/state'
|
|
23
|
+
import { javascript } from '@codemirror/lang-javascript'
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Forbidden keywords in AsyncJS
|
|
27
|
+
*/
|
|
28
|
+
export const FORBIDDEN_KEYWORDS = new Set([
|
|
29
|
+
'new',
|
|
30
|
+
'class',
|
|
31
|
+
'async',
|
|
32
|
+
'await',
|
|
33
|
+
'var',
|
|
34
|
+
'this',
|
|
35
|
+
'super',
|
|
36
|
+
'extends',
|
|
37
|
+
'implements',
|
|
38
|
+
'interface',
|
|
39
|
+
'type',
|
|
40
|
+
'yield',
|
|
41
|
+
'import',
|
|
42
|
+
'export',
|
|
43
|
+
'require',
|
|
44
|
+
])
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create the AsyncJS extension for CodeMirror 6
|
|
48
|
+
*
|
|
49
|
+
* This function creates the extension inline since CodeMirror 6's
|
|
50
|
+
* modular architecture makes bundling complex.
|
|
51
|
+
*
|
|
52
|
+
* @param {Object} cm - Object containing CodeMirror imports
|
|
53
|
+
* @param {typeof import('@codemirror/view')} cm.view
|
|
54
|
+
* @param {typeof import('@codemirror/state')} cm.state
|
|
55
|
+
* @param {typeof import('@codemirror/lang-javascript')} cm.langJs
|
|
56
|
+
* @returns {import('@codemirror/state').Extension}
|
|
57
|
+
*/
|
|
58
|
+
export function createAjsExtension({ view, state, langJs }) {
|
|
59
|
+
const { EditorView, Decoration, ViewPlugin } = view
|
|
60
|
+
const { RangeSetBuilder } = state
|
|
61
|
+
const { javascript } = langJs
|
|
62
|
+
|
|
63
|
+
const forbiddenMark = Decoration.mark({ class: 'cm-ajs-forbidden' })
|
|
64
|
+
|
|
65
|
+
const forbiddenHighlighter = ViewPlugin.fromClass(
|
|
66
|
+
class {
|
|
67
|
+
constructor(view) {
|
|
68
|
+
this.decorations = this.buildDecorations(view)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
update(update) {
|
|
72
|
+
if (update.docChanged || update.viewportChanged) {
|
|
73
|
+
this.decorations = this.buildDecorations(update.view)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
buildDecorations(view) {
|
|
78
|
+
const builder = new RangeSetBuilder()
|
|
79
|
+
const doc = view.state.doc.toString()
|
|
80
|
+
const pattern = new RegExp(
|
|
81
|
+
`\\b(${Array.from(FORBIDDEN_KEYWORDS).join('|')})\\b`,
|
|
82
|
+
'g'
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
let match
|
|
86
|
+
while ((match = pattern.exec(doc)) !== null) {
|
|
87
|
+
builder.add(match.index, match.index + match[0].length, forbiddenMark)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return builder.finish()
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{ decorations: (v) => v.decorations }
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
const ajsTheme = EditorView.theme({
|
|
97
|
+
'.cm-ajs-forbidden': {
|
|
98
|
+
color: '#dc2626',
|
|
99
|
+
textDecoration: 'wavy underline #dc2626',
|
|
100
|
+
backgroundColor: 'rgba(220, 38, 38, 0.1)',
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
return [javascript(), forbiddenHighlighter, ajsTheme]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Alias for backwards compatibility
|
|
108
|
+
export { ajsEditorExtension as ajs }
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Minimal CSS for AsyncJS highlighting (can be added to page if theme doesn't work)
|
|
112
|
+
*/
|
|
113
|
+
export const ajsStyles = `
|
|
114
|
+
.cm-ajs-forbidden {
|
|
115
|
+
color: #dc2626 !important;
|
|
116
|
+
text-decoration: wavy underline #dc2626;
|
|
117
|
+
background-color: rgba(220, 38, 38, 0.1);
|
|
118
|
+
}
|
|
119
|
+
`
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Find all string and comment regions in the document
|
|
123
|
+
* Returns array of [start, end] ranges to skip
|
|
124
|
+
*/
|
|
125
|
+
function findSkipRegions(doc) {
|
|
126
|
+
const regions = []
|
|
127
|
+
const len = doc.length
|
|
128
|
+
let i = 0
|
|
129
|
+
|
|
130
|
+
while (i < len) {
|
|
131
|
+
const ch = doc[i]
|
|
132
|
+
const next = doc[i + 1]
|
|
133
|
+
|
|
134
|
+
// Single-line comment
|
|
135
|
+
if (ch === '/' && next === '/') {
|
|
136
|
+
const start = i
|
|
137
|
+
i += 2
|
|
138
|
+
while (i < len && doc[i] !== '\n') i++
|
|
139
|
+
regions.push([start, i])
|
|
140
|
+
continue
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Multi-line comment
|
|
144
|
+
if (ch === '/' && next === '*') {
|
|
145
|
+
const start = i
|
|
146
|
+
i += 2
|
|
147
|
+
while (i < len - 1 && !(doc[i] === '*' && doc[i + 1] === '/')) i++
|
|
148
|
+
i += 2 // skip */
|
|
149
|
+
regions.push([start, i])
|
|
150
|
+
continue
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Template literal - skip string parts but NOT ${...} expressions
|
|
154
|
+
if (ch === '`') {
|
|
155
|
+
let stringStart = i
|
|
156
|
+
i++
|
|
157
|
+
while (i < len) {
|
|
158
|
+
if (doc[i] === '\\') {
|
|
159
|
+
i += 2 // skip escaped char
|
|
160
|
+
continue
|
|
161
|
+
}
|
|
162
|
+
if (doc[i] === '`') {
|
|
163
|
+
// End of template - add final string region
|
|
164
|
+
regions.push([stringStart, i + 1])
|
|
165
|
+
i++
|
|
166
|
+
break
|
|
167
|
+
}
|
|
168
|
+
if (doc[i] === '$' && doc[i + 1] === '{') {
|
|
169
|
+
// Add string region before ${
|
|
170
|
+
regions.push([stringStart, i])
|
|
171
|
+
i += 2 // skip ${
|
|
172
|
+
// Skip the expression inside ${...} (don't add to regions - it's code!)
|
|
173
|
+
let braceDepth = 1
|
|
174
|
+
while (i < len && braceDepth > 0) {
|
|
175
|
+
if (doc[i] === '{') braceDepth++
|
|
176
|
+
else if (doc[i] === '}') braceDepth--
|
|
177
|
+
if (braceDepth > 0) i++
|
|
178
|
+
}
|
|
179
|
+
i++ // skip closing }
|
|
180
|
+
stringStart = i // next string region starts here
|
|
181
|
+
continue
|
|
182
|
+
}
|
|
183
|
+
i++
|
|
184
|
+
}
|
|
185
|
+
continue
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Single or double quoted string
|
|
189
|
+
if (ch === '"' || ch === "'") {
|
|
190
|
+
const quote = ch
|
|
191
|
+
const start = i
|
|
192
|
+
i++
|
|
193
|
+
while (i < len) {
|
|
194
|
+
if (doc[i] === '\\') {
|
|
195
|
+
i += 2 // skip escaped char
|
|
196
|
+
continue
|
|
197
|
+
}
|
|
198
|
+
if (doc[i] === quote) {
|
|
199
|
+
i++
|
|
200
|
+
break
|
|
201
|
+
}
|
|
202
|
+
if (doc[i] === '\n') break // unterminated string
|
|
203
|
+
i++
|
|
204
|
+
}
|
|
205
|
+
regions.push([start, i])
|
|
206
|
+
continue
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
i++
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return regions
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Check if a position is inside any skip region
|
|
217
|
+
*/
|
|
218
|
+
function isInSkipRegion(pos, regions) {
|
|
219
|
+
for (const [start, end] of regions) {
|
|
220
|
+
if (pos >= start && pos < end) return true
|
|
221
|
+
if (start > pos) break // regions are sorted, no need to check further
|
|
222
|
+
}
|
|
223
|
+
return false
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Ready-to-use AsyncJS language extension for CodeMirror 6
|
|
228
|
+
*
|
|
229
|
+
* Returns an array of extensions that provide:
|
|
230
|
+
* - JavaScript syntax highlighting
|
|
231
|
+
* - Red underline highlighting for forbidden keywords (new, class, async, etc.)
|
|
232
|
+
* but NOT inside strings or comments
|
|
233
|
+
*
|
|
234
|
+
* @returns {import('@codemirror/state').Extension[]}
|
|
235
|
+
*/
|
|
236
|
+
export function ajsEditorExtension() {
|
|
237
|
+
const forbiddenMark = Decoration.mark({ class: 'cm-ajs-forbidden' })
|
|
238
|
+
|
|
239
|
+
const forbiddenHighlighter = ViewPlugin.fromClass(
|
|
240
|
+
class {
|
|
241
|
+
constructor(view) {
|
|
242
|
+
this.decorations = this.buildDecorations(view)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
update(update) {
|
|
246
|
+
if (update.docChanged || update.viewportChanged) {
|
|
247
|
+
this.decorations = this.buildDecorations(update.view)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
buildDecorations(view) {
|
|
252
|
+
const builder = new RangeSetBuilder()
|
|
253
|
+
const doc = view.state.doc.toString()
|
|
254
|
+
const skipRegions = findSkipRegions(doc)
|
|
255
|
+
const pattern = new RegExp(
|
|
256
|
+
`\\b(${Array.from(FORBIDDEN_KEYWORDS).join('|')})\\b`,
|
|
257
|
+
'g'
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
let match
|
|
261
|
+
while ((match = pattern.exec(doc)) !== null) {
|
|
262
|
+
// Skip if inside string or comment
|
|
263
|
+
if (!isInSkipRegion(match.index, skipRegions)) {
|
|
264
|
+
builder.add(
|
|
265
|
+
match.index,
|
|
266
|
+
match.index + match[0].length,
|
|
267
|
+
forbiddenMark
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return builder.finish()
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
{ decorations: (v) => v.decorations }
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
const ajsTheme = EditorView.theme({
|
|
279
|
+
'.cm-ajs-forbidden': {
|
|
280
|
+
color: '#dc2626',
|
|
281
|
+
textDecoration: 'wavy underline #dc2626',
|
|
282
|
+
backgroundColor: 'rgba(220, 38, 38, 0.1)',
|
|
283
|
+
},
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
return [javascript(), forbiddenHighlighter, ajsTheme]
|
|
287
|
+
}
|