@typecad/framework-arduino 0.1.0-alpha.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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +192 -0
  3. package/dist/arduino/i2c-arduino.d.ts +47 -0
  4. package/dist/arduino/i2c-arduino.js +6 -0
  5. package/dist/arduino/index.d.ts +6 -0
  6. package/dist/arduino/index.js +8 -0
  7. package/dist/arduino/spi-arduino.d.ts +42 -0
  8. package/dist/arduino/spi-arduino.js +6 -0
  9. package/dist/arduino/stubs-uno.d.ts +9 -0
  10. package/dist/arduino/stubs-uno.js +65 -0
  11. package/dist/arduino/uart-arduino.d.ts +41 -0
  12. package/dist/arduino/uart-arduino.js +6 -0
  13. package/dist/arduino-class-map.d.ts +5 -0
  14. package/dist/arduino-class-map.js +21 -0
  15. package/dist/arduino-compile.d.ts +24 -0
  16. package/dist/arduino-compile.js +316 -0
  17. package/dist/arduino-libs.d.ts +6 -0
  18. package/dist/arduino-libs.js +11 -0
  19. package/dist/cli-metadata.d.ts +12 -0
  20. package/dist/cli-metadata.js +196 -0
  21. package/dist/cpp-parser.d.ts +47 -0
  22. package/dist/cpp-parser.js +292 -0
  23. package/dist/debug-codegen.d.ts +20 -0
  24. package/dist/debug-codegen.js +115 -0
  25. package/dist/displays/ili9341-spi.d.ts +6 -0
  26. package/dist/displays/ili9341-spi.js +28 -0
  27. package/dist/displays/ssd1309-i2c.d.ts +2 -0
  28. package/dist/displays/ssd1309-i2c.js +16 -0
  29. package/dist/displays/st7796-spi.d.ts +2 -0
  30. package/dist/displays/st7796-spi.js +20 -0
  31. package/dist/graphics/ili9341.d.ts +24 -0
  32. package/dist/graphics/ili9341.js +59 -0
  33. package/dist/index.d.ts +13 -0
  34. package/dist/index.js +27 -0
  35. package/dist/lib-declaration.d.ts +35 -0
  36. package/dist/lib-declaration.js +399 -0
  37. package/dist/lib-discovery.d.ts +38 -0
  38. package/dist/lib-discovery.js +189 -0
  39. package/dist/profile.d.ts +8 -0
  40. package/dist/profile.js +584 -0
  41. package/dist/strategy.d.ts +174 -0
  42. package/dist/strategy.js +2032 -0
  43. package/package.json +73 -0
  44. package/src/arduino/i2c-arduino.ts +72 -0
  45. package/src/arduino/index.ts +18 -0
  46. package/src/arduino/spi-arduino.ts +63 -0
  47. package/src/arduino/stubs-uno.ts +80 -0
  48. package/src/arduino/uart-arduino.ts +59 -0
  49. package/src/arduino-class-map.ts +32 -0
  50. package/src/arduino-compile.ts +359 -0
  51. package/src/arduino-libs.ts +33 -0
  52. package/src/cli-metadata.ts +250 -0
  53. package/src/cpp-parser.ts +361 -0
  54. package/src/debug-codegen.ts +155 -0
  55. package/src/displays/ili9341-spi.ts +33 -0
  56. package/src/displays/ssd1309-i2c.ts +19 -0
  57. package/src/displays/st7796-spi.ts +23 -0
  58. package/src/graphics/ili9341.ts +80 -0
  59. package/src/index.ts +37 -0
  60. package/src/lib-declaration.ts +493 -0
  61. package/src/lib-discovery.ts +267 -0
  62. package/src/profile.ts +676 -0
  63. package/src/strategy.ts +2126 -0
