Skip to content

Commit

Permalink
refactoring to support loading soupification (wip), fix many command
Browse files Browse the repository at this point in the history
line usability issues when not interactive, add dev server reset, allow
runtime selection
  • Loading branch information
seveibar committed Mar 22, 2024
1 parent 540893a commit c446c91
Show file tree
Hide file tree
Showing 28 changed files with 302 additions and 98 deletions.
3 changes: 3 additions & 0 deletions dev-server-api/routes/api/dev_package_examples/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default withEdgeSpec({
export_name: z.string().default("default"),
tscircuit_soup: z.any(),
error: z.string().nullable().optional().default(null),
is_loading: z.boolean().optional(),
}),
jsonResponse: z.object({
dev_package_example: z.object({
Expand All @@ -31,13 +32,15 @@ export default withEdgeSpec({
export_name: req.jsonBody.export_name,
error: req.jsonBody.error,
tscircuit_soup,
is_loading: req.jsonBody.is_loading ? 1 : 0,
last_updated_at: new Date().toISOString(),
})
.onConflict((oc) =>
oc.columns(["file_path"]).doUpdateSet({
export_name: req.jsonBody.export_name,
error: req.jsonBody.error,
tscircuit_soup,
is_loading: req.jsonBody.is_loading ? 1 : 0,
last_updated_at: new Date().toISOString(),
})
)
Expand Down
22 changes: 13 additions & 9 deletions dev-server-api/routes/api/dev_package_examples/list.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { sql } from "kysely"
import { withEdgeSpec } from "src/with-edge-spec"
import { z } from "zod"

Expand All @@ -9,21 +10,24 @@ export default withEdgeSpec({
dev_package_example_id: z.coerce.number(),
file_path: z.string(),
export_name: z.string(),
is_loading: z.coerce.boolean(),
last_updated_at: z.string().datetime(),
})
),
}),
auth: "none",
})(async (req, ctx) => {
const dev_package_examples = await ctx.db
.selectFrom("dev_package_example")
.select([
"dev_package_example_id",
"file_path",
"export_name",
"last_updated_at",
sql`(is_loading = 1)`.$castTo<boolean>().as("is_loading"),
])
.execute()
return ctx.json({
dev_package_examples: await ctx.db
.selectFrom("dev_package_example")
.select([
"dev_package_example_id",
"file_path",
"export_name",
"last_updated_at",
])
.execute(),
dev_package_examples,
})
})
15 changes: 15 additions & 0 deletions dev-server-api/routes/api/dev_server/reset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { sql } from "kysely"
import { withEdgeSpec } from "src/with-edge-spec"
import { z } from "zod"
import { unlinkSync } from "fs"
import { getDbFilePath } from "src/db/get-db"

export default (req: Request) => {
unlinkSync(getDbFilePath())

return new Response(JSON.stringify({}), {
headers: {
"content-type": "application/json",
},
})
}
1 change: 1 addition & 0 deletions dev-server-api/src/db/create-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const createSchema = async (db: DbClient) => {
.addColumn("export_name", "text")
.addColumn("tscircuit_soup", "json")
.addColumn("error", "text")
.addColumn("is_loading", "boolean", (cb) => cb.defaultTo(0).notNull())
.addColumn("last_updated_at", "text")
.execute()
}
7 changes: 5 additions & 2 deletions dev-server-api/src/db/get-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface DevPackageExample {
file_path: string
export_name: string
error: string | null
is_loading: 1 | 0
last_updated_at: string
}

Expand All @@ -22,11 +23,13 @@ export type DbClient = Kysely<KyselyDatabaseSchema>

let globalDb: Kysely<KyselyDatabaseSchema> | undefined

export const getDbFilePath = () =>
process.env.TSCI_DEV_SERVER_DB ?? "./.tscircuit/dev-server.db"

