@tscircuit/cli 0.0.2
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/.prettierrc +1 -0
- package/README.md +50 -0
- package/build-cli.ts +14 -0
- package/bun.lockb +0 -0
- package/cli.ts +12 -0
- package/dev-server-api/README.md +3 -0
- package/dev-server-api/bun.lockb +0 -0
- package/dev-server-api/edgespec.config.ts +4 -0
- package/dev-server-api/index.ts +1 -0
- package/dev-server-api/package-lock.json +1201 -0
- package/dev-server-api/package.json +24 -0
- package/dev-server-api/routes/api/dev_package_examples/create.ts +43 -0
- package/dev-server-api/routes/api/dev_package_examples/get.ts +37 -0
- package/dev-server-api/routes/api/dev_package_examples/list.ts +29 -0
- package/dev-server-api/routes/api/dev_package_examples/update.ts +31 -0
- package/dev-server-api/routes/api/health.ts +11 -0
- package/dev-server-api/src/db/create-schema.ts +14 -0
- package/dev-server-api/src/db/get-db.ts +78 -0
- package/dev-server-api/src/middlewares/with-db.ts +14 -0
- package/dev-server-api/src/middlewares/with-error-response.ts +24 -0
- package/dev-server-api/src/with-edge-spec.ts +8 -0
- package/dev-server-api/tsconfig.json +28 -0
- package/dev-server-frontend/.eslintrc.cjs +20 -0
- package/dev-server-frontend/README.md +3 -0
- package/dev-server-frontend/bun.lockb +0 -0
- package/dev-server-frontend/components.json +17 -0
- package/dev-server-frontend/index.html +13 -0
- package/dev-server-frontend/package.json +62 -0
- package/dev-server-frontend/postcss.config.js +6 -0
- package/dev-server-frontend/src/App.tsx +22 -0
- package/dev-server-frontend/src/ExampleContentView.tsx +60 -0
- package/dev-server-frontend/src/Header.tsx +53 -0
- package/dev-server-frontend/src/HeaderMenu.tsx +188 -0
- package/dev-server-frontend/src/components/command-k.tsx +62 -0
- package/dev-server-frontend/src/components/global-context-providers.tsx +11 -0
- package/dev-server-frontend/src/components/select-example-search.tsx +137 -0
- package/dev-server-frontend/src/components/ui/alert-dialog.tsx +139 -0
- package/dev-server-frontend/src/components/ui/alert.tsx +59 -0
- package/dev-server-frontend/src/components/ui/breadcrumb.tsx +115 -0
- package/dev-server-frontend/src/components/ui/button.tsx +57 -0
- package/dev-server-frontend/src/components/ui/card.tsx +76 -0
- package/dev-server-frontend/src/components/ui/command.tsx +153 -0
- package/dev-server-frontend/src/components/ui/context-menu.tsx +202 -0
- package/dev-server-frontend/src/components/ui/dialog.tsx +120 -0
- package/dev-server-frontend/src/components/ui/menubar.tsx +238 -0
- package/dev-server-frontend/src/components/ui/navigation-menu.tsx +128 -0
- package/dev-server-frontend/src/components/ui/popover.tsx +31 -0
- package/dev-server-frontend/src/components/ui/select.tsx +162 -0
- package/dev-server-frontend/src/components/ui/tabs.tsx +53 -0
- package/dev-server-frontend/src/components/ui/toggle-group.tsx +59 -0
- package/dev-server-frontend/src/components/ui/toggle.tsx +43 -0
- package/dev-server-frontend/src/components/ui/tooltip.tsx +28 -0
- package/dev-server-frontend/src/hooks/toast-if-api-not-connected.ts +23 -0
- package/dev-server-frontend/src/hooks/use-global-store.ts +42 -0
- package/dev-server-frontend/src/index.css +76 -0
- package/dev-server-frontend/src/lib/utils.ts +6 -0
- package/dev-server-frontend/src/main.tsx +13 -0
- package/dev-server-frontend/src/vite-env.d.ts +1 -0
- package/dev-server-frontend/tailwind.config.js +77 -0
- package/dev-server-frontend/tsconfig.json +26 -0
- package/dev-server-frontend/tsconfig.node.json +13 -0
- package/dev-server-frontend/vite.config.ts +23 -0
- package/dist/cli.js +1326 -0
- package/lib/cmd-fns/auth-login.ts +59 -0
- package/lib/cmd-fns/auth-logout.ts +3 -0
- package/lib/cmd-fns/auth-sessions-create.ts +3 -0
- package/lib/cmd-fns/auth-sessions-get.ts +3 -0
- package/lib/cmd-fns/auth-sessions-list.ts +5 -0
- package/lib/cmd-fns/config-print-config.ts +6 -0
- package/lib/cmd-fns/config-reveal-location.ts +5 -0
- package/lib/cmd-fns/config-set-log-requests.ts +7 -0
- package/lib/cmd-fns/config-set-registry.ts +7 -0
- package/lib/cmd-fns/config-set-session.ts +7 -0
- package/lib/cmd-fns/dev.ts +217 -0
- package/lib/cmd-fns/index.ts +27 -0
- package/lib/cmd-fns/package-examples-create.ts +33 -0
- package/lib/cmd-fns/package-examples-get.ts +20 -0
- package/lib/cmd-fns/package-examples-list.ts +18 -0
- package/lib/cmd-fns/package-files-create.ts +31 -0
- package/lib/cmd-fns/package-files-download.ts +29 -0
- package/lib/cmd-fns/package-files-get.ts +3 -0
- package/lib/cmd-fns/package-files-list.ts +28 -0
- package/lib/cmd-fns/package-files-upload-directory.ts +6 -0
- package/lib/cmd-fns/package-releases-create.ts +35 -0
- package/lib/cmd-fns/package-releases-get.ts +3 -0
- package/lib/cmd-fns/package-releases-list.ts +32 -0
- package/lib/cmd-fns/packages-create.ts +16 -0
- package/lib/cmd-fns/packages-get.ts +16 -0
- package/lib/cmd-fns/packages-list.ts +16 -0
- package/lib/cmd-fns/publish.ts +3 -0
- package/lib/cmd-fns/soupify.ts +27 -0
- package/lib/get-program.ts +191 -0
- package/lib/param-handlers/index.ts +16 -0
- package/lib/param-handlers/interact-for-local-directory.ts +58 -0
- package/lib/param-handlers/interact-for-local-file.ts +59 -0
- package/lib/param-handlers/interact-for-package-example-id.ts +25 -0
- package/lib/param-handlers/interact-for-package-name-with-version.ts +63 -0
- package/lib/param-handlers/interact-for-package-name.ts +45 -0
- package/lib/param-handlers/interact-for-package-release-id.ts +16 -0
- package/lib/param-handlers/param-handler-type.ts +7 -0
- package/lib/soupify.ts +71 -0
- package/lib/util/app-context.ts +14 -0
- package/lib/util/create-context-and-run-program.ts +116 -0
- package/package.json +62 -0
- package/tests/assets/example-project/examples/basic-capacitor.tsx +1 -0
- package/tests/assets/example-project/examples/basic-resistor.tsx +3 -0
- package/tests/assets/example-project/package.json +8 -0
- package/tests/assets/example-project/src/MyCircuit.tsx +3 -0
- package/tests/soupify.test.ts +9 -0
- package/tsconfig.json +109 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AppContext } from "../util/app-context"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
import * as Path from "path"
|
|
4
|
+
import { unlink } from "node:fs/promises"
|
|
5
|
+
import { soupify } from "lib/soupify"
|
|
6
|
+
import { writeFileSync } from "fs"
|
|
7
|
+
|
|
8
|
+
export const soupifyCmd = async (ctx: AppContext, args: any) => {
|
|
9
|
+
const params = z
|
|
10
|
+
.object({
|
|
11
|
+
file: z.string(),
|
|
12
|
+
export: z.string().optional(),
|
|
13
|
+
output: z.string().optional(),
|
|
14
|
+
})
|
|
15
|
+
.parse(args)
|
|
16
|
+
|
|
17
|
+
const soup = await soupify({
|
|
18
|
+
filePath: params.file,
|
|
19
|
+
exportName: params.export,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
if (params.output) {
|
|
23
|
+
await writeFileSync(params.output, JSON.stringify(soup, null, 2))
|
|
24
|
+
} else {
|
|
25
|
+
console.log(JSON.stringify(soup, null, 2))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { Command } from "commander"
|
|
2
|
+
import packageJson from "../package.json"
|
|
3
|
+
import { AppContext } from "./util/app-context"
|
|
4
|
+
import * as CMDFN from "lib/cmd-fns"
|
|
5
|
+
|
|
6
|
+
// | Endpoint | Description |
|
|
7
|
+
// | ------------------------------------- | ---------------------------- |
|
|
8
|
+
// | /packages/search | Search for packages |
|
|
9
|
+
// | /packages/list | List packages with a filter |
|
|
10
|
+
// | /packages/get | Get a package by id or name |
|
|
11
|
+
// | /packages/create | Create a new package |
|
|
12
|
+
// | /package_releases/list | List package releases |
|
|
13
|
+
// | /package_releases/get | Get a package release by id |
|
|
14
|
+
// | /package_releases/create | Create a new package release |
|
|
15
|
+
// | /package_files/list | List package files |
|
|
16
|
+
// | /package_files/get | Get a package file by id |
|
|
17
|
+
// | /package_files/download | Download a package file |
|
|
18
|
+
// | /package_files/create | Create a new package file |
|
|
19
|
+
// | /package_examples/list | List package examples |
|
|
20
|
+
// | /package_examples/get | Get a package example by id |
|
|
21
|
+
// | /package_examples/create | Create a new package example |
|
|
22
|
+
|
|
23
|
+
export const getProgram = (ctx: AppContext) => {
|
|
24
|
+
const cmd = new Command("tsci")
|
|
25
|
+
|
|
26
|
+
cmd.version(packageJson.version)
|
|
27
|
+
|
|
28
|
+
const authCmd = cmd.command("auth")
|
|
29
|
+
authCmd.command("login").action((args) => CMDFN.authLogin(ctx, args))
|
|
30
|
+
authCmd.command("logout").action((args) => CMDFN.authLogout(ctx, args))
|
|
31
|
+
|
|
32
|
+
const configCmd = cmd.command("config")
|
|
33
|
+
|
|
34
|
+
configCmd
|
|
35
|
+
.command("reveal-location")
|
|
36
|
+
.action((args) => CMDFN.configRevealLocation(ctx, args))
|
|
37
|
+
configCmd
|
|
38
|
+
.command("set-registry")
|
|
39
|
+
.requiredOption("--server <server>", "Registry URL")
|
|
40
|
+
.action((args) => CMDFN.configSetRegistry(ctx, args))
|
|
41
|
+
configCmd
|
|
42
|
+
.command("set-session")
|
|
43
|
+
.requiredOption("--session-token <session_token>", "Session Token")
|
|
44
|
+
.action((args) => CMDFN.configSetSession(ctx, args))
|
|
45
|
+
configCmd
|
|
46
|
+
.command("set-log-requests")
|
|
47
|
+
.requiredOption("--log-requests", "Should log requests to registry")
|
|
48
|
+
.action((args) => CMDFN.configSetLogRequests(ctx, args))
|
|
49
|
+
configCmd
|
|
50
|
+
.command("print-config")
|
|
51
|
+
.action((args) => CMDFN.configPrintConfig(ctx, args))
|
|
52
|
+
|
|
53
|
+
const authSessionsCmd = authCmd.command("sessions")
|
|
54
|
+
|
|
55
|
+
authSessionsCmd
|
|
56
|
+
.command("create")
|
|
57
|
+
.action((args) => CMDFN.authSessionsCreate(ctx, args))
|
|
58
|
+
authSessionsCmd
|
|
59
|
+
.command("list")
|
|
60
|
+
.action((args) => CMDFN.authSessionsList(ctx, args))
|
|
61
|
+
authSessionsCmd
|
|
62
|
+
.command("get")
|
|
63
|
+
.action((args) => CMDFN.authSessionsGet(ctx, args))
|
|
64
|
+
|
|
65
|
+
const packagesCmd = cmd.command("packages")
|
|
66
|
+
|
|
67
|
+
packagesCmd.command("list").action((args) => CMDFN.packagesList(ctx, args))
|
|
68
|
+
packagesCmd
|
|
69
|
+
.command("get")
|
|
70
|
+
.option("--package-id <package_id>", "Package Id")
|
|
71
|
+
.option("--name <name>", "Package name")
|
|
72
|
+
.action((args) => CMDFN.packagesGet(ctx, args))
|
|
73
|
+
packagesCmd
|
|
74
|
+
.command("create")
|
|
75
|
+
.requiredOption("--name <name>", "Package name")
|
|
76
|
+
.option("--author-id <author_account_id>", "Author Id")
|
|
77
|
+
.option("--description <description>", "Package description")
|
|
78
|
+
.action((args) => CMDFN.packagesCreate(ctx, args))
|
|
79
|
+
|
|
80
|
+
const packageReleases = cmd.command("package_releases")
|
|
81
|
+
|
|
82
|
+
packageReleases
|
|
83
|
+
.command("list")
|
|
84
|
+
.requiredOption("--package-name <package_name>", "Package name")
|
|
85
|
+
.option("--verbose", "Verbose objects (includes uuids)")
|
|
86
|
+
.action((args) => CMDFN.packageReleasesList(ctx, args))
|
|
87
|
+
packageReleases
|
|
88
|
+
.command("get")
|
|
89
|
+
.action((args) => CMDFN.packageReleasesGet(ctx, args))
|
|
90
|
+
packageReleases
|
|
91
|
+
.command("create")
|
|
92
|
+
.option(
|
|
93
|
+
"-p, --package-name-with-version <package_name_with_version>",
|
|
94
|
+
"Package name and version"
|
|
95
|
+
)
|
|
96
|
+
.option("--package-name <package_name>", "Package name")
|
|
97
|
+
.option("--release-version <release_version>", "Version to publish")
|
|
98
|
+
.action((args) => CMDFN.packageReleasesCreate(ctx, args))
|
|
99
|
+
|
|
100
|
+
const packageFiles = cmd.command("package_files")
|
|
101
|
+
|
|
102
|
+
packageFiles
|
|
103
|
+
.command("list")
|
|
104
|
+
.option(
|
|
105
|
+
"--package-name-with-version <package_name_with_version>",
|
|
106
|
+
"Package name with version"
|
|
107
|
+
)
|
|
108
|
+
.option(
|
|
109
|
+
"--package-name <package_name>",
|
|
110
|
+
"Package name (use latest version)"
|
|
111
|
+
)
|
|
112
|
+
.option("--package-release-id <package_release_id>", "Package Release Id")
|
|
113
|
+
.action((args) => CMDFN.packageFilesList(ctx, args))
|
|
114
|
+
packageFiles.command("get").action((args) => CMDFN.packageFilesGet(ctx, args))
|
|
115
|
+
packageFiles
|
|
116
|
+
.command("download")
|
|
117
|
+
.requiredOption(
|
|
118
|
+
"--package-name-with-version <package_name_with_version>",
|
|
119
|
+
"Package name and version"
|
|
120
|
+
)
|
|
121
|
+
.requiredOption("--remote-file-path <remote_file_path>", "Remote file path")
|
|
122
|
+
.option(
|
|
123
|
+
"--output <output>",
|
|
124
|
+
"Output file path (optional), prints to stdout if not provided"
|
|
125
|
+
)
|
|
126
|
+
.action((args) => CMDFN.packageFilesDownload(ctx, args))
|
|
127
|
+
packageFiles
|
|
128
|
+
.command("create")
|
|
129
|
+
.option(
|
|
130
|
+
"-p, --package-release-id <package_release_id>",
|
|
131
|
+
"Package Release Id"
|
|
132
|
+
)
|
|
133
|
+
.option(
|
|
134
|
+
"--package-name-with-version <package_name_with_version>",
|
|
135
|
+
"Package name with version e.g. @tscircuit/arduino@1.2.3"
|
|
136
|
+
)
|
|
137
|
+
.requiredOption("--file <file>", "File to upload")
|
|
138
|
+
.action((args) => CMDFN.packageFilesCreate(ctx, args))
|
|
139
|
+
|
|
140
|
+
packageFiles
|
|
141
|
+
.command("upload-directory")
|
|
142
|
+
.requiredOption("--directory <directory>", "Directory to upload")
|
|
143
|
+
.action((args) => CMDFN.packageFilesUploadDirectory(ctx, args))
|
|
144
|
+
|
|
145
|
+
const packageExamples = cmd.command("package_examples")
|
|
146
|
+
|
|
147
|
+
packageExamples
|
|
148
|
+
.command("list")
|
|
149
|
+
.requiredOption("--package-name-with-version <package_name_with_version>")
|
|
150
|
+
.action((args) => CMDFN.packageExamplesList(ctx, args))
|
|
151
|
+
packageExamples
|
|
152
|
+
.command("get")
|
|
153
|
+
.requiredOption("--package-example-id <package_example_id>")
|
|
154
|
+
.action((args) => CMDFN.packageExamplesGet(ctx, args))
|
|
155
|
+
packageExamples
|
|
156
|
+
.command("create")
|
|
157
|
+
.requiredOption("--package-name-with-version <package_name_with_version>")
|
|
158
|
+
.requiredOption("--file <file>")
|
|
159
|
+
.option("--export <export>", "Name of export to soupify")
|
|
160
|
+
.action((args) => CMDFN.packageExamplesCreate(ctx, args))
|
|
161
|
+
|
|
162
|
+
cmd.command("publish").action((args) => CMDFN.publish(ctx, args))
|
|
163
|
+
|
|
164
|
+
cmd
|
|
165
|
+
.command("version")
|
|
166
|
+
.action(() => console.log(`tsci v${packageJson.version}`))
|
|
167
|
+
|
|
168
|
+
cmd.command("login").action((args) => CMDFN.authLogin(ctx, args))
|
|
169
|
+
cmd.command("logout").action((args) => CMDFN.authLogout(ctx, args))
|
|
170
|
+
|
|
171
|
+
cmd
|
|
172
|
+
.command("soupify")
|
|
173
|
+
.requiredOption("--file <file>", "Input example files")
|
|
174
|
+
.option(
|
|
175
|
+
"--export <export_name>",
|
|
176
|
+
"Name of export to soupify, if not specified, soupify the default/only export"
|
|
177
|
+
)
|
|
178
|
+
.action((args) => CMDFN.soupify(ctx, args))
|
|
179
|
+
|
|
180
|
+
cmd
|
|
181
|
+
.command("dev")
|
|
182
|
+
.option("--cwd <cwd>", "Current working directory")
|
|
183
|
+
.option("--port <port>", "Port to run dev server on")
|
|
184
|
+
.action((args) => CMDFN.dev(ctx, args))
|
|
185
|
+
|
|
186
|
+
cmd.command("add").action((args) => {})
|
|
187
|
+
cmd.command("remove").action((args) => {})
|
|
188
|
+
cmd.command("install").action((args) => {})
|
|
189
|
+
|
|
190
|
+
return cmd
|
|
191
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { interactForLocalDirectory } from "./interact-for-local-directory"
|
|
2
|
+
import { interactForLocalFile } from "./interact-for-local-file"
|
|
3
|
+
import { interactForPackageExampleId } from "./interact-for-package-example-id"
|
|
4
|
+
import { interactForPackageName } from "./interact-for-package-name"
|
|
5
|
+
import { interactForPackageNameWithVersion } from "./interact-for-package-name-with-version"
|
|
6
|
+
import { interactForPackageReleaseId } from "./interact-for-package-release-id"
|
|
7
|
+
import { ParamHandler } from "./param-handler-type"
|
|
8
|
+
|
|
9
|
+
export const PARAM_HANDLERS_BY_PARAM_NAME: Record<string, ParamHandler> = {
|
|
10
|
+
file: interactForLocalFile,
|
|
11
|
+
cwd: interactForLocalDirectory,
|
|
12
|
+
package_release_id: interactForPackageReleaseId,
|
|
13
|
+
package_name: interactForPackageName,
|
|
14
|
+
package_name_with_version: interactForPackageNameWithVersion,
|
|
15
|
+
package_example_id: interactForPackageExampleId,
|
|
16
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { ParamHandler } from "./param-handler-type"
|
|
2
|
+
import * as fs from "fs/promises"
|
|
3
|
+
|
|
4
|
+
export const interactForLocalDirectory: ParamHandler = async ({ prompts }) => {
|
|
5
|
+
const { selectionMode } = await prompts({
|
|
6
|
+
type: "select",
|
|
7
|
+
name: "selectionMode",
|
|
8
|
+
message: "Select a directory",
|
|
9
|
+
choices: [
|
|
10
|
+
{ title: "Manually Enter Path", value: "manual" },
|
|
11
|
+
{ title: "Browse for Directory", value: "browse" },
|
|
12
|
+
],
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
if (selectionMode === "manual") {
|
|
16
|
+
const { manualPath } = await prompts({
|
|
17
|
+
type: "text",
|
|
18
|
+
name: "manualPath",
|
|
19
|
+
message: "Enter the path to the directory",
|
|
20
|
+
})
|
|
21
|
+
return manualPath
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let currentDirectory = "."
|
|
25
|
+
while (true) {
|
|
26
|
+
const files = await fs.readdir(currentDirectory)
|
|
27
|
+
const dirChoices = files
|
|
28
|
+
.filter((d) => !d.includes("."))
|
|
29
|
+
.map((file) => ({ title: file, value: file }))
|
|
30
|
+
const { selectedDir } = await prompts({
|
|
31
|
+
type: "autocomplete",
|
|
32
|
+
name: "selectedDir",
|
|
33
|
+
message: "Select a directory",
|
|
34
|
+
initial: "__select__",
|
|
35
|
+
choices: [
|
|
36
|
+
{ title: ".. (Go Up)", value: ".." },
|
|
37
|
+
{ title: `["${currentDirectory}"]`, value: "__select__" },
|
|
38
|
+
...dirChoices,
|
|
39
|
+
],
|
|
40
|
+
})
|
|
41
|
+
if (selectedDir === "..") {
|
|
42
|
+
// Go up one directory
|
|
43
|
+
const lastIndex = currentDirectory.lastIndexOf("/")
|
|
44
|
+
currentDirectory = currentDirectory.substring(0, lastIndex)
|
|
45
|
+
} else if (selectedDir === "__select__") {
|
|
46
|
+
return currentDirectory
|
|
47
|
+
} else {
|
|
48
|
+
// Check if selectedFile is a file or directory
|
|
49
|
+
const stats = await fs.stat(`${currentDirectory}/${selectedDir}`)
|
|
50
|
+
if (stats.isFile()) {
|
|
51
|
+
throw new Error("Selected file is a file, not a directory")
|
|
52
|
+
} else {
|
|
53
|
+
// Go into the selected directory
|
|
54
|
+
currentDirectory = `${currentDirectory}/${selectedDir}`
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ParamHandler } from "./param-handler-type"
|
|
2
|
+
import * as fs from "fs/promises"
|
|
3
|
+
|
|
4
|
+
// Use prompts to allow searching for a file
|
|
5
|
+
// 1. Show a prompt with two options
|
|
6
|
+
// - "Manually Enter Path"
|
|
7
|
+
// - "Browse for File"
|
|
8
|
+
// 2. If Browse for File is selected, show all the files in the current
|
|
9
|
+
// directory with the "autocomplete" prompts type, then allow the user
|
|
10
|
+
// to select a file or directory
|
|
11
|
+
export const interactForLocalFile: ParamHandler = async ({ prompts }) => {
|
|
12
|
+
const { selectionMode } = await prompts({
|
|
13
|
+
type: "select",
|
|
14
|
+
name: "selectionMode",
|
|
15
|
+
message: "Select a file",
|
|
16
|
+
choices: [
|
|
17
|
+
{ title: "Manually Enter Path", value: "manual" },
|
|
18
|
+
{ title: "Browse for File", value: "browse" },
|
|
19
|
+
],
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
if (selectionMode === "manual") {
|
|
23
|
+
const { manualPath } = await prompts({
|
|
24
|
+
type: "text",
|
|
25
|
+
name: "manualPath",
|
|
26
|
+
message: "Enter the path to the file",
|
|
27
|
+
})
|
|
28
|
+
return manualPath
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let currentDirectory = "."
|
|
32
|
+
while (true) {
|
|
33
|
+
const files = await fs.readdir(currentDirectory)
|
|
34
|
+
const { selectedFile } = await prompts({
|
|
35
|
+
type: "autocomplete",
|
|
36
|
+
name: "selectedFile",
|
|
37
|
+
message: "Select a file or directory",
|
|
38
|
+
choices: [
|
|
39
|
+
{ title: ".. (Go Up)", value: ".." },
|
|
40
|
+
...files.map((file) => ({ title: file, value: file })),
|
|
41
|
+
],
|
|
42
|
+
})
|
|
43
|
+
if (selectedFile === "..") {
|
|
44
|
+
// Go up one directory
|
|
45
|
+
const lastIndex = currentDirectory.lastIndexOf("/")
|
|
46
|
+
currentDirectory = currentDirectory.substring(0, lastIndex)
|
|
47
|
+
} else {
|
|
48
|
+
// Check if selectedFile is a file or directory
|
|
49
|
+
const stats = await fs.stat(`${currentDirectory}/${selectedFile}`)
|
|
50
|
+
if (stats.isFile()) {
|
|
51
|
+
// Break out of the loop and return the selected file
|
|
52
|
+
return `${currentDirectory}/${selectedFile}`
|
|
53
|
+
} else {
|
|
54
|
+
// Go into the selected directory
|
|
55
|
+
currentDirectory = `${currentDirectory}/${selectedFile}`
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { interactForPackageReleaseId } from "./interact-for-package-release-id"
|
|
2
|
+
import { ParamHandler } from "./param-handler-type"
|
|
3
|
+
|
|
4
|
+
export const interactForPackageExampleId: ParamHandler = async (params) => {
|
|
5
|
+
const { prompts, ctx } = params
|
|
6
|
+
const package_release_id = await interactForPackageReleaseId(params)
|
|
7
|
+
|
|
8
|
+
const package_examples = await ctx.axios
|
|
9
|
+
.post("/package_examples/list", {
|
|
10
|
+
package_release_id,
|
|
11
|
+
})
|
|
12
|
+
.then((r) => r.data.package_examples)
|
|
13
|
+
|
|
14
|
+
const { package_example_id } = await prompts({
|
|
15
|
+
type: "autocomplete",
|
|
16
|
+
name: "package_example_id",
|
|
17
|
+
message: "Select a package example",
|
|
18
|
+
choices: package_examples.map((p: any) => ({
|
|
19
|
+
title: `${p.file_path} (${p.export_name})`,
|
|
20
|
+
value: p.package_example_id,
|
|
21
|
+
})),
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
return package_example_id
|
|
25
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ParamHandler } from "./param-handler-type"
|
|
2
|
+
|
|
3
|
+
export const interactForPackageNameWithVersion: ParamHandler = async ({
|
|
4
|
+
prompts,
|
|
5
|
+
ctx,
|
|
6
|
+
}) => {
|
|
7
|
+
// Find all package names by this user
|
|
8
|
+
const myPackages: Array<{ name: string; latest_version: string }> =
|
|
9
|
+
await ctx.axios
|
|
10
|
+
.post("/packages/list", {
|
|
11
|
+
is_writable: true,
|
|
12
|
+
})
|
|
13
|
+
.then((r) => r.data.packages)
|
|
14
|
+
|
|
15
|
+
// Autocomplete prompts with all packages, first option is "Enter Manually"
|
|
16
|
+
const { selectedPackage } = await prompts({
|
|
17
|
+
type: "autocomplete",
|
|
18
|
+
name: "selectedPackage",
|
|
19
|
+
message: "Select a package",
|
|
20
|
+
choices: [
|
|
21
|
+
{
|
|
22
|
+
title: "Enter Manually",
|
|
23
|
+
value: null,
|
|
24
|
+
},
|
|
25
|
+
...myPackages.flatMap((p) => [
|
|
26
|
+
{
|
|
27
|
+
title: `${p.name}@${p.latest_version}`,
|
|
28
|
+
value: `${p.name}@${p.latest_version}`,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: `${p.name}@...`,
|
|
32
|
+
value: `${p.name}@...`,
|
|
33
|
+
},
|
|
34
|
+
]),
|
|
35
|
+
],
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
if (selectedPackage.endsWith("@...")) {
|
|
39
|
+
// TODO Poll for all versions available
|
|
40
|
+
|
|
41
|
+
const { version } = await prompts({
|
|
42
|
+
type: "text",
|
|
43
|
+
name: "version",
|
|
44
|
+
message: "Enter the version",
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
return selectedPackage.replace("@...", `@${version}`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (selectedPackage === "Enter Manually") {
|
|
51
|
+
const { packageName } = await prompts({
|
|
52
|
+
type: "text",
|
|
53
|
+
name: "packageName",
|
|
54
|
+
message: "Enter the package name",
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
return packageName
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// TODO cache recently selected packages
|
|
61
|
+
|
|
62
|
+
return selectedPackage
|
|
63
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ParamHandler } from "./param-handler-type"
|
|
2
|
+
import * as fs from "fs/promises"
|
|
3
|
+
|
|
4
|
+
export const interactForPackageName: ParamHandler = async ({
|
|
5
|
+
prompts,
|
|
6
|
+
ctx,
|
|
7
|
+
}) => {
|
|
8
|
+
// Find all package names by this user
|
|
9
|
+
const myPackages: Array<{ name: string }> = await ctx.axios
|
|
10
|
+
.post("/packages/list", {
|
|
11
|
+
is_writable: true,
|
|
12
|
+
})
|
|
13
|
+
.then((r) => r.data.packages)
|
|
14
|
+
|
|
15
|
+
// Autocomplete prompts with all packages, first option is "Enter Manually"
|
|
16
|
+
const { selectedPackage } = await prompts({
|
|
17
|
+
type: "autocomplete",
|
|
18
|
+
name: "selectedPackage",
|
|
19
|
+
message: "Select a package",
|
|
20
|
+
choices: [
|
|
21
|
+
{
|
|
22
|
+
title: "Enter Manually",
|
|
23
|
+
value: null,
|
|
24
|
+
},
|
|
25
|
+
...myPackages.map((p) => ({
|
|
26
|
+
title: p.name,
|
|
27
|
+
value: p.name,
|
|
28
|
+
})),
|
|
29
|
+
],
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
if (selectedPackage === "Enter Manually") {
|
|
33
|
+
const { packageName } = await prompts({
|
|
34
|
+
type: "text",
|
|
35
|
+
name: "packageName",
|
|
36
|
+
message: "Enter the package name",
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return packageName
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// TODO cache recently selected packages
|
|
43
|
+
|
|
44
|
+
return selectedPackage
|
|
45
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { interactForPackageNameWithVersion } from "./interact-for-package-name-with-version"
|
|
2
|
+
import { ParamHandler } from "./param-handler-type"
|
|
3
|
+
|
|
4
|
+
export const interactForPackageReleaseId: ParamHandler = async (params) => {
|
|
5
|
+
const { ctx, prompts } = params
|
|
6
|
+
|
|
7
|
+
const package_name_with_version = await interactForPackageNameWithVersion(
|
|
8
|
+
params
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
return await ctx.axios
|
|
12
|
+
.post("/package_releases/get", {
|
|
13
|
+
package_name_with_version,
|
|
14
|
+
})
|
|
15
|
+
.then((r) => r.data.package_release.package_release_id)
|
|
16
|
+
}
|
package/lib/soupify.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { AppContext } from "./util/app-context"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
import $ from "dax-sh"
|
|
4
|
+
import * as Path from "path"
|
|
5
|
+
import { unlink } from "node:fs/promises"
|
|
6
|
+
import kleur from "kleur"
|
|
7
|
+
import { writeFileSync } from "fs"
|
|
8
|
+
|
|
9
|
+
export const soupify = async ({
|
|
10
|
+
filePath,
|
|
11
|
+
exportName,
|
|
12
|
+
}: {
|
|
13
|
+
filePath: string
|
|
14
|
+
exportName?: string
|
|
15
|
+
}) => {
|
|
16
|
+
const tmpFilePath = Path.join(
|
|
17
|
+
Path.dirname(filePath),
|
|
18
|
+
Path.basename(filePath).replace(/\.[^\.]+$/, "") + ".__tmp_entrypoint.tsx"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
writeFileSync(
|
|
22
|
+
tmpFilePath,
|
|
23
|
+
`
|
|
24
|
+
import React from "react"
|
|
25
|
+
import { createRoot } from "@tscircuit/react-fiber"
|
|
26
|
+
import { createProjectBuilder } from "@tscircuit/builder"
|
|
27
|
+
|
|
28
|
+
import * as EXPORTS from "./${Path.basename(filePath)}"
|
|
29
|
+
|
|
30
|
+
const Component = EXPORTS["${exportName}"]
|
|
31
|
+
|
|
32
|
+
if (!Component) {
|
|
33
|
+
console.log(JSON.stringify({
|
|
34
|
+
COMPILE_ERROR: 'Failed to find "${exportName}" export in "${filePath}"'
|
|
35
|
+
}))
|
|
36
|
+
process.exit(0)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const projectBuilder = createProjectBuilder()
|
|
40
|
+
const elements = await createRoot().render(<Component />, projectBuilder)
|
|
41
|
+
|
|
42
|
+
console.log(JSON.stringify(elements))
|
|
43
|
+
|
|
44
|
+
`.trim()
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
const processResult = await $`bun ${tmpFilePath}`.captureCombined(true)
|
|
48
|
+
|
|
49
|
+
const rawSoup = processResult.stdout
|
|
50
|
+
const errText = processResult.stderr
|
|
51
|
+
|
|
52
|
+
await unlink(tmpFilePath)
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const soup = JSON.parse(rawSoup)
|
|
56
|
+
|
|
57
|
+
if (soup.COMPILE_ERROR) {
|
|
58
|
+
// console.log(kleur.red(`Failed to compile ${filePath}`))
|
|
59
|
+
// console.log(soup.COMPILE_ERROR)
|
|
60
|
+
throw new Error(soup.COMPILE_ERROR)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return soup
|
|
64
|
+
} catch (e: any) {
|
|
65
|
+
// console.log(kleur.red(`Failed to parse result of soupify: ${e.toString()}`))
|
|
66
|
+
const t = Date.now()
|
|
67
|
+
console.log(`Outputting raw soupify result to .tscircuit/err-${t}.log`)
|
|
68
|
+
writeFileSync(`.tscircuit/err-${t}.log`, rawSoup + "\n\n" + errText)
|
|
69
|
+
throw e
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AxiosInstance } from "axios"
|
|
2
|
+
import Configstore from "configstore"
|
|
3
|
+
|
|
4
|
+
export type AppContext = {
|
|
5
|
+
args: any
|
|
6
|
+
cwd: string
|
|
7
|
+
cmd: string[]
|
|
8
|
+
params: Record<string, any>
|
|
9
|
+
registry_url: string
|
|
10
|
+
axios: AxiosInstance
|
|
11
|
+
profile: string
|
|
12
|
+
profile_config: Configstore
|
|
13
|
+
global_config: Configstore
|
|
14
|
+
}
|