@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
@@ -0,0 +1,267 @@
1
+ // ---------------------------------------------------------------------------
2
+ // @typecad/framework-arduino — Arduino Library Discovery
3
+ //
4
+ // Handles finding installed Arduino libraries via arduino-cli, locating
5
+ // their headers and sources, and detecting Arduino library imports.
6
+ // ---------------------------------------------------------------------------
7
+
8
+ import { spawnSync } from "node:child_process";
9
+ import path from "node:path";
10
+ import fs from "node:fs";
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // Public types
14
+ // ---------------------------------------------------------------------------
15
+
16
+ /**
17
+ * Information about an installed Arduino library.
18
+ */
19
+ export interface ArduinoLibrary {
20
+ /** Library name (e.g., "BH1750") */
21
+ name: string;
22
+ /** Version string */
23
+ version?: string;
24
+ /** Path to the library directory */
25
+ path: string;
26
+ /** Author information */
27
+ author?: string;
28
+ /** Brief description */
29
+ sentence?: string;
30
+ }
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Internal types
34
+ // ---------------------------------------------------------------------------
35
+
36
+ /**
37
+ * Result from arduino-cli lib list --format json
38
+ */
39
+ interface ArduinoCliLibrary {
40
+ name: string;
41
+ version?: string;
42
+ install_dir?: string;
43
+ author?: string;
44
+ sentence?: string;
45
+ }
46
+
47
+ /**
48
+ * Result from arduino-cli lib list --format json (wrapped format)
49
+ */
50
+ interface ArduinoCliLibListResult {
51
+ installed_libraries?: {
52
+ library: ArduinoCliLibrary;
53
+ }[];
54
+ }
55
+
56
+ // ---------------------------------------------------------------------------
57
+ // Library cache
58
+ // ---------------------------------------------------------------------------
59
+
60
+ let libraryCache: Map<string, ArduinoLibrary> | null = null;
61
+ let cacheTimestamp = 0;
62
+ const CACHE_TTL = 60000; // 1 minute cache
63
+
64
+ /**
65
+ * Clear the library cache (useful for testing or after installing new libraries).
66
+ */
67
+ export function clearLibraryCache(): void {
68
+ libraryCache = null;
69
+ cacheTimestamp = 0;
70
+ }
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // arduino-cli runner
74
+ // ---------------------------------------------------------------------------
75
+
76
+ /**
77
+ * Execute arduino-cli and return parsed JSON output.
78
+ */
79
+ function runArduinoCli(args: string[]): unknown | null {
80
+ try {
81
+ const result = spawnSync("arduino-cli", args, {
82
+ encoding: "utf8",
83
+ timeout: 30000,
84
+ });
85
+
86
+ if (result.status !== 0) {
87
+ return null;
88
+ }
89
+
90
+ const output = result.stdout?.trim();
91
+ if (!output) {
92
+ return null;
93
+ }
94
+
95
+ return JSON.parse(output);
96
+ } catch {
97
+ return null;
98
+ }
99
+ }
100
+
101
+ // ---------------------------------------------------------------------------
102
+ // Library discovery
103
+ // ---------------------------------------------------------------------------
104
+
105
+ /**
106
+ * Get all installed Arduino libraries using arduino-cli.
107
+ */
108
+ export function getInstalledLibraries(): Map<string, ArduinoLibrary> {
109
+ // Check cache
110
+ const now = Date.now();
111
+ if (libraryCache && (now - cacheTimestamp) < CACHE_TTL) {
112
+ return libraryCache;
113
+ }
114
+
115
+ const libraries = new Map<string, ArduinoLibrary>();
116
+
117
+ // Run arduino-cli lib list --format json
118
+ const result = runArduinoCli(["lib", "list", "--format", "json"]);
119
+
120
+ if (!result) {
121
+ libraryCache = libraries;
122
+ cacheTimestamp = now;
123
+ return libraries;
124
+ }
125
+
126
+ // Handle both formats:
127
+ // 1. { installed_libraries: [{ library: {...} }] } (newer arduino-cli)
128
+ // 2. [{ ... }] (older format or different command)
129
+ let libList: ArduinoCliLibrary[] = [];
130
+
131
+ if (Array.isArray(result)) {
132
+ libList = result as ArduinoCliLibrary[];
133
+ } else if (typeof result === "object" && result !== null) {
134
+ const wrapped = result as ArduinoCliLibListResult;
135
+ if (wrapped.installed_libraries && Array.isArray(wrapped.installed_libraries)) {
136
+ libList = wrapped.installed_libraries.map(item => item.library);
137
+ }
138
+ }
139
+
140
+ for (const lib of libList) {
141
+ if (!lib.name || !lib.install_dir) {
142
+ continue;
143
+ }
144
+
145
+ const library: ArduinoLibrary = {
146
+ name: lib.name,
147
+ version: lib.version,
148
+ path: lib.install_dir,
149
+ author: lib.author,
150
+ sentence: lib.sentence,
151
+ };
152
+
153
+ // Store by name (case-insensitive key)
154
+ libraries.set(lib.name.toLowerCase(), library);
155
+ // Also store with original casing
156
+ if (lib.name !== lib.name.toLowerCase()) {
157
+ libraries.set(lib.name, library);
158
+ }
159
+ }
160
+
161
+ libraryCache = libraries;
162
+ cacheTimestamp = now;
163
+ return libraries;
164
+ }
165
+
166
+ /**
167
+ * Find an Arduino library by name.
168
+ */
169
+ export function findArduinoLibrary(name: string): ArduinoLibrary | undefined {
170
+ const libraries = getInstalledLibraries();
171
+
172
+ // Try exact match first, then case-insensitive
173
+ return libraries.get(name) || libraries.get(name.toLowerCase());
174
+ }
175
+
176
+ /**
177
+ * Find the main header file for an Arduino library.
178
+ * Arduino libraries typically have a .h file matching the library name.
179
+ */
180
+ export function findLibraryHeader(library: ArduinoLibrary): string | undefined {
181
+ const libName = library.name;
182
+ const libDir = library.path;
183
+
184
+ if (!fs.existsSync(libDir)) {
185
+ return undefined;
186
+ }
187
+
188
+ // Common header locations:
189
+ // 1. LibraryName.h in root
190
+ // 2. src/LibraryName.h
191
+ // 3. Any .h file in root if only one exists
192
+
193
+ const candidates = [
194
+ path.join(libDir, `${libName}.h`),
195
+ path.join(libDir, "src", `${libName}.h`),
196
+ ];
197
+
198
+ for (const candidate of candidates) {
199
+ if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
200
+ return candidate;
201
+ }
202
+ }
203
+
204
+ // Fallback: look for any .h file in the root or src directory
205
+ const dirs = [libDir, path.join(libDir, "src")];
206
+ for (const dir of dirs) {
207
+ if (!fs.existsSync(dir)) continue;
208
+
209
+ const headers: string[] = [];
210
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
211
+ if (entry.isFile() && entry.name.toLowerCase().endsWith(".h")) {
212
+ headers.push(path.join(dir, entry.name));
213
+ }
214
+ }
215
+
216
+ // If there's only one header, use it
217
+ if (headers.length === 1) {
218
+ return headers[0];
219
+ }
220
+
221
+ // If there are multiple, prefer one matching the library name
222
+ for (const h of headers) {
223
+ if (path.basename(h, ".h").toLowerCase() === libName.toLowerCase()) {
224
+ return h;
225
+ }
226
+ }
227
+ }
228
+
229
+ return undefined;
230
+ }
231
+
232
+ /**
233
+ * Check if a module specifier looks like an Arduino library import.
234
+ * Arduino library imports are bare names like "BH1750", "Servo", "Wire"
235
+ * (not relative paths, not npm packages).
236
+ */
237
+ export function isArduinoLibraryImport(moduleSpecifier: string): boolean {
238
+ // Skip relative imports
239
+ if (moduleSpecifier.startsWith(".")) {
240
+ return false;
241
+ }
242
+
243
+ // Skip npm-style imports (scoped or with path separators)
244
+ if (moduleSpecifier.startsWith("@") || moduleSpecifier.includes("/")) {
245
+ return false;
246
+ }
247
+
248
+ // Skip known non-Arduino imports
249
+ const skipList = new Set([
250
+ "TypeCAD",
251
+ "typescript",
252
+ "node",
253
+ "fs",
254
+ "path",
255
+ "http",
256
+ "https",
257
+ "crypto",
258
+ "os",
259
+ "util",
260
+ ]);
261
+
262
+ if (skipList.has(moduleSpecifier.toLowerCase())) {
263
+ return false;
264
+ }
265
+
266
+ return true;
267
+ }