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.
Files changed (91) hide show
  1. package/CONTEXT.md +594 -0
  2. package/LICENSE +190 -0
  3. package/README.md +220 -0
  4. package/bin/benchmarks.ts +351 -0
  5. package/bin/dev.ts +205 -0
  6. package/bin/docs.js +170 -0
  7. package/bin/install-cursor.sh +71 -0
  8. package/bin/install-vscode.sh +71 -0
  9. package/bin/select-local-models.d.ts +1 -0
  10. package/bin/select-local-models.js +28 -0
  11. package/bin/select-local-models.ts +31 -0
  12. package/demo/autocomplete.test.ts +232 -0
  13. package/demo/docs.json +186 -0
  14. package/demo/examples.test.ts +598 -0
  15. package/demo/index.html +91 -0
  16. package/demo/src/autocomplete.ts +482 -0
  17. package/demo/src/capabilities.ts +859 -0
  18. package/demo/src/demo-nav.ts +2097 -0
  19. package/demo/src/examples.test.ts +161 -0
  20. package/demo/src/examples.ts +476 -0
  21. package/demo/src/imports.test.ts +196 -0
  22. package/demo/src/imports.ts +421 -0
  23. package/demo/src/index.ts +639 -0
  24. package/demo/src/module-store.ts +635 -0
  25. package/demo/src/module-sw.ts +132 -0
  26. package/demo/src/playground.ts +949 -0
  27. package/demo/src/service-host.ts +389 -0
  28. package/demo/src/settings.ts +440 -0
  29. package/demo/src/style.ts +280 -0
  30. package/demo/src/tjs-playground.ts +1605 -0
  31. package/demo/src/ts-examples.ts +478 -0
  32. package/demo/src/ts-playground.ts +1092 -0
  33. package/demo/static/favicon.svg +30 -0
  34. package/demo/static/photo-1.jpg +0 -0
  35. package/demo/static/photo-2.jpg +0 -0
  36. package/demo/static/texts/ai-history.txt +9 -0
  37. package/demo/static/texts/coffee-origins.txt +9 -0
  38. package/demo/static/texts/renewable-energy.txt +9 -0
  39. package/dist/index.js +256 -0
  40. package/dist/index.js.map +37 -0
  41. package/dist/tjs-batteries.js +4 -0
  42. package/dist/tjs-batteries.js.map +15 -0
  43. package/dist/tjs-full.js +256 -0
  44. package/dist/tjs-full.js.map +37 -0
  45. package/dist/tjs-transpiler.js +220 -0
  46. package/dist/tjs-transpiler.js.map +21 -0
  47. package/dist/tjs-vm.js +4 -0
  48. package/dist/tjs-vm.js.map +14 -0
  49. package/docs/CNAME +1 -0
  50. package/docs/favicon.svg +30 -0
  51. package/docs/index.html +91 -0
  52. package/docs/index.js +10468 -0
  53. package/docs/index.js.map +92 -0
  54. package/docs/photo-1.jpg +0 -0
  55. package/docs/photo-1.webp +0 -0
  56. package/docs/photo-2.jpg +0 -0
  57. package/docs/photo-2.webp +0 -0
  58. package/docs/texts/ai-history.txt +9 -0
  59. package/docs/texts/coffee-origins.txt +9 -0
  60. package/docs/texts/renewable-energy.txt +9 -0
  61. package/docs/tjs-lang.svg +31 -0
  62. package/docs/tosijs-agent.svg +31 -0
  63. package/editors/README.md +325 -0
  64. package/editors/ace/ajs-mode.js +328 -0
  65. package/editors/ace/ajs-mode.ts +269 -0
  66. package/editors/ajs-syntax.ts +212 -0
  67. package/editors/build-grammars.ts +510 -0
  68. package/editors/codemirror/ajs-language.js +287 -0
  69. package/editors/codemirror/ajs-language.ts +1447 -0
  70. package/editors/codemirror/autocomplete.test.ts +531 -0
  71. package/editors/codemirror/component.ts +404 -0
  72. package/editors/monaco/ajs-monarch.js +243 -0
  73. package/editors/monaco/ajs-monarch.ts +225 -0
  74. package/editors/tjs-syntax.ts +115 -0
  75. package/editors/vscode/language-configuration.json +37 -0
  76. package/editors/vscode/package.json +65 -0
  77. package/editors/vscode/syntaxes/ajs-injection.tmLanguage.json +107 -0
  78. package/editors/vscode/syntaxes/ajs.tmLanguage.json +252 -0
  79. package/editors/vscode/syntaxes/tjs.tmLanguage.json +333 -0
  80. package/package.json +83 -0
  81. package/src/cli/commands/check.ts +41 -0
  82. package/src/cli/commands/convert.ts +133 -0
  83. package/src/cli/commands/emit.ts +260 -0
  84. package/src/cli/commands/run.ts +68 -0
  85. package/src/cli/commands/test.ts +194 -0
  86. package/src/cli/commands/types.ts +20 -0
  87. package/src/cli/create-app.ts +236 -0
  88. package/src/cli/playground.ts +250 -0
  89. package/src/cli/tjs.ts +166 -0
  90. package/src/cli/tjsx.ts +160 -0
  91. 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
+ }