@animaapp/anima-sdk 0.2.1 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@animaapp/anima-sdk",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "description": "Anima's JavaScript utilities library",
6
6
  "author": "Anima App, Inc.",
@@ -34,4 +34,4 @@
34
34
  "vite-tsconfig-paths": "^5.1.4",
35
35
  "vitest": "^3.0.5"
36
36
  }
37
- }
37
+ }
package/src/anima.ts CHANGED
@@ -9,7 +9,7 @@ import {
9
9
 
10
10
  export type Auth =
11
11
  | { token: string; teamId: string } // for Anima user, it's mandatory to have an associated team
12
- | { token: string; userId?: string }; // for users from a 3rd-party client (e.g., Bolt) they may have optionally a user id
12
+ | { token: string; userId?: string }; // for users from a 3rd-party integrations, they may have optionally a user id
13
13
 
14
14
  export class Anima {
15
15
  #auth?: Auth;
@@ -84,6 +84,7 @@ export class Anima {
84
84
  uiLibrary: settings.uiLibrary,
85
85
  enableTranslation: settings.enableTranslation,
86
86
  enableUILibraryTheming: settings.enableUILibraryTheming,
87
+ enableCompactStructure: settings.enableCompactStructure,
87
88
  }),
88
89
  });
89
90
 
@@ -225,6 +226,7 @@ export class Anima {
225
226
  reason: "No files found",
226
227
  });
227
228
  }
229
+ result.tokenUsage = data.payload.tokenUsage;
228
230
  return result as AnimaSDKResult;
229
231
  }
230
232
  }
package/src/dataStream.ts CHANGED
@@ -38,7 +38,12 @@ export const createCodegenStream = (
38
38
  }
39
39
  })
40
40
  .then((_result) => {
41
- controller.enqueue({ type: "done" });
41
+ controller.enqueue({
42
+ type: "done", payload: {
43
+ tokenUsage: _result.tokenUsage,
44
+ sessionId: _result.sessionId,
45
+ }
46
+ });
42
47
  controller.close();
43
48
  })
44
49
  .catch((error) => {
package/src/settings.ts CHANGED
@@ -20,6 +20,7 @@ const CodegenSettingsSchema = z
20
20
  ]),
21
21
  uiLibrary: z.enum(["mui", "antd", "radix", "shadcn"]).optional(),
22
22
  enableUILibraryTheming: z.boolean().optional(),
23
+ enableCompactStructure: z.boolean().optional(),
23
24
  }),