package/src/index.ts ADDED
@@ -0,0 +1,37 @@
1
+ // ---------------------------------------------------------------------------
2
+ // @typecad/framework-arduino — Arduino framework strategy
3
+ //
4
+ // Provides the ArduinoStrategy implementation for Arduino framework code
5
+ // generation. This is the main entry point for the framework-arduino package.
6
+ // ---------------------------------------------------------------------------
7
+
8
+ // Export the main strategy class
9
+ export { ArduinoStrategy } from './strategy.js';
10
+
11
+ // Export as FrameworkStrategy for consistency with framework package naming
12
+ export { ArduinoStrategy as FrameworkStrategy } from './strategy.js';
13
+
14
+ // Arduino compile/upload/monitor
15
+ export {
16
+ flattenGeneratedModulesIntoSketch,
17
+ compileArduinoSketch,
18
+ uploadArduinoSketch,
19
+ monitorArduinoSketch,
20
+ } from './arduino-compile.js';
21
+
22
+ // Toolchain object for the framework registry
23
+ import { flattenGeneratedModulesIntoSketch, compileArduinoSketch, uploadArduinoSketch, monitorArduinoSketch } from './arduino-compile.js';
24
+ export const Toolchain = {
25
+ prepare: flattenGeneratedModulesIntoSketch,
26
+ compile: (options: any) => compileArduinoSketch(options.sourcePath, options.buildTarget, {
27
+ extraFlags: options.extraFlags,
28
+ defines: options.defines,
29
+ }),
30
+ upload: (options: any) => uploadArduinoSketch(options.outputDir, options.buildTarget, options.port),
31
+ monitor: (options: any) => monitorArduinoSketch(options.port, options.baud),
32
+ };
33
+
34
+ // Library discovery — consumed by the transpiler's dynamic module loader
35
+ export { isArduinoLibraryImport as isFrameworkLibraryImport, getArduinoLibraryHeaderName as getFrameworkLibraryHeaderName } from './arduino-libs.js';
36
+ export { tryGenerateArduinoLibDecl as tryGenerateLibDecl } from './arduino-libs.js';
37
+ export { buildArduinoClassNameMap as buildClassNameMap } from './arduino-class-map.js';
@@ -0,0 +1,493 @@
1
+ // ---------------------------------------------------------------------------
2
+ // @typecad/framework-arduino — Arduino Library Declaration Generator
3
+ //
4
+ // Generates TypeScript .d.ts declarations and usage documentation from
5
+ // parsed Arduino library C++ headers.
6
+ // ---------------------------------------------------------------------------
7
+
8
+ import path from "node:path";
9
+ import fs from "node:fs";
10
+ import { type ArduinoLibrary, isArduinoLibraryImport, findArduinoLibrary, findLibraryHeader } from "./lib-discovery.js";
11
+ import { type CppParseResult, parseCppClass } from "./cpp-parser.js";
12
+
13
+ // ---------------------------------------------------------------------------
14
+ // Public types
15
+ // ---------------------------------------------------------------------------
16
+
17
+ /**
18
+ * Result of generating a .d.ts file for an Arduino library.
19
+ */
20
+ export interface GeneratedArduinoLib {
21
+ /** Path to the generated .d.ts file */
22
+ declPath: string;
23
+ /** The actual header file name (e.g., "Microfire_SHT3x.h") */
24
+ headerName: string;
25
+ }
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // Project root detection
29
+ // ---------------------------------------------------------------------------
30
+
31
+ /**
32
+ * Find the project root by looking for package.json or tsconfig.json.
33
+ */
34
+ function findProjectRoot(fromFile: string): string | undefined {
35
+ let currentDir = path.dirname(path.resolve(fromFile));
36
+
37
+ while (currentDir !== path.dirname(currentDir)) {
38
+ if (fs.existsSync(path.join(currentDir, "package.json")) ||
39
+ fs.existsSync(path.join(currentDir, "tsconfig.json"))) {
40
+ return currentDir;
41
+ }
42
+ currentDir = path.dirname(currentDir);
43
+ }
44
+
45
+ return undefined;
46
+ }
47
+
48
+ // ---------------------------------------------------------------------------
49
+ // Declaration generation
50
+ // ---------------------------------------------------------------------------
51
+
52
+ /**
53
+ * Generate export-based declaration content for @types packages.
54
+ */
55
+ function generateExportDeclaration(
56
+ parsed: CppParseResult,
57
+ moduleDocstring?: string,
58
+ ): string {
59
+ const lines: string[] = [];
60
+
61
+ // Add header comment explaining auto-generation and manual editing
62
+ lines.push("/**");
63
+ if (moduleDocstring) {
64
+ lines.push(` * ${moduleDocstring}`);
65
+ }
66
+ lines.push(" *");
67
+ lines.push(" * Auto-generated by TypeCAD from Arduino library C++ headers.");
68
+ lines.push(" * Arduino peripheral types (TwoWire, HardwareSerial, etc.) are mapped to TypeCAD equivalents.");
69
+ lines.push(" *");
70
+ lines.push(" * You can manually edit this file to:");
71
+ lines.push(" * - Add missing methods or properties");
72
+ lines.push(" * - Fix incorrect type mappings");
73
+ lines.push(" * - Add JSDoc documentation");
74
+ lines.push(" *");
75
+ lines.push(" * To regenerate: delete this file and re-run TypeCAD transpile.");
76
+ lines.push(" */");
77
+ lines.push("");
78
+
79
+ // Export constants
80
+ for (const constant of parsed.constants) {
81
+ lines.push(`export declare const ${constant.name}: ${constant.type};`);
82
+ }
83
+
84
+ if (parsed.constants.length > 0 && parsed.classes.length > 0) {
85
+ lines.push("");
86
+ }
87
+
88
+ // Export classes
89
+ for (const cppClass of parsed.classes) {
90
+ lines.push(`export declare class ${cppClass.name} {`);
91
+
92
+ // Add constructors
93
+ for (const ctor of cppClass.constructors) {
94
+ const params = ctor.parameters
95
+ .filter(p => p.name)
96
+ .map(p => `${p.name}: ${p.type}`)
97
+ .join(", ");
98
+ lines.push(` constructor(${params});`);
99
+ }
100
+
101
+ // Add public methods
102
+ const publicMethods = cppClass.methods.filter(m => m.isPublic);
103
+ for (const method of publicMethods) {
104
+ const params = method.parameters
105
+ .filter(p => p.name)
106
+ .map(p => `${p.name}: ${p.type}`)
107
+ .join(", ");
108
+ lines.push(` ${method.name}(${params}): ${method.returnType};`);
109
+ }
110
+
111
+ lines.push("}");
112
+ }
113
+
114
+ lines.push("");
115
+
116
+ return lines.join("\n");
117
+ }
118
+
119
+ // ---------------------------------------------------------------------------
120
+ // Public API
121
+ // ---------------------------------------------------------------------------
122
+
123
+ /**
124
+ * Generate a .d.ts file for an Arduino library.
125
+ * Returns the path to the generated file and header info, or undefined if generation failed.
126
+ */
127
+ export function generateArduinoLibDecl(
128
+ library: ArduinoLibrary,
129
+ fromFile: string
130
+ ): GeneratedArduinoLib | undefined {
131
+ // Find the main header file
132
+ const headerPath = findLibraryHeader(library);
133
+ if (!headerPath) {
134
+ console.log(` No header file found for Arduino library '${library.name}'`);
135
+ return undefined;
136
+ }
137
+
138
+ if (!fs.existsSync(headerPath)) {
139
+ console.log(` Header file does not exist: ${headerPath}`);
140
+ return undefined;
141
+ }
142
+
143
+ const content = fs.readFileSync(headerPath, "utf8");
144
+ const parsed = parseCppClass(content);
145
+
146
+ if (parsed.classes.length === 0 && parsed.constants.length === 0) {
147
+ console.log(` No class definitions found in '${library.name}' header`);
148
+ return undefined;
149
+ }
150
+
151
+ // Generate export-based declaration for @types
152
+ const declaration = generateExportDeclaration(
153
+ parsed,
154
+ `Arduino library: ${library.name}`
155
+ );
156
+
157
+ // Find project root
158
+ const projectRoot = findProjectRoot(fromFile);
159
+ if (!projectRoot) {
160
+ console.log(` Could not find project root for '${fromFile}'`);
161
+ return undefined;
162
+ }
163
+
164
+ // Place declarations in node_modules/@types/LibraryName/
165
+ // TypeScript automatically looks here for type declarations
166
+ const typeDir = path.join(projectRoot, "node_modules", "@types", library.name);
167
+
168
+ // Ensure output directory exists
169
+ if (!fs.existsSync(typeDir)) {
170
+ fs.mkdirSync(typeDir, { recursive: true });
171
+ }
172
+
173
+ const declPath = path.join(typeDir, "index.d.ts");
174
+
175
+ // Write the declaration file
176
+ fs.writeFileSync(declPath, declaration, "utf8");
177
+
178
+ // Also write a minimal package.json for module resolution
179
+ const packageJson = {
180
+ name: `@types/${library.name}`,
181
+ version: "0.0.0",
182
+ main: "index.d.ts",
183
+ types: "index.d.ts"
184
+ };
185
+ fs.writeFileSync(
186
+ path.join(typeDir, "package.json"),
187
+ JSON.stringify(packageJson, null, 2),
188
+ "utf8"
189
+ );
190
+
191
+ // Extract the actual header file name from the path
192
+ const headerName = path.basename(headerPath);
193
+
194
+ // Generate usage documentation
195
+ const usageDoc = generateUsageDocumentation(parsed, library.name, library);
196
+ fs.writeFileSync(
197
+ path.join(typeDir, "USAGE.md"),
198
+ usageDoc,
199
+ "utf8"
200
+ );
201
+
202
+ return { declPath, headerName };
203
+ }
204
+
205
+ /**
206
+ * Try to generate .d.ts for a missing Arduino library import.
207
+ * Returns the path to the generated declaration file, or undefined if not found.
208
+ */
209
+ export function tryGenerateArduinoLibDecl(
210
+ moduleSpecifier: string,
211
+ fromFile: string
212
+ ): string | undefined {
213
+ if (!isArduinoLibraryImport(moduleSpecifier)) {
214
+ return undefined;
215
+ }
216
+
217
+ const library = findArduinoLibrary(moduleSpecifier);
218
+ if (!library) {
219
+ return undefined;
220
+ }
221
+
222
+ console.log(`\n Found Arduino library '${library.name}' at: ${library.path}`);
223
+
224
+ const result = generateArduinoLibDecl(library, fromFile);
225
+
226
+ if (result) {
227
+ console.log(` Generated declaration: ${result.declPath}`);
228
+ console.log(` Review the generated types and adjust if needed.\n`);
229
+ return result.declPath;
230
+ }
231
+
232
+ return undefined;
233
+ }
234
+
235
+ /**
236
+ * Try to get the actual header file name for an Arduino library import.
237
+ * Returns the header file name (e.g., "Microfire_SHT3x.h") or undefined if not found.
238
+ */
239
+ export function getArduinoLibraryHeaderName(moduleSpecifier: string): string | undefined {
240
+ if (!isArduinoLibraryImport(moduleSpecifier)) {
241
+ return undefined;
242
+ }
243
+
244
+ const library = findArduinoLibrary(moduleSpecifier);
245
+ if (!library) {
246
+ return undefined;
247
+ }
248
+
249
+ const headerPath = findLibraryHeader(library);
250
+ if (!headerPath) {
251
+ return undefined;
252
+ }
253
+
254
+ return path.basename(headerPath);
255
+ }
256
+
257
+ /**
258
+ * Get fully qualified class names for an Arduino library.
259
+ * Returns a map of simple class name to fully qualified name (e.g., "SHT3x" -> "Microfire::SHT3x").
260
+ */
261
+ export function getArduinoLibraryClassNames(moduleSpecifier: string): Map<string, string> {
262
+ const result = new Map<string, string>();
263
+
264
+ if (!isArduinoLibraryImport(moduleSpecifier)) {
265
+ return result;
266
+ }
267
+
268
+ const library = findArduinoLibrary(moduleSpecifier);
269
+ if (!library) {
270
+ return result;
271
+ }
272
+
273
+ const headerPath = findLibraryHeader(library);
274
+ if (!headerPath || !fs.existsSync(headerPath)) {
275
+ return result;
276
+ }
277
+
278
+ const content = fs.readFileSync(headerPath, "utf8");
279
+ const parsed = parseCppClass(content);
280
+
281
+ for (const cppClass of parsed.classes) {
282
+ result.set(cppClass.name, cppClass.fullName);
283
+ }
284
+
285
+ return result;
286
+ }
287
+
288
+ // ---------------------------------------------------------------------------
289
+ // Documentation generation
290
+ // ---------------------------------------------------------------------------
291
+
292
+ /**
293
+ * Generate usage documentation for an Arduino library.
294
+ */
295
+ export function generateUsageDocumentation(
296
+ parsed: CppParseResult,
297
+ libraryName: string,
298
+ library?: ArduinoLibrary
299
+ ): string {
300
+ const lines: string[] = [];
301
+
302
+ lines.push(`# ${libraryName} - TypeCAD Usage Guide`);
303
+ lines.push("");
304
+
305
+ if (library?.sentence) {
306
+ lines.push(`> ${library.sentence}`);
307
+ lines.push("");
308
+ }
309
+
310
+ if (library?.author) {
311
+ lines.push(`**Author:** ${library.author}`);
312
+ lines.push("");
313
+ }
314
+
315
+ lines.push("## Overview");
316
+ lines.push("");
317
+ lines.push(`This library was auto-discovered from your Arduino installation and TypeCAD`);
318
+ lines.push(`has generated TypeScript type definitions for it.`);
319
+ lines.push("");
320
+
321
+ if (parsed.classes.length > 0) {
322
+ lines.push("## Classes");
323
+ lines.push("");
324
+
325
+ for (const cppClass of parsed.classes) {
326
+ lines.push(`### ${cppClass.name}`);
327
+ lines.push("");
328
+
329
+ // Show C++ fully qualified name if different
330
+ if (cppClass.fullName !== cppClass.name) {
331
+ lines.push(`**C++:** \`${cppClass.fullName}\``);
332
+ lines.push("");
333
+ }
334
+
335
+ // Constructor
336
+ if (cppClass.constructors.length > 0) {
337
+ lines.push("#### Constructor");
338
+ lines.push("");
339
+ lines.push("```typescript");
340
+ lines.push(`import { ${cppClass.name} } from '${libraryName}';`);
341
+ lines.push("");
342
+
343
+ for (const ctor of cppClass.constructors) {
344
+ const params = ctor.parameters
345
+ .filter(p => p.name)
346
+ .map(p => `${p.name}: ${p.type}`)
347
+ .join(", ");
348
+ lines.push(`const sensor = new ${cppClass.name}(${params});`);
349
+ }
350
+ lines.push("```");
351
+ lines.push("");
352
+ }
353
+
354
+ // Methods
355
+ if (cppClass.methods.length > 0) {
356
+ lines.push("#### Methods");
357
+ lines.push("");
358
+ lines.push("| Method | Parameters | Returns |");
359
+ lines.push("|--------|------------|---------|");
360
+
361
+ for (const method of cppClass.methods) {
362
+ const params = method.parameters
363
+ .filter(p => p.name)
364
+ .map(p => `${p.name}: ${p.type}`)
365
+ .join(", ");
366
+ lines.push(`| \`${method.name}()\` | ${params || "none"} | ${method.returnType} |`);
367
+ }
368
+ lines.push("");
369
+
370
+ // Usage examples
371
+ lines.push("#### Example Usage");
372
+ lines.push("");
373
+ lines.push("```typescript");
374
+ lines.push(`import { ${cppClass.name} } from '${libraryName}';`);
375
+
376
+ // Add peripheral imports if needed
377
+ const peripheralTypes = new Set<string>();
378
+ for (const method of cppClass.methods) {
379
+ for (const param of method.parameters) {
380
+ if (param.type === "I2C0" || param.type === "I2C1") {
381
+ peripheralTypes.add("I2C0");
382
+ } else if (param.type === "SPI0" || param.type === "SPI1") {
383
+ peripheralTypes.add("SPI0");
384
+ } else if (param.type === "UART0" || param.type === "UART1") {
385
+ peripheralTypes.add("UART0");
386
+ }
387
+ }
388
+ for (const ctor of cppClass.constructors) {
389
+ for (const param of ctor.parameters) {
390
+ if (param.type === "I2C0" || param.type === "I2C1") {
391
+ peripheralTypes.add("I2C0");
392
+ } else if (param.type === "SPI0" || param.type === "SPI1") {
393
+ peripheralTypes.add("SPI0");
394
+ } else if (param.type === "UART0" || param.type === "UART1") {
395
+ peripheralTypes.add("UART0");
396
+ }
397
+ }
398
+ }
399
+ }
400
+
401
+ if (peripheralTypes.size > 0) {
402
+ lines.push(`import { ${[...peripheralTypes].join(", ")} } from '@typecad/board';`);
403
+ }
404
+ lines.push("");
405
+
406
+ // Constructor example
407
+ if (cppClass.constructors.length > 0) {
408
+ const ctor = cppClass.constructors[0];
409
+ const args = ctor.parameters
410
+ .filter(p => p.name)
411
+ .map(p => {
412
+ // Provide example values for common types
413
+ if (p.type === "I2C0") return "I2C0";
414
+ if (p.type === "SPI0") return "SPI0";
415
+ if (p.type === "UART0") return "UART0";
416
+ if (p.type === "number") return "0x44";
417
+ if (p.type === "boolean") return "true";
418
+ if (p.type === "string") return '"example"';
419
+ return p.name;
420
+ })
421
+ .join(", ");
422
+ lines.push(`const device = new ${cppClass.name}(${args});`);
423
+ } else {
424
+ lines.push(`const device = new ${cppClass.name}();`);
425
+ }
426
+ lines.push("");
427
+
428
+ // Show common method calls
429
+ const beginMethod = cppClass.methods.find(m => m.name === "begin");
430
+ if (beginMethod) {
431
+ const args = beginMethod.parameters
432
+ .filter(p => p.name)
433
+ .map(p => {
434
+ if (p.type === "I2C0") return "I2C0";
435
+ if (p.type === "SPI0") return "SPI0";
436
+ if (p.type === "UART0") return "UART0";
437
+ if (p.type === "number") return "0x44";
438
+ if (p.type === "boolean") return "true";
439
+ return p.name;
440
+ })
441
+ .join(", ");
442
+ lines.push(`device.begin(${args});`);
443
+ }
444
+
445
+ const measureMethod = cppClass.methods.find(m => m.name === "measure" || m.name === "read");
446
+ if (measureMethod) {
447
+ lines.push(`device.${measureMethod.name}();`);
448
+ }
449
+
450
+ const connectedMethod = cppClass.methods.find(m => m.name === "connected" || m.name === "begin");
451
+ if (connectedMethod && connectedMethod.returnType === "boolean") {
452
+ lines.push("");
453
+ lines.push(`if (device.${connectedMethod.name}()) {`);
454
+ lines.push(` // Device is ready`);
455
+ lines.push(`}`);
456
+ }
457
+
458
+ lines.push("```");
459
+ lines.push("");
460
+ }
461
+ }
462
+ }
463
+
464
+ // Type mappings section
465
+ lines.push("## Type Mappings");
466
+ lines.push("");
467
+ lines.push("TypeCAD automatically maps Arduino C++ types to TypeScript equivalents:");
468
+ lines.push("");
469
+ lines.push("| Arduino C++ | TypeCAD TypeScript |");
470
+ lines.push("|-------------|---------------------|");
471
+ lines.push("| `TwoWire` / `TwoWire*` | `I2C0` |");
472
+ lines.push("| `SPIClass` / `SPIClass*` | `SPI0` |");
473
+ lines.push("| `HardwareSerial` / `HardwareSerial*` | `UART0` |");
474
+ lines.push("| `int`, `uint8_t`, `uint16_t`, etc. | `number` |");
475
+ lines.push("| `float`, `double` | `number` |");
476
+ lines.push("| `bool` | `boolean` |");
477
+ lines.push("| `String`, `const char*` | `string` |");
478
+ lines.push("");
479
+
480
+ lines.push("## Editing Type Definitions");
481
+ lines.push("");
482
+ lines.push("The generated type definitions are best-effort. You can manually edit the");
483
+ lines.push(`\`node_modules/@types/${libraryName}/index.d.ts\` file to:`);
484
+ lines.push("");
485
+ lines.push("- Add missing methods or properties");
486
+ lines.push("- Fix incorrect type mappings");
487
+ lines.push("- Add JSDoc documentation");
488
+ lines.push("");
489
+ lines.push("To regenerate: delete the file and re-run TypeCAD transpile.");
490
+ lines.push("");
491
+
492
+ return lines.join("\n");
493
+ }