export const getDb = async (): Promise<Kysely<KyselyDatabaseSchema>> => {
if (globalDb) return globalDb

const devServerDbPath =
process.env.TSCI_DEV_SERVER_DB ?? "./.tscircuit/dev-server.db"
const devServerDbPath = getDbFilePath()

mkdirSync(Path.dirname(devServerDbPath), { recursive: true })

Expand Down
17 changes: 15 additions & 2 deletions dev-server-api/src/middlewares/with-error-response.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import type { Middleware } from "edgespec/middleware"
import { NotFoundError, type Middleware } from "edgespec/middleware"
import kleur from "kleur"

export const withErrorResponse: Middleware<{}, {}> = async (req, ctx, next) => {
try {
return await next(req, ctx)
} catch (error: any) {
console.error(kleur.red("Intercepted error:"), error)
// If error is a Response, return it
if (error instanceof Response) {
return error
}
if (error instanceof NotFoundError) {
return (ctx as any).json(
{
ok: false,
error: {
message: error?.message,
error_code: "not_found",
},
},
{ status: error?.status || 404 }
)
}

console.error(kleur.red("Intercepted unhandled error:"), error)
return (ctx as any).json(
{
ok: false,
Expand Down
24 changes: 23 additions & 1 deletion dev-server-frontend/src/ExampleContentView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ export const ExampleContentView = () => {
(s) => s.active_dev_example_package_id
)

const { data: pkg } = useQuery(
const {
data: pkg,
error,
isError,
isLoading,
} = useQuery(
["dev_package_example", devExamplePackageId],
async () =>
axios
Expand All @@ -20,9 +25,12 @@ export const ExampleContentView = () => {
.then((r) => r.data.dev_package_example),
{
refetchIntervalInBackground: true,
retry: false,
}
)

const notFound = (error as any)?.response?.status === 404

const viewMode = useGlobalStore((s) => s.view_mode)
const splitMode = useGlobalStore((s) => s.split_mode)

Expand All @@ -44,6 +52,20 @@ export const ExampleContentView = () => {
viewMode === "split" && splitMode === "vertical" && "grid grid-rows-2"
)}
>
{notFound && (
<div className="absolute top-0 w-full flex justify-center">
<div className="bg-yellow-50 shadow-lg p-4 m-16 border-yellow-200 border rounded-lg whitespace-pre max-w-[400px]">
Select an example from the menu above
</div>
</div>
)}
{isLoading && !isError && (
<div className="absolute top-0 w-full flex justify-center">
<div className="bg-gray-50 shadow-lg p-4 m-16 border-gray-200 border rounded-lg whitespace-pre">
Loading...
</div>
</div>
)}
{pkg && (viewMode === "schematic" || viewMode === "split") && (
<Schematic
key={pkg?.last_updated_at}
Expand Down
34 changes: 29 additions & 5 deletions dev-server-frontend/src/components/command-k.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
CommandShortcut,
} from "./ui/command"
import { useGlobalStore } from "src/hooks/use-global-store"
import { useDevPackageExamples } from "./select-example-search"
import { CommandSeparator } from "cmdk"

export const CommandK = () => {
const [open, setOpen] = useState(false)
Expand All @@ -19,23 +21,28 @@ export const CommandK = () => {
e.preventDefault()
setOpen((open) => !open)
}
if (e.key === "Escape") {
setOpen(false)
}
}

document.addEventListener("keydown", down)
return () => document.removeEventListener("keydown", down)
}, [])

const { data: examples } = useDevPackageExamples()

const close = () => {
setOpen(false)
return true
}

return (
<CommandDialog open={open}>
<CommandDialog open={open} onOpenChange={(open) => setOpen(open)}>
<Command className="rounded-lg border shadow-md">
<CommandInput placeholder="Type a command or search..." />
<CommandGroup>
<CommandList>
<CommandList>
<CommandGroup heading="Viewing Options">
<CommandItem
onSelect={() => close() && store.setViewMode("schematic")}
>
Expand All @@ -54,8 +61,25 @@ export const CommandK = () => {
Vertical Split
<CommandShortcut></CommandShortcut>
</CommandItem>
</CommandList>
</CommandGroup>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Examples">
{examples?.map((ex) => (
<CommandItem
key={ex.dev_package_example_id}
value={ex.expath}
onSelect={() =>
close() &&
store.setActiveDevExamplePackageId(
ex.dev_package_example_id.toString()
)
}
>
{ex.expath}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</CommandDialog>
)
Expand Down
7 changes: 7 additions & 0 deletions lib/cmd-fns/config-set-runtime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { AppContext } from "../util/app-context"
import { z } from "zod"

export const configSetRuntime = async (ctx: AppContext, args: any) => {
const params = z.object({ runtime: z.enum(["bun", "node"]) }).parse(args)
ctx.global_config.set("runtime", params.runtime)
}
4 changes: 2 additions & 2 deletions lib/cmd-fns/dev-server-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ export const devServerUpload = async (ctx: AppContext, args: any) => {
const devServerAxios = getDevServerAxios({ serverUrl })

console.log(`Loading examples...`)
await uploadExamplesFromDirectory({ devServerAxios, cwd: params.dir })
await uploadExamplesFromDirectory({ devServerAxios, cwd: params.dir }, ctx)

if (params.watch) {
// Start watcher
const watcher = await startWatcher({ cwd: params.dir, devServerAxios })
const watcher = await startWatcher({ cwd: params.dir, devServerAxios }, ctx)
}
}
11 changes: 7 additions & 4 deletions lib/cmd-fns/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import { initCmd } from "../init"
export const devCmd = async (ctx: AppContext, args: any) => {
const params = z
.object({
cwd: z.string().optional().default(process.cwd()),
port: z.coerce.number().optional().default(3020),
})
.parse(args)

const { cwd, port } = params
const { port } = params
const { cwd } = ctx

// In the future we should automatically run "tsci init" if the directory
// isn't properly initialized, for now we're just going to do a spot check
Expand Down Expand Up @@ -66,12 +66,15 @@ export const devCmd = async (ctx: AppContext, args: any) => {

const server = await startDevServer({ port, devServerAxios })

// Reset the database, allows migration to re-run
await devServerAxios.post("/api/dev_server/reset")

// Soupify all examples
console.log(`Loading examples...`)
await uploadExamplesFromDirectory({ devServerAxios, cwd })
await uploadExamplesFromDirectory({ devServerAxios, cwd }, ctx)

// Start watcher
const watcher = await startWatcher({ cwd, devServerAxios })
const watcher = await startWatcher({ cwd, devServerAxios }, ctx)

while (true) {
const { action } = await prompts({
Expand Down
18 changes: 18 additions & 0 deletions lib/cmd-fns/dev/mark-all-examples-loading.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { AxiosInstance } from "axios"

export const markAllExamplesLoading = async ({
devServerAxios,
}: {
devServerAxios: AxiosInstance
}) => {
const examples = await devServerAxios
.post("/api/dev_package_examples/list")
.then((r) => r.data.dev_package_examples)

for (const example of examples) {
await devServerAxios.post("/api/dev_package_examples/update", {
dev_package_example_id: example.dev_package_example_id,
is_loading: true,
})
}
}
43 changes: 29 additions & 14 deletions lib/cmd-fns/dev/soupify-and-upload-example-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,33 @@ import { readdirSync, readFileSync } from "fs"
import { soupify } from "lib/soupify"
import { inferExportNameFromSource } from "./infer-export-name-from-source"

export const soupifyAndUploadExampleFile = async ({
examplesDir,
exampleFileName,
devServerAxios,
}: {
examplesDir: string
exampleFileName: string
devServerAxios: AxiosInstance
}) => {
export const soupifyAndUploadExampleFile = async (
{
examplesDir,
exampleFileName,
devServerAxios,
}: {
examplesDir: string
exampleFileName: string
devServerAxios: AxiosInstance
},
ctx: { runtime: "node" | "bun" }
) => {
try {
const startTime = Date.now()
const examplePath = joinPath(examplesDir, exampleFileName)
const exampleContent = readFileSync(examplePath).toString()

const exportName = inferExportNameFromSource(exampleContent)

console.log(kleur.gray(`[soupifying] ${exampleFileName}...`))
const { soup, error } = await soupify({
filePath: examplePath,
exportName,
})
const { soup, error } = await soupify(
{
filePath: examplePath,
exportName,
},
ctx
)
.then((soup) => ({ soup, error: null }))
.catch((e) => ({ error: e, soup: undefined }))

Expand All @@ -38,8 +45,16 @@ export const soupifyAndUploadExampleFile = async ({
error: error?.toString() || null,
file_path: examplePath,
export_name: exportName,
is_loading: false,
})
console.log(kleur.gray(`[ done ] ${exampleFileName}!`))
const timeTaken = Date.now() - startTime
console.log(
kleur.gray(
`[ done ] [ ${Math.round(timeTaken)
.toString()
.padStart(5, " ")}ms ] ${exampleFileName}!`
)
)
} catch (e: any) {
console.log(kleur.red(`[ error ] ${e.toString()}`))
}
Expand Down
Loading

0 comments on commit c446c91

Please sign in to comment.