24
25
  z.object({
25
26
  framework: z.literal("html"),
@@ -32,7 +33,7 @@ const CodegenSettingsSchema = z
32
33
  // We don't use the z.infer method here because the types returned by zod aren't ergonic
33
34
  export type CodegenSettings = {
34
35
  language?: "typescript" | "javascript";
35
- model?: string,
36
+ model?: string;
36
37
  framework: "react" | "html";
37
38
  styling:
38
39
  | "plain_css"
@@ -41,10 +42,11 @@ export type CodegenSettings = {
41
42
  | "tailwind"
42
43
  | "sass"
43
44
  | "scss"
44
- | "inline_styles"
45
+ | "inline_styles";
45
46
  uiLibrary?: "mui" | "antd" | "radix" | "shadcn";
46
47
  enableTranslation?: boolean;
47
48
  enableUILibraryTheming?: boolean;
49
+ enableCompactStructure?: boolean;
48
50
  };
49
51
 
50
52
  export const validateSettings = (obj: unknown): CodegenSettings => {
package/src/types.ts CHANGED
@@ -13,6 +13,7 @@ export type BaseResult = {
13
13
  sessionId: string;
14
14
  figmaFileName: string;
15
15
  figmaSelectedFrameName: string;
16
+ tokenUsage: number;
16
17
  };
17
18
 
18
19
  export type AnimaSDKResult = BaseResult & {
@@ -39,32 +40,32 @@ export type GetCodeParams = {
39
40
  export type GetCodeHandler =
40
41
  | ((message: SSECodgenMessage) => void)
41
42
  | {
42
- onStart?: ({ sessionId }: { sessionId: string }) => void;
43
- onPreCodegen?: ({ message }: { message: string }) => void;
44
- onAssetsUploaded?: () => void;
45
- onAssetsList?: ({
46
- assets,
47
- }: {
48
- assets: Array<{ name: string; url: string }>;
49
- }) => void;
50
- onFigmaMetadata?: ({
51
- figmaFileName,
52
- figmaSelectedFrameName,
53
- }: {
54
- figmaFileName: string;
55
- figmaSelectedFrameName: string;
56
- }) => void;
57
- onGeneratingCode?: ({
58
- status,
59
- progress,
60
- files,
61
- }: {
62
- status: "success" | "running" | "failure";
63
- progress: number;
64
- files: AnimaFiles;
65
- }) => void;
66
- onCodegenCompleted?: () => void;
67
- };
43
+ onStart?: ({ sessionId }: { sessionId: string }) => void;
44
+ onPreCodegen?: ({ message }: { message: string }) => void;
45
+ onAssetsUploaded?: () => void;
46
+ onAssetsList?: ({
47
+ assets,
48
+ }: {
49
+ assets: Array<{ name: string; url: string }>;
50
+ }) => void;
51
+ onFigmaMetadata?: ({
52
+ figmaFileName,
53
+ figmaSelectedFrameName,
54
+ }: {
55
+ figmaFileName: string;
56
+ figmaSelectedFrameName: string;
57
+ }) => void;
58
+ onGeneratingCode?: ({
59
+ status,
60
+ progress,
61
+ files,
62
+ }: {
63
+ status: "success" | "running" | "failure";
64
+ progress: number;
65
+ files: AnimaFiles;
66
+ }) => void;
67
+ onCodegenCompleted?: () => void;
68
+ };
68
69
 
69
70
  export type GeneratingCodePayload = {
70
71
  status: "success" | "running" | "failure";
@@ -77,20 +78,20 @@ export type SSECodgenMessage =
77
78
  | { type: "start"; sessionId: string }
78
79
  | { type: "pre_codegen"; message: string }
79
80
  | {
80
- type: "figma_metadata";
81
- figmaFileName: string;
82
- figmaSelectedFrameName: string;
83
- }
81
+ type: "figma_metadata";
82
+ figmaFileName: string;
83
+ figmaSelectedFrameName: string;
84
+ }
84
85
  | { type: "generating_code"; payload: GeneratingCodePayload }
85
86
  | { type: "codegen_completed" }
86
87
  | { type: "assets_uploaded" }
87
88
  | {
88
- type: "assets_list";
89
- payload: { assets: Array<{ name: string; url: string }> };
90
- }
89
+ type: "assets_list";
90
+ payload: { assets: Array<{ name: string; url: string }> };
91
+ }
91
92
  | { type: "aborted" }
92
93
  | { type: "error"; payload: SSECodgenMessageErrorPayload }
93
- | { type: "done" };
94
+ | { type: "done", payload: { sessionId: string, tokenUsage: number } };
94
95
  export type SSECodgenMessageErrorPayload = {
95
96
  errorName: string;
96
97
  task?: string;
@@ -0,0 +1,95 @@
1
+ import { AnimaFiles } from "../types";
2
+
3
+ export const getRelatedScreenFiles = ({
4
+ files,
5
+ screenPath = "src/screens",
6
+ }: {
7
+ files: AnimaFiles;
8
+ screenPath?: string;
9
+ }) => {
10
+ const result: AnimaFiles = {};
11
+ const processed = new Set<string>();
12
+
13
+ function processFile(filePath: string) {
14
+ if (processed.has(filePath) || !files[filePath]) {
15
+ return;
16
+ }
17
+
18
+ processed.add(filePath);
19
+ result[filePath] = files[filePath];
20
+
21
+ const imports = parseImports(files[filePath].content);
22
+
23
+ imports.forEach((importPath) => {
24
+ try {
25
+ const resolvedPath = resolveImportPath(filePath, importPath);
26
+
27
+ if (resolvedPath.startsWith("src/")) {
28
+ const importDir = resolvedPath.split("/").slice(0, -1).join("/");
29
+ const dirFiles = getAllFilesInDirectory(files, importDir);
30
+ dirFiles.forEach((file) => {
31
+ if (!processed.has(file)) {
32
+ processFile(file);
33
+ }
34
+ });
35
+ }
36
+ } catch (error) {
37
+ console.warn(
38
+ `Failed to resolve import ${importPath} in ${filePath}:`,
39
+ error
40
+ );
41
+ }
42
+ });
43
+ }
44
+
45
+ Object.entries(files).forEach(([key, value]) => {
46
+ if (key.startsWith(screenPath)) {
47
+ processFile(key);
48
+ } else if (!key.startsWith("src/")) {
49
+ result[key] = value;
50
+ }
51
+ });
52
+
53
+ return result;
54
+ };
55
+
56
+ function parseImports(content: string): string[] {
57
+ const importRegex = /import.*?["']([^"']+)["']/g;
58
+ const exports = /export.*from\s+["']([^"']+)["']/g;
59
+ const imports: string[] = [];
60
+ let match;
61
+
62
+ while ((match = importRegex.exec(content)) !== null) {
63
+ imports.push(match[1]);
64
+ }
65
+
66
+ while ((match = exports.exec(content)) !== null) {
67
+ imports.push(match[1]);
68
+ }
69
+
70
+ return [...new Set(imports)];
71
+ }
72
+
73
+ function resolveImportPath(basePath: string, importPath: string): string {
74
+ if (!importPath.startsWith(".")) {
75
+ return importPath;
76
+ }
77
+
78
+ const baseDir = basePath.split("/").slice(0, -1);
79
+ const importParts = importPath.split("/");
80
+ const resolvedParts: string[] = [...baseDir];
81
+
82
+ for (const part of importParts) {
83
+ if (part === "..") {
84
+ resolvedParts.pop();
85
+ } else if (part !== ".") {
86
+ resolvedParts.push(part);
87
+ }
88
+ }
89
+
90
+ return resolvedParts.join("/");
91
+ }
92
+
93
+ function getAllFilesInDirectory(files: AnimaFiles, dirPath: string): string[] {
94
+ return Object.keys(files).filter((file) => file.startsWith(dirPath));
95
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./figma";
2
+ export * from "./files";
File without changes