karma-lang 0.1.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/karma-ai.js ADDED
@@ -0,0 +1,454 @@
1
+ // Karma — AI prompt processor (v1.0)
2
+ // Extracts and processes embedded AI prompts with full grammar context
3
+ // Usage: node karma-ai.js file.karma [--execute] [--model gpt-4]
4
+
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import { fileURLToPath } from "url";
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+
12
+ const arg = process.argv[2];
13
+ const execute = process.argv.includes("--execute");
14
+ const model = process.argv.includes("--model")
15
+ ? process.argv[process.argv.indexOf("--model") + 1]
16
+ : "gpt-4";
17
+
18
+ if (!arg) {
19
+ console.error('Usage: node karma-ai.js <file.karma> [--execute] [--model gpt-4]');
20
+ process.exit(1);
21
+ }
22
+
23
+ // ========== KARMA GRAMMAR SCHEMA ==========
24
+ // This defines all valid Karma constructs for AI context
25
+ const KARMA_GRAMMAR = {
26
+ description: "Karma Language v1.7 - Schema for static page markup",
27
+
28
+ // Tag definitions with grammar rules
29
+ tags: {
30
+ PAGE: {
31
+ type: "container",
32
+ description: "Root page container (required)",
33
+ attributes: {
34
+ TITLE: { type: "string", required: true, description: "Page title" },
35
+ LAYOUT: { type: "string", required: false, description: "Layout template name" },
36
+ BRAND: { type: "string", required: false, description: "Brand name for layout" },
37
+ TAGLINE: { type: "string", required: false, description: "Short tagline" }
38
+ },
39
+ children: "any tag",
40
+ example: '<PAGE TITLE="My Site"><HEADING TEXT="Welcome" LEVEL="1" /></PAGE>'
41
+ },
42
+
43
+ HEADING: {
44
+ type: "inline",
45
+ description: "Semantic heading (H1-H6)",
46
+ attributes: {
47
+ TEXT: { type: "string", required: true, description: "Heading content" },
48
+ LEVEL: { type: "number", min: 1, max: 6, default: 2, description: "Heading level" },
49
+ SIZE: { type: "enum", values: ["large"], required: false, description: "Size variant" }
50
+ },
51
+ selfClosing: true,
52
+ example: '<HEADING TEXT="Title" LEVEL="1" />'
53
+ },
54
+
55
+ PARA: {
56
+ type: "inline",
57
+ description: "Paragraph text block",
58
+ attributes: {
59
+ TEXT: { type: "string", required: true, description: "Paragraph content" }
60
+ },
61
+ selfClosing: true,
62
+ example: '<PARA TEXT="Your content here" />'
63
+ },
64
+
65
+ IMAGE: {
66
+ type: "block",
67
+ description: "Image display with variants",
68
+ attributes: {
69
+ SRC: { type: "string", required: true, description: "Image URL" },
70
+ ALT: { type: "string", required: false, description: "Alt text" },
71
+ TITLE: { type: "string", required: false, description: "Image title" },
72
+ CAPTION: { type: "string", required: false, description: "Caption text" },
73
+ VARIANT: { type: "enum", values: ["card", "split", "hero"], default: "card", description: "Display variant" },
74
+ POSITION: { type: "enum", values: ["left", "right"], default: "left", description: "Image position" },
75
+ LINK: { type: "string", required: false, description: "Click destination" }
76
+ },
77
+ selfClosing: true,
78
+ example: '<IMAGE SRC="photo.jpg" ALT="Description" VARIANT="hero" />'
79
+ },
80
+
81
+ VIDEO: {
82
+ type: "block",
83
+ description: "Video embedding (local or URL)",
84
+ attributes: {
85
+ SRC: { type: "string", required: false, description: "Local video file path" },
86
+ URL: { type: "string", required: false, description: "Embed URL (YouTube, etc)" },
87
+ TITLE: { type: "string", required: false, description: "Video title" }
88
+ },
89
+ selfClosing: true,
90
+ example: '<VIDEO SRC="video.mp4" TITLE="Demo" />'
91
+ },
92
+
93
+ SECTION: {
94
+ type: "container",
95
+ description: "Content section with background",
96
+ attributes: {
97
+ TITLE: { type: "string", required: false, description: "Section heading" },
98
+ BG: { type: "enum", values: ["default", "dark", "light"], default: "default", description: "Background style" },
99
+ PADDING: { type: "css", required: false, description: "Padding (CSS value)" }
100
+ },
101
+ children: "any tag",
102
+ example: '<SECTION TITLE="Features" BG="dark"><PARA TEXT="Content" /></SECTION>'
103
+ },
104
+
105
+ GRID: {
106
+ type: "layout",
107
+ description: "Multi-column responsive grid",
108
+ attributes: {
109
+ COLS: { type: "number", min: 1, max: 4, default: 2, description: "Number of columns" },
110
+ GAP: { type: "css", default: "14px", description: "Column gap (CSS value)" }
111
+ },
112
+ children: "any block element",
113
+ responsive: "auto-stacks to 1 column on mobile",
114
+ example: '<GRID COLS="3"><Card>Item 1</Card><Card>Item 2</Card></GRID>'
115
+ },
116
+
117
+ HEADING: {
118
+ type: "text",
119
+ description: "Semantic heading",
120
+ attributes: {
121
+ TEXT: { type: "string", required: true },
122
+ LEVEL: { type: "number", min: 1, max: 6, default: 2 },
123
+ SIZE: { type: "enum", values: ["large"] }
124
+ },
125
+ selfClosing: true
126
+ },
127
+
128
+ BADGE: {
129
+ type: "inline",
130
+ description: "Status badge/label",
131
+ attributes: {
132
+ TEXT: { type: "string", required: true, description: "Badge text" },
133
+ TYPE: { type: "enum", values: ["default", "success", "warning", "error"], default: "default", description: "Badge style" }
134
+ },
135
+ selfClosing: true,
136
+ example: '<BADGE TEXT="New" TYPE="success" />'
137
+ },
138
+
139
+ TAGS: {
140
+ type: "inline",
141
+ description: "Display multiple tags",
142
+ attributes: {
143
+ LIST: { type: "csv", required: false, description: "Comma-separated tag names" }
144
+ },
145
+ selfClosing: true,
146
+ example: '<TAGS LIST="javascript, react, web" />'
147
+ },
148
+
149
+ ALERT: {
150
+ type: "block",
151
+ description: "Highlighted message box",
152
+ attributes: {
153
+ TEXT: { type: "string", required: true, description: "Alert message" },
154
+ TYPE: { type: "enum", values: ["info", "success", "warning", "error"], default: "info", description: "Alert type" }
155
+ },
156
+ selfClosing: true,
157
+ example: '<ALERT TEXT="Warning!" TYPE="warning" />'
158
+ },
159
+
160
+ CODE: {
161
+ type: "block",
162
+ description: "Code snippet display",
163
+ attributes: {
164
+ TEXT: { type: "string", required: true, description: "Code content" },
165
+ LANG: { type: "enum", values: ["javascript", "bash", "html", "css", "python", "plaintext"], default: "plaintext", description: "Language" },
166
+ TITLE: { type: "string", required: false, description: "Code block title" }
167
+ },
168
+ selfClosing: true,
169
+ example: '<CODE TEXT="console.log(\'hi\');" LANG="javascript" />'
170
+ },
171
+
172
+ COLLAPSE: {
173
+ type: "container",
174
+ description: "Expandable/collapsible section",
175
+ attributes: {
176
+ TITLE: { type: "string", required: true, description: "Collapse header" },
177
+ OPEN: { type: "boolean", default: false, description: "Initially open?" }
178
+ },
179
+ children: "any tag",
180
+ example: '<COLLAPSE TITLE="Details"><PARA TEXT="Hidden content" /></COLLAPSE>'
181
+ },
182
+
183
+ TIMELINE: {
184
+ type: "container",
185
+ description: "Timeline container",
186
+ attributes: {
187
+ TITLE: { type: "string", required: false, description: "Timeline title" }
188
+ },
189
+ children: ["TIMELINE-ITEM"],
190
+ example: '<TIMELINE TITLE="History"><TIMELINE-ITEM DATE="Jan" TITLE="Event" /></TIMELINE>'
191
+ },
192
+
193
+ "TIMELINE-ITEM": {
194
+ type: "block",
195
+ description: "Individual timeline entry",
196
+ attributes: {
197
+ DATE: { type: "string", required: false, description: "Date/time period" },
198
+ TITLE: { type: "string", required: true, description: "Event name" },
199
+ TEXT: { type: "string", required: false, description: "Event description" }
200
+ },
201
+ selfClosing: true,
202
+ parent: "TIMELINE"
203
+ },
204
+
205
+ STAT: {
206
+ type: "block",
207
+ description: "Dashboard statistic box",
208
+ attributes: {
209
+ VALUE: { type: "string", required: true, description: "Stat value" },
210
+ LABEL: { type: "string", required: true, description: "Stat label" },
211
+ ICON: { type: "emoji", required: false, description: "Optional emoji icon" }
212
+ },
213
+ selfClosing: true,
214
+ example: '<STAT VALUE="1,234" LABEL="Users" ICON="šŸ‘„" />'
215
+ },
216
+
217
+ QUOTE: {
218
+ type: "block",
219
+ description: "Blockquote with attribution",
220
+ attributes: {
221
+ TEXT: { type: "string", required: true, description: "Quote text" },
222
+ AUTHOR: { type: "string", required: false, description: "Quote author" },
223
+ ROLE: { type: "string", required: false, description: "Author role" }
224
+ },
225
+ selfClosing: true,
226
+ example: '<QUOTE TEXT="Be yourself." AUTHOR="Oscar Wilde" ROLE="Writer" />'
227
+ },
228
+
229
+ PROGRESS: {
230
+ type: "block",
231
+ description: "Progress bar indicator",
232
+ attributes: {
233
+ VALUE: { type: "number", min: 0, max: 100, default: 50, description: "Progress percentage" },
234
+ LABEL: { type: "string", required: false, description: "Label text" },
235
+ COLOR: { type: "enum", values: ["blue", "green", "red"], default: "blue", description: "Bar color" }
236
+ },
237
+ selfClosing: true,
238
+ example: '<PROGRESS VALUE="75" LABEL="75% Complete" COLOR="blue" />'
239
+ },
240
+
241
+ NAV: {
242
+ type: "block",
243
+ description: "Navigation menu",
244
+ attributes: {
245
+ LINKS: { type: "string", required: false, description: "Links as 'Label:URL' pairs" },
246
+ TITLE: { type: "string", required: false, description: "Menu title" },
247
+ TYPE: { type: "enum", values: ["bar"], default: "bar", description: "Menu style" },
248
+ POSITION: { type: "enum", values: ["top"], default: "top", description: "Menu position" }
249
+ },
250
+ selfClosing: true,
251
+ example: '<NAV LINKS="Home:index.karma, About:about.karma" />'
252
+ },
253
+
254
+ LINK: {
255
+ type: "inline",
256
+ description: "Button/hyperlink",
257
+ attributes: {
258
+ TEXT: { type: "string", required: true, description: "Link text" },
259
+ HREF: { type: "string", required: true, description: "Link URL (.karma → .html auto-converts)" },
260
+ VARIANT: { type: "enum", values: ["primary", "secondary"], default: "primary", description: "Button style" }
261
+ },
262
+ selfClosing: true,
263
+ example: '<LINK TEXT="Click Me" HREF="page.karma" VARIANT="primary" />'
264
+ },
265
+
266
+ EMAIL: {
267
+ type: "inline",
268
+ description: "Email link",
269
+ attributes: {
270
+ TO: { type: "email", required: true, description: "Email address" },
271
+ TEXT: { type: "string", required: false, description: "Link text" },
272
+ SUBJECT: { type: "string", required: false, description: "Pre-filled subject" },
273
+ BODY: { type: "string", required: false, description: "Pre-filled message" }
274
+ },
275
+ selfClosing: true,
276
+ example: '<EMAIL TO="hello@example.com" TEXT="Contact Us" />'
277
+ },
278
+
279
+ PHONE: {
280
+ type: "inline",
281
+ description: "Phone link (tel: protocol)",
282
+ attributes: {
283
+ NUMBER: { type: "phone", required: true, description: "Phone number" },
284
+ TEXT: { type: "string", required: false, description: "Link text" }
285
+ },
286
+ selfClosing: true,
287
+ example: '<PHONE NUMBER="+1 206 555 0123" TEXT="Call Us" />'
288
+ },
289
+
290
+ TABLE: {
291
+ type: "block",
292
+ description: "Data table",
293
+ attributes: {
294
+ TITLE: { type: "string", required: false, description: "Table heading" },
295
+ COLS: { type: "number", min: 2, max: 6, default: 3, description: "Number of columns" },
296
+ ROWS: { type: "number", min: 2, max: 10, default: 2, description: "Number of rows" }
297
+ },
298
+ selfClosing: true,
299
+ example: '<TABLE TITLE="Data" COLS="3" ROWS="4" />'
300
+ },
301
+
302
+ FORM: {
303
+ type: "block",
304
+ description: "Contact/input form (placeholder - needs backend integration)",
305
+ attributes: {
306
+ TITLE: { type: "string", required: false, description: "Form heading" },
307
+ FIELDS: { type: "csv", required: false, description: "Field names (comma-separated)" },
308
+ SUBMIT: { type: "string", required: false, description: "Submit button text" }
309
+ },
310
+ selfClosing: true,
311
+ note: "Textarea if field name contains 'message' or 'notes'",
312
+ example: '<FORM TITLE="Contact" FIELDS="name, email, message" SUBMIT="Send" />'
313
+ }
314
+ },
315
+
316
+ // Global rules
317
+ rules: {
318
+ "PAGE required": "Every .karma file MUST have exactly one <PAGE></PAGE> block",
319
+ "self-closing": "Self-closing tags must use <TAG ... />",
320
+ "nested containers": "Only SECTION, GRID, TIMELINE, COLLAPSE, and PAGE can contain other tags",
321
+ "attribute format": "Attributes: UPPERCASE_NAME=\"value\"",
322
+ "links auto-convert": ".karma file extensions automatically convert to .html",
323
+ "nesting": "Tags must be properly nested - no overlapping tags",
324
+ "comments": "Embedded prompts use <!-- @ai your prompt --> format"
325
+ },
326
+
327
+ // AI usage patterns
328
+ aiPatterns: {
329
+ "prompt_format": "<!-- @ai describe what you want here -->",
330
+ "placement": "Can appear anywhere in the file to guide generation",
331
+ "context": "AI has access to this full grammar schema for understanding"
332
+ }
333
+ };
334
+
335
+ // ========== PROMPT PROCESSOR ==========
336
+ class AIPromptProcessor {
337
+ constructor(filepath) {
338
+ this.filepath = filepath;
339
+ this.content = fs.readFileSync(filepath, "utf8");
340
+ this.prompts = this.extractPrompts();
341
+ }
342
+
343
+ // Extract embedded prompts with context
344
+ extractPrompts() {
345
+ const promptPattern = /<!--\s*@ai\s*(.*?)\s*-->/gi;
346
+ const prompts = [];
347
+ let match;
348
+
349
+ while ((match = promptPattern.exec(this.content))) {
350
+ const lineNum = this.content.substring(0, match.index).split("\n").length;
351
+ const promptText = match[1].trim();
352
+
353
+ // Get context (surrounding lines)
354
+ const lines = this.content.split("\n");
355
+ const contextStart = Math.max(0, lineNum - 3);
356
+ const contextEnd = Math.min(lines.length, lineNum + 2);
357
+ const context = lines.slice(contextStart, contextEnd).join("\n");
358
+
359
+ prompts.push({
360
+ line: lineNum,
361
+ text: promptText,
362
+ context: context,
363
+ grammarSchema: KARMA_GRAMMAR
364
+ });
365
+ }
366
+
367
+ return prompts;
368
+ }
369
+
370
+ // Generate AI prompt with full context
371
+ generateAIContext(prompt) {
372
+ return `
373
+ You are a Karma Language code generator. You have the following schema:
374
+
375
+ ${JSON.stringify(KARMA_GRAMMAR, null, 2)}
376
+
377
+ User Request: "${prompt.text}"
378
+
379
+ Context (surrounding code):
380
+ \`\`\`karma
381
+ ${prompt.context}
382
+ \`\`\`
383
+
384
+ Rules:
385
+ 1. Only use tags defined in the KARMA_GRAMMAR schema
386
+ 2. All attributes must match the defined types and constraints
387
+ 3. Self-closing tags must use /> syntax
388
+ 4. Nested tags must follow parent-child rules
389
+ 5. Generate valid .karma code that compiles without errors
390
+
391
+ Respond with ONLY the generated Karma code, no explanations.
392
+ `;
393
+ }
394
+
395
+ // Print prompts for review
396
+ printPrompts() {
397
+ console.log("\nšŸ“‹ AI Prompts Found\n");
398
+ console.log("=".repeat(60) + "\n");
399
+
400
+ this.prompts.forEach((prompt, idx) => {
401
+ console.log(`Prompt ${idx + 1} (Line ${prompt.line}):`);
402
+ console.log(`\n Request: "${prompt.text}"\n`);
403
+ console.log(` Context:`);
404
+ console.log(" ```karma");
405
+ prompt.context.split("\n").forEach(line => {
406
+ console.log(` ${line}`);
407
+ });
408
+ console.log(" ```\n");
409
+ });
410
+
411
+ console.log("=".repeat(60));
412
+ console.log(`\nTotal prompts: ${this.prompts.length}\n`);
413
+ }
414
+
415
+ // Export prompts for API processing
416
+ exportForAPI() {
417
+ return this.prompts.map(p => ({
418
+ line: p.line,
419
+ request: p.text,
420
+ context: p.context,
421
+ schema: KARMA_GRAMMAR,
422
+ model: model
423
+ }));
424
+ }
425
+ }
426
+
427
+ // ========== MAIN ==========
428
+ function main() {
429
+ const inputPath = path.resolve(process.cwd(), arg);
430
+
431
+ if (!fs.existsSync(inputPath)) {
432
+ console.error(`āŒ File not found: ${inputPath}`);
433
+ process.exit(1);
434
+ }
435
+
436
+ const processor = new AIPromptProcessor(inputPath);
437
+
438
+ if (processor.prompts.length === 0) {
439
+ console.log(`āœ… No embedded AI prompts found in ${arg}\n`);
440
+ process.exit(0);
441
+ }
442
+
443
+ processor.printPrompts();
444
+
445
+ if (execute) {
446
+ console.log("šŸ¤– Processing with AI...\n");
447
+ const context = processor.exportForAPI();
448
+ console.log("API Ready JSON:\n");
449
+ console.log(JSON.stringify(context, null, 2));
450
+ console.log("\nTo execute: Send this to OpenAI/Claude API with the model:", model);
451
+ }
452
+ }
453
+
454
+ main();
package/karma-cli.js ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ // karma-cli.js (v1)
3
+ // Simple wrapper around karma-compiler.js
4
+ // Examples:
5
+ // node karma-cli.js test.karma --pro
6
+ // node karma-cli.js --all --pro
7
+ // node karma-cli.js --help
8
+
9
+ import { spawnSync } from "child_process";
10
+ import path from "path";
11
+ import { fileURLToPath } from "url";
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+
16
+ const args = process.argv.slice(2);
17
+ const wantsHelp = args.includes("--help") || args.includes("-h");
18
+
19
+ if (wantsHelp || args.length === 0) {
20
+ console.log(`
21
+ Karma CLI (v1)
22
+
23
+ Usage:
24
+ node karma-cli.js <file.karma> [--pro]
25
+ node karma-cli.js --all [--pro]
26
+
27
+ Notes:
28
+ --pro enables layouts (LAYOUT="main")
29
+ `);
30
+ process.exit(0);
31
+ }
32
+
33
+ const compilerPath = path.join(__dirname, "karma-compiler.js");
34
+
35
+ // Forward args to compiler
36
+ const result = spawnSync(process.execPath, [compilerPath, ...args], {
37
+ stdio: "inherit",
38
+ cwd: process.cwd()
39
+ });
40
+
41
+ process.exit(result.status ?? 0);