Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions packages/charm/src/iframe/recipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ export const getIframeRecipe = (
runtime: Runtime,
): {
recipeId: string;
// `src` is either a single file string source, or the entry
// file source code in a recipe.
src?: string;
iframe?: IFrameRecipe;
} => {
Expand All @@ -76,9 +78,13 @@ export const getIframeRecipe = (
console.warn("No recipeId found for charm", getEntityId(charm));
return { recipeId, src: "", iframe: undefined };
}
const src = runtime.recipeManager.getRecipeMeta({ recipeId })?.src;
const meta = runtime.recipeManager.getRecipeMeta({ recipeId });
const src = meta
? (meta.src ??
meta.program?.files.find((file) => file.name === meta.program?.main)
?.contents)
: undefined;
if (!src) {
console.warn("No src found for charm", getEntityId(charm));
return { recipeId };
}
try {
Expand Down
6 changes: 5 additions & 1 deletion packages/charm/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ export {
modifyCharm,
renameCharm,
} from "./commands.ts";
export { getIframeRecipe, type IFrameRecipe } from "./iframe/recipe.ts";
export {
buildFullRecipe,
getIframeRecipe,
type IFrameRecipe,
} from "./iframe/recipe.ts";
export { type ParsedMention, type ProcessedPrompt } from "./imagine.ts";
export { formatPromptWithMentions, parseComposerDocument } from "./format.ts";

Expand Down
77 changes: 62 additions & 15 deletions packages/cli/lib/charm.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
import { ANYONE, Identity, Session } from "@commontools/identity";
import { ensureDir } from "@std/fs";
import { loadIdentity } from "./identity.ts";
import {
Cell,
getEntityId,
NAME,
Recipe,
RecipeMeta,
Runtime,
} from "@commontools/runner";
import { Cell, NAME, Recipe, RecipeMeta, Runtime } from "@commontools/runner";
import { StorageManager } from "@commontools/runner/storage/cache";
import {
buildFullRecipe,
Charm,
charmId,
CharmManager,
compileRecipe,
extractUserCode,
getIframeRecipe,
getRecipeIdFromCharm,
injectUserCode,
processSchema,
} from "@commontools/charm";
import { dirname, join } from "@std/path";
import { join } from "@std/path";
import { CliProgram } from "./dev.ts";

export interface SpaceConfig {
Expand Down Expand Up @@ -97,6 +94,29 @@ async function getRecipeMeta(
) as RecipeMeta;
}

async function getIframeRecipeFromFile(
manager: CharmManager,
mainPath: string,
charmId: string,
): Promise<Recipe> {
const charm = await manager.get(charmId);
if (!charm) {
throw new Error(`Charm "${charmId}" not found.`);
}
const iframeRecipe = getIframeRecipe(charm, manager.runtime);
if (!iframeRecipe.iframe) {
throw new Error(`Expected charm "${charmId}" to be an iframe recipe.`);
}
iframeRecipe.iframe.src = injectUserCode(await Deno.readTextFile(mainPath));
return await compileRecipe(
buildFullRecipe(iframeRecipe.iframe),
"recipe",
manager.runtime,
manager.getSpace(),
undefined,
);
}

async function getRecipeFromFile(
manager: CharmManager,
mainPath: string,
Expand All @@ -119,6 +139,10 @@ async function getRecipeFromService(
charmId: string,
): Promise<Recipe> {
const charm = await manager.get(charmId, false);
if (!charm) {
throw new Error(`Charm "${charmId}" not found`);
}

const recipeId = getRecipeIdFromCharm(charm!);
return await manager.runtime.recipeManager.loadRecipe(
recipeId,
Expand Down Expand Up @@ -180,10 +204,15 @@ export async function setCharmRecipe(
mainPath: string,
): Promise<void> {
const manager = await loadManager(config);
const recipe = await getRecipeFromFile(
manager,
mainPath,
);
let recipe;
if (mainPath.endsWith(".iframe.js")) {
recipe = await getIframeRecipeFromFile(manager, mainPath, config.charm);
} else {
recipe = await getRecipeFromFile(
manager,
mainPath,
);
}
await exec({ manager, recipe, charmId: config.charm });
}

Expand All @@ -193,9 +222,27 @@ export async function saveCharmRecipe(
): Promise<void> {
await ensureDir(outPath);
const manager = await loadManager(config);
const meta = await getRecipeMeta(manager, config.charm);
const recipe = await getRecipeFromService(manager, config.charm);
const meta = manager.runtime.recipeManager.getRecipeMeta(
recipe,
) as RecipeMeta;

if (meta.src) {
const charm = await manager.get(config.charm);
if (!charm) {
throw new Error(`Charm ${config.charm} not found.`);
}

const iframeRecipe = getIframeRecipe(charm, manager.runtime);
if (iframeRecipe.iframe) {
const userCode = extractUserCode(iframeRecipe.iframe.src);
if (!userCode) {
throw new Error(`No user code found in iframe recipe "${config.charm}".`);
}
await Deno.writeTextFile(
join(outPath, "main.iframe.js"),
userCode,
);
} else if (meta.src) {
// Write the main source file
await Deno.writeTextFile(join(outPath, "main.tsx"), meta.src);
} else if (meta.program) {
Expand Down