kimchilang 1.0.1

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 (90) hide show
  1. package/.github/workflows/ci.yml +66 -0
  2. package/README.md +1547 -0
  3. package/create-kimchi-app/README.md +44 -0
  4. package/create-kimchi-app/index.js +214 -0
  5. package/create-kimchi-app/package.json +22 -0
  6. package/editors/README.md +121 -0
  7. package/editors/sublime/KimchiLang.sublime-syntax +138 -0
  8. package/editors/vscode/README.md +90 -0
  9. package/editors/vscode/kimchilang-1.1.0.vsix +0 -0
  10. package/editors/vscode/language-configuration.json +37 -0
  11. package/editors/vscode/package.json +55 -0
  12. package/editors/vscode/src/extension.js +354 -0
  13. package/editors/vscode/syntaxes/kimchi.tmLanguage.json +215 -0
  14. package/examples/api/client.km +36 -0
  15. package/examples/async_pipe.km +58 -0
  16. package/examples/basic.kimchi +109 -0
  17. package/examples/cli_framework/README.md +92 -0
  18. package/examples/cli_framework/calculator.km +61 -0
  19. package/examples/cli_framework/deploy.km +126 -0
  20. package/examples/cli_framework/greeter.km +26 -0
  21. package/examples/config.static +27 -0
  22. package/examples/config.static.js +10 -0
  23. package/examples/env_test.km +37 -0
  24. package/examples/fibonacci.kimchi +17 -0
  25. package/examples/greeter.km +15 -0
  26. package/examples/hello.js +1 -0
  27. package/examples/hello.kimchi +3 -0
  28. package/examples/js_interop.km +42 -0
  29. package/examples/logger_example.km +34 -0
  30. package/examples/memo_fibonacci.km +17 -0
  31. package/examples/myapp/lib/http.js +14 -0
  32. package/examples/myapp/lib/http.km +16 -0
  33. package/examples/myapp/main.km +16 -0
  34. package/examples/myapp/main_with_mock.km +42 -0
  35. package/examples/myapp/services/api.js +18 -0
  36. package/examples/myapp/services/api.km +18 -0
  37. package/examples/new_features.kimchi +52 -0
  38. package/examples/project_example.static +20 -0
  39. package/examples/readme_examples.km +240 -0
  40. package/examples/reduce_pattern_match.km +85 -0
  41. package/examples/regex_match.km +46 -0
  42. package/examples/sample.js +45 -0
  43. package/examples/sample.km +39 -0
  44. package/examples/secrets.static +35 -0
  45. package/examples/secrets.static.js +30 -0
  46. package/examples/shell-example.mjs +144 -0
  47. package/examples/shell_example.km +19 -0
  48. package/examples/stdlib_test.km +22 -0
  49. package/examples/test_example.km +69 -0
  50. package/examples/testing/README.md +88 -0
  51. package/examples/testing/http_client.km +18 -0
  52. package/examples/testing/math.km +48 -0
  53. package/examples/testing/math.test.km +93 -0
  54. package/examples/testing/user_service.km +29 -0
  55. package/examples/testing/user_service.test.km +72 -0
  56. package/examples/use-config.mjs +141 -0
  57. package/examples/use_config.km +13 -0
  58. package/install.sh +59 -0
  59. package/package.json +29 -0
  60. package/pantry/acorn/index.km +1 -0
  61. package/pantry/is_number/index.km +1 -0
  62. package/pantry/is_odd/index.km +2 -0
  63. package/project.static +6 -0
  64. package/src/cli.js +1245 -0
  65. package/src/generator.js +1241 -0
  66. package/src/index.js +141 -0
  67. package/src/js2km.js +568 -0
  68. package/src/lexer.js +822 -0
  69. package/src/linter.js +810 -0
  70. package/src/package-manager.js +307 -0
  71. package/src/parser.js +1876 -0
  72. package/src/static-parser.js +500 -0
  73. package/src/typechecker.js +950 -0
  74. package/stdlib/array.km +0 -0
  75. package/stdlib/bitwise.km +38 -0
  76. package/stdlib/console.km +49 -0
  77. package/stdlib/date.km +97 -0
  78. package/stdlib/function.km +44 -0
  79. package/stdlib/http.km +197 -0
  80. package/stdlib/http.md +333 -0
  81. package/stdlib/index.km +26 -0
  82. package/stdlib/json.km +17 -0
  83. package/stdlib/logger.js +114 -0
  84. package/stdlib/logger.km +104 -0
  85. package/stdlib/math.km +120 -0
  86. package/stdlib/object.km +41 -0
  87. package/stdlib/promise.km +33 -0
  88. package/stdlib/string.km +93 -0
  89. package/stdlib/testing.md +265 -0
  90. package/test/test.js +599 -0
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "kimchilang",
3
+ "displayName": "KimchiLang",
4
+ "description": "Syntax highlighting, error checking, and language support for KimchiLang",
5
+ "version": "1.1.0",
6
+ "publisher": "kimchilang",
7
+ "engines": {
8
+ "vscode": "^1.60.0"
9
+ },
10
+ "categories": [
11
+ "Programming Languages",
12
+ "Linters"
13
+ ],
14
+ "activationEvents": [
15
+ "onLanguage:kimchi"
16
+ ],
17
+ "main": "./src/extension.js",
18
+ "contributes": {
19
+ "languages": [
20
+ {
21
+ "id": "kimchi",
22
+ "aliases": ["KimchiLang", "kimchi"],
23
+ "extensions": [".km", ".kimchi", ".kc", ".static"],
24
+ "configuration": "./language-configuration.json"
25
+ }
26
+ ],
27
+ "grammars": [
28
+ {
29
+ "language": "kimchi",
30
+ "scopeName": "source.kimchi",
31
+ "path": "./syntaxes/kimchi.tmLanguage.json"
32
+ }
33
+ ],
34
+ "configuration": {
35
+ "title": "KimchiLang",
36
+ "properties": {
37
+ "kimchi.validateOnSave": {
38
+ "type": "boolean",
39
+ "default": true,
40
+ "description": "Validate KimchiLang files on save"
41
+ },
42
+ "kimchi.validateOnChange": {
43
+ "type": "boolean",
44
+ "default": true,
45
+ "description": "Validate KimchiLang files as you type"
46
+ }
47
+ }
48
+ }
49
+ },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/kimchilang/kimchilang"
53
+ },
54
+ "license": "MIT"
55
+ }
@@ -0,0 +1,354 @@
1
+ const vscode = require('vscode');
2
+ const path = require('path');
3
+ const { spawn } = require('child_process');
4
+
5
+ let diagnosticCollection;
6
+
7
+ function activate(context) {
8
+ console.log('KimchiLang extension activated');
9
+
10
+ // Create diagnostic collection for showing errors
11
+ diagnosticCollection = vscode.languages.createDiagnosticCollection('kimchi');
12
+ context.subscriptions.push(diagnosticCollection);
13
+
14
+ // Validate on document open
15
+ context.subscriptions.push(
16
+ vscode.workspace.onDidOpenTextDocument(validateDocument)
17
+ );
18
+
19
+ // Validate on document save
20
+ context.subscriptions.push(
21
+ vscode.workspace.onDidSaveTextDocument(validateDocument)
22
+ );
23
+
24
+ // Validate on document change (with debounce)
25
+ let timeout;
26
+ context.subscriptions.push(
27
+ vscode.workspace.onDidChangeTextDocument(event => {
28
+ clearTimeout(timeout);
29
+ timeout = setTimeout(() => validateDocument(event.document), 500);
30
+ })
31
+ );
32
+
33
+ // Validate all open kimchi documents on activation
34
+ vscode.workspace.textDocuments.forEach(validateDocument);
35
+ }
36
+
37
+ function deactivate() {
38
+ if (diagnosticCollection) {
39
+ diagnosticCollection.dispose();
40
+ }
41
+ }
42
+
43
+ async function validateDocument(document) {
44
+ // Only validate kimchi files
45
+ if (!isKimchiFile(document)) {
46
+ return;
47
+ }
48
+
49
+ const text = document.getText();
50
+ const uri = document.uri;
51
+
52
+ try {
53
+ const errors = await runKimchiCheck(text, document.fileName);
54
+ const diagnostics = errors.map(error => createDiagnostic(error, document));
55
+ diagnosticCollection.set(uri, diagnostics);
56
+ } catch (err) {
57
+ console.error('KimchiLang validation error:', err);
58
+ }
59
+ }
60
+
61
+ function isKimchiFile(document) {
62
+ const ext = path.extname(document.fileName);
63
+ return ['.km', '.kimchi', '.kc', '.static'].includes(ext);
64
+ }
65
+
66
+ async function runKimchiCheck(source, filePath) {
67
+ return new Promise((resolve) => {
68
+ // Try to find kimchi CLI
69
+ const kimchiPath = findKimchiCli(filePath);
70
+
71
+ if (!kimchiPath) {
72
+ // Fall back to inline validation
73
+ resolve(validateInline(source, filePath));
74
+ return;
75
+ }
76
+
77
+ // Write source to a temp file for the check command
78
+ const fs = require('fs');
79
+ const os = require('os');
80
+ const tempFile = path.join(os.tmpdir(), `kimchi_check_${Date.now()}.km`);
81
+
82
+ try {
83
+ fs.writeFileSync(tempFile, source);
84
+ } catch (err) {
85
+ resolve(validateInline(source, filePath));
86
+ return;
87
+ }
88
+
89
+ // Run: node src/cli.js check <tempfile>
90
+ const proc = spawn('node', [kimchiPath, 'check', tempFile], {
91
+ cwd: path.dirname(kimchiPath).replace(/\/src$/, ''),
92
+ env: { ...process.env },
93
+ });
94
+
95
+ let stdout = '';
96
+ let stderr = '';
97
+
98
+ proc.stdout.on('data', (data) => {
99
+ stdout += data.toString();
100
+ });
101
+
102
+ proc.stderr.on('data', (data) => {
103
+ stderr += data.toString();
104
+ });
105
+
106
+ proc.on('close', (code) => {
107
+ // Clean up temp file
108
+ try { fs.unlinkSync(tempFile); } catch {}
109
+
110
+ const output = stdout + stderr;
111
+ if (output) {
112
+ try {
113
+ const result = JSON.parse(output);
114
+ resolve(result.errors || result || []);
115
+ } catch {
116
+ resolve(parseErrorOutput(output));
117
+ }
118
+ } else {
119
+ resolve([]);
120
+ }
121
+ });
122
+
123
+ proc.on('error', () => {
124
+ try { fs.unlinkSync(tempFile); } catch {}
125
+ resolve(validateInline(source, filePath));
126
+ });
127
+ });
128
+ }
129
+
130
+ function findKimchiCli(filePath) {
131
+ const fs = require('fs');
132
+ const workspaceFolder = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(filePath));
133
+
134
+ if (workspaceFolder) {
135
+ const wsPath = workspaceFolder.uri.fsPath;
136
+
137
+ // Try src/cli.js (KimchiLang project structure)
138
+ const srcCli = path.join(wsPath, 'src', 'cli.js');
139
+ if (fs.existsSync(srcCli)) {
140
+ return srcCli;
141
+ }
142
+
143
+ // Try node_modules/.bin/kimchi
144
+ const localKimchi = path.join(wsPath, 'node_modules', '.bin', 'kimchi');
145
+ if (fs.existsSync(localKimchi)) {
146
+ return localKimchi;
147
+ }
148
+ }
149
+
150
+ // Try global kimchi
151
+ return null;
152
+ }
153
+
154
+ function validateInline(source, filePath) {
155
+ const errors = [];
156
+
157
+ // Try to import the compiler modules
158
+ try {
159
+ // Look for the compiler in the workspace
160
+ const workspaceFolder = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(filePath));
161
+ let compilerPath;
162
+
163
+ if (workspaceFolder) {
164
+ compilerPath = path.join(workspaceFolder.uri.fsPath, 'src', 'index.js');
165
+ }
166
+
167
+ // This is a simplified inline check - parse errors only
168
+ // For full validation, the CLI should be used
169
+ const lines = source.split('\n');
170
+
171
+ // Check for common syntax issues
172
+ let braceCount = 0;
173
+ let bracketCount = 0;
174
+ let parenCount = 0;
175
+ let inString = false;
176
+ let stringChar = '';
177
+
178
+ for (let lineNum = 0; lineNum < lines.length; lineNum++) {
179
+ const line = lines[lineNum];
180
+
181
+ for (let col = 0; col < line.length; col++) {
182
+ const char = line[col];
183
+ const prevChar = col > 0 ? line[col - 1] : '';
184
+
185
+ // Track string state
186
+ if ((char === '"' || char === "'" || char === '`') && prevChar !== '\\') {
187
+ if (!inString) {
188
+ inString = true;
189
+ stringChar = char;
190
+ } else if (char === stringChar) {
191
+ inString = false;
192
+ stringChar = '';
193
+ }
194
+ }
195
+
196
+ if (!inString) {
197
+ if (char === '{') braceCount++;
198
+ if (char === '}') braceCount--;
199
+ if (char === '[') bracketCount++;
200
+ if (char === ']') bracketCount--;
201
+ if (char === '(') parenCount++;
202
+ if (char === ')') parenCount--;
203
+
204
+ // Check for unbalanced closing
205
+ if (braceCount < 0) {
206
+ errors.push({
207
+ line: lineNum + 1,
208
+ column: col + 1,
209
+ message: 'Unexpected closing brace }',
210
+ });
211
+ braceCount = 0;
212
+ }
213
+ if (bracketCount < 0) {
214
+ errors.push({
215
+ line: lineNum + 1,
216
+ column: col + 1,
217
+ message: 'Unexpected closing bracket ]',
218
+ });
219
+ bracketCount = 0;
220
+ }
221
+ if (parenCount < 0) {
222
+ errors.push({
223
+ line: lineNum + 1,
224
+ column: col + 1,
225
+ message: 'Unexpected closing parenthesis )',
226
+ });
227
+ parenCount = 0;
228
+ }
229
+ }
230
+ }
231
+
232
+ // Check for unclosed string on line
233
+ if (inString && stringChar !== '`') {
234
+ errors.push({
235
+ line: lineNum + 1,
236
+ column: line.length,
237
+ message: `Unclosed string literal`,
238
+ });
239
+ inString = false;
240
+ stringChar = '';
241
+ }
242
+ }
243
+
244
+ // Check for unclosed braces at end
245
+ if (braceCount > 0) {
246
+ errors.push({
247
+ line: lines.length,
248
+ column: 1,
249
+ message: `Unclosed brace: ${braceCount} opening { without matching }`,
250
+ });
251
+ }
252
+ if (bracketCount > 0) {
253
+ errors.push({
254
+ line: lines.length,
255
+ column: 1,
256
+ message: `Unclosed bracket: ${bracketCount} opening [ without matching ]`,
257
+ });
258
+ }
259
+ if (parenCount > 0) {
260
+ errors.push({
261
+ line: lines.length,
262
+ column: 1,
263
+ message: `Unclosed parenthesis: ${parenCount} opening ( without matching )`,
264
+ });
265
+ }
266
+
267
+ } catch (err) {
268
+ // Ignore import errors
269
+ }
270
+
271
+ return errors;
272
+ }
273
+
274
+ function parseErrorOutput(output) {
275
+ const errors = [];
276
+
277
+ if (!output) return errors;
278
+
279
+ // Parse error messages in various formats
280
+ // Format 1: "Error at line:column: message"
281
+ // Format 2: "Parse Error at line:column: message"
282
+ // Format 3: "Type Error: message"
283
+ // Format 4: "Lint Error [rule]: message"
284
+
285
+ const patterns = [
286
+ /(?:Parse |Lexer |Type |Compile |Lint )?Error(?: \[[\w-]+\])? at (\d+):(\d+):\s*(.+)/gi,
287
+ /(\d+):(\d+):\s*(?:error|Error):\s*(.+)/gi,
288
+ /line (\d+)(?:, column (\d+))?:\s*(.+)/gi,
289
+ ];
290
+
291
+ for (const pattern of patterns) {
292
+ let match;
293
+ while ((match = pattern.exec(output)) !== null) {
294
+ errors.push({
295
+ line: parseInt(match[1], 10),
296
+ column: parseInt(match[2], 10) || 1,
297
+ message: match[3].trim(),
298
+ });
299
+ }
300
+ }
301
+
302
+ // If no structured errors found, treat the whole output as an error
303
+ if (errors.length === 0 && output.trim()) {
304
+ const lines = output.trim().split('\n');
305
+ for (const line of lines) {
306
+ if (line.includes('Error') || line.includes('error')) {
307
+ errors.push({
308
+ line: 1,
309
+ column: 1,
310
+ message: line.trim(),
311
+ });
312
+ }
313
+ }
314
+ }
315
+
316
+ return errors;
317
+ }
318
+
319
+ function createDiagnostic(error, document) {
320
+ const line = Math.max(0, (error.line || 1) - 1);
321
+ const column = Math.max(0, (error.column || 1) - 1);
322
+
323
+ // Get the line text to determine range
324
+ let endColumn = column;
325
+ try {
326
+ const lineText = document.lineAt(line).text;
327
+ // Highlight to end of word or rest of line
328
+ const restOfLine = lineText.substring(column);
329
+ const wordMatch = restOfLine.match(/^\w+/);
330
+ if (wordMatch) {
331
+ endColumn = column + wordMatch[0].length;
332
+ } else {
333
+ endColumn = Math.min(column + 10, lineText.length);
334
+ }
335
+ } catch {
336
+ endColumn = column + 1;
337
+ }
338
+
339
+ const range = new vscode.Range(line, column, line, endColumn);
340
+
341
+ const severity = error.severity === 'warning'
342
+ ? vscode.DiagnosticSeverity.Warning
343
+ : vscode.DiagnosticSeverity.Error;
344
+
345
+ const diagnostic = new vscode.Diagnostic(range, error.message, severity);
346
+ diagnostic.source = 'kimchi';
347
+
348
+ return diagnostic;
349
+ }
350
+
351
+ module.exports = {
352
+ activate,
353
+ deactivate,
354
+ };
@@ -0,0 +1,215 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
3
+ "name": "KimchiLang",
4
+ "scopeName": "source.kimchi",
5
+ "patterns": [
6
+ { "include": "#comments" },
7
+ { "include": "#strings" },
8
+ { "include": "#numbers" },
9
+ { "include": "#keywords" },
10
+ { "include": "#storage" },
11
+ { "include": "#constants" },
12
+ { "include": "#operators" },
13
+ { "include": "#functions" },
14
+ { "include": "#pattern-matching" },
15
+ { "include": "#identifiers" }
16
+ ],
17
+ "repository": {
18
+ "comments": {
19
+ "patterns": [
20
+ {
21
+ "name": "comment.line.double-slash.kimchi",
22
+ "match": "//.*$"
23
+ },
24
+ {
25
+ "name": "comment.block.kimchi",
26
+ "begin": "/\\*",
27
+ "end": "\\*/"
28
+ }
29
+ ]
30
+ },
31
+ "strings": {
32
+ "patterns": [
33
+ {
34
+ "name": "string.quoted.double.kimchi",
35
+ "begin": "\"",
36
+ "end": "\"",
37
+ "patterns": [
38
+ {
39
+ "name": "constant.character.escape.kimchi",
40
+ "match": "\\\\."
41
+ }
42
+ ]
43
+ },
44
+ {
45
+ "name": "string.quoted.single.kimchi",
46
+ "begin": "'",
47
+ "end": "'",
48
+ "patterns": [
49
+ {
50
+ "name": "constant.character.escape.kimchi",
51
+ "match": "\\\\."
52
+ }
53
+ ]
54
+ },
55
+ {
56
+ "name": "string.template.kimchi",
57
+ "begin": "`",
58
+ "end": "`",
59
+ "patterns": [
60
+ {
61
+ "name": "constant.character.escape.kimchi",
62
+ "match": "\\\\."
63
+ },
64
+ {
65
+ "name": "variable.other.template.kimchi",
66
+ "begin": "\\$\\{",
67
+ "end": "\\}"
68
+ }
69
+ ]
70
+ }
71
+ ]
72
+ },
73
+ "numbers": {
74
+ "patterns": [
75
+ {
76
+ "name": "constant.numeric.float.kimchi",
77
+ "match": "\\b\\d+\\.\\d+\\b"
78
+ },
79
+ {
80
+ "name": "constant.numeric.integer.kimchi",
81
+ "match": "\\b\\d+\\b"
82
+ },
83
+ {
84
+ "name": "constant.numeric.hex.kimchi",
85
+ "match": "\\b0x[0-9a-fA-F]+\\b"
86
+ }
87
+ ]
88
+ },
89
+ "keywords": {
90
+ "patterns": [
91
+ {
92
+ "name": "keyword.control.kimchi",
93
+ "match": "\\b(if|else|for|while|return|try|catch|throw|in|await|async|break|continue)\\b"
94
+ },
95
+ {
96
+ "name": "keyword.other.kimchi",
97
+ "match": "\\b(dep|arg|expose|print|new|shell|js|test|describe|expect|assert|secret|env|enum|is)\\b"
98
+ },
99
+ {
100
+ "name": "keyword.operator.logical.kimchi",
101
+ "match": "\\b(and|or|not)\\b"
102
+ }
103
+ ]
104
+ },
105
+ "storage": {
106
+ "patterns": [
107
+ {
108
+ "name": "storage.type.kimchi",
109
+ "match": "\\b(fn|memo|dec|as|var)\\b"
110
+ },
111
+ {
112
+ "name": "storage.modifier.kimchi",
113
+ "match": "\\b(expose)\\b"
114
+ }
115
+ ]
116
+ },
117
+ "constants": {
118
+ "patterns": [
119
+ {
120
+ "name": "constant.language.boolean.kimchi",
121
+ "match": "\\b(true|false)\\b"
122
+ },
123
+ {
124
+ "name": "constant.language.null.kimchi",
125
+ "match": "\\b(null|undefined)\\b"
126
+ }
127
+ ]
128
+ },
129
+ "operators": {
130
+ "patterns": [
131
+ {
132
+ "name": "keyword.operator.arrow.kimchi",
133
+ "match": "=>"
134
+ },
135
+ {
136
+ "name": "keyword.operator.flow.kimchi",
137
+ "match": "\\|>"
138
+ },
139
+ {
140
+ "name": "keyword.operator.range.kimchi",
141
+ "match": "\\.\\."
142
+ },
143
+ {
144
+ "name": "keyword.operator.spread.kimchi",
145
+ "match": "\\.\\.\\."
146
+ },
147
+ {
148
+ "name": "keyword.operator.comparison.kimchi",
149
+ "match": "(===|!==|==|!=|<=|>=|<|>)"
150
+ },
151
+ {
152
+ "name": "keyword.operator.assignment.kimchi",
153
+ "match": "="
154
+ },
155
+ {
156
+ "name": "keyword.operator.arithmetic.kimchi",
157
+ "match": "(\\+|-|\\*|/|%)"
158
+ },
159
+ {
160
+ "name": "keyword.operator.logical.kimchi",
161
+ "match": "(&&|\\|\\||!)"
162
+ }
163
+ ]
164
+ },
165
+ "functions": {
166
+ "patterns": [
167
+ {
168
+ "name": "entity.name.function.kimchi",
169
+ "match": "\\b(fn)\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\(",
170
+ "captures": {
171
+ "1": { "name": "storage.type.function.kimchi" },
172
+ "2": { "name": "entity.name.function.kimchi" }
173
+ }
174
+ },
175
+ {
176
+ "name": "meta.function-call.kimchi",
177
+ "match": "\\b([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\(",
178
+ "captures": {
179
+ "1": { "name": "entity.name.function.kimchi" }
180
+ }
181
+ }
182
+ ]
183
+ },
184
+ "pattern-matching": {
185
+ "patterns": [
186
+ {
187
+ "name": "meta.pattern-match.kimchi",
188
+ "begin": "\\|(?!>)",
189
+ "end": "\\|\\s*=>",
190
+ "beginCaptures": {
191
+ "0": { "name": "punctuation.definition.pattern.begin.kimchi" }
192
+ },
193
+ "endCaptures": {
194
+ "0": { "name": "punctuation.definition.pattern.end.kimchi" }
195
+ },
196
+ "patterns": [
197
+ { "include": "#strings" },
198
+ { "include": "#numbers" },
199
+ { "include": "#constants" },
200
+ { "include": "#operators" },
201
+ { "include": "#identifiers" }
202
+ ]
203
+ }
204
+ ]
205
+ },
206
+ "identifiers": {
207
+ "patterns": [
208
+ {
209
+ "name": "variable.other.kimchi",
210
+ "match": "\\b[a-zA-Z_][a-zA-Z0-9_]*\\b"
211
+ }
212
+ ]
213
+ }
214
+ }
215
+ }
@@ -0,0 +1,36 @@
1
+ // Example API client module with args and help functions
2
+
3
+ !arg clientId
4
+ arg timeout = 5000
5
+
6
+ as http dep pantry.axios
7
+
8
+ expose fn _describe() {
9
+ return "API client for connecting to external services"
10
+ }
11
+
12
+ expose fn _help() {
13
+ return "
14
+ This module provides HTTP client functionality.
15
+
16
+ Example:
17
+ kimchi api.client --client-id YOUR_ID
18
+
19
+ The client will authenticate and make requests on your behalf.
20
+ "
21
+ }
22
+
23
+ expose fn connect() {
24
+ print "Connecting with client ID: ${clientId}"
25
+ print "Timeout: ${timeout}ms"
26
+ return { connected: true, clientId: clientId }
27
+ }
28
+
29
+ expose fn get(url) {
30
+ print "GET ${url}"
31
+ return { status: 200, data: "response" }
32
+ }
33
+
34
+ // Run on module load
35
+ print "API Client initialized"
36
+ connect()