-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
328 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -174,4 +174,6 @@ dist | |
# Finder (MacOS) folder config | ||
.DS_Store | ||
|
||
.vscode | ||
.vscode | ||
.aider* | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
{ | ||
"$schema": "https://biomejs.dev/schemas/1.9.3/schema.json", | ||
"organizeImports": { | ||
"enabled": true | ||
}, | ||
"formatter": { | ||
"enabled": true, | ||
"indentStyle": "space" | ||
}, | ||
"files": { | ||
"ignore": ["cosmos-export", "dist", "package.json"] | ||
}, | ||
"javascript": { | ||
"formatter": { | ||
"jsxQuoteStyle": "double", | ||
"quoteProperties": "asNeeded", | ||
"trailingCommas": "all", | ||
"semicolons": "asNeeded", | ||
"arrowParentheses": "always", | ||
"bracketSpacing": true, | ||
"bracketSameLine": false | ||
} | ||
}, | ||
"linter": { | ||
"enabled": true, | ||
"rules": { | ||
"recommended": true, | ||
"suspicious": { | ||
"noExplicitAny": "off" | ||
}, | ||
"complexity": { | ||
"noForEach": "info" | ||
}, | ||
"style": { | ||
"noUselessElse": "off", | ||
"noNonNullAssertion": "off", | ||
"useNumberNamespace": "off", | ||
"useFilenamingConvention": { | ||
"level": "error", | ||
"options": { | ||
"strictCase": true, | ||
"requireAscii": true, | ||
"filenameCases": ["kebab-case", "export"] | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
#!/usr/bin/env node | ||
import { Command } from "commander" | ||
import * as path from "path" | ||
import * as chokidar from "chokidar" | ||
import * as fs from "fs" | ||
import { createServer } from "../lib/server/createServer" | ||
import { getLocalFileDependencies } from "../lib/dependency-analysis/getLocalFileDependencies" | ||
|
||
const program = new Command() | ||
|
||
program | ||
.name("snippets") | ||
.description("CLI for developing tscircuit snippets") | ||
.version("1.0.0") | ||
|
||
program | ||
.command("dev") | ||
.description("Start development server for a snippet") | ||
.argument("<file>", "Path to the snippet file") | ||
.option("-p, --port <number>", "Port to run server on", "3000") | ||
.action(async (file: string, options: { port: string }) => { | ||
const absolutePath = path.resolve(file) | ||
const port = parseInt(options.port) | ||
|
||
// Start the server | ||
await createServer(port) | ||
|
||
// Function to update file content | ||
const updateFile = async (filePath: string) => { | ||
try { | ||
const content = await fs.promises.readFile(filePath, "utf-8") | ||
const response = await fetch( | ||
`http://localhost:${port}/api/files/upsert`, | ||
{ | ||
method: "POST", | ||
headers: { "Content-Type": "application/json" }, | ||
body: JSON.stringify({ | ||
file_path: path.relative(process.cwd(), filePath), | ||
text_content: content, | ||
}), | ||
}, | ||
) | ||
if (!response.ok) { | ||
console.error(`Failed to update ${filePath}`) | ||
} | ||
} catch (error) { | ||
console.error(`Error updating ${filePath}:`, error) | ||
} | ||
} | ||
|
||
// Get initial dependencies | ||
let dependencies = new Set([absolutePath]) | ||
try { | ||
const deps = getLocalFileDependencies(absolutePath) | ||
deps.forEach((dep) => dependencies.add(dep)) | ||
} catch (error) { | ||
console.warn("Failed to analyze dependencies:", error) | ||
} | ||
|
||
// Watch the main file and its dependencies | ||
const watcher = chokidar.watch(Array.from(dependencies), { | ||
persistent: true, | ||
ignoreInitial: false, | ||
}) | ||
|
||
watcher.on("change", async (filePath) => { | ||
console.log(`File ${filePath} changed`) | ||
await updateFile(filePath) | ||
}) | ||
|
||
watcher.on("add", async (filePath) => { | ||
console.log(`File ${filePath} added`) | ||
await updateFile(filePath) | ||
}) | ||
|
||
console.log(`Watching ${file} and its dependencies...`) | ||
}) | ||
|
||
program.parse() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useRedLed } from "@tsci/seveibar.red-led" | ||
import { usePushButton } from "@tsci/seveibar.push-button" | ||
import { useUsbC } from "@tsci/seveibar.smd-usb-c" | ||
|
||
export default () => { | ||
const USBC = useUsbC("USBC") | ||
const Button = usePushButton("SW1") | ||
const Led = useRedLed("LED") | ||
return ( | ||
<board width="12mm" height="30mm" schAutoLayoutEnabled> | ||
<USBC GND="net.GND" pcbY={-10} VBUS1="net.VBUS" /> | ||
<Led neg="net.GND" pcbY={12} /> | ||
<Button pcbY={0} pin2=".R1 > .pos" pin3="net.VBUS" /> | ||
<resistor name="R1" footprint="0603" resistance="1k" pcbY={7} /> | ||
<trace from=".R1 > .neg" to={Led.pos} /> | ||
</board> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,127 +1,129 @@ | ||
import * as ts from 'typescript'; | ||
import * as path from 'path'; | ||
import * as fs from 'fs'; | ||
import * as ts from "typescript" | ||
import * as path from "path" | ||
import * as fs from "fs" | ||
|
||
interface DependencyAnalyzerOptions { | ||
baseDir: string; | ||
includeNodeModules?: boolean; | ||
includeCssModules?: boolean; | ||
baseDir: string | ||
includeNodeModules?: boolean | ||
includeCssModules?: boolean | ||
} | ||
|
||
class DependencyAnalyzer { | ||
private readonly baseDir: string; | ||
private readonly includeNodeModules: boolean; | ||
private readonly includeCssModules: boolean; | ||
private readonly cache: Map<string, Set<string>> = new Map(); | ||
private readonly baseDir: string | ||
private readonly includeNodeModules: boolean | ||
private readonly includeCssModules: boolean | ||
private readonly cache: Map<string, Set<string>> = new Map() | ||
|
||
constructor(options: DependencyAnalyzerOptions) { | ||
this.baseDir = options.baseDir; | ||
this.includeNodeModules = options.includeNodeModules ?? false; | ||
this.includeCssModules = options.includeCssModules ?? true; | ||
this.baseDir = options.baseDir | ||
this.includeNodeModules = options.includeNodeModules ?? false | ||
this.includeCssModules = options.includeCssModules ?? true | ||
} | ||
|
||
public analyze(filePath: string): Set<string> { | ||
if (this.cache.has(filePath)) { | ||
return this.cache.get(filePath)!; | ||
return this.cache.get(filePath)! | ||
} | ||
|
||
const dependencies = new Set<string>(); | ||
const sourceFile = this.createSourceFile(filePath); | ||
const dependencies = new Set<string>() | ||
const sourceFile = this.createSourceFile(filePath) | ||
|
||
if (!sourceFile) { | ||
return dependencies; | ||
return dependencies | ||
} | ||
|
||
this.visitNode(sourceFile, dependencies); | ||
this.cache.set(filePath, dependencies); | ||
this.visitNode(sourceFile, dependencies) | ||
this.cache.set(filePath, dependencies) | ||
|
||
return dependencies; | ||
return dependencies | ||
} | ||
|
||
private createSourceFile(filePath: string): ts.SourceFile | null { | ||
try { | ||
const content = fs.readFileSync(filePath, 'utf-8'); | ||
const content = fs.readFileSync(filePath, "utf-8") | ||
return ts.createSourceFile( | ||
filePath, | ||
content, | ||
ts.ScriptTarget.Latest, | ||
true | ||
); | ||
true, | ||
) | ||
} catch (error) { | ||
console.error(`Error reading file ${filePath}:`, error); | ||
return null; | ||
console.error(`Error reading file ${filePath}:`, error) | ||
return null | ||
} | ||
} | ||
|
||
private visitNode(node: ts.Node, dependencies: Set<string>): void { | ||
if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) { | ||
const moduleSpecifier = node.moduleSpecifier; | ||
const moduleSpecifier = node.moduleSpecifier | ||
if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) { | ||
const importPath = moduleSpecifier.text; | ||
this.addDependency(importPath, dependencies); | ||
const importPath = moduleSpecifier.text | ||
this.addDependency(importPath, dependencies) | ||
} | ||
} | ||
|
||
// Check for dynamic imports | ||
if (ts.isCallExpression(node) && | ||
node.expression.kind === ts.SyntaxKind.ImportKeyword) { | ||
const argument = node.arguments[0]; | ||
if ( | ||
ts.isCallExpression(node) && | ||
node.expression.kind === ts.SyntaxKind.ImportKeyword | ||
) { | ||
const argument = node.arguments[0] | ||
if (argument && ts.isStringLiteral(argument)) { | ||
this.addDependency(argument.text, dependencies); | ||
this.addDependency(argument.text, dependencies) | ||
} | ||
} | ||
|
||
ts.forEachChild(node, child => this.visitNode(child, dependencies)); | ||
ts.forEachChild(node, (child) => this.visitNode(child, dependencies)) | ||
} | ||
|
||
private addDependency(importPath: string, dependencies: Set<string>): void { | ||
// Skip node_modules unless explicitly included | ||
if (!this.includeNodeModules && importPath.startsWith('node_modules')) { | ||
return; | ||
if (!this.includeNodeModules && importPath.startsWith("node_modules")) { | ||
return | ||
} | ||
|
||
// Handle CSS modules if enabled | ||
if (this.includeCssModules && importPath.endsWith('.css')) { | ||
const resolvedPath = this.resolvePath(importPath); | ||
if (this.includeCssModules && importPath.endsWith(".css")) { | ||
const resolvedPath = this.resolvePath(importPath) | ||
if (resolvedPath) { | ||
dependencies.add(resolvedPath); | ||
dependencies.add(resolvedPath) | ||
} | ||
return; | ||
return | ||
} | ||
|
||
// Resolve relative imports | ||
if (importPath.startsWith('.')) { | ||
const resolvedPath = this.resolvePath(importPath); | ||
if (importPath.startsWith(".")) { | ||
const resolvedPath = this.resolvePath(importPath) | ||
if (resolvedPath) { | ||
dependencies.add(resolvedPath); | ||
dependencies.add(resolvedPath) | ||
} | ||
} | ||
} | ||
|
||
private resolvePath(importPath: string): string | null { | ||
try { | ||
const extensions = ['.tsx', '.ts', '.jsx', '.js', '.css']; | ||
const resolvedPath = path.resolve(this.baseDir, importPath); | ||
const extensions = [".tsx", ".ts", ".jsx", ".js", ".css"] | ||
const resolvedPath = path.resolve(this.baseDir, importPath) | ||
|
||
// Try exact path first | ||
if (fs.existsSync(resolvedPath)) { | ||
return resolvedPath; | ||
return resolvedPath | ||
} | ||
|
||
// Try with extensions | ||
for (const ext of extensions) { | ||
const pathWithExt = resolvedPath + ext; | ||
const pathWithExt = resolvedPath + ext | ||
if (fs.existsSync(pathWithExt)) { | ||
return pathWithExt; | ||
return pathWithExt | ||
} | ||
} | ||
|
||
return null; | ||
return null | ||
} catch (error) { | ||
console.error(`Error resolving path ${importPath}:`, error); | ||
return null; | ||
console.error(`Error resolving path ${importPath}:`, error) | ||
return null | ||
} | ||
} | ||
} | ||
|
||
export { DependencyAnalyzer, type DependencyAnalyzerOptions }; | ||
export { DependencyAnalyzer, type DependencyAnalyzerOptions } |
Oops, something went wrong.