@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.
- package/LICENSE +21 -0
- package/README.md +192 -0
- package/dist/arduino/i2c-arduino.d.ts +47 -0
- package/dist/arduino/i2c-arduino.js +6 -0
- package/dist/arduino/index.d.ts +6 -0
- package/dist/arduino/index.js +8 -0
- package/dist/arduino/spi-arduino.d.ts +42 -0
- package/dist/arduino/spi-arduino.js +6 -0
- package/dist/arduino/stubs-uno.d.ts +9 -0
- package/dist/arduino/stubs-uno.js +65 -0
- package/dist/arduino/uart-arduino.d.ts +41 -0
- package/dist/arduino/uart-arduino.js +6 -0
- package/dist/arduino-class-map.d.ts +5 -0
- package/dist/arduino-class-map.js +21 -0
- package/dist/arduino-compile.d.ts +24 -0
- package/dist/arduino-compile.js +316 -0
- package/dist/arduino-libs.d.ts +6 -0
- package/dist/arduino-libs.js +11 -0
- package/dist/cli-metadata.d.ts +12 -0
- package/dist/cli-metadata.js +196 -0
- package/dist/cpp-parser.d.ts +47 -0
- package/dist/cpp-parser.js +292 -0
- package/dist/debug-codegen.d.ts +20 -0
- package/dist/debug-codegen.js +115 -0
- package/dist/displays/ili9341-spi.d.ts +6 -0
- package/dist/displays/ili9341-spi.js +28 -0
- package/dist/displays/ssd1309-i2c.d.ts +2 -0
- package/dist/displays/ssd1309-i2c.js +16 -0
- package/dist/displays/st7796-spi.d.ts +2 -0
- package/dist/displays/st7796-spi.js +20 -0
- package/dist/graphics/ili9341.d.ts +24 -0
- package/dist/graphics/ili9341.js +59 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +27 -0
- package/dist/lib-declaration.d.ts +35 -0
- package/dist/lib-declaration.js +399 -0
- package/dist/lib-discovery.d.ts +38 -0
- package/dist/lib-discovery.js +189 -0
- package/dist/profile.d.ts +8 -0
- package/dist/profile.js +584 -0
- package/dist/strategy.d.ts +174 -0
- package/dist/strategy.js +2032 -0
- package/package.json +73 -0
- package/src/arduino/i2c-arduino.ts +72 -0
- package/src/arduino/index.ts +18 -0
- package/src/arduino/spi-arduino.ts +63 -0
- package/src/arduino/stubs-uno.ts +80 -0
- package/src/arduino/uart-arduino.ts +59 -0
- package/src/arduino-class-map.ts +32 -0
- package/src/arduino-compile.ts +359 -0
- package/src/arduino-libs.ts +33 -0
- package/src/cli-metadata.ts +250 -0
- package/src/cpp-parser.ts +361 -0
- package/src/debug-codegen.ts +155 -0
- package/src/displays/ili9341-spi.ts +33 -0
- package/src/displays/ssd1309-i2c.ts +19 -0
- package/src/displays/st7796-spi.ts +23 -0
- package/src/graphics/ili9341.ts +80 -0
- package/src/index.ts +37 -0
- package/src/lib-declaration.ts +493 -0
- package/src/lib-discovery.ts +267 -0
- package/src/profile.ts +676 -0
- 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
|
+
}
|