@figma/code-connect 1.4.2 → 1.4.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.
- package/README.md +2 -22
- package/dist/commands/connect.d.ts +5 -2
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +93 -29
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/connect_template.d.ts +36 -0
- package/dist/commands/connect_template.d.ts.map +1 -0
- package/dist/commands/connect_template.js +324 -0
- package/dist/commands/connect_template.js.map +1 -0
- package/dist/commands/filter_project_info.d.ts +7 -0
- package/dist/commands/filter_project_info.d.ts.map +1 -0
- package/dist/commands/filter_project_info.js +32 -0
- package/dist/commands/filter_project_info.js.map +1 -0
- package/dist/commands/preview_utils.d.ts +49 -0
- package/dist/commands/preview_utils.d.ts.map +1 -0
- package/dist/commands/preview_utils.js +390 -0
- package/dist/commands/preview_utils.js.map +1 -0
- package/dist/connect/batch_templates.d.ts +11 -0
- package/dist/connect/batch_templates.d.ts.map +1 -0
- package/dist/connect/batch_templates.js +70 -0
- package/dist/connect/batch_templates.js.map +1 -0
- package/dist/connect/create.d.ts.map +1 -1
- package/dist/connect/create.js +13 -0
- package/dist/connect/create.js.map +1 -1
- package/dist/connect/create_template.d.ts +22 -0
- package/dist/connect/create_template.d.ts.map +1 -0
- package/dist/connect/create_template.js +195 -0
- package/dist/connect/create_template.js.map +1 -0
- package/dist/connect/delete_docs.d.ts +2 -1
- package/dist/connect/delete_docs.d.ts.map +1 -1
- package/dist/connect/delete_docs.js +2 -2
- package/dist/connect/delete_docs.js.map +1 -1
- package/dist/connect/figma_rest_api.d.ts +1 -5
- package/dist/connect/figma_rest_api.d.ts.map +1 -1
- package/dist/connect/figma_rest_api.js +9 -3
- package/dist/connect/figma_rest_api.js.map +1 -1
- package/dist/connect/intrinsics.d.ts +3 -3
- package/dist/connect/intrinsics.d.ts.map +1 -1
- package/dist/connect/intrinsics.js +21 -10
- package/dist/connect/intrinsics.js.map +1 -1
- package/dist/connect/migration_helpers.d.ts +10 -3
- package/dist/connect/migration_helpers.d.ts.map +1 -1
- package/dist/connect/migration_helpers.js +43 -22
- package/dist/connect/migration_helpers.js.map +1 -1
- package/dist/connect/parser_common.d.ts +3 -2
- package/dist/connect/parser_common.d.ts.map +1 -1
- package/dist/connect/parser_common.js +2 -2
- package/dist/connect/parser_common.js.map +1 -1
- package/dist/connect/project.d.ts +9 -7
- package/dist/connect/project.d.ts.map +1 -1
- package/dist/connect/project.js +39 -25
- package/dist/connect/project.js.map +1 -1
- package/dist/connect/raw_templates.d.ts +8 -1
- package/dist/connect/raw_templates.d.ts.map +1 -1
- package/dist/connect/raw_templates.js +20 -7
- package/dist/connect/raw_templates.js.map +1 -1
- package/dist/connect/upload.d.ts +3 -1
- package/dist/connect/upload.d.ts.map +1 -1
- package/dist/connect/upload.js +23 -8
- package/dist/connect/upload.js.map +1 -1
- package/dist/connect/validation.d.ts +2 -2
- package/dist/connect/validation.d.ts.map +1 -1
- package/dist/connect/validation.js +4 -4
- package/dist/connect/validation.js.map +1 -1
- package/dist/connect/wizard/helpers.js.map +1 -1
- package/dist/html/parser.d.ts +2 -2
- package/dist/html/parser.d.ts.map +1 -1
- package/dist/html/parser.js +7 -5
- package/dist/html/parser.js.map +1 -1
- package/dist/react/parser.d.ts +3 -3
- package/dist/react/parser.d.ts.map +1 -1
- package/dist/react/parser.js +9 -7
- package/dist/react/parser.js.map +1 -1
- package/dist/storybook/convert.d.ts +7 -1
- package/dist/storybook/convert.d.ts.map +1 -1
- package/dist/storybook/convert.js +11 -4
- package/dist/storybook/convert.js.map +1 -1
- package/{figma-module.d.ts → figma-types.d.ts} +13 -3
- package/package.json +8 -4
|
@@ -94,7 +94,7 @@ function extractMetadataFields(fileContent) {
|
|
|
94
94
|
}
|
|
95
95
|
return { fields, templateStartLine };
|
|
96
96
|
}
|
|
97
|
-
function parseRawFile(filePath, label, config, dir) {
|
|
97
|
+
function parseRawFile(filePath, label, config, dir, batchOverrides) {
|
|
98
98
|
let fileContent = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
99
99
|
// Extract metadata fields BEFORE transpilation to avoid losing comments
|
|
100
100
|
// that appear before type-only imports (which TypeScript erases)
|
|
@@ -102,10 +102,16 @@ function parseRawFile(filePath, label, config, dir) {
|
|
|
102
102
|
if (filePath.endsWith('.ts')) {
|
|
103
103
|
fileContent = transpileTypeScriptTemplate(filePath, fileContent);
|
|
104
104
|
}
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
// For batch templates, metadata comes from the batch entry instead of comments
|
|
106
|
+
const component = batchOverrides?.component || fields.component;
|
|
107
|
+
const source = batchOverrides?.source || fields.source || '';
|
|
108
|
+
const figmaUrl = batchOverrides?.url || fields.url;
|
|
109
|
+
if (!figmaUrl) {
|
|
110
|
+
throw new Error(batchOverrides
|
|
111
|
+
? `Missing required "url" field in ${batchOverrides.batchFilePath}. Please add "url" to each entry in your .figma.batch.json file.`
|
|
112
|
+
: `Missing required url field in ${filePath}. Please add a // url=... comment to the top of the file.`);
|
|
107
113
|
}
|
|
108
|
-
let figmaNodeUrl =
|
|
114
|
+
let figmaNodeUrl = figmaUrl;
|
|
109
115
|
// Extract template from the transpiled content, starting at the line
|
|
110
116
|
// where the metadata comments ended in the original source
|
|
111
117
|
const transpiledLines = fileContent.split('\n');
|
|
@@ -121,7 +127,14 @@ function parseRawFile(filePath, label, config, dir) {
|
|
|
121
127
|
templateStartIndex = i;
|
|
122
128
|
break;
|
|
123
129
|
}
|
|
124
|
-
|
|
130
|
+
let template = transpiledLines.slice(templateStartIndex).join('\n');
|
|
131
|
+
// For batch templates, set globalThis['__FIGMA_BATCH'] so the runtime exposes it as
|
|
132
|
+
// figma.batch. Using globalThis rather than a const so it's accessible from
|
|
133
|
+
// __FIGMA_CODE_CONNECT_REQUIRE's closure regardless of where require('figma') is called.
|
|
134
|
+
// (globalThis works in both browser and Node.js, unlike window.)
|
|
135
|
+
if (batchOverrides) {
|
|
136
|
+
template = `globalThis['__FIGMA_BATCH'] = ${JSON.stringify(batchOverrides.batchData)}\n${template}`;
|
|
137
|
+
}
|
|
125
138
|
// Apply documentUrlSubstitutions if provided
|
|
126
139
|
if (config?.documentUrlSubstitutions) {
|
|
127
140
|
figmaNodeUrl = (0, helpers_1.applyDocumentUrlSubstitutions)(figmaNodeUrl, config.documentUrlSubstitutions);
|
|
@@ -131,7 +144,7 @@ function parseRawFile(filePath, label, config, dir) {
|
|
|
131
144
|
const language = config?.language || (0, label_language_mapping_1.getInferredLanguageForRaw)(effectiveLabel);
|
|
132
145
|
return {
|
|
133
146
|
figmaNode: figmaNodeUrl,
|
|
134
|
-
component
|
|
147
|
+
component,
|
|
135
148
|
template,
|
|
136
149
|
// nestable by default unless user specifies in template
|
|
137
150
|
// (templateData.nestable AND template.metadata.nestable need to
|
|
@@ -139,7 +152,7 @@ function parseRawFile(filePath, label, config, dir) {
|
|
|
139
152
|
templateData: { nestable: true, isParserless: true },
|
|
140
153
|
language,
|
|
141
154
|
label: effectiveLabel,
|
|
142
|
-
source
|
|
155
|
+
source,
|
|
143
156
|
sourceLocation: { line: -1 },
|
|
144
157
|
metadata: {
|
|
145
158
|
cliVersion: require('../../package.json').version,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"raw_templates.js","sourceRoot":"","sources":["../../src/connect/raw_templates.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs'\nimport ts from 'typescript'\nimport { CodeConnectJSON } from './figma_connect'\nimport { CodeConnectConfig } from './project'\nimport { CodeConnectLabel, getInferredLanguageForRaw } from './label_language_mapping'\nimport { applyDocumentUrlSubstitutions } from './helpers'\n\n/**\n * Returns true if the file content looks like a raw template file, i.e. its\n * leading comment block contains a `// url=`, `// component=`, or `// source=`\n * directive. Used to distinguish raw `.figma.ts` templates from React/HTML\n * Code Connect files that share the same extension.\n */\nexport function isRawTemplate(content: string): boolean {\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (trimmed === '' || trimmed.startsWith('//')) {\n if (/^\\/\\/\\s*(url|component|source)=/.test(trimmed)) {\n return true\n }\n continue\n }\n // First non-comment, non-blank line reached without finding a known directive — not a raw template\n break\n }\n return false\n}\n\nfunction transpileTypeScriptTemplate(filePath: string, fileContent: string): string {\n // Convert ESM import of 'figma' to require syntax\n // Supports: import figma from 'figma'\n const figmaImportRegex = /^import\\s+figma\\s+from\\s+['\"]figma['\"]\\s*;?\\s*$/m\n if (figmaImportRegex.test(fileContent)) {\n fileContent = fileContent.replace(figmaImportRegex, \"const figma = require('figma')\")\n }\n\n // Detect any remaining non-type import statements. Type-only imports (`import type`)\n // are erased by the TS compiler and are fine. Regular imports (except the figma\n // import we just converted) are not supported in Phase 1 (no bundling), so we show\n // a helpful error.\n const importRegex = /^import\\s+(?!type\\s)/m\n if (importRegex.test(fileContent)) {\n const match = fileContent.match(/^(import\\s+.+)$/m)\n const importLine = match ? match[1] : 'import ...'\n throw new Error(\n `TypeScript template files only support importing from 'figma'.\\n` +\n `Found in ${filePath}:\\n` +\n ` ${importLine}\\n\\n` +\n `Use \"const figma = require('figma')\" or \"import figma from 'figma'\" to access the Figma API.\\n` +\n `Other module imports will be supported in a future version.`,\n )\n }\n\n const result = ts.transpileModule(fileContent, {\n compilerOptions: {\n module: ts.ModuleKind.ESNext,\n target: ts.ScriptTarget.ES2021,\n removeComments: false,\n },\n })\n\n return result.outputText\n}\n\n/**\n * Extracts metadata fields (url, component, source) from the leading comments\n * of a raw template file. This must be done before transpilation because\n * TypeScript can remove comments that appear before type-only imports.\n */\nfunction extractMetadataFields(fileContent: string): {\n fields: { url?: string; component?: string; source?: string }\n templateStartLine: number\n} {\n const lines = fileContent.split('\\n')\n const fields: { url?: string; component?: string; source?: string } = {}\n let templateStartLine = 0\n\n // Parse consecutive comment lines at the start of the file\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim()\n // Match pattern: // fieldName=value\n const match = line.match(/^\\/\\/\\s*(\\w+)=(.+)$/)\n if (match) {\n const [, fieldName, fieldValue] = match\n const normalizedFieldName = fieldName.toLowerCase()\n if (\n normalizedFieldName === 'url' ||\n normalizedFieldName === 'component' ||\n normalizedFieldName === 'source'\n ) {\n fields[normalizedFieldName] = fieldValue.trim()\n }\n templateStartLine = i + 1\n } else if (line === '' || line.startsWith('//')) {\n // Allow blank lines or other comments, but don't increment template start\n continue\n } else {\n // First non-comment line found\n break\n }\n }\n\n return { fields, templateStartLine }\n}\n\nexport function parseRawFile(\n filePath: string,\n label: string | undefined,\n config?: CodeConnectConfig,\n dir?: string,\n): CodeConnectJSON {\n let fileContent = fs.readFileSync(filePath, 'utf-8')\n\n // Extract metadata fields BEFORE transpilation to avoid losing comments\n // that appear before type-only imports (which TypeScript erases)\n const { fields, templateStartLine } = extractMetadataFields(fileContent)\n\n if (filePath.endsWith('.ts')) {\n fileContent = transpileTypeScriptTemplate(filePath, fileContent)\n }\n\n if (!fields.url) {\n throw new Error(\n `Missing required url field in ${filePath}. Please add a // url=... comment to the top of the file.`,\n )\n }\n let figmaNodeUrl = fields.url\n\n // Extract template from the transpiled content, starting at the line\n // where the metadata comments ended in the original source\n const transpiledLines = fileContent.split('\\n')\n let templateStartIndex = 0\n\n // Skip lines until we've passed the original metadata comment section\n for (let i = 0; i < transpiledLines.length; i++) {\n const line = transpiledLines[i].trim()\n // Skip blank lines and comments at the start\n if (line === '' || line.startsWith('//')) {\n continue\n }\n // First non-comment line in transpiled output\n templateStartIndex = i\n break\n }\n\n const template = transpiledLines.slice(templateStartIndex).join('\\n')\n\n // Apply documentUrlSubstitutions if provided\n if (config?.documentUrlSubstitutions) {\n figmaNodeUrl = applyDocumentUrlSubstitutions(figmaNodeUrl, config.documentUrlSubstitutions)\n }\n\n // Determine effective label from parameter, config, or default\n const effectiveLabel = label || config?.label || CodeConnectLabel.Code\n\n const language = config?.language || getInferredLanguageForRaw(effectiveLabel)\n\n return {\n figmaNode: figmaNodeUrl,\n component: fields.component,\n template,\n // nestable by default unless user specifies in template\n // (templateData.nestable AND template.metadata.nestable need to\n // be true for instance to be nested)\n templateData: { nestable: true, isParserless: true },\n language,\n label: effectiveLabel,\n source: fields.source || '',\n sourceLocation: { line: -1 },\n metadata: {\n cliVersion: require('../../package.json').version,\n },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"raw_templates.js","sourceRoot":"","sources":["../../src/connect/raw_templates.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs'\nimport ts from 'typescript'\nimport { CodeConnectJSON } from './figma_connect'\nimport { CodeConnectConfig } from './project'\nimport { CodeConnectLabel, getInferredLanguageForRaw } from './label_language_mapping'\nimport { applyDocumentUrlSubstitutions } from './helpers'\n\n/**\n * Returns true if the file content looks like a raw template file, i.e. its\n * leading comment block contains a `// url=`, `// component=`, or `// source=`\n * directive. Used to distinguish raw `.figma.ts` templates from React/HTML\n * Code Connect files that share the same extension.\n */\nexport function isRawTemplate(content: string): boolean {\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n if (trimmed === '' || trimmed.startsWith('//')) {\n if (/^\\/\\/\\s*(url|component|source)=/.test(trimmed)) {\n return true\n }\n continue\n }\n // First non-comment, non-blank line reached without finding a known directive — not a raw template\n break\n }\n return false\n}\n\nfunction transpileTypeScriptTemplate(filePath: string, fileContent: string): string {\n // Convert ESM import of 'figma' to require syntax\n // Supports: import figma from 'figma'\n const figmaImportRegex = /^import\\s+figma\\s+from\\s+['\"]figma['\"]\\s*;?\\s*$/m\n if (figmaImportRegex.test(fileContent)) {\n fileContent = fileContent.replace(figmaImportRegex, \"const figma = require('figma')\")\n }\n\n // Detect any remaining non-type import statements. Type-only imports (`import type`)\n // are erased by the TS compiler and are fine. Regular imports (except the figma\n // import we just converted) are not supported in Phase 1 (no bundling), so we show\n // a helpful error.\n const importRegex = /^import\\s+(?!type\\s)/m\n if (importRegex.test(fileContent)) {\n const match = fileContent.match(/^(import\\s+.+)$/m)\n const importLine = match ? match[1] : 'import ...'\n throw new Error(\n `TypeScript template files only support importing from 'figma'.\\n` +\n `Found in ${filePath}:\\n` +\n ` ${importLine}\\n\\n` +\n `Use \"const figma = require('figma')\" or \"import figma from 'figma'\" to access the Figma API.\\n` +\n `Other module imports will be supported in a future version.`,\n )\n }\n\n const result = ts.transpileModule(fileContent, {\n compilerOptions: {\n module: ts.ModuleKind.ESNext,\n target: ts.ScriptTarget.ES2021,\n removeComments: false,\n },\n })\n\n return result.outputText\n}\n\n/**\n * Extracts metadata fields (url, component, source) from the leading comments\n * of a raw template file. This must be done before transpilation because\n * TypeScript can remove comments that appear before type-only imports.\n */\nfunction extractMetadataFields(fileContent: string): {\n fields: { url?: string; component?: string; source?: string }\n templateStartLine: number\n} {\n const lines = fileContent.split('\\n')\n const fields: { url?: string; component?: string; source?: string } = {}\n let templateStartLine = 0\n\n // Parse consecutive comment lines at the start of the file\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim()\n // Match pattern: // fieldName=value\n const match = line.match(/^\\/\\/\\s*(\\w+)=(.+)$/)\n if (match) {\n const [, fieldName, fieldValue] = match\n const normalizedFieldName = fieldName.toLowerCase()\n if (\n normalizedFieldName === 'url' ||\n normalizedFieldName === 'component' ||\n normalizedFieldName === 'source'\n ) {\n fields[normalizedFieldName] = fieldValue.trim()\n }\n templateStartLine = i + 1\n } else if (line === '' || line.startsWith('//')) {\n // Allow blank lines or other comments, but don't increment template start\n continue\n } else {\n // First non-comment line found\n break\n }\n }\n\n return { fields, templateStartLine }\n}\n\nexport interface BatchOverrides {\n url: string\n source?: string\n component?: string\n batchData: Record<string, any>\n batchFilePath: string\n}\n\nexport function parseRawFile(\n filePath: string,\n label: string | undefined,\n config?: CodeConnectConfig,\n dir?: string,\n batchOverrides?: BatchOverrides,\n): CodeConnectJSON {\n let fileContent = fs.readFileSync(filePath, 'utf-8')\n\n // Extract metadata fields BEFORE transpilation to avoid losing comments\n // that appear before type-only imports (which TypeScript erases)\n const { fields, templateStartLine } = extractMetadataFields(fileContent)\n\n if (filePath.endsWith('.ts')) {\n fileContent = transpileTypeScriptTemplate(filePath, fileContent)\n }\n\n // For batch templates, metadata comes from the batch entry instead of comments\n const component = batchOverrides?.component || fields.component\n const source = batchOverrides?.source || fields.source || ''\n\n const figmaUrl = batchOverrides?.url || fields.url\n if (!figmaUrl) {\n throw new Error(\n batchOverrides\n ? `Missing required \"url\" field in ${batchOverrides.batchFilePath}. Please add \"url\" to each entry in your .figma.batch.json file.`\n : `Missing required url field in ${filePath}. Please add a // url=... comment to the top of the file.`,\n )\n }\n let figmaNodeUrl = figmaUrl\n\n // Extract template from the transpiled content, starting at the line\n // where the metadata comments ended in the original source\n const transpiledLines = fileContent.split('\\n')\n let templateStartIndex = 0\n\n // Skip lines until we've passed the original metadata comment section\n for (let i = 0; i < transpiledLines.length; i++) {\n const line = transpiledLines[i].trim()\n // Skip blank lines and comments at the start\n if (line === '' || line.startsWith('//')) {\n continue\n }\n // First non-comment line in transpiled output\n templateStartIndex = i\n break\n }\n\n let template = transpiledLines.slice(templateStartIndex).join('\\n')\n\n // For batch templates, set globalThis['__FIGMA_BATCH'] so the runtime exposes it as\n // figma.batch. Using globalThis rather than a const so it's accessible from\n // __FIGMA_CODE_CONNECT_REQUIRE's closure regardless of where require('figma') is called.\n // (globalThis works in both browser and Node.js, unlike window.)\n if (batchOverrides) {\n template = `globalThis['__FIGMA_BATCH'] = ${JSON.stringify(batchOverrides.batchData)}\\n${template}`\n }\n\n // Apply documentUrlSubstitutions if provided\n if (config?.documentUrlSubstitutions) {\n figmaNodeUrl = applyDocumentUrlSubstitutions(figmaNodeUrl, config.documentUrlSubstitutions)\n }\n\n // Determine effective label from parameter, config, or default\n const effectiveLabel = label || config?.label || CodeConnectLabel.Code\n\n const language = config?.language || getInferredLanguageForRaw(effectiveLabel)\n\n return {\n figmaNode: figmaNodeUrl,\n component,\n template,\n // nestable by default unless user specifies in template\n // (templateData.nestable AND template.metadata.nestable need to\n // be true for instance to be nested)\n templateData: { nestable: true, isParserless: true },\n language,\n label: effectiveLabel,\n source,\n sourceLocation: { line: -1 },\n metadata: {\n cliVersion: require('../../package.json').version,\n },\n }\n}\n"]}
|
package/dist/connect/upload.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { CodeConnectJSON } from '../connect/figma_connect';
|
|
2
2
|
interface Args {
|
|
3
3
|
accessToken: string;
|
|
4
|
+
useOAuth?: boolean;
|
|
4
5
|
docs: CodeConnectJSON[];
|
|
5
6
|
batchSize?: number;
|
|
6
7
|
verbose: boolean;
|
|
7
8
|
apiUrl?: string;
|
|
9
|
+
force?: boolean;
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* Creates a map from fileKey-nodeId to original docs for easy lookup
|
|
11
13
|
*/
|
|
12
14
|
export declare function createDocsMap(docs: CodeConnectJSON[], verbose: boolean): Map<string, CodeConnectJSON[]>;
|
|
13
|
-
export declare function upload({ accessToken, docs, batchSize, verbose, apiUrl: apiUrlOverride, }: Args): Promise<void>;
|
|
15
|
+
export declare function upload({ accessToken, useOAuth, docs, batchSize, verbose, apiUrl: apiUrlOverride, force, }: Args): Promise<void>;
|
|
14
16
|
export {};
|
|
15
17
|
//# sourceMappingURL=upload.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/connect/upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/connect/upload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAyC1D,UAAU,IAAI;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,eAAe,EAAE,CAAA;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AA0CD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,eAAe,EAAE,EACvB,OAAO,EAAE,OAAO,GACf,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAkBhC;AAED,wBAAsB,MAAM,CAAC,EAC3B,WAAW,EACX,QAAgB,EAChB,IAAI,EACJ,SAAS,EACT,OAAO,EACP,MAAM,EAAE,cAAc,EACtB,KAAK,GACN,EAAE,IAAI,iBAuNN"}
|
package/dist/connect/upload.js
CHANGED
|
@@ -7,11 +7,12 @@ const figma_rest_api_1 = require("./figma_rest_api");
|
|
|
7
7
|
const helpers_1 = require("./helpers");
|
|
8
8
|
const validation_1 = require("./validation");
|
|
9
9
|
const fetch_1 = require("../common/fetch");
|
|
10
|
+
const COMPONENT_BROWSER_CONFLICT_REASON = 'Code Connect UI mapping already exists';
|
|
10
11
|
const RETRY_DELAYS_MS = [5_000, 15_000, 30_000];
|
|
11
|
-
async function postWithRetry(apiUrl, batch, accessToken) {
|
|
12
|
+
async function postWithRetry(apiUrl, batch, accessToken, useOAuth = false) {
|
|
12
13
|
for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {
|
|
13
14
|
try {
|
|
14
|
-
return await fetch_1.request.post(apiUrl, batch, { headers: (0, figma_rest_api_1.getHeaders)(accessToken) });
|
|
15
|
+
return await fetch_1.request.post(apiUrl, batch, { headers: (0, figma_rest_api_1.getHeaders)(accessToken, useOAuth) });
|
|
15
16
|
}
|
|
16
17
|
catch (err) {
|
|
17
18
|
if ((0, fetch_1.isFetchError)(err) && (err.response.status === 429 || err.response.status >= 500)) {
|
|
@@ -73,8 +74,10 @@ function createDocsMap(docs, verbose) {
|
|
|
73
74
|
}
|
|
74
75
|
return docsMap;
|
|
75
76
|
}
|
|
76
|
-
async function upload({ accessToken, docs, batchSize, verbose, apiUrl: apiUrlOverride, }) {
|
|
77
|
-
const apiUrl = (0, figma_rest_api_1.getApiUrl)(docs?.[0]?.figmaNode ?? '', apiUrlOverride) +
|
|
77
|
+
async function upload({ accessToken, useOAuth = false, docs, batchSize, verbose, apiUrl: apiUrlOverride, force, }) {
|
|
78
|
+
const apiUrl = (0, figma_rest_api_1.getApiUrl)(docs?.[0]?.figmaNode ?? '', apiUrlOverride) +
|
|
79
|
+
'/code_connect' +
|
|
80
|
+
(force ? '?force=true' : '');
|
|
78
81
|
// Strip internal fields before uploading to Figma
|
|
79
82
|
const cleanedDocs = docs.map((doc) => {
|
|
80
83
|
const { _codeConnectFilePath, ...cleanDoc } = doc;
|
|
@@ -129,7 +132,7 @@ async function upload({ accessToken, docs, batchSize, verbose, apiUrl: apiUrlOve
|
|
|
129
132
|
(0, helpers_1.exitWithFeedbackMessage)(1);
|
|
130
133
|
}
|
|
131
134
|
logging_1.logger.debug(`Uploading ${size.toFixed(2)}mb to Figma`);
|
|
132
|
-
const response = await postWithRetry(apiUrl, batch, accessToken);
|
|
135
|
+
const response = await postWithRetry(apiUrl, batch, accessToken, useOAuth);
|
|
133
136
|
const data = response.data;
|
|
134
137
|
if (data.meta?.published_nodes) {
|
|
135
138
|
data.meta.published_nodes.forEach((node) => allUploadedNodes.add(getKeyFromFigmaNode(node.figmaNode)));
|
|
@@ -150,8 +153,8 @@ async function upload({ accessToken, docs, batchSize, verbose, apiUrl: apiUrlOve
|
|
|
150
153
|
(0, helpers_1.exitWithFeedbackMessage)(1);
|
|
151
154
|
}
|
|
152
155
|
logging_1.logger.debug(`Uploading ${size.toFixed(2)}mb to Figma`);
|
|
153
|
-
logging_1.logger.info(`
|
|
154
|
-
const response = await postWithRetry(apiUrl, cleanedDocs, accessToken);
|
|
156
|
+
logging_1.logger.info(`Uploading to ${apiUrl}`);
|
|
157
|
+
const response = await postWithRetry(apiUrl, cleanedDocs, accessToken, useOAuth);
|
|
155
158
|
const data = response.data;
|
|
156
159
|
if (data.meta?.published_nodes) {
|
|
157
160
|
data.meta.published_nodes.forEach((node) => allUploadedNodes.add(getKeyFromFigmaNode(node.figmaNode)));
|
|
@@ -187,8 +190,20 @@ async function upload({ accessToken, docs, batchSize, verbose, apiUrl: apiUrlOve
|
|
|
187
190
|
logging_1.logger.info(`Successfully uploaded to Figma, for ${label}:\n${docs.map((doc) => `-> ${codeConnectStr(doc)}`).join('\n')}`);
|
|
188
191
|
}
|
|
189
192
|
if (Object.keys(failedDocsByLabel).length > 0) {
|
|
193
|
+
let hasComponentBrowserConflicts = false;
|
|
190
194
|
for (const [label, failedItems] of Object.entries(failedDocsByLabel)) {
|
|
191
|
-
|
|
195
|
+
const conflicts = failedItems.filter((item) => item.reason.includes(COMPONENT_BROWSER_CONFLICT_REASON));
|
|
196
|
+
const otherFailures = failedItems.filter((item) => !item.reason.includes(COMPONENT_BROWSER_CONFLICT_REASON));
|
|
197
|
+
if (conflicts.length > 0) {
|
|
198
|
+
hasComponentBrowserConflicts = true;
|
|
199
|
+
logging_1.logger.warn((0, logging_1.warn)(`Warning: ${conflicts.length} node(s) already have UI-created Code Connect mappings in Figma for label "${label}":\n${conflicts.map((item) => `-> ${codeConnectStr(item.doc)}`).join('\n')}`));
|
|
200
|
+
}
|
|
201
|
+
if (otherFailures.length > 0) {
|
|
202
|
+
logging_1.logger.error(`Failed to upload to Figma, for ${label}:\n${otherFailures.map((item) => `-> ${codeConnectStr(item.doc)} (${item.reason})`).join('\n')}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (hasComponentBrowserConflicts && !force) {
|
|
206
|
+
logging_1.logger.warn((0, logging_1.warn)(`Re-run with --force to overwrite the existing UI-created mappings with your Code Connect files.`));
|
|
192
207
|
}
|
|
193
208
|
}
|
|
194
209
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/connect/upload.ts"],"names":[],"mappings":"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","sourcesContent":["import { CodeConnectJSON } from '../connect/figma_connect'\nimport { logger, underline, highlight } from '../common/logging'\nimport { getApiUrl, getHeaders } from './figma_rest_api'\nimport { exitWithFeedbackMessage } from './helpers'\nimport { parseFigmaNode } from './validation'\nimport { isFetchError, request } from '../common/fetch'\n\nconst RETRY_DELAYS_MS = [5_000, 15_000, 30_000]\n\nasync function postWithRetry<T>(\n apiUrl: string,\n batch: CodeConnectJSON[],\n accessToken: string,\n): Promise<{ data: T }> {\n for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {\n try {\n return await request.post<T>(apiUrl, batch, { headers: getHeaders(accessToken) })\n } catch (err) {\n if (isFetchError(err) && (err.response.status === 429 || err.response.status >= 500)) {\n if (attempt === RETRY_DELAYS_MS.length) {\n throw err\n }\n const retryAfterSec = err.response.headers.get('Retry-After')\n const delayMs = retryAfterSec\n ? parseInt(retryAfterSec, 10) * 1_000\n : RETRY_DELAYS_MS[attempt]\n logger.warn(\n `Received ${err.response.status}, retrying in ${delayMs / 1000}s (attempt ${attempt + 1}/${RETRY_DELAYS_MS.length})...`,\n )\n await new Promise((resolve) => setTimeout(resolve, delayMs))\n } else {\n throw err\n }\n }\n }\n throw new Error('Unreachable')\n}\n\ninterface Args {\n accessToken: string\n docs: CodeConnectJSON[]\n batchSize?: number\n verbose: boolean\n apiUrl?: string\n}\n\ninterface UploadResponse {\n status: number\n error: boolean\n meta: {\n success: boolean\n published_count: number\n failed_count: number\n published_nodes: Array<{ figmaNode: string; label: string }>\n failed_nodes: Array<{ figmaNode: string; label: string; reason: string }>\n }\n}\n\n/**\n * Returns a string representation of the code connect JSON\n * @param doc - The code connect JSON\n * @returns A string representation of the code connect JSON\n */\nfunction codeConnectStr(doc: CodeConnectJSON): string {\n return `${highlight(doc.component ?? '')}${doc.variant ? `(${Object.entries(doc.variant).map(([key, value]) => `${key}=${value}`)})` : ''} ${underline(doc.figmaNode)}`\n}\n\n/**\n * Extracts the fileKey and nodeId from the Figma node URL and returns a key in the format of fileKey-nodeId\n * @param figmaNode - The Figma node URL\n * @returns The key in the format of fileKey-nodeId\n */\nfunction getKeyFromFigmaNode(figmaNode: string): string {\n const url = new URL(figmaNode)\n\n // Extract fileKey from path (after /file/ or /design/)\n const pathMatch = url.pathname.match(/\\/(file|design)\\/([A-Za-z0-9]+)/)\n const fileKey = pathMatch ? pathMatch[2] : ''\n\n // Extract nodeId from query parameter and convert format (1-24 -> 1:24)\n const nodeIdParam = url.searchParams.get('node-id') || ''\n const nodeId = nodeIdParam.replace(/-/g, ':')\n\n return `${fileKey}-${nodeId}`\n}\n\n/**\n * Creates a map from fileKey-nodeId to original docs for easy lookup\n */\nexport function createDocsMap(\n docs: CodeConnectJSON[],\n verbose: boolean,\n): Map<string, CodeConnectJSON[]> {\n const docsMap = new Map<string, CodeConnectJSON[]>()\n\n for (const doc of docs) {\n const parsedData = parseFigmaNode(verbose, doc)\n if (!parsedData) {\n continue\n }\n\n const mapKey = `${parsedData.fileKey}-${parsedData.nodeId}`\n if (!docsMap.has(mapKey)) {\n docsMap.set(mapKey, [])\n }\n\n docsMap.get(mapKey)?.push(doc)\n }\n\n return docsMap\n}\n\nexport async function upload({\n accessToken,\n docs,\n batchSize,\n verbose,\n apiUrl: apiUrlOverride,\n}: Args) {\n const apiUrl = getApiUrl(docs?.[0]?.figmaNode ?? '', apiUrlOverride) + '/code_connect'\n\n // Strip internal fields before uploading to Figma\n const cleanedDocs = docs.map((doc) => {\n const { _codeConnectFilePath, ...cleanDoc } = doc\n return cleanDoc as CodeConnectJSON\n })\n\n try {\n logger.info(`Uploading to Figma...`)\n\n // Create a map from fileKey-nodeId to original docs for detailed output\n const docsMap = createDocsMap(cleanedDocs, verbose)\n\n let allUploadedNodes = new Set<string>()\n let allFailedNodes = new Map<string, string>() // key -> failure reason\n\n if (batchSize) {\n if (typeof batchSize !== 'number') {\n logger.error('Batch size must be a number')\n exitWithFeedbackMessage(1)\n }\n\n // batch together based on fileKey + nodeId as all variants etc of the same node should be uploaded together\n // Otherwise, the server will overwrite the previous upload\n const groupedDocs = cleanedDocs.reduce(\n (acc, doc) => {\n const parsedData = parseFigmaNode(verbose, doc)\n\n if (!parsedData) {\n exitWithFeedbackMessage(1)\n }\n\n const { fileKey, nodeId } = parsedData\n const accKey = fileKey + ',' + nodeId\n if (!acc[accKey]) {\n acc[accKey] = []\n }\n acc[accKey].push(doc)\n return acc\n },\n {} as Record<string, CodeConnectJSON[]>,\n )\n\n const batchedDocs: CodeConnectJSON[][] = []\n const nodeKeys = Object.keys(groupedDocs)\n\n for (let i = 0; i < nodeKeys.length; i += batchSize) {\n const batch: CodeConnectJSON[] = []\n for (let j = i; j < i + batchSize && j < nodeKeys.length; j++) {\n const nodeKey = nodeKeys[j]\n batch.push(...groupedDocs[nodeKey])\n }\n batchedDocs.push(batch)\n }\n\n let currentBatch = 1\n const noOfBatches = batchedDocs.length\n for (const batch of batchedDocs) {\n process.stderr.write('\\x1b[2K\\x1b[0G')\n process.stderr.write(`Uploading batch ${currentBatch}/${noOfBatches}`)\n\n var size = Buffer.byteLength(JSON.stringify(batch)) / (1024 * 1024)\n\n // Server has a limit of 5mb\n if (size > 5) {\n logger.error(\n `Failed to upload to Figma: The request is too large (${size.toFixed(2)}mb).`,\n )\n logger.error(\n 'Please try reducing the size of uploads by splitting them into smaller requests by running again and decreasing the --batch-size parameter.',\n )\n exitWithFeedbackMessage(1)\n }\n\n logger.debug(`Uploading ${size.toFixed(2)}mb to Figma`)\n\n const response = await postWithRetry<UploadResponse>(apiUrl, batch, accessToken)\n\n const data = response.data\n\n if (data.meta?.published_nodes) {\n data.meta.published_nodes.forEach((node) =>\n allUploadedNodes.add(getKeyFromFigmaNode(node.figmaNode)),\n )\n }\n if (data.meta?.failed_nodes) {\n data.meta.failed_nodes.forEach((node) =>\n allFailedNodes.set(getKeyFromFigmaNode(node.figmaNode), node.reason),\n )\n }\n\n currentBatch++\n }\n process.stderr.write(`\\n`)\n } else {\n var size = Buffer.byteLength(JSON.stringify(cleanedDocs)) / (1024 * 1024)\n\n // Server has a limit of 5mb\n if (size > 5) {\n logger.error(`Failed to upload to Figma: The request is too large (${size.toFixed(2)}mb).`)\n logger.error(\n 'Please try reducing the size of uploads by splitting them into smaller requests by running again with the --batch-size parameter. You can do also this by running on different subdirectories using the --dir flag or by iteratively adjusting the includes field in the configuration.',\n )\n exitWithFeedbackMessage(1)\n }\n\n logger.debug(`Uploading ${size.toFixed(2)}mb to Figma`)\n logger.info(`uploading to ${apiUrl}`)\n\n const response = await postWithRetry<UploadResponse>(apiUrl, cleanedDocs, accessToken)\n\n const data = response.data\n\n if (data.meta?.published_nodes) {\n data.meta.published_nodes.forEach((node) =>\n allUploadedNodes.add(getKeyFromFigmaNode(node.figmaNode)),\n )\n }\n if (data.meta?.failed_nodes) {\n data.meta.failed_nodes.forEach((node) =>\n allFailedNodes.set(getKeyFromFigmaNode(node.figmaNode), node.reason),\n )\n }\n }\n\n // Separate successful and failed uploads\n const successfulDocsByLabel: Record<string, CodeConnectJSON[]> = {}\n const failedDocsByLabel: Record<string, Array<{ doc: CodeConnectJSON; reason: string }>> = {}\n\n for (const [mapKey, nodeDocs] of docsMap.entries()) {\n for (const doc of nodeDocs) {\n const label = doc.label\n const docKey = getKeyFromFigmaNode(doc.figmaNode)\n const isUploaded = allUploadedNodes.has(docKey)\n const failureReason = allFailedNodes.get(docKey)\n\n if (isUploaded) {\n if (!successfulDocsByLabel[label]) {\n successfulDocsByLabel[label] = []\n }\n successfulDocsByLabel[label].push(doc)\n } else if (failureReason) {\n if (!failedDocsByLabel[label]) {\n failedDocsByLabel[label] = []\n }\n failedDocsByLabel[label].push({ doc, reason: failureReason })\n }\n }\n }\n\n for (const [label, docs] of Object.entries(successfulDocsByLabel)) {\n logger.info(\n `Successfully uploaded to Figma, for ${label}:\\n${docs.map((doc) => `-> ${codeConnectStr(doc)}`).join('\\n')}`,\n )\n }\n\n if (Object.keys(failedDocsByLabel).length > 0) {\n for (const [label, failedItems] of Object.entries(failedDocsByLabel)) {\n logger.error(\n `Failed to upload to Figma, for ${label}:\\n${failedItems.map((item) => `-> ${codeConnectStr(item.doc)} (${item.reason})`).join('\\n')}`,\n )\n }\n }\n } catch (err) {\n if (isFetchError(err)) {\n if (err.response) {\n logger.error(\n `Failed to upload to Figma (${err.response.status}): ${err.response.status} ${err.data?.message}`,\n )\n } else {\n logger.error(`Failed to upload to Figma: ${err.message}`)\n }\n logger.debug(JSON.stringify(err?.data))\n } else {\n logger.error(`Failed to upload to Figma: ${err}`)\n }\n exitWithFeedbackMessage(1)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/connect/upload.ts"],"names":[],"mappings":"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","sourcesContent":["import { CodeConnectJSON } from '../connect/figma_connect'\nimport { logger, underline, highlight, warn } from '../common/logging'\nimport { getApiUrl, getHeaders } from './figma_rest_api'\nimport { exitWithFeedbackMessage } from './helpers'\nimport { parseFigmaNode } from './validation'\nimport { isFetchError, request } from '../common/fetch'\n\nconst COMPONENT_BROWSER_CONFLICT_REASON = 'Code Connect UI mapping already exists'\n\nconst RETRY_DELAYS_MS = [5_000, 15_000, 30_000]\n\nasync function postWithRetry<T>(\n apiUrl: string,\n batch: CodeConnectJSON[],\n accessToken: string,\n useOAuth = false,\n): Promise<{ data: T }> {\n for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {\n try {\n return await request.post<T>(apiUrl, batch, { headers: getHeaders(accessToken, useOAuth) })\n } catch (err) {\n if (isFetchError(err) && (err.response.status === 429 || err.response.status >= 500)) {\n if (attempt === RETRY_DELAYS_MS.length) {\n throw err\n }\n const retryAfterSec = err.response.headers.get('Retry-After')\n const delayMs = retryAfterSec\n ? parseInt(retryAfterSec, 10) * 1_000\n : RETRY_DELAYS_MS[attempt]\n logger.warn(\n `Received ${err.response.status}, retrying in ${delayMs / 1000}s (attempt ${attempt + 1}/${RETRY_DELAYS_MS.length})...`,\n )\n await new Promise((resolve) => setTimeout(resolve, delayMs))\n } else {\n throw err\n }\n }\n }\n throw new Error('Unreachable')\n}\n\ninterface Args {\n accessToken: string\n useOAuth?: boolean\n docs: CodeConnectJSON[]\n batchSize?: number\n verbose: boolean\n apiUrl?: string\n force?: boolean\n}\n\ninterface UploadResponse {\n status: number\n error: boolean\n meta: {\n success: boolean\n published_count: number\n failed_count: number\n published_nodes: Array<{ figmaNode: string; label: string }>\n failed_nodes: Array<{ figmaNode: string; label: string; reason: string }>\n }\n}\n\n/**\n * Returns a string representation of the code connect JSON\n * @param doc - The code connect JSON\n * @returns A string representation of the code connect JSON\n */\nfunction codeConnectStr(doc: CodeConnectJSON): string {\n return `${highlight(doc.component ?? '')}${doc.variant ? `(${Object.entries(doc.variant).map(([key, value]) => `${key}=${value}`)})` : ''} ${underline(doc.figmaNode)}`\n}\n\n/**\n * Extracts the fileKey and nodeId from the Figma node URL and returns a key in the format of fileKey-nodeId\n * @param figmaNode - The Figma node URL\n * @returns The key in the format of fileKey-nodeId\n */\nfunction getKeyFromFigmaNode(figmaNode: string): string {\n const url = new URL(figmaNode)\n\n // Extract fileKey from path (after /file/ or /design/)\n const pathMatch = url.pathname.match(/\\/(file|design)\\/([A-Za-z0-9]+)/)\n const fileKey = pathMatch ? pathMatch[2] : ''\n\n // Extract nodeId from query parameter and convert format (1-24 -> 1:24)\n const nodeIdParam = url.searchParams.get('node-id') || ''\n const nodeId = nodeIdParam.replace(/-/g, ':')\n\n return `${fileKey}-${nodeId}`\n}\n\n/**\n * Creates a map from fileKey-nodeId to original docs for easy lookup\n */\nexport function createDocsMap(\n docs: CodeConnectJSON[],\n verbose: boolean,\n): Map<string, CodeConnectJSON[]> {\n const docsMap = new Map<string, CodeConnectJSON[]>()\n\n for (const doc of docs) {\n const parsedData = parseFigmaNode(verbose, doc)\n if (!parsedData) {\n continue\n }\n\n const mapKey = `${parsedData.fileKey}-${parsedData.nodeId}`\n if (!docsMap.has(mapKey)) {\n docsMap.set(mapKey, [])\n }\n\n docsMap.get(mapKey)?.push(doc)\n }\n\n return docsMap\n}\n\nexport async function upload({\n accessToken,\n useOAuth = false,\n docs,\n batchSize,\n verbose,\n apiUrl: apiUrlOverride,\n force,\n}: Args) {\n const apiUrl =\n getApiUrl(docs?.[0]?.figmaNode ?? '', apiUrlOverride) +\n '/code_connect' +\n (force ? '?force=true' : '')\n\n // Strip internal fields before uploading to Figma\n const cleanedDocs = docs.map((doc) => {\n const { _codeConnectFilePath, ...cleanDoc } = doc\n return cleanDoc as CodeConnectJSON\n })\n\n try {\n logger.info(`Uploading to Figma...`)\n\n // Create a map from fileKey-nodeId to original docs for detailed output\n const docsMap = createDocsMap(cleanedDocs, verbose)\n\n let allUploadedNodes = new Set<string>()\n let allFailedNodes = new Map<string, string>() // key -> failure reason\n\n if (batchSize) {\n if (typeof batchSize !== 'number') {\n logger.error('Batch size must be a number')\n exitWithFeedbackMessage(1)\n }\n\n // batch together based on fileKey + nodeId as all variants etc of the same node should be uploaded together\n // Otherwise, the server will overwrite the previous upload\n const groupedDocs = cleanedDocs.reduce(\n (acc, doc) => {\n const parsedData = parseFigmaNode(verbose, doc)\n\n if (!parsedData) {\n exitWithFeedbackMessage(1)\n }\n\n const { fileKey, nodeId } = parsedData\n const accKey = fileKey + ',' + nodeId\n if (!acc[accKey]) {\n acc[accKey] = []\n }\n acc[accKey].push(doc)\n return acc\n },\n {} as Record<string, CodeConnectJSON[]>,\n )\n\n const batchedDocs: CodeConnectJSON[][] = []\n const nodeKeys = Object.keys(groupedDocs)\n\n for (let i = 0; i < nodeKeys.length; i += batchSize) {\n const batch: CodeConnectJSON[] = []\n for (let j = i; j < i + batchSize && j < nodeKeys.length; j++) {\n const nodeKey = nodeKeys[j]\n batch.push(...groupedDocs[nodeKey])\n }\n batchedDocs.push(batch)\n }\n\n let currentBatch = 1\n const noOfBatches = batchedDocs.length\n for (const batch of batchedDocs) {\n process.stderr.write('\\x1b[2K\\x1b[0G')\n process.stderr.write(`Uploading batch ${currentBatch}/${noOfBatches}`)\n\n var size = Buffer.byteLength(JSON.stringify(batch)) / (1024 * 1024)\n\n // Server has a limit of 5mb\n if (size > 5) {\n logger.error(\n `Failed to upload to Figma: The request is too large (${size.toFixed(2)}mb).`,\n )\n logger.error(\n 'Please try reducing the size of uploads by splitting them into smaller requests by running again and decreasing the --batch-size parameter.',\n )\n exitWithFeedbackMessage(1)\n }\n\n logger.debug(`Uploading ${size.toFixed(2)}mb to Figma`)\n\n const response = await postWithRetry<UploadResponse>(apiUrl, batch, accessToken, useOAuth)\n\n const data = response.data\n\n if (data.meta?.published_nodes) {\n data.meta.published_nodes.forEach((node) =>\n allUploadedNodes.add(getKeyFromFigmaNode(node.figmaNode)),\n )\n }\n if (data.meta?.failed_nodes) {\n data.meta.failed_nodes.forEach((node) =>\n allFailedNodes.set(getKeyFromFigmaNode(node.figmaNode), node.reason),\n )\n }\n\n currentBatch++\n }\n process.stderr.write(`\\n`)\n } else {\n var size = Buffer.byteLength(JSON.stringify(cleanedDocs)) / (1024 * 1024)\n\n // Server has a limit of 5mb\n if (size > 5) {\n logger.error(`Failed to upload to Figma: The request is too large (${size.toFixed(2)}mb).`)\n logger.error(\n 'Please try reducing the size of uploads by splitting them into smaller requests by running again with the --batch-size parameter. You can do also this by running on different subdirectories using the --dir flag or by iteratively adjusting the includes field in the configuration.',\n )\n exitWithFeedbackMessage(1)\n }\n\n logger.debug(`Uploading ${size.toFixed(2)}mb to Figma`)\n logger.info(`Uploading to ${apiUrl}`)\n\n const response = await postWithRetry<UploadResponse>(\n apiUrl,\n cleanedDocs,\n accessToken,\n useOAuth,\n )\n\n const data = response.data\n\n if (data.meta?.published_nodes) {\n data.meta.published_nodes.forEach((node) =>\n allUploadedNodes.add(getKeyFromFigmaNode(node.figmaNode)),\n )\n }\n if (data.meta?.failed_nodes) {\n data.meta.failed_nodes.forEach((node) =>\n allFailedNodes.set(getKeyFromFigmaNode(node.figmaNode), node.reason),\n )\n }\n }\n\n // Separate successful and failed uploads\n const successfulDocsByLabel: Record<string, CodeConnectJSON[]> = {}\n const failedDocsByLabel: Record<string, Array<{ doc: CodeConnectJSON; reason: string }>> = {}\n\n for (const [mapKey, nodeDocs] of docsMap.entries()) {\n for (const doc of nodeDocs) {\n const label = doc.label\n const docKey = getKeyFromFigmaNode(doc.figmaNode)\n const isUploaded = allUploadedNodes.has(docKey)\n const failureReason = allFailedNodes.get(docKey)\n\n if (isUploaded) {\n if (!successfulDocsByLabel[label]) {\n successfulDocsByLabel[label] = []\n }\n successfulDocsByLabel[label].push(doc)\n } else if (failureReason) {\n if (!failedDocsByLabel[label]) {\n failedDocsByLabel[label] = []\n }\n failedDocsByLabel[label].push({ doc, reason: failureReason })\n }\n }\n }\n\n for (const [label, docs] of Object.entries(successfulDocsByLabel)) {\n logger.info(\n `Successfully uploaded to Figma, for ${label}:\\n${docs.map((doc) => `-> ${codeConnectStr(doc)}`).join('\\n')}`,\n )\n }\n\n if (Object.keys(failedDocsByLabel).length > 0) {\n let hasComponentBrowserConflicts = false\n for (const [label, failedItems] of Object.entries(failedDocsByLabel)) {\n const conflicts = failedItems.filter((item) =>\n item.reason.includes(COMPONENT_BROWSER_CONFLICT_REASON),\n )\n const otherFailures = failedItems.filter(\n (item) => !item.reason.includes(COMPONENT_BROWSER_CONFLICT_REASON),\n )\n\n if (conflicts.length > 0) {\n hasComponentBrowserConflicts = true\n logger.warn(\n warn(\n `Warning: ${conflicts.length} node(s) already have UI-created Code Connect mappings in Figma for label \"${label}\":\\n${conflicts.map((item) => `-> ${codeConnectStr(item.doc)}`).join('\\n')}`,\n ),\n )\n }\n\n if (otherFailures.length > 0) {\n logger.error(\n `Failed to upload to Figma, for ${label}:\\n${otherFailures.map((item) => `-> ${codeConnectStr(item.doc)} (${item.reason})`).join('\\n')}`,\n )\n }\n }\n\n if (hasComponentBrowserConflicts && !force) {\n logger.warn(\n warn(\n `Re-run with --force to overwrite the existing UI-created mappings with your Code Connect files.`,\n ),\n )\n }\n }\n } catch (err) {\n if (isFetchError(err)) {\n if (err.response) {\n logger.error(\n `Failed to upload to Figma (${err.response.status}): ${err.response.status} ${err.data?.message}`,\n )\n } else {\n logger.error(`Failed to upload to Figma: ${err.message}`)\n }\n logger.debug(JSON.stringify(err?.data))\n } else {\n logger.error(`Failed to upload to Figma: ${err}`)\n }\n exitWithFeedbackMessage(1)\n }\n}\n"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { CodeConnectJSON } from '../connect/figma_connect';
|
|
2
|
-
import { BaseCommand } from '../commands/connect';
|
|
2
|
+
import type { BaseCommand } from '../commands/connect';
|
|
3
3
|
export declare function parseFigmaNode(verbose: boolean, doc: CodeConnectJSON, silent?: boolean): {
|
|
4
4
|
fileKey: string;
|
|
5
5
|
nodeId: string;
|
|
6
6
|
} | null;
|
|
7
7
|
export declare const STATE_BOOLEAN_VALUE_PAIRS: string[][];
|
|
8
8
|
export declare function validateDoc(doc: CodeConnectJSON, figmaNode: any, nodeId: string): boolean;
|
|
9
|
-
export declare function validateDocs(cmd: BaseCommand, accessToken: string, docs: CodeConnectJSON[], apiUrlOverride?: string): Promise<boolean>;
|
|
9
|
+
export declare function validateDocs(cmd: BaseCommand, accessToken: string, docs: CodeConnectJSON[], apiUrlOverride?: string, useOAuth?: boolean): Promise<boolean>;
|
|
10
10
|
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/connect/validation.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAI1D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/connect/validation.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAI1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAGtD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,eAAe,EACpB,MAAM,GAAE,OAAe,GACtB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAoB5C;AA6HD,eAAO,MAAM,yBAAyB,YAIrC,CAAA;AAgED,wBAAgB,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAmCzF;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,WAAW,EAChB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,eAAe,EAAE,EACvB,cAAc,CAAC,EAAE,MAAM,EACvB,QAAQ,UAAQ,GACf,OAAO,CAAC,OAAO,CAAC,CA0DlB"}
|
|
@@ -65,9 +65,9 @@ function parseFigmaNode(verbose, doc, silent = false) {
|
|
|
65
65
|
return null;
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
-
async function fetchNodeInfo(baseApiUrl, fileKey, nodeIdsChunk, accessToken) {
|
|
68
|
+
async function fetchNodeInfo(baseApiUrl, fileKey, nodeIdsChunk, accessToken, useOAuth = false) {
|
|
69
69
|
try {
|
|
70
|
-
const response = await fetch_1.request.get(`${baseApiUrl}${fileKey}/nodes?ids=${nodeIdsChunk.join(',')}`, { headers: (0, figma_rest_api_1.getHeaders)(accessToken) });
|
|
70
|
+
const response = await fetch_1.request.get(`${baseApiUrl}${fileKey}/nodes?ids=${nodeIdsChunk.join(',')}`, { headers: (0, figma_rest_api_1.getHeaders)(accessToken, useOAuth) });
|
|
71
71
|
if (response.response.status !== 200) {
|
|
72
72
|
logging_1.logger.error('Failed to fetch node info: ' + response.response.status + ' ' + response.data?.message);
|
|
73
73
|
return null;
|
|
@@ -228,7 +228,7 @@ function validateDoc(doc, figmaNode, nodeId) {
|
|
|
228
228
|
}
|
|
229
229
|
return true;
|
|
230
230
|
}
|
|
231
|
-
async function validateDocs(cmd, accessToken, docs, apiUrlOverride) {
|
|
231
|
+
async function validateDocs(cmd, accessToken, docs, apiUrlOverride, useOAuth = false) {
|
|
232
232
|
let baseApiUrl = (0, figma_rest_api_1.getApiUrl)(docs?.[0]?.figmaNode ?? '', apiUrlOverride) + '/files/';
|
|
233
233
|
const fileKeyToNodeIds = {};
|
|
234
234
|
let valid = true;
|
|
@@ -258,7 +258,7 @@ async function validateDocs(cmd, accessToken, docs, apiUrlOverride) {
|
|
|
258
258
|
for (let batch = 0; batch < chunks.length; batch++) {
|
|
259
259
|
const nodeIdsChunk = chunks[batch];
|
|
260
260
|
logging_1.logger.debug(`Running for ${baseApiUrl + fileKey + '/nodes?ids=' + nodeIdsChunk.join(',')}`);
|
|
261
|
-
const nodeMapRet = await fetchNodeInfo(baseApiUrl, fileKey, nodeIdsChunk, accessToken);
|
|
261
|
+
const nodeMapRet = await fetchNodeInfo(baseApiUrl, fileKey, nodeIdsChunk, accessToken, useOAuth);
|
|
262
262
|
if (!nodeMapRet) {
|
|
263
263
|
return false;
|
|
264
264
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/connect/validation.ts"],"names":[],"mappings":"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","sourcesContent":["import * as url from 'url'\nimport { chunk } from 'lodash'\n\nimport { CodeConnectJSON } from '../connect/figma_connect'\nimport { logger } from '../common/logging'\nimport { validateNodeId } from './helpers'\nimport { getApiUrl, getHeaders } from './figma_rest_api'\nimport { BaseCommand } from '../commands/connect'\nimport { isFetchError, request } from '../common/fetch'\n\nexport function parseFigmaNode(\n verbose: boolean,\n doc: CodeConnectJSON,\n silent: boolean = false,\n): { fileKey: string; nodeId: string } | null {\n const figmaNodeUrl = url.parse(doc.figmaNode, true)\n const fileKeyMatch = figmaNodeUrl.path?.match(/(file|design)\\/([a-zA-Z0-9]+)/)\n if (!fileKeyMatch) {\n if (!silent || verbose) {\n logger.error(`Failed to parse ${doc.figmaNode}`)\n }\n return null\n }\n const fileKey = fileKeyMatch[2]\n const nodeId = figmaNodeUrl.query['node-id']\n if (nodeId && typeof nodeId === 'string') {\n const figmaNodeId = validateNodeId(nodeId)\n return { fileKey, nodeId: figmaNodeId }\n } else {\n if (!silent || verbose) {\n logger.error(`Failed to get node-id from ${doc.figmaNode}`)\n }\n return null\n }\n}\n\nasync function fetchNodeInfo(\n baseApiUrl: string,\n fileKey: string,\n nodeIdsChunk: string[],\n accessToken: string,\n): Promise<any> {\n try {\n const response = await request.get<{ message: string; nodes: any }>(\n `${baseApiUrl}${fileKey}/nodes?ids=${nodeIdsChunk.join(',')}`,\n { headers: getHeaders(accessToken) },\n )\n if (response.response.status !== 200) {\n logger.error(\n 'Failed to fetch node info: ' + response.response.status + ' ' + response.data?.message,\n )\n return null\n }\n return response.data.nodes\n } catch (err) {\n if (isFetchError(err)) {\n if (err.response) {\n logger.error(\n `Failed to to fetch node info (${err.response.status}): ${err.response.status} ${err.data?.err ?? err.data?.message}`,\n )\n } else {\n logger.error(`Failed to to fetch node info: ${err.message}`)\n }\n logger.debug(JSON.stringify(err.data))\n } else {\n logger.error(`Failed to to fetch node info: ${err}`)\n }\n return null\n }\n}\n\nfunction validateProps(doc: CodeConnectJSON, document: any): boolean {\n if (doc.templateData && doc.templateData?.props) {\n let propsValid = true\n const codeConnectProps = Object.keys(doc.templateData.props ?? {})\n\n for (let i = 0; i < codeConnectProps.length; i++) {\n const codeConnectProp = doc.templateData?.props[codeConnectProps[i]]\n if (codeConnectProp.kind === 'children') {\n const codeConnectLayerNames = codeConnectProp.args.layers\n // Get all layer names in the figma doc\n const figmaLayerNames: string[] = []\n const getLayerNames = (layer: any) => {\n if (layer.name) {\n figmaLayerNames.push(layer.name)\n }\n if (layer.children) {\n layer.children.forEach((child: any) => getLayerNames(child))\n }\n }\n getLayerNames(document)\n // And make sure that the layer names in the code connect file are present in the figma doc\n for (const codeConnectLayerName of codeConnectLayerNames) {\n const regex = new RegExp('^' + codeConnectLayerName.replace('*', '.*'))\n if (figmaLayerNames.every((name) => !regex.test(name))) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): The layer \"${codeConnectLayerName}\" does not exist on the Figma component`,\n )\n propsValid = false\n }\n }\n continue\n }\n if (\n codeConnectProp.kind === 'boolean' ||\n codeConnectProp.kind === 'enum' ||\n codeConnectProp.kind === 'string'\n ) {\n const codeConnectFigmaPropName = codeConnectProp?.args?.figmaPropName\n\n if (\n !document.componentPropertyDefinitions ||\n !Object.keys(document.componentPropertyDefinitions).find((figmaProp) =>\n propMatches(figmaProp, codeConnectFigmaPropName, document.componentPropertyDefinitions),\n )\n ) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): The property \"${codeConnectFigmaPropName}\" does not exist on the Figma component`,\n )\n propsValid = false\n }\n }\n }\n\n if (!propsValid) {\n return false\n }\n }\n return true\n}\n\nfunction getPropName(componentPropertyDefinitions: any, propName: string): string {\n const prop = componentPropertyDefinitions[propName]\n if (prop.type === 'VARIANT') {\n return propName\n }\n\n // non Variant Keys are of the form \"name#id\"\n // We have to take the last one in case the name contains #'s\n const lastIndex = propName.lastIndexOf('#')\n if (lastIndex !== -1) {\n return propName.substring(0, lastIndex)\n }\n return propName\n}\n\nfunction propMatches(\n figmaProp: any,\n codeConnectPropName: string,\n componentPropertyDefinitions: any,\n): boolean {\n const figmaPropName = getPropName(componentPropertyDefinitions, figmaProp)\n return figmaPropName === codeConnectPropName\n}\n\n\n\n\nexport const STATE_BOOLEAN_VALUE_PAIRS = [\n ['yes', 'no'],\n ['true', 'false'],\n ['on', 'off'],\n]\n\nfunction isVariantBoolean(variantPossibleValues: string[]) {\n if (variantPossibleValues.length === 2) {\n const lowerCaseOptions = variantPossibleValues.map((p) => p.toLowerCase())\n for (const pair of STATE_BOOLEAN_VALUE_PAIRS) {\n const i = lowerCaseOptions.indexOf(pair[0]!)\n const j = lowerCaseOptions.indexOf(pair[1]!)\n if (i !== -1 && j !== -1) {\n return true\n }\n }\n }\n return false\n}\n\nfunction validateVariantRestrictions(doc: CodeConnectJSON, document: any): boolean {\n if (doc.variant) {\n let variantRestrictionsValid = true\n const codeConnectVariantRestrictions = Object.keys(doc.variant)\n\n for (let i = 0; i < codeConnectVariantRestrictions.length; i++) {\n const variantRestriction: any = codeConnectVariantRestrictions[i]\n\n const match = Object.keys(document.componentPropertyDefinitions ?? {}).find((figmaProp) =>\n propMatches(figmaProp, variantRestriction, document.componentPropertyDefinitions),\n )\n if (!match) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): The property \"${variantRestriction}\" does not exist on the Figma component`,\n )\n variantRestrictionsValid = false\n continue\n }\n\n const variantRestrictionValue = doc.variant[variantRestriction]\n const variantOrProp = document.componentPropertyDefinitions[match]\n\n // Only check `variantOptions` for Variants, and not for props, since props\n // don't have a set of possible values we can check against\n const isValidBooleanVariant =\n typeof variantRestrictionValue === 'boolean' &&\n Array.isArray(variantOrProp.variantOptions) &&\n isVariantBoolean(variantOrProp.variantOptions)\n\n const isValidVariantValue =\n variantOrProp.variantOptions?.includes(variantRestrictionValue) || isValidBooleanVariant\n\n if (variantOrProp.type === 'VARIANT' && !isValidVariantValue) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): The Figma Variant \"${match}\" does not have an option for ${variantRestrictionValue}`,\n )\n variantRestrictionsValid = false\n continue\n }\n }\n\n if (!variantRestrictionsValid) {\n return false\n }\n }\n return true\n}\n\nexport function validateDoc(doc: CodeConnectJSON, figmaNode: any, nodeId: string): boolean {\n if (!figmaNode || !figmaNode.document) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): node not found in file`,\n )\n return false\n }\n\n const document = figmaNode.document\n if (document.type !== 'COMPONENT' && document.type !== 'COMPONENT_SET') {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): corresponding node is not a component or component set`,\n )\n return false\n }\n\n const component = figmaNode.components[nodeId]\n if (component && component.componentSetId) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): node is not a top level component or component set. Please check that the node is not a variant`,\n )\n return false\n }\n\n const propsValid = validateProps(doc, document)\n if (!propsValid) {\n return false\n }\n\n const variantRestrictionsValid = validateVariantRestrictions(doc, document)\n if (!variantRestrictionsValid) {\n return false\n }\n\n return true\n}\n\nexport async function validateDocs(\n cmd: BaseCommand,\n accessToken: string,\n docs: CodeConnectJSON[],\n apiUrlOverride?: string,\n): Promise<boolean> {\n let baseApiUrl = getApiUrl(docs?.[0]?.figmaNode ?? '', apiUrlOverride) + '/files/'\n\n const fileKeyToNodeIds: { [key: string]: any } = {}\n let valid = true\n docs.forEach((doc) => {\n const parsedNode = parseFigmaNode(cmd.verbose, doc)\n if (!parsedNode) {\n valid = false\n return\n }\n fileKeyToNodeIds[parsedNode.fileKey] ||= {}\n fileKeyToNodeIds[parsedNode.fileKey][parsedNode.nodeId] ||= []\n fileKeyToNodeIds[parsedNode.fileKey][parsedNode.nodeId].push(doc)\n })\n\n if (!valid) {\n return false\n }\n\n logger.debug('fileKeyToNodeIds')\n logger.debug(JSON.stringify(fileKeyToNodeIds, null, 2))\n\n const fileKeys = Object.keys(fileKeyToNodeIds)\n for (let i = 0; i < fileKeys.length; i++) {\n const fileKey = fileKeys[i]\n logger.debug(`Validating file ${fileKey}`)\n const nodeMap = fileKeyToNodeIds[fileKey]\n const nodeIds = Object.keys(nodeMap)\n logger.debug(`Validating ${nodeIds.length} nodes`)\n const chunks = chunk(nodeIds, 400)\n\n for (let batch = 0; batch < chunks.length; batch++) {\n const nodeIdsChunk = chunks[batch]\n logger.debug(`Running for ${baseApiUrl + fileKey + '/nodes?ids=' + nodeIdsChunk.join(',')}`)\n const nodeMapRet = await fetchNodeInfo(baseApiUrl, fileKey, nodeIdsChunk, accessToken)\n if (!nodeMapRet) {\n return false\n }\n\n valid =\n valid &&\n nodeIdsChunk\n .map((nodeId: string) => {\n return nodeMap[nodeId]\n .map((doc: CodeConnectJSON) => validateDoc(doc, nodeMapRet[nodeId], nodeId))\n .every(Boolean)\n })\n .every(Boolean)\n }\n }\n return valid\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/connect/validation.ts"],"names":[],"mappings":"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","sourcesContent":["import * as url from 'url'\nimport { chunk } from 'lodash'\n\nimport { CodeConnectJSON } from '../connect/figma_connect'\nimport { logger } from '../common/logging'\nimport { validateNodeId } from './helpers'\nimport { getApiUrl, getHeaders } from './figma_rest_api'\nimport type { BaseCommand } from '../commands/connect'\nimport { isFetchError, request } from '../common/fetch'\n\nexport function parseFigmaNode(\n verbose: boolean,\n doc: CodeConnectJSON,\n silent: boolean = false,\n): { fileKey: string; nodeId: string } | null {\n const figmaNodeUrl = url.parse(doc.figmaNode, true)\n const fileKeyMatch = figmaNodeUrl.path?.match(/(file|design)\\/([a-zA-Z0-9]+)/)\n if (!fileKeyMatch) {\n if (!silent || verbose) {\n logger.error(`Failed to parse ${doc.figmaNode}`)\n }\n return null\n }\n const fileKey = fileKeyMatch[2]\n const nodeId = figmaNodeUrl.query['node-id']\n if (nodeId && typeof nodeId === 'string') {\n const figmaNodeId = validateNodeId(nodeId)\n return { fileKey, nodeId: figmaNodeId }\n } else {\n if (!silent || verbose) {\n logger.error(`Failed to get node-id from ${doc.figmaNode}`)\n }\n return null\n }\n}\n\nasync function fetchNodeInfo(\n baseApiUrl: string,\n fileKey: string,\n nodeIdsChunk: string[],\n accessToken: string,\n useOAuth = false,\n): Promise<any> {\n try {\n const response = await request.get<{ message: string; nodes: any }>(\n `${baseApiUrl}${fileKey}/nodes?ids=${nodeIdsChunk.join(',')}`,\n { headers: getHeaders(accessToken, useOAuth) },\n )\n if (response.response.status !== 200) {\n logger.error(\n 'Failed to fetch node info: ' + response.response.status + ' ' + response.data?.message,\n )\n return null\n }\n return response.data.nodes\n } catch (err) {\n if (isFetchError(err)) {\n if (err.response) {\n logger.error(\n `Failed to to fetch node info (${err.response.status}): ${err.response.status} ${err.data?.err ?? err.data?.message}`,\n )\n } else {\n logger.error(`Failed to to fetch node info: ${err.message}`)\n }\n logger.debug(JSON.stringify(err.data))\n } else {\n logger.error(`Failed to to fetch node info: ${err}`)\n }\n return null\n }\n}\n\nfunction validateProps(doc: CodeConnectJSON, document: any): boolean {\n if (doc.templateData && doc.templateData?.props) {\n let propsValid = true\n const codeConnectProps = Object.keys(doc.templateData.props ?? {})\n\n for (let i = 0; i < codeConnectProps.length; i++) {\n const codeConnectProp = doc.templateData?.props[codeConnectProps[i]]\n if (codeConnectProp.kind === 'children') {\n const codeConnectLayerNames = codeConnectProp.args.layers\n // Get all layer names in the figma doc\n const figmaLayerNames: string[] = []\n const getLayerNames = (layer: any) => {\n if (layer.name) {\n figmaLayerNames.push(layer.name)\n }\n if (layer.children) {\n layer.children.forEach((child: any) => getLayerNames(child))\n }\n }\n getLayerNames(document)\n // And make sure that the layer names in the code connect file are present in the figma doc\n for (const codeConnectLayerName of codeConnectLayerNames) {\n const regex = new RegExp('^' + codeConnectLayerName.replace('*', '.*'))\n if (figmaLayerNames.every((name) => !regex.test(name))) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): The layer \"${codeConnectLayerName}\" does not exist on the Figma component`,\n )\n propsValid = false\n }\n }\n continue\n }\n if (\n codeConnectProp.kind === 'boolean' ||\n codeConnectProp.kind === 'enum' ||\n codeConnectProp.kind === 'string'\n ) {\n const codeConnectFigmaPropName = codeConnectProp?.args?.figmaPropName\n\n if (\n !document.componentPropertyDefinitions ||\n !Object.keys(document.componentPropertyDefinitions).find((figmaProp) =>\n propMatches(figmaProp, codeConnectFigmaPropName, document.componentPropertyDefinitions),\n )\n ) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): The property \"${codeConnectFigmaPropName}\" does not exist on the Figma component`,\n )\n propsValid = false\n }\n }\n }\n\n if (!propsValid) {\n return false\n }\n }\n return true\n}\n\nfunction getPropName(componentPropertyDefinitions: any, propName: string): string {\n const prop = componentPropertyDefinitions[propName]\n if (prop.type === 'VARIANT') {\n return propName\n }\n\n // non Variant Keys are of the form \"name#id\"\n // We have to take the last one in case the name contains #'s\n const lastIndex = propName.lastIndexOf('#')\n if (lastIndex !== -1) {\n return propName.substring(0, lastIndex)\n }\n return propName\n}\n\nfunction propMatches(\n figmaProp: any,\n codeConnectPropName: string,\n componentPropertyDefinitions: any,\n): boolean {\n const figmaPropName = getPropName(componentPropertyDefinitions, figmaProp)\n return figmaPropName === codeConnectPropName\n}\n\n\n\n\nexport const STATE_BOOLEAN_VALUE_PAIRS = [\n ['yes', 'no'],\n ['true', 'false'],\n ['on', 'off'],\n]\n\nfunction isVariantBoolean(variantPossibleValues: string[]) {\n if (variantPossibleValues.length === 2) {\n const lowerCaseOptions = variantPossibleValues.map((p) => p.toLowerCase())\n for (const pair of STATE_BOOLEAN_VALUE_PAIRS) {\n const i = lowerCaseOptions.indexOf(pair[0]!)\n const j = lowerCaseOptions.indexOf(pair[1]!)\n if (i !== -1 && j !== -1) {\n return true\n }\n }\n }\n return false\n}\n\nfunction validateVariantRestrictions(doc: CodeConnectJSON, document: any): boolean {\n if (doc.variant) {\n let variantRestrictionsValid = true\n const codeConnectVariantRestrictions = Object.keys(doc.variant)\n\n for (let i = 0; i < codeConnectVariantRestrictions.length; i++) {\n const variantRestriction: any = codeConnectVariantRestrictions[i]\n\n const match = Object.keys(document.componentPropertyDefinitions ?? {}).find((figmaProp) =>\n propMatches(figmaProp, variantRestriction, document.componentPropertyDefinitions),\n )\n if (!match) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): The property \"${variantRestriction}\" does not exist on the Figma component`,\n )\n variantRestrictionsValid = false\n continue\n }\n\n const variantRestrictionValue = doc.variant[variantRestriction]\n const variantOrProp = document.componentPropertyDefinitions[match]\n\n // Only check `variantOptions` for Variants, and not for props, since props\n // don't have a set of possible values we can check against\n const isValidBooleanVariant =\n typeof variantRestrictionValue === 'boolean' &&\n Array.isArray(variantOrProp.variantOptions) &&\n isVariantBoolean(variantOrProp.variantOptions)\n\n const isValidVariantValue =\n variantOrProp.variantOptions?.includes(variantRestrictionValue) || isValidBooleanVariant\n\n if (variantOrProp.type === 'VARIANT' && !isValidVariantValue) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): The Figma Variant \"${match}\" does not have an option for ${variantRestrictionValue}`,\n )\n variantRestrictionsValid = false\n continue\n }\n }\n\n if (!variantRestrictionsValid) {\n return false\n }\n }\n return true\n}\n\nexport function validateDoc(doc: CodeConnectJSON, figmaNode: any, nodeId: string): boolean {\n if (!figmaNode || !figmaNode.document) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): node not found in file`,\n )\n return false\n }\n\n const document = figmaNode.document\n if (document.type !== 'COMPONENT' && document.type !== 'COMPONENT_SET') {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): corresponding node is not a component or component set`,\n )\n return false\n }\n\n const component = figmaNode.components[nodeId]\n if (component && component.componentSetId) {\n logger.error(\n `Validation failed for ${doc.component} (${doc.figmaNode}): node is not a top level component or component set. Please check that the node is not a variant`,\n )\n return false\n }\n\n const propsValid = validateProps(doc, document)\n if (!propsValid) {\n return false\n }\n\n const variantRestrictionsValid = validateVariantRestrictions(doc, document)\n if (!variantRestrictionsValid) {\n return false\n }\n\n return true\n}\n\nexport async function validateDocs(\n cmd: BaseCommand,\n accessToken: string,\n docs: CodeConnectJSON[],\n apiUrlOverride?: string,\n useOAuth = false,\n): Promise<boolean> {\n let baseApiUrl = getApiUrl(docs?.[0]?.figmaNode ?? '', apiUrlOverride) + '/files/'\n\n const fileKeyToNodeIds: { [key: string]: any } = {}\n let valid = true\n docs.forEach((doc) => {\n const parsedNode = parseFigmaNode(cmd.verbose, doc)\n if (!parsedNode) {\n valid = false\n return\n }\n fileKeyToNodeIds[parsedNode.fileKey] ||= {}\n fileKeyToNodeIds[parsedNode.fileKey][parsedNode.nodeId] ||= []\n fileKeyToNodeIds[parsedNode.fileKey][parsedNode.nodeId].push(doc)\n })\n\n if (!valid) {\n return false\n }\n\n logger.debug('fileKeyToNodeIds')\n logger.debug(JSON.stringify(fileKeyToNodeIds, null, 2))\n\n const fileKeys = Object.keys(fileKeyToNodeIds)\n for (let i = 0; i < fileKeys.length; i++) {\n const fileKey = fileKeys[i]\n logger.debug(`Validating file ${fileKey}`)\n const nodeMap = fileKeyToNodeIds[fileKey]\n const nodeIds = Object.keys(nodeMap)\n logger.debug(`Validating ${nodeIds.length} nodes`)\n const chunks = chunk(nodeIds, 400)\n\n for (let batch = 0; batch < chunks.length; batch++) {\n const nodeIdsChunk = chunks[batch]\n logger.debug(`Running for ${baseApiUrl + fileKey + '/nodes?ids=' + nodeIdsChunk.join(',')}`)\n const nodeMapRet = await fetchNodeInfo(\n baseApiUrl,\n fileKey,\n nodeIdsChunk,\n accessToken,\n useOAuth,\n )\n if (!nodeMapRet) {\n return false\n }\n\n valid =\n valid &&\n nodeIdsChunk\n .map((nodeId: string) => {\n return nodeMap[nodeId]\n .map((doc: CodeConnectJSON) => validateDoc(doc, nodeMapRet[nodeId], nodeId))\n .every(Boolean)\n })\n .every(Boolean)\n }\n }\n return valid\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/connect/wizard/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import * as prettier from 'prettier'\nimport fs from 'fs'\nimport {\n CodeConnectConfig,\n CodeConnectParser,\n DEFAULT_INCLUDE_GLOBS_BY_PARSER,\n DEFAULT_LABEL_PER_PARSER,\n ProjectInfo,\n ReactProjectInfo,\n getDefaultConfigPath,\n getEnvPath,\n} from '../project'\nimport { exitWithError, logger, success } from '../../common/logging'\nimport path from 'path'\nimport prompts, { Choice } from 'prompts'\nimport { BaseCommand } from '../../commands/connect'\nimport { isFigmaConnectFile } from '../parser_common'\nimport { parseFileKey } from '../helpers'\n\nexport function maybePrefillWizardQuestionsForTesting() {\n if (process.env.JEST_WORKER_ID && process.env.WIZARD_ANSWERS_TO_PREFILL) {\n const unescapedJson = JSON.parse(process.env.WIZARD_ANSWERS_TO_PREFILL.replace(/\\\\\"/g, '\"'))\n prompts.inject(unescapedJson)\n }\n}\n\n/**\n *\n * Gets the default include globs for config.parser with componentDirectory prepended\n * @param args\n * @param args.dir project root path\n * @param args.componentDirectory optional path to where includes should be limited to\n * @param args.config CodeConnectConfig\n * @returns array of include globs\n */\nexport function getIncludesGlob({\n dir,\n componentDirectory,\n config,\n}: {\n dir: string\n componentDirectory: string | null\n config: CodeConnectConfig\n}) {\n if (componentDirectory) {\n // use unix separators for config file globs\n const pathToComponentsDir = path.relative(dir, componentDirectory).replaceAll(path.sep, '/')\n if (config.parser === 'custom') {\n return []\n }\n return DEFAULT_INCLUDE_GLOBS_BY_PARSER[config.parser].map(\n (defaultIncludeGlob) => `${pathToComponentsDir}/${defaultIncludeGlob}`,\n )\n }\n return DEFAULT_INCLUDE_GLOBS_BY_PARSER[config.parser]\n}\n\nexport async function createEnvFile({ dir, accessToken }: { dir: string; accessToken?: string }) {\n // Create .env file\n const filePath = getDefaultConfigPath(dir)\n fs.writeFileSync(getEnvPath(dir), `FIGMA_ACCESS_TOKEN=\"${accessToken}\"`)\n logger.info(success(`Created ${filePath}`))\n}\n\nexport function addTokenToEnvFile({ dir, accessToken }: { dir: string; accessToken?: string }) {\n const filePath = getDefaultConfigPath(dir)\n fs.appendFileSync(getEnvPath(dir), `\\nFIGMA_ACCESS_TOKEN=\"${accessToken}\"`)\n logger.info(success(`Appended access token to ${filePath}`))\n}\n\nexport async function createCodeConnectConfig({\n dir,\n componentDirectory,\n config,\n figmaUrl,\n}: {\n dir: string\n componentDirectory: string | null\n config: CodeConnectConfig\n figmaUrl: string\n}) {\n const label = DEFAULT_LABEL_PER_PARSER[config.parser as CodeConnectParser]\n const includesGlob = getIncludesGlob({ dir, componentDirectory, config })\n\n const configJson = label\n ? `{\n \"codeConnect\": {\n \"include\": [\"${includesGlob}\"],\n \"label\": \"${label}\",\n \"interactiveSetupFigmaFileUrl\": \"${figmaUrl}\",\n}\n}`\n : `{\n \"codeConnect\": {\n \"include\": [\"${includesGlob}\"],\n \"interactiveSetupFigmaFileUrl\": \"${figmaUrl}\",\n }\n}`\n\n const formatted = await prettier.format(configJson, {\n parser: 'json',\n })\n const filePath = getDefaultConfigPath(dir)\n\n fs.writeFileSync(filePath, formatted)\n\n logger.info(success(`Created ${filePath}`))\n}\n\nconst FILEPATH_EXPORT_DELIMITER = '~'\n\nexport function parseFilepathExport(filepathExport: string) {\n const delimiterLastIndex = filepathExport.lastIndexOf(FILEPATH_EXPORT_DELIMITER)\n\n if (delimiterLastIndex === -1) {\n return {\n filepath: filepathExport,\n exportName: null,\n }\n }\n return {\n filepath: filepathExport.substring(0, delimiterLastIndex),\n exportName: filepathExport.substring(delimiterLastIndex + 1),\n }\n}\n\nexport function getFilepathExport(filepath: string, exp: string) {\n return `${filepath}${FILEPATH_EXPORT_DELIMITER}${exp}`\n}\n\n/**\n * Formats an array of filepathExports into a map of filepaths->exports\n *\n * @param filepathExports an array of components in the format `${filepath}~${componentName}\n * @returns a map of filepaths to an array of their exports. Array is empty if no exports found\n */\nexport function getComponentOptionsMap(filepathExports: string[]) {\n return filepathExports.reduce(\n (acc, filepathExport) => {\n const { filepath, exportName } = parseFilepathExport(filepathExport)\n acc[filepath] = acc[filepath] || []\n if (exportName) {\n acc[filepath].push({\n title: exportName,\n value: getFilepathExport(filepath, exportName),\n })\n }\n return acc\n },\n {} as Record<string, Choice[]>,\n )\n}\n\n/**\n * Parses a ProjectInfo for any TS exports (or filepaths if not a TS project)\n *\n * @param projectInfo\n * @returns an array of components in the format `${filepath}~${componentName}\n */\nexport function getFilepathExportsFromFiles(projectInfo: ProjectInfo, cmd: BaseCommand) {\n return projectInfo.files.reduce((options, filepath) => {\n if (projectInfo.config.parser === 'react') {\n const { tsProgram } = projectInfo as ReactProjectInfo\n if (!isFigmaConnectFile(tsProgram, filepath, 'tsx')) {\n const checker = tsProgram.getTypeChecker()\n const sourceFile = tsProgram.getSourceFile(filepath)\n if (!sourceFile) {\n if (cmd.verbose) {\n logger.warn(`Could not parse file for TypeScript: ${filepath}`)\n }\n } else {\n try {\n const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile)!\n const exports = checker.getExportsOfModule(sourceFileSymbol)\n\n exports.forEach((exp) => {\n options.push(getFilepathExport(filepath, exp.getName()))\n })\n } catch (e) {\n if (cmd.verbose) {\n logger.warn(`Could not parse exports of file: ${filepath}`)\n }\n // ignore invalid files\n }\n }\n }\n } else {\n options.push(filepath)\n }\n return options\n }, [] as string[])\n}\n\nexport function isValidFigmaUrl(url: string) {\n try {\n const { hostname } = new URL(url)\n if (\n !hostname.includes('figma.com')\n ) {\n return false\n }\n\n return !!parseFileKey(url)\n } catch (e) {\n return false\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/connect/wizard/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import * as prettier from 'prettier'\nimport fs from 'fs'\nimport {\n CodeConnectConfig,\n CodeConnectParser,\n DEFAULT_INCLUDE_GLOBS_BY_PARSER,\n DEFAULT_LABEL_PER_PARSER,\n ProjectInfo,\n ReactProjectInfo,\n getDefaultConfigPath,\n getEnvPath,\n} from '../project'\nimport { exitWithError, logger, success } from '../../common/logging'\nimport path from 'path'\nimport prompts, { Choice } from 'prompts'\nimport { BaseCommand } from '../../commands/connect'\nimport { isFigmaConnectFile } from '../parser_common'\nimport { parseFileKey } from '../helpers'\n\nexport function maybePrefillWizardQuestionsForTesting() {\n if (process.env.JEST_WORKER_ID && process.env.WIZARD_ANSWERS_TO_PREFILL) {\n const unescapedJson = JSON.parse(process.env.WIZARD_ANSWERS_TO_PREFILL.replace(/\\\\\"/g, '\"'))\n prompts.inject(unescapedJson)\n }\n}\n\n/**\n *\n * Gets the default include globs for config.parser with componentDirectory prepended\n * @param args\n * @param args.dir project root path\n * @param args.componentDirectory optional path to where includes should be limited to\n * @param args.config CodeConnectConfig\n * @returns array of include globs\n */\nexport function getIncludesGlob({\n dir,\n componentDirectory,\n config,\n}: {\n dir: string\n componentDirectory: string | null\n config: CodeConnectConfig\n}) {\n if (componentDirectory) {\n // use unix separators for config file globs\n const pathToComponentsDir = path.relative(dir, componentDirectory).replaceAll(path.sep, '/')\n if (config.parser === 'custom') {\n return []\n }\n return DEFAULT_INCLUDE_GLOBS_BY_PARSER[config.parser!].map(\n (defaultIncludeGlob) => `${pathToComponentsDir}/${defaultIncludeGlob}`,\n )\n }\n return DEFAULT_INCLUDE_GLOBS_BY_PARSER[config.parser!]\n}\n\nexport async function createEnvFile({ dir, accessToken }: { dir: string; accessToken?: string }) {\n // Create .env file\n const filePath = getDefaultConfigPath(dir)\n fs.writeFileSync(getEnvPath(dir), `FIGMA_ACCESS_TOKEN=\"${accessToken}\"`)\n logger.info(success(`Created ${filePath}`))\n}\n\nexport function addTokenToEnvFile({ dir, accessToken }: { dir: string; accessToken?: string }) {\n const filePath = getDefaultConfigPath(dir)\n fs.appendFileSync(getEnvPath(dir), `\\nFIGMA_ACCESS_TOKEN=\"${accessToken}\"`)\n logger.info(success(`Appended access token to ${filePath}`))\n}\n\nexport async function createCodeConnectConfig({\n dir,\n componentDirectory,\n config,\n figmaUrl,\n}: {\n dir: string\n componentDirectory: string | null\n config: CodeConnectConfig\n figmaUrl: string\n}) {\n const label = DEFAULT_LABEL_PER_PARSER[config.parser as CodeConnectParser]\n const includesGlob = getIncludesGlob({ dir, componentDirectory, config })\n\n const configJson = label\n ? `{\n \"codeConnect\": {\n \"include\": [\"${includesGlob}\"],\n \"label\": \"${label}\",\n \"interactiveSetupFigmaFileUrl\": \"${figmaUrl}\",\n}\n}`\n : `{\n \"codeConnect\": {\n \"include\": [\"${includesGlob}\"],\n \"interactiveSetupFigmaFileUrl\": \"${figmaUrl}\",\n }\n}`\n\n const formatted = await prettier.format(configJson, {\n parser: 'json',\n })\n const filePath = getDefaultConfigPath(dir)\n\n fs.writeFileSync(filePath, formatted)\n\n logger.info(success(`Created ${filePath}`))\n}\n\nconst FILEPATH_EXPORT_DELIMITER = '~'\n\nexport function parseFilepathExport(filepathExport: string) {\n const delimiterLastIndex = filepathExport.lastIndexOf(FILEPATH_EXPORT_DELIMITER)\n\n if (delimiterLastIndex === -1) {\n return {\n filepath: filepathExport,\n exportName: null,\n }\n }\n return {\n filepath: filepathExport.substring(0, delimiterLastIndex),\n exportName: filepathExport.substring(delimiterLastIndex + 1),\n }\n}\n\nexport function getFilepathExport(filepath: string, exp: string) {\n return `${filepath}${FILEPATH_EXPORT_DELIMITER}${exp}`\n}\n\n/**\n * Formats an array of filepathExports into a map of filepaths->exports\n *\n * @param filepathExports an array of components in the format `${filepath}~${componentName}\n * @returns a map of filepaths to an array of their exports. Array is empty if no exports found\n */\nexport function getComponentOptionsMap(filepathExports: string[]) {\n return filepathExports.reduce(\n (acc, filepathExport) => {\n const { filepath, exportName } = parseFilepathExport(filepathExport)\n acc[filepath] = acc[filepath] || []\n if (exportName) {\n acc[filepath].push({\n title: exportName,\n value: getFilepathExport(filepath, exportName),\n })\n }\n return acc\n },\n {} as Record<string, Choice[]>,\n )\n}\n\n/**\n * Parses a ProjectInfo for any TS exports (or filepaths if not a TS project)\n *\n * @param projectInfo\n * @returns an array of components in the format `${filepath}~${componentName}\n */\nexport function getFilepathExportsFromFiles(projectInfo: ProjectInfo, cmd: BaseCommand) {\n return projectInfo.files.reduce((options, filepath) => {\n if (projectInfo.config.parser === 'react') {\n const { tsProgram } = projectInfo as ReactProjectInfo\n if (!isFigmaConnectFile(tsProgram, filepath, 'tsx')) {\n const checker = tsProgram.getTypeChecker()\n const sourceFile = tsProgram.getSourceFile(filepath)\n if (!sourceFile) {\n if (cmd.verbose) {\n logger.warn(`Could not parse file for TypeScript: ${filepath}`)\n }\n } else {\n try {\n const sourceFileSymbol = checker.getSymbolAtLocation(sourceFile)!\n const exports = checker.getExportsOfModule(sourceFileSymbol)\n\n exports.forEach((exp) => {\n options.push(getFilepathExport(filepath, exp.getName()))\n })\n } catch (e) {\n if (cmd.verbose) {\n logger.warn(`Could not parse exports of file: ${filepath}`)\n }\n // ignore invalid files\n }\n }\n }\n } else {\n options.push(filepath)\n }\n return options\n }, [] as string[])\n}\n\nexport function isValidFigmaUrl(url: string) {\n try {\n const { hostname } = new URL(url)\n if (\n !hostname.includes('figma.com')\n ) {\n return false\n }\n\n return !!parseFileKey(url)\n } catch (e) {\n return false\n }\n}\n"]}
|
package/dist/html/parser.d.ts
CHANGED
|
@@ -11,9 +11,9 @@ import { ParserContext, ParseOptions } from '../connect/parser_common';
|
|
|
11
11
|
*
|
|
12
12
|
* @returns The code of the render function and a list of imports
|
|
13
13
|
*/
|
|
14
|
-
export declare function parseExampleTemplate(exp: ts.ArrowFunction, parserContext: ParserContext, propMappings?: PropMappings,
|
|
14
|
+
export declare function parseExampleTemplate(exp: ts.ArrowFunction, parserContext: ParserContext, propMappings?: PropMappings, isForMigration?: boolean): {
|
|
15
15
|
code: string;
|
|
16
16
|
nestable: boolean;
|
|
17
17
|
};
|
|
18
|
-
export declare function parseHtmlDoc(node: ts.CallExpression, parserContext: ParserContext, {
|
|
18
|
+
export declare function parseHtmlDoc(node: ts.CallExpression, parserContext: ParserContext, { isForMigration }: ParseOptions): Promise<CodeConnectJSON>;
|
|
19
19
|
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/html/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2D,MAAM,YAAY,CAAA;AAMpF,OAAO,EAAsB,YAAY,EAAoB,MAAM,uBAAuB,CAAA;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAI1D,OAAO,EAEL,aAAa,EAOb,YAAY,EACb,MAAM,0BAA0B,CAAA;AA4KjC;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,EAAE,CAAC,aAAa,EACrB,aAAa,EAAE,aAAa,EAC5B,YAAY,CAAC,EAAE,YAAY,EAC3B,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/html/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2D,MAAM,YAAY,CAAA;AAMpF,OAAO,EAAsB,YAAY,EAAoB,MAAM,uBAAuB,CAAA;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAI1D,OAAO,EAEL,aAAa,EAOb,YAAY,EACb,MAAM,0BAA0B,CAAA;AA4KjC;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,EAAE,CAAC,aAAa,EACrB,aAAa,EAAE,aAAa,EAC5B,YAAY,CAAC,EAAE,YAAY,EAC3B,cAAc,CAAC,EAAE,OAAO;;;EA+OzB;AAiID,wBAAsB,YAAY,CAChC,IAAI,EAAE,EAAE,CAAC,cAAc,EACvB,aAAa,EAAE,aAAa,EAC5B,EAAE,cAAc,EAAE,EAAE,YAAY,GAC/B,OAAO,CAAC,eAAe,CAAC,CA4D1B"}
|
package/dist/html/parser.js
CHANGED
|
@@ -197,7 +197,7 @@ function escapeTemplateString(code) {
|
|
|
197
197
|
*
|
|
198
198
|
* @returns The code of the render function and a list of imports
|
|
199
199
|
*/
|
|
200
|
-
function parseExampleTemplate(exp, parserContext, propMappings,
|
|
200
|
+
function parseExampleTemplate(exp, parserContext, propMappings, isForMigration) {
|
|
201
201
|
const { sourceFile } = parserContext;
|
|
202
202
|
if (exp.parameters.length > 1) {
|
|
203
203
|
throw new parser_common_1.ParserError(`Expected a single props parameter for the render function, got ${exp.parameters.length} parameters`, { sourceFile, node: exp });
|
|
@@ -218,7 +218,7 @@ function parseExampleTemplate(exp, parserContext, propMappings, skipTemplateHelp
|
|
|
218
218
|
}
|
|
219
219
|
let exampleCode = printer.printNode(typescript_1.default.EmitHint.Unspecified, exp.body, sourceFile);
|
|
220
220
|
let templateCode = '';
|
|
221
|
-
if (!
|
|
221
|
+
if (!isForMigration) {
|
|
222
222
|
templateCode = (0, parser_template_helpers_1.getParsedTemplateHelpersString)() + '\n\n';
|
|
223
223
|
}
|
|
224
224
|
templateCode += `const figma = require('figma')\n\n`;
|
|
@@ -226,6 +226,7 @@ function parseExampleTemplate(exp, parserContext, propMappings, skipTemplateHelp
|
|
|
226
226
|
propMappings,
|
|
227
227
|
exp,
|
|
228
228
|
sourceFile,
|
|
229
|
+
isForMigration,
|
|
229
230
|
});
|
|
230
231
|
exampleCode = exampleCode.replace(/`/g, '\\`');
|
|
231
232
|
// Body is a string literal, so there aren't any placeholders
|
|
@@ -365,7 +366,7 @@ function parseExampleTemplate(exp, parserContext, propMappings, skipTemplateHelp
|
|
|
365
366
|
throw new parser_common_1.ParserError(`Expected a template expression as the body of the render function, got ${typescript_1.SyntaxKind[templateNode.template.kind]}`, { sourceFile, node: templateNode.template });
|
|
366
367
|
}
|
|
367
368
|
let templateCode = '';
|
|
368
|
-
if (!
|
|
369
|
+
if (!isForMigration) {
|
|
369
370
|
templateCode = (0, parser_template_helpers_1.getParsedTemplateHelpersString)() + '\n\n';
|
|
370
371
|
}
|
|
371
372
|
templateCode += `const figma = require('figma')\n\n`;
|
|
@@ -373,6 +374,7 @@ function parseExampleTemplate(exp, parserContext, propMappings, skipTemplateHelp
|
|
|
373
374
|
propMappings,
|
|
374
375
|
exp,
|
|
375
376
|
sourceFile,
|
|
377
|
+
isForMigration,
|
|
376
378
|
});
|
|
377
379
|
templateCode += `export default figma.html\`${exampleCode}\`\n`;
|
|
378
380
|
return {
|
|
@@ -479,7 +481,7 @@ function parseConfigObjectArg(configArg, parserContext) {
|
|
|
479
481
|
importsArg,
|
|
480
482
|
};
|
|
481
483
|
}
|
|
482
|
-
async function parseHtmlDoc(node, parserContext, {
|
|
484
|
+
async function parseHtmlDoc(node, parserContext, { isForMigration }) {
|
|
483
485
|
const { checker, sourceFile, config } = parserContext;
|
|
484
486
|
// Parse the arguments to the `figma.connect()` call
|
|
485
487
|
const { figmaNodeUrlArg, configObjArg } = parseFigmaConnectArgs(node, parserContext);
|
|
@@ -492,7 +494,7 @@ async function parseHtmlDoc(node, parserContext, { skipTemplateHelpers }) {
|
|
|
492
494
|
const metadata = undefined;
|
|
493
495
|
const props = propsArg ? (0, intrinsics_1.parsePropsObject)(propsArg, parserContext) : undefined;
|
|
494
496
|
const render = exampleArg
|
|
495
|
-
? parseExampleTemplate(exampleArg, parserContext, props,
|
|
497
|
+
? parseExampleTemplate(exampleArg, parserContext, props, isForMigration)
|
|
496
498
|
: undefined;
|
|
497
499
|
const variant = variantArg ? (0, parser_common_1.parseVariant)(variantArg, sourceFile, checker) : undefined;
|
|
498
500
|
const links = linksArg ? (0, parser_common_1.parseLinks)(linksArg, parserContext) : undefined;
|