@animaapp/anima-sdk 0.3.1 → 0.3.4

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.
@@ -1,73 +0,0 @@
1
- import type { GetFileResponse, Node } from '@figma/rest-api-spec';
2
- import { FigmaRestApi } from '@animaapp/http-client-figma';
3
- import { handleFigmaApiError, type FigmaApiError } from './figmaError';
4
-
5
- export type FigmaNode = Node;
6
- export type GetFileParams = { fileKey: string; authToken?: string; figmaRestApi?: FigmaRestApi };
7
-
8
- export type FigmaPage = { id: string; name: string };
9
- export type GetFilePagesParams = {
10
- fileKey: string;
11
- authToken?: string;
12
- figmaRestApi?: FigmaRestApi;
13
- params?: Record<string, string | number | undefined>;
14
- };
15
- export type GetFilePagesResult = FigmaPage[] | undefined;
16
- export type GetFileNodesParams = {
17
- fileKey: string;
18
- authToken?: string;
19
- nodeIds: string[];
20
- figmaRestApi?: FigmaRestApi;
21
- params?: Record<string, string | number>;
22
- };
23
-
24
- export type GetFigmaFileResult = GetFileResponse | undefined;
25
-
26
- export const getFigmaFile = async ({
27
- fileKey,
28
- authToken,
29
- figmaRestApi = new FigmaRestApi(),
30
- params = {},
31
- }: GetFilePagesParams): Promise<GetFigmaFileResult> => {
32
- if (authToken) {
33
- figmaRestApi.token = authToken;
34
- }
35
-
36
- try {
37
- const rootFile = await figmaRestApi.files.get({
38
- fileKey,
39
- params,
40
- });
41
-
42
- return rootFile;
43
- } catch (error) {
44
- console.error(error);
45
- throw error;
46
- }
47
- };
48
-
49
- export const getFileNodes = async ({
50
- fileKey,
51
- authToken,
52
- nodeIds,
53
- figmaRestApi = new FigmaRestApi(),
54
- params = {},
55
- }: GetFileNodesParams) => {
56
- if (authToken) {
57
- figmaRestApi.token = authToken;
58
- }
59
-
60
- try {
61
- const data = await figmaRestApi.nodes.get({
62
- fileKey,
63
- nodeIds,
64
- params: {
65
- ...params,
66
- },
67
- });
68
-
69
- return data.nodes;
70
- } catch (error) {
71
- return handleFigmaApiError(error as FigmaApiError, fileKey);
72
- }
73
- };
package/src/index.ts DELETED
@@ -1,7 +0,0 @@
1
- export * from "./anima";
2
- export * from "./types";
3
- export * from "./errors";
4
- export * from "./utils";
5
- export * from "./figma";
6
- export * from "./settings";
7
- export * from "./dataStream";
package/src/settings.ts DELETED
@@ -1,68 +0,0 @@
1
- import { z } from "zod";
2
-
3
- const CodegenSettingsSchema = z
4
- .object({
5
- language: z.enum(["typescript", "javascript"]).optional(),
6
- disableMarkedForExport: z.boolean().optional(),
7
- })
8
- .and(
9
- z.union([
10
- z.object({
11
- framework: z.literal("react"),
12
- model: z.string().optional(),
13
- styling: z.enum([
14
- "plain_css",
15
- "css_modules",
16
- "styled_components",
17
- "tailwind",
18
- "sass",
19
- "scss",
20
- "inline_styles",
21
- ]),
22
- uiLibrary: z.enum(["mui", "antd", "radix", "shadcn"]).optional(),
23
- enableUILibraryTheming: z.boolean().optional(),
24
- enableCompactStructure: z.boolean().optional(),
25
- enableAutoSplit: z.boolean().optional(),
26
- autoSplitThreshold: z.number().optional(),
27
- }),
28
- z.object({
29
- framework: z.literal("html"),
30
- styling: z.enum(["plain_css", "inline_styles"]),
31
- enableTranslation: z.boolean().optional(),
32
- }),
33
- ])
34
- );
35
-
36
- // We don't use the z.infer method here because the types returned by zod aren't ergonic
37
- export type CodegenSettings = {
38
- language?: "typescript" | "javascript";
39
- model?: string;
40
- framework: "react" | "html";
41
- styling:
42
- | "plain_css"
43
- | "css_modules"
44
- | "styled_components"
45
- | "tailwind"
46
- | "sass"
47
- | "scss"
48
- | "inline_styles";
49
- uiLibrary?: "mui" | "antd" | "radix" | "shadcn";
50
- enableTranslation?: boolean;
51
- enableUILibraryTheming?: boolean;
52
- enableCompactStructure?: boolean;
53
- enableAutoSplit?: boolean;
54
- autoSplitThreshold?: number;
55
- disableMarkedForExport?: boolean;
56
- };
57
-
58
- export const validateSettings = (obj: unknown): CodegenSettings => {
59
- const parsedObj = CodegenSettingsSchema.safeParse(obj);
60
-
61
- if (parsedObj.success === false) {
62
- const error = new Error("Invalid codegen settings");
63
- error.cause = parsedObj.error;
64
- throw error;
65
- }
66
-
67
- return parsedObj.data;
68
- };
package/src/types.ts DELETED
@@ -1,106 +0,0 @@
1
- import type { CodegenErrorReason } from "./errors";
2
- import type { CodegenSettings } from "./settings";
3
-
4
- export type AnimaFiles = Record<
5
- string,
6
- {
7
- content: string;
8
- isBinary: boolean;
9
- }
10
- >;
11
-
12
- export type BaseResult = {
13
- sessionId: string;
14
- figmaFileName: string;
15
- figmaSelectedFrameName: string;
16
- tokenUsage: number;
17
- };
18
-
19
- export type AnimaSDKResult = BaseResult & {
20
- files: AnimaFiles;
21
- assets?: Array<{ name: string; url: string }>;
22
- };
23
-
24
- export type CodegenResult = BaseResult & {
25
- files: Record<string, { code: string; type: "code" }>;
26
- };
27
-
28
- export type AssetsStorage =
29
- | { strategy: "host" }
30
- | { strategy: "external"; url: string };
31
-
32
- export type TrackingInfos = {
33
- externalId: string;
34
- }
35
-
36
- export type GetCodeParams = {
37
- fileKey: string;
38
- figmaToken?: string;
39
- nodesId: string[];
40
- assetsStorage?: AssetsStorage;
41
- settings: CodegenSettings;
42
- tracking?: TrackingInfos;
43
- };
44
-
45
- export type GetCodeHandler =
46
- | ((message: SSECodgenMessage) => void)
47
- | {
48
- onQueueing?: () => void;
49
- onStart?: ({ sessionId }: { sessionId: string }) => void;
50
- onPreCodegen?: ({ message }: { message: string }) => void;
51
- onAssetsUploaded?: () => void;
52
- onAssetsList?: ({
53
- assets,
54
- }: {
55
- assets: Array<{ name: string; url: string }>;
56
- }) => void;
57
- onFigmaMetadata?: ({
58
- figmaFileName,
59
- figmaSelectedFrameName,
60
- }: {
61
- figmaFileName: string;
62
- figmaSelectedFrameName: string;
63
- }) => void;
64
- onGeneratingCode?: ({
65
- status,
66
- progress,
67
- files,
68
- }: {
69
- status: "success" | "running" | "failure";
70
- progress: number;
71
- files: AnimaFiles;
72
- }) => void;
73
- onCodegenCompleted?: () => void;
74
- };
75
-
76
- export type GeneratingCodePayload = {
77
- status: "success" | "running" | "failure";
78
- progress: number;
79
- files: AnimaFiles;
80
- };
81
-
82
- // TODO: `SSECodgenMessage` and `SSECodgenMessageErrorPayload` should be imported from `anima-public-api`
83
- export type SSECodgenMessage =
84
- | { type: "queueing" }
85
- | { type: "start"; sessionId: string }
86
- | { type: "pre_codegen"; message: string }
87
- | {
88
- type: "figma_metadata";
89
- figmaFileName: string;
90
- figmaSelectedFrameName: string;
91
- }
92
- | { type: "generating_code"; payload: GeneratingCodePayload }
93
- | { type: "codegen_completed" }
94
- | { type: "assets_uploaded" }
95
- | {
96
- type: "assets_list";
97
- payload: { assets: Array<{ name: string; url: string }> };
98
- }
99
- | { type: "aborted" }
100
- | { type: "error"; payload: SSECodgenMessageErrorPayload }
101
- | { type: "done"; payload: { sessionId: string; tokenUsage: number } };
102
- export type SSECodgenMessageErrorPayload = {
103
- errorName: string;
104
- task?: string;
105
- reason: CodegenErrorReason;
106
- };
@@ -1,31 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { formatToFigmaLink } from "./figma";
3
-
4
- describe("# figma", () => {
5
- describe(".formatToFigmaLink", () => {
6
- it("generates a link with file key and node id", () => {
7
- const url = formatToFigmaLink({
8
- fileKey: "file-key",
9
- nodeId: "1:2",
10
- });
11
-
12
- expect(url.href).toBe(
13
- "https://www.figma.com/design/file-key?node-id=1-2"
14
- );
15
- });
16
-
17
- describe('when the "duplicate" flag is enabled', () => {
18
- it("generates a link including the '/duplicated' path", () => {
19
- const url = formatToFigmaLink({
20
- fileKey: "file-key",
21
- nodeId: "1:2",
22
- duplicate: true,
23
- });
24
-
25
- expect(url.href).toBe(
26
- "https://www.figma.com/design/file-key/duplicate?node-id=1-2"
27
- );
28
- });
29
- });
30
- });
31
- });
@@ -1,59 +0,0 @@
1
- export const isValidFigmaUrl = (
2
- figmaLink: string
3
- ): [hasCorrectPrefix: boolean, fileKey: string, nodeId: string] => {
4
- if (!figmaLink) {
5
- return [false, "", ""];
6
- }
7
-
8
- try {
9
- const url = new URL(figmaLink);
10
- const path = url.pathname;
11
-
12
- if (url.origin !== "https://www.figma.com") {
13
- return [false, "", ""];
14
- }
15
-
16
- const nodeId = (url.searchParams.get("node-id") ?? "").replace(/-/g, ":");
17
- const fileKey = path.split("/")[2];
18
- const hasCorrectPrefix =
19
- (path.startsWith("/file/") &&
20
- url.searchParams.get("type") !== "whiteboard") ||
21
- path.startsWith("/design/");
22
-
23
- return [hasCorrectPrefix && fileKey.length === 22, fileKey, nodeId];
24
- } catch {
25
- return [false, "", ""];
26
- }
27
- };
28
-
29
- export const formatToFigmaLink = ({
30
- fileKey,
31
- nodeId,
32
- duplicate,
33
- }: {
34
- fileKey: string;
35
- nodeId: string;
36
- duplicate?: boolean;
37
- }) => {
38
- const url = new URL("https://www.figma.com");
39
- url.pathname = `design/${fileKey}`;
40
-
41
- if (duplicate) {
42
- url.pathname = `${url.pathname}/duplicate`;
43
- }
44
-
45
- if (nodeId) {
46
- url.searchParams.set("node-id", nodeId.replace(":", "-"));
47
- }
48
-
49
- return url;
50
- };
51
-
52
- export class ResponseError extends Error {
53
- response: Response;
54
-
55
- constructor(message: string, res: Response) {
56
- super(message);
57
- this.response = res;
58
- }
59
- }
@@ -1,95 +0,0 @@
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
- }
@@ -1,2 +0,0 @@
1
- export * from "./figma";
2
- export * from "./files";
package/vite.config.ts DELETED
@@ -1,24 +0,0 @@
1
- import { defineConfig } from "vite";
2
- import dts from "vite-plugin-dts";
3
- import tsconfigPaths from "vite-tsconfig-paths";
4
-
5
- export default defineConfig({
6
- build: {
7
- lib: {
8
- entry: "./src/index.ts",
9
- formats: ["cjs", "es"],
10
- fileName: "index",
11
- },
12
- outDir: "./dist",
13
- emptyOutDir: true,
14
- target: "es6",
15
- sourcemap: true,
16
- },
17
- plugins: [
18
- tsconfigPaths(),
19
- dts({
20
- rollupTypes: true,
21
- insertTypesEntry: true,
22
- }),
23
- ],
24
- });