@figma/code-connect 0.1.2 → 0.2.1
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 +123 -25
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/connect.d.ts +15 -0
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +137 -76
- package/dist/commands/connect.js.map +1 -1
- package/dist/common/__test__/project.test.d.ts +2 -0
- package/dist/common/__test__/project.test.d.ts.map +1 -0
- package/dist/common/__test__/project.test.js +14 -0
- package/dist/common/__test__/project.test.js.map +1 -0
- package/dist/common/api.d.ts +56 -2
- package/dist/common/api.d.ts.map +1 -1
- package/dist/common/external.d.ts +6 -3
- package/dist/common/external.d.ts.map +1 -1
- package/dist/common/external.js +13 -1
- package/dist/common/external.js.map +1 -1
- package/dist/common/figma_connect.d.ts +10 -8
- package/dist/common/figma_connect.d.ts.map +1 -1
- package/dist/common/intrinsics.d.ts +38 -6
- package/dist/common/intrinsics.d.ts.map +1 -1
- package/dist/common/intrinsics.js +160 -26
- package/dist/common/intrinsics.js.map +1 -1
- package/dist/common/logging.d.ts +9 -0
- package/dist/common/logging.d.ts.map +1 -1
- package/dist/common/logging.js +21 -1
- package/dist/common/logging.js.map +1 -1
- package/dist/common/updates.d.ts +4 -0
- package/dist/common/updates.d.ts.map +1 -0
- package/dist/common/updates.js +87 -0
- package/dist/common/updates.js.map +1 -0
- package/dist/connect/create.d.ts +5 -1
- package/dist/connect/create.d.ts.map +1 -1
- package/dist/connect/create.js +55 -69
- package/dist/connect/create.js.map +1 -1
- package/dist/connect/delete_docs.d.ts.map +1 -1
- package/dist/connect/delete_docs.js +1 -4
- package/dist/connect/delete_docs.js.map +1 -1
- package/dist/connect/figma_rest_api.d.ts +5 -0
- package/dist/connect/figma_rest_api.d.ts.map +1 -1
- package/dist/connect/figma_rest_api.js +10 -1
- package/dist/connect/figma_rest_api.js.map +1 -1
- package/dist/connect/helpers.d.ts +1 -1
- package/dist/connect/helpers.d.ts.map +1 -1
- package/dist/connect/helpers.js +6 -5
- package/dist/connect/helpers.js.map +1 -1
- package/dist/connect/parser_executable_types.d.ts +297 -0
- package/dist/connect/parser_executable_types.d.ts.map +1 -0
- package/dist/connect/parser_executable_types.js +108 -0
- package/dist/connect/parser_executable_types.js.map +1 -0
- package/dist/connect/parser_executables.d.ts +8 -0
- package/dist/connect/parser_executables.d.ts.map +1 -0
- package/dist/connect/parser_executables.js +132 -0
- package/dist/connect/parser_executables.js.map +1 -0
- package/dist/connect/project.d.ts +137 -0
- package/dist/connect/project.d.ts.map +1 -0
- package/dist/connect/project.js +411 -0
- package/dist/connect/project.js.map +1 -0
- package/dist/connect/upload.d.ts.map +1 -1
- package/dist/connect/upload.js +1 -4
- package/dist/connect/upload.js.map +1 -1
- package/dist/connect/validation.d.ts +6 -1
- package/dist/connect/validation.d.ts.map +1 -1
- package/dist/connect/validation.js +23 -18
- package/dist/connect/validation.js.map +1 -1
- package/dist/connect/wizard/helpers.d.ts +7 -0
- package/dist/connect/wizard/helpers.d.ts.map +1 -0
- package/dist/connect/wizard/helpers.js +55 -0
- package/dist/connect/wizard/helpers.js.map +1 -0
- package/dist/connect/wizard/run_wizard.d.ts +3 -0
- package/dist/connect/wizard/run_wizard.d.ts.map +1 -0
- package/dist/connect/wizard/run_wizard.js +480 -0
- package/dist/connect/wizard/run_wizard.js.map +1 -0
- package/dist/parser_scripts/get_file_if_exists.d.ts +2 -0
- package/dist/parser_scripts/get_file_if_exists.d.ts.map +1 -0
- package/dist/parser_scripts/get_file_if_exists.js +10 -0
- package/dist/parser_scripts/get_file_if_exists.js.map +1 -0
- package/dist/parser_scripts/get_gradlew_path.d.ts +3 -0
- package/dist/parser_scripts/get_gradlew_path.d.ts.map +1 -0
- package/dist/parser_scripts/get_gradlew_path.js +24 -0
- package/dist/parser_scripts/get_gradlew_path.js.map +1 -0
- package/dist/parser_scripts/get_swift_parser_dir.d.ts +2 -0
- package/dist/parser_scripts/get_swift_parser_dir.d.ts.map +1 -0
- package/dist/parser_scripts/get_swift_parser_dir.js +93 -0
- package/dist/parser_scripts/get_swift_parser_dir.js.map +1 -0
- package/dist/react/create.d.ts +4 -0
- package/dist/react/create.d.ts.map +1 -0
- package/dist/react/create.js +132 -0
- package/dist/react/create.js.map +1 -0
- package/dist/react/parser.d.ts +6 -15
- package/dist/react/parser.d.ts.map +1 -1
- package/dist/react/parser.js +55 -62
- package/dist/react/parser.js.map +1 -1
- package/dist/react/parser_template_helpers.d.ts +21 -0
- package/dist/react/parser_template_helpers.d.ts.map +1 -1
- package/dist/react/parser_template_helpers.js +107 -43
- package/dist/react/parser_template_helpers.js.map +1 -1
- package/dist/storybook/convert.d.ts +2 -2
- package/dist/storybook/convert.d.ts.map +1 -1
- package/dist/storybook/convert.js +6 -4
- package/dist/storybook/convert.js.map +1 -1
- package/package.json +36 -11
- package/dist/common/project.d.ts +0 -94
- package/dist/common/project.d.ts.map +0 -1
- package/dist/common/project.js +0 -198
- package/dist/common/project.js.map +0 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSwiftParserDir = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const logging_1 = require("../common/logging");
|
|
6
|
+
const get_file_if_exists_1 = require("./get_file_if_exists");
|
|
7
|
+
// Find the location of the Code Connect Swift package on disk, so that we can
|
|
8
|
+
// call `swift run figma-swift` from the correct location. This requires parsing
|
|
9
|
+
// the output of xcodebuild for .xcodeproj projects, or parsing Package.swift
|
|
10
|
+
// for SPM projects.
|
|
11
|
+
//
|
|
12
|
+
// As this is a first party parser, we do this in TypeScript and call it as part
|
|
13
|
+
// of our code. For third party parsers, logic like this would need to be
|
|
14
|
+
// implemented in a script/binary which the user points Code Connect to.
|
|
15
|
+
async function getSwiftParserDir(cwd, xcodeprojPath) {
|
|
16
|
+
let figmaPackageDir;
|
|
17
|
+
// Check for the supported project types.
|
|
18
|
+
const xcodeProjFile = xcodeprojPath || (0, get_file_if_exists_1.getFileIfExists)(cwd, '*.xcodeproj');
|
|
19
|
+
const packageSwiftFile = (0, get_file_if_exists_1.getFileIfExists)(cwd, 'Package.swift');
|
|
20
|
+
if (!(xcodeProjFile || packageSwiftFile)) {
|
|
21
|
+
(0, logging_1.exitWithError)('No supported project found. Supported project types are .xcodeproj or Package.swift. You can specify the location of your .xcodeproj file with the `xcodeprojPath` config option.');
|
|
22
|
+
}
|
|
23
|
+
if (xcodeProjFile) {
|
|
24
|
+
// Use xcodebuild to get the build settings, so we can find where the Code
|
|
25
|
+
// Connect Swift package is installed
|
|
26
|
+
const buildSettings = (0, child_process_1.execSync)(`xcodebuild -project ${xcodeProjFile} -showBuildSettings`, {
|
|
27
|
+
cwd,
|
|
28
|
+
}).toString();
|
|
29
|
+
// Extract the source and version of the Code Connect Swift package from the
|
|
30
|
+
// xcodebuild output, which can be in any of the following formats depending
|
|
31
|
+
// on how it is installed:
|
|
32
|
+
// - Figma: https://github.com/figma/code-connect @ 0.1.2
|
|
33
|
+
// - Figma: /path/to/code-connect @ local
|
|
34
|
+
// - Figma: /path/to/code-connect
|
|
35
|
+
const figmaPackageMatch = buildSettings.match(/\s+Figma: ([^\s]*)(?: @ (.*))?/);
|
|
36
|
+
if (!figmaPackageMatch) {
|
|
37
|
+
(0, logging_1.exitWithError)('Code Connect Swift package not found');
|
|
38
|
+
}
|
|
39
|
+
// Find the package's location on disk, to compile and run the parser binary from
|
|
40
|
+
const [_, figmaPackageSource, figmaPackageVersion] = figmaPackageMatch;
|
|
41
|
+
// The package version is `local` if installed via the "Add package" dialog,
|
|
42
|
+
// or undefined if installed via the "Frameworks" section directly (which we
|
|
43
|
+
// do for our test project, because the dialog won't allow ancestors to be
|
|
44
|
+
// added)
|
|
45
|
+
const isLocalFigmaPackage = figmaPackageVersion === 'local' || figmaPackageVersion === undefined;
|
|
46
|
+
if (isLocalFigmaPackage) {
|
|
47
|
+
// If the version is 'local', the package is installed from a local checkout,
|
|
48
|
+
// and the path on disk is the source output by xcodebuild.
|
|
49
|
+
figmaPackageDir = figmaPackageSource;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Otherwise, the package will be installed to
|
|
53
|
+
// <DerviedData>/SourcePackages/checkouts/code-connect. We find the
|
|
54
|
+
// DerivedData location from the BUILD_DIR (which points to
|
|
55
|
+
// <DerivedData>/Build/Products).
|
|
56
|
+
const buildDir = buildSettings.match(/\s+BUILD_DIR = (.*)/);
|
|
57
|
+
if (!buildDir) {
|
|
58
|
+
(0, logging_1.exitWithError)('BUILD_DIR not found in xcodebuild output');
|
|
59
|
+
}
|
|
60
|
+
figmaPackageDir = `${buildDir[1]}/../../SourcePackages/checkouts/code-connect`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if (packageSwiftFile) {
|
|
64
|
+
// Use the Swift command to determine if the package is installed locally or from Git
|
|
65
|
+
try {
|
|
66
|
+
const packageInfo = JSON.parse((0, child_process_1.execSync)('swift package describe --type json', { cwd }).toString());
|
|
67
|
+
const codeConnectPackage = packageInfo.dependencies.find((p) => p.identity === 'code-connect') ??
|
|
68
|
+
// Our local directory is called figmadoc, so this is what swift outputs as the identity
|
|
69
|
+
packageInfo.dependencies.find((p) => p.identity === 'figmadoc');
|
|
70
|
+
if (!codeConnectPackage) {
|
|
71
|
+
(0, logging_1.exitWithError)('Code Connect Swift package not found in Package.swift');
|
|
72
|
+
}
|
|
73
|
+
if (codeConnectPackage.path) {
|
|
74
|
+
// Installed locally
|
|
75
|
+
figmaPackageDir = codeConnectPackage.path;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// Installed from git, SPM clones it into this directory
|
|
79
|
+
figmaPackageDir = '.build/checkouts/code-connect';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
(0, logging_1.exitWithError)(`Error calling Swift command: ${e}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (!figmaPackageDir) {
|
|
87
|
+
(0, logging_1.exitWithError)('Figma package could not be found');
|
|
88
|
+
}
|
|
89
|
+
logging_1.logger.info(`Found Code Connect Swift package at ${figmaPackageDir}, building parser binary. This may take a few minutes if this is the first time you've run Code Connect.`);
|
|
90
|
+
return figmaPackageDir;
|
|
91
|
+
}
|
|
92
|
+
exports.getSwiftParserDir = getSwiftParserDir;
|
|
93
|
+
//# sourceMappingURL=get_swift_parser_dir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_swift_parser_dir.js","sourceRoot":"","sources":["../../src/parser_scripts/get_swift_parser_dir.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { CreateRequestPayload, CreateResponsePayload } from '../connect/parser_executable_types';
|
|
3
|
+
export declare function createReactCodeConnect(payload: CreateRequestPayload): Promise<z.infer<typeof CreateResponsePayload>>;
|
|
4
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/react/create.ts"],"names":[],"mappings":"AAGA,OAAO,CAAC,MAAM,KAAK,CAAA;AACnB,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAA;AAyFhG,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAoChD"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.createReactCodeConnect = void 0;
|
|
30
|
+
const lodash_1 = require("lodash");
|
|
31
|
+
const prettier = __importStar(require("prettier"));
|
|
32
|
+
const fs_1 = __importDefault(require("fs"));
|
|
33
|
+
const path_1 = __importDefault(require("path"));
|
|
34
|
+
function isBooleanKind(propValue) {
|
|
35
|
+
const normalized = propValue.toLowerCase();
|
|
36
|
+
return (normalized === 'true' ||
|
|
37
|
+
normalized === 'false' ||
|
|
38
|
+
normalized === 'yes' ||
|
|
39
|
+
normalized === 'no' ||
|
|
40
|
+
normalized === 'on' ||
|
|
41
|
+
normalized === 'off');
|
|
42
|
+
}
|
|
43
|
+
function normalizePropName(name) {
|
|
44
|
+
return name.replace(/#[0-9:]*/g, '');
|
|
45
|
+
}
|
|
46
|
+
function generateCodePropName(name) {
|
|
47
|
+
return (0, lodash_1.camelCase)(name.replace(/[^a-zA-Z]/g, ''));
|
|
48
|
+
}
|
|
49
|
+
function normalizePropValue(name) {
|
|
50
|
+
// Convert the string to kebab-case
|
|
51
|
+
return name.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase();
|
|
52
|
+
}
|
|
53
|
+
function generateProps(component) {
|
|
54
|
+
const props = [];
|
|
55
|
+
if (!component.componentPropertyDefinitions ||
|
|
56
|
+
Object.keys(component.componentPropertyDefinitions).length === 0) {
|
|
57
|
+
return `{}`;
|
|
58
|
+
}
|
|
59
|
+
for (const [propName, propDef] of Object.entries(component.componentPropertyDefinitions)) {
|
|
60
|
+
const codePropName = generateCodePropName(propName);
|
|
61
|
+
const figmaPropName = normalizePropName(propName);
|
|
62
|
+
if (propDef.type === 'BOOLEAN') {
|
|
63
|
+
props.push(`"${codePropName}": figma.boolean('${figmaPropName}')`);
|
|
64
|
+
}
|
|
65
|
+
if (propDef.type === 'TEXT') {
|
|
66
|
+
props.push(`"${codePropName}": figma.string('${figmaPropName}')`);
|
|
67
|
+
}
|
|
68
|
+
if (propDef.type === 'VARIANT') {
|
|
69
|
+
if (propDef.variantOptions?.find((value) => isBooleanKind(value))) {
|
|
70
|
+
props.push(`"${codePropName}": figma.boolean('${figmaPropName}')`);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
props.push(`"${codePropName}": figma.enum('${figmaPropName}', { \n${propDef.variantOptions
|
|
74
|
+
?.map((value) => ` "${value}": "${normalizePropValue(value)}"`)
|
|
75
|
+
.join(',\n')}})`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (propDef.type === 'INSTANCE_SWAP') {
|
|
79
|
+
props.push(`"${codePropName}": figma.instance('${figmaPropName}')`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return `{
|
|
83
|
+
${props.join(',\n ')}
|
|
84
|
+
}`;
|
|
85
|
+
}
|
|
86
|
+
function getOutFileName({ outFile, outDir, componentName, }) {
|
|
87
|
+
if (outFile) {
|
|
88
|
+
return outFile;
|
|
89
|
+
}
|
|
90
|
+
const baseName = `${componentName}.figma.tsx`;
|
|
91
|
+
if (outDir) {
|
|
92
|
+
return path_1.default.join(outDir, baseName);
|
|
93
|
+
}
|
|
94
|
+
return path_1.default.join(process.env.INIT_CWD ?? process.cwd(), baseName);
|
|
95
|
+
}
|
|
96
|
+
async function createReactCodeConnect(payload) {
|
|
97
|
+
const { component, destinationFile, destinationDir } = payload;
|
|
98
|
+
const { normalizedName, figmaNodeUrl } = component;
|
|
99
|
+
const filePath = getOutFileName({
|
|
100
|
+
outFile: destinationFile,
|
|
101
|
+
outDir: destinationDir,
|
|
102
|
+
componentName: normalizedName,
|
|
103
|
+
});
|
|
104
|
+
const codeConnect = `
|
|
105
|
+
import React from 'react'
|
|
106
|
+
import { ${normalizedName} } from './${normalizedName}'
|
|
107
|
+
import figma from '@figma/code-connect'
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* -- This file was auto-generated by \`figma connect create\` --
|
|
111
|
+
* \`props\` includes a mapping from Figma properties and variants to
|
|
112
|
+
* suggested values. You should update this to match the props of your
|
|
113
|
+
* code component, and update the \`example\` function to return the
|
|
114
|
+
* code example you'd like to see in Figma
|
|
115
|
+
*/
|
|
116
|
+
|
|
117
|
+
figma.connect(${normalizedName}, "${figmaNodeUrl}", {
|
|
118
|
+
props: ${generateProps(component)},
|
|
119
|
+
example: (props) => <${normalizedName} />
|
|
120
|
+
})
|
|
121
|
+
`;
|
|
122
|
+
let formatted = await prettier.format(codeConnect, {
|
|
123
|
+
parser: 'typescript',
|
|
124
|
+
semi: false,
|
|
125
|
+
trailingComma: 'all',
|
|
126
|
+
});
|
|
127
|
+
fs_1.default.mkdirSync(path_1.default.dirname(filePath), { recursive: true });
|
|
128
|
+
fs_1.default.writeFileSync(filePath, formatted);
|
|
129
|
+
return { createdFiles: [{ filePath }], messages: [] };
|
|
130
|
+
}
|
|
131
|
+
exports.createReactCodeConnect = createReactCodeConnect;
|
|
132
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/react/create.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mCAAkC;AAClC,mDAAoC;AACpC,4CAAmB;AAInB,gDAAuB;AAEvB,SAAS,aAAa,CAAC,SAAiB;IACtC,MAAM,UAAU,GAAG,SAAS,CAAC,WAAW,EAAE,CAAA;IAC1C,OAAO,CACL,UAAU,KAAK,MAAM;QACrB,UAAU,KAAK,OAAO;QACtB,UAAU,KAAK,KAAK;QACpB,UAAU,KAAK,IAAI;QACnB,UAAU,KAAK,IAAI;QACnB,UAAU,KAAK,KAAK,CACrB,CAAA;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;AACtC,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAY;IACxC,OAAO,IAAA,kBAAS,EAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACtC,mCAAmC;IACnC,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;AACzD,CAAC;AAED,SAAS,aAAa,CAAC,SAA4C;IACjE,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IACE,CAAC,SAAS,CAAC,4BAA4B;QACvC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC,MAAM,KAAK,CAAC,EAChE,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,4BAA4B,CAAC,EAAE,CAAC;QACzF,MAAM,YAAY,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAA;QACnD,MAAM,aAAa,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;QACjD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,IAAI,YAAY,qBAAqB,aAAa,IAAI,CAAC,CAAA;QACpE,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC5B,KAAK,CAAC,IAAI,CAAC,IAAI,YAAY,oBAAoB,aAAa,IAAI,CAAC,CAAA;QACnE,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBAClE,KAAK,CAAC,IAAI,CAAC,IAAI,YAAY,qBAAqB,aAAa,IAAI,CAAC,CAAA;YACpE,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CACR,IAAI,YAAY,kBAAkB,aAAa,UAAU,OAAO,CAAC,cAAc;oBAC7E,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,KAAK,OAAO,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC;qBAC/D,IAAI,CAAC,KAAK,CAAC,IAAI,CACnB,CAAA;YACH,CAAC;QACH,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,IAAI,YAAY,sBAAsB,aAAa,IAAI,CAAC,CAAA;QACrE,CAAC;IACH,CAAC;IACD,OAAO;IACL,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;EACrB,CAAA;AACF,CAAC;AAED,SAAS,cAAc,CAAC,EACtB,OAAO,EACP,MAAM,EACN,aAAa,GAKd;IACC,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,aAAa,YAAY,CAAA;IAE7C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,cAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACpC,CAAC;IAED,OAAO,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAA;AACnE,CAAC;AAEM,KAAK,UAAU,sBAAsB,CAC1C,OAA6B;IAE7B,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,cAAc,EAAE,GAAG,OAAO,CAAA;IAC9D,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,GAAG,SAAS,CAAA;IAClD,MAAM,QAAQ,GAAG,cAAc,CAAC;QAC9B,OAAO,EAAE,eAAe;QACxB,MAAM,EAAE,cAAc;QACtB,aAAa,EAAE,cAAc;KAC9B,CAAC,CAAA;IAEF,MAAM,WAAW,GAAG;;WAEX,cAAc,cAAc,cAAc;;;;;;;;;;;gBAWrC,cAAc,MAAM,YAAY;WACrC,aAAa,CAAC,SAAS,CAAC;yBACV,cAAc;;CAEtC,CAAA;IACC,IAAI,SAAS,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE;QACjD,MAAM,EAAE,YAAY;QACpB,IAAI,EAAE,KAAK;QACX,aAAa,EAAE,KAAK;KACrB,CAAC,CAAA;IACF,YAAE,CAAC,SAAS,CAAC,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,YAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;IAErC,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAA;AACvD,CAAC;AAtCD,wDAsCC"}
|
package/dist/react/parser.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { CodeConnectReactConfig } from '../connect/project';
|
|
3
|
+
import { PropMappings } from '../common/intrinsics';
|
|
4
4
|
interface ParserErrorContext {
|
|
5
5
|
sourceFile: ts.SourceFile;
|
|
6
6
|
node: ts.Node | undefined;
|
|
@@ -18,18 +18,9 @@ export declare class InternalError extends ParserError {
|
|
|
18
18
|
export interface ParserContext {
|
|
19
19
|
checker: ts.TypeChecker;
|
|
20
20
|
sourceFile: ts.SourceFile;
|
|
21
|
-
config:
|
|
21
|
+
config: CodeConnectReactConfig;
|
|
22
|
+
absPath: string;
|
|
22
23
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Parsers the `props` field of a `figma.connect()` call, returning a mapping of
|
|
25
|
-
* prop names to their respective intrinsic types
|
|
26
|
-
*
|
|
27
|
-
* @param objectLiteral An object literal expression
|
|
28
|
-
* @param parserContext Parser context
|
|
29
|
-
* @returns
|
|
30
|
-
*/
|
|
31
|
-
export declare function parsePropsObject(objectLiteral: ts.ObjectLiteralExpression, parserContext: ParserContext): PropMappings;
|
|
32
|
-
export type PropMappings = Record<string, Intrinsic>;
|
|
33
24
|
/**
|
|
34
25
|
* Extract metadata about the referenced React component. Used by both the
|
|
35
26
|
* Code Connect and Storybook commands.
|
|
@@ -40,7 +31,7 @@ export type PropMappings = Record<string, Intrinsic>;
|
|
|
40
31
|
* @param node The node being parsed. Used for error logging.
|
|
41
32
|
* @returns Metadata object
|
|
42
33
|
*/
|
|
43
|
-
export declare function parseComponentMetadata(node: ts.PropertyAccessExpression | ts.Identifier | ts.Expression, { checker, sourceFile }: ParserContext): Promise<{
|
|
34
|
+
export declare function parseComponentMetadata(node: ts.PropertyAccessExpression | ts.Identifier | ts.Expression, { checker, sourceFile, absPath }: ParserContext): Promise<{
|
|
44
35
|
source: string;
|
|
45
36
|
line: number;
|
|
46
37
|
component: string;
|
|
@@ -72,6 +63,6 @@ export declare function parseRenderFunction(exp: ts.ArrowFunction | ts.FunctionE
|
|
|
72
63
|
nestable: boolean;
|
|
73
64
|
};
|
|
74
65
|
export declare function getDefaultTemplate(componentMetadata: Awaited<ReturnType<typeof parseComponentMetadata>>): string;
|
|
75
|
-
export declare function parse(program: ts.Program, file: string,
|
|
66
|
+
export declare function parse(program: ts.Program, file: string, config: CodeConnectReactConfig, absPath: string, repoUrl?: string, debug?: boolean): Promise<any[]>;
|
|
76
67
|
export {};
|
|
77
68
|
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/react/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/react/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EAAE,sBAAsB,EAAuC,MAAM,oBAAoB,CAAA;AAahG,OAAO,EAGL,YAAY,EAGb,MAAM,sBAAsB,CAAA;AAM7B,UAAU,kBAAkB;IAC1B,UAAU,EAAE,EAAE,CAAC,UAAU,CAAA;IACzB,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,SAAS,CAAA;CAC1B;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,kBAAkB,EAAE,EAAE,CAAC,gBAAgB,GAAG,IAAI,CAAA;IAC9C,cAAc,EAAE,MAAM,CAAA;gBAEV,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB;IAUzD,QAAQ;IAUR,aAAa;CAGd;AAED,qBAAa,aAAc,SAAQ,WAAW;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,EAAE,CAAC,WAAW,CAAA;IACvB,UAAU,EAAE,EAAE,CAAC,UAAU,CAAA;IACzB,MAAM,EAAE,sBAAsB,CAAA;IAC9B,OAAO,EAAE,MAAM,CAAA;CAChB;AAwID;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,EAAE,CAAC,wBAAwB,GAAG,EAAE,CAAC,UAAU,GAAG,EAAE,CAAC,UAAU,EACjE,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,aAAa;;;;GAyGhD;AAeD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,WAmBnE;AAkFD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,EAAE,CAAC,aAAa,GAAG,EAAE,CAAC,kBAAkB,GAAG,EAAE,CAAC,mBAAmB,EACtE,aAAa,EAAE,aAAa,EAC5B,YAAY,CAAC,EAAE,YAAY;;;;;;;EAmS5B;AA+LD,wBAAgB,kBAAkB,CAChC,iBAAiB,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC,UAItE;AAiHD,wBAAsB,KAAK,CACzB,OAAO,EAAE,EAAE,CAAC,OAAO,EACnB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,GAAG,EAAE,CAAC,CAmChB"}
|
package/dist/react/parser.js
CHANGED
|
@@ -3,9 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.parse = exports.getDefaultTemplate = exports.parseRenderFunction = exports.isFigmaConnectFile = exports.parseComponentMetadata = exports.
|
|
6
|
+
exports.parse = exports.getDefaultTemplate = exports.parseRenderFunction = exports.isFigmaConnectFile = exports.parseComponentMetadata = exports.InternalError = exports.ParserError = void 0;
|
|
7
7
|
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
-
const project_1 = require("../
|
|
8
|
+
const project_1 = require("../connect/project");
|
|
9
9
|
const logging_1 = require("../common/logging");
|
|
10
10
|
const compiler_1 = require("../typescript/compiler");
|
|
11
11
|
const intrinsics_1 = require("../common/intrinsics");
|
|
@@ -152,23 +152,6 @@ function getImportsForIdentifiers({ sourceFile }, _identifiers) {
|
|
|
152
152
|
}
|
|
153
153
|
return imports;
|
|
154
154
|
}
|
|
155
|
-
/**
|
|
156
|
-
* Parsers the `props` field of a `figma.connect()` call, returning a mapping of
|
|
157
|
-
* prop names to their respective intrinsic types
|
|
158
|
-
*
|
|
159
|
-
* @param objectLiteral An object literal expression
|
|
160
|
-
* @param parserContext Parser context
|
|
161
|
-
* @returns
|
|
162
|
-
*/
|
|
163
|
-
function parsePropsObject(objectLiteral, parserContext) {
|
|
164
|
-
const { sourceFile, checker } = parserContext;
|
|
165
|
-
return (0, compiler_1.convertObjectLiteralToJs)(objectLiteral, sourceFile, checker, (valueNode) => {
|
|
166
|
-
if (typescript_1.default.isCallExpression(valueNode)) {
|
|
167
|
-
return (0, intrinsics_1.parseIntrinsic)(valueNode, parserContext);
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
exports.parsePropsObject = parsePropsObject;
|
|
172
155
|
/**
|
|
173
156
|
* Extract metadata about the referenced React component. Used by both the
|
|
174
157
|
* Code Connect and Storybook commands.
|
|
@@ -179,7 +162,7 @@ exports.parsePropsObject = parsePropsObject;
|
|
|
179
162
|
* @param node The node being parsed. Used for error logging.
|
|
180
163
|
* @returns Metadata object
|
|
181
164
|
*/
|
|
182
|
-
async function parseComponentMetadata(node, { checker, sourceFile }) {
|
|
165
|
+
async function parseComponentMetadata(node, { checker, sourceFile, absPath }) {
|
|
183
166
|
let componentSymbol = checker.getSymbolAtLocation(node);
|
|
184
167
|
let componentSourceFile = sourceFile;
|
|
185
168
|
let component = '';
|
|
@@ -381,15 +364,22 @@ function parseRenderFunction(exp, parserContext, propMappings) {
|
|
|
381
364
|
// Keep track of any props which are referenced in the example so that we can
|
|
382
365
|
// insert the appropriate `figma.properties` call in the JS template
|
|
383
366
|
const referencedProps = new Set();
|
|
384
|
-
function createPropPlaceholder(name, node, wrapInJsxExpression = false) {
|
|
385
|
-
|
|
367
|
+
function createPropPlaceholder({ name, node, wrapInJsxExpression = false, }) {
|
|
368
|
+
let propReferenceName = name;
|
|
369
|
+
// for nested prop references like `nested.prop`, we only want to look for
|
|
370
|
+
// the prop mapping of `nested`, but include the full `nested.prop` in the
|
|
371
|
+
// __PROP__ call
|
|
372
|
+
if (name.includes('.')) {
|
|
373
|
+
propReferenceName = name.split('.')[0];
|
|
374
|
+
}
|
|
375
|
+
const mappedProp = propMappings && propMappings[propReferenceName];
|
|
386
376
|
if (!mappedProp) {
|
|
387
|
-
throw new ParserError(`Could not find prop mapping for ${
|
|
377
|
+
throw new ParserError(`Could not find prop mapping for ${propReferenceName} in the props object`, {
|
|
388
378
|
sourceFile,
|
|
389
379
|
node,
|
|
390
380
|
});
|
|
391
381
|
}
|
|
392
|
-
referencedProps.add(
|
|
382
|
+
referencedProps.add(propReferenceName);
|
|
393
383
|
const callExpression = typescript_1.default.factory.createCallExpression(typescript_1.default.factory.createIdentifier('__PROP__'), undefined, [typescript_1.default.factory.createStringLiteral(name)]);
|
|
394
384
|
if (wrapInJsxExpression) {
|
|
395
385
|
return typescript_1.default.factory.createJsxExpression(undefined, callExpression);
|
|
@@ -415,8 +405,13 @@ function parseRenderFunction(exp, parserContext, propMappings) {
|
|
|
415
405
|
if (typescript_1.default.isIdentifier(propsParameter.name) &&
|
|
416
406
|
typescript_1.default.isPropertyAccessExpression(node) &&
|
|
417
407
|
node.expression.getText().startsWith(propsParameter.name.getText())) {
|
|
408
|
+
// nested notation e.g `props.nested.prop`
|
|
409
|
+
if (typescript_1.default.isPropertyAccessExpression(node.expression)) {
|
|
410
|
+
const name = `${node.expression.name.getText()}.${node.name.getText()}`;
|
|
411
|
+
return createPropPlaceholder({ name, node });
|
|
412
|
+
}
|
|
418
413
|
const name = node.name.getText();
|
|
419
|
-
return createPropPlaceholder(name, node);
|
|
414
|
+
return createPropPlaceholder({ name, node });
|
|
420
415
|
}
|
|
421
416
|
// `props[""]` notation
|
|
422
417
|
if (typescript_1.default.isIdentifier(propsParameter.name) &&
|
|
@@ -424,15 +419,15 @@ function parseRenderFunction(exp, parserContext, propMappings) {
|
|
|
424
419
|
node.expression.getText().startsWith(propsParameter.name.getText()) &&
|
|
425
420
|
typescript_1.default.isStringLiteral(node.argumentExpression)) {
|
|
426
421
|
const name = (0, compiler_1.stripQuotes)(node.argumentExpression);
|
|
427
|
-
return createPropPlaceholder(name, node);
|
|
422
|
+
return createPropPlaceholder({ name, node });
|
|
428
423
|
}
|
|
429
424
|
// object destructuring references
|
|
430
425
|
if (typescript_1.default.isObjectBindingPattern(propsParameter.name) &&
|
|
431
426
|
typescript_1.default.isJsxExpression(node) &&
|
|
432
427
|
node.expression &&
|
|
433
|
-
propsParameter.name.elements.find((el) =>
|
|
428
|
+
propsParameter.name.elements.find((el) => node.expression?.getText().startsWith(el.name.getText()))) {
|
|
434
429
|
const name = node.expression.getText();
|
|
435
|
-
return createPropPlaceholder(name, node, true);
|
|
430
|
+
return createPropPlaceholder({ name, node, wrapInJsxExpression: true });
|
|
436
431
|
}
|
|
437
432
|
// Replaces {...props} with all the prop mapped props we know about,
|
|
438
433
|
// e.g. <Button {...props} /> becomes:
|
|
@@ -455,7 +450,11 @@ function parseRenderFunction(exp, parserContext, propMappings) {
|
|
|
455
450
|
? Object.keys(propMappings)
|
|
456
451
|
.filter((prop) => !propsToExclude.includes(prop))
|
|
457
452
|
.map((prop) => {
|
|
458
|
-
return typescript_1.default.factory.createJsxAttribute(typescript_1.default.factory.createIdentifier(prop), createPropPlaceholder(
|
|
453
|
+
return typescript_1.default.factory.createJsxAttribute(typescript_1.default.factory.createIdentifier(prop), createPropPlaceholder({
|
|
454
|
+
name: prop,
|
|
455
|
+
node,
|
|
456
|
+
wrapInJsxExpression: true,
|
|
457
|
+
}));
|
|
459
458
|
})
|
|
460
459
|
: [];
|
|
461
460
|
if (propMappings) {
|
|
@@ -502,15 +501,18 @@ function parseRenderFunction(exp, parserContext, propMappings) {
|
|
|
502
501
|
// parser_template_helpers.ts)
|
|
503
502
|
exampleCode = exampleCode.replace(
|
|
504
503
|
// match " reactPropName={__PROP__("figmaPropName")}" and extract the names
|
|
505
|
-
/ ([A-Za-z0-9]+)=\{__PROP__\("([A-Za-z0-
|
|
504
|
+
/ ([A-Za-z0-9]+)=\{__PROP__\("([A-Za-z0-9_\.]+)"\)\}/g, (_match, reactPropName, figmaPropName) => {
|
|
506
505
|
return `\${_fcc_renderReactProp('${reactPropName}', ${figmaPropName})}`;
|
|
507
506
|
});
|
|
508
507
|
// Replace React children placeholders like `${__PROP__("propName")}` with
|
|
509
|
-
//
|
|
510
|
-
|
|
508
|
+
// calls to _fcc_renderReactChildren, which renders them correctly (see
|
|
509
|
+
// parser_template_helpers.ts)
|
|
510
|
+
exampleCode = exampleCode.replace(/\{__PROP__\("([A-Za-z_\.]+)"\)\}/g, (_match, figmaPropName) => {
|
|
511
|
+
return `\${_fcc_renderReactChildren(${figmaPropName})}`;
|
|
512
|
+
});
|
|
511
513
|
// Replace object values like `{ prop: __PROP__("propName") }` with
|
|
512
514
|
// `{ prop: ${propName} }`. These never need special treatment based on their type.
|
|
513
|
-
exampleCode = exampleCode.replace(/([A-Za-z0-9]+):\s+__PROP__\("([A-Za-
|
|
515
|
+
exampleCode = exampleCode.replace(/([A-Za-z0-9]+):\s+__PROP__\("([A-Za-z_\.]+)"\)/g, (_match, objectKey, figmaPropName) => {
|
|
514
516
|
return `${objectKey}: \${${figmaPropName}}`;
|
|
515
517
|
});
|
|
516
518
|
// Generate the template code
|
|
@@ -518,6 +520,7 @@ function parseRenderFunction(exp, parserContext, propMappings) {
|
|
|
518
520
|
templateCode = (0, parser_template_helpers_1.getParsedTemplateHelpersString)() + '\n\n';
|
|
519
521
|
// Require the template API
|
|
520
522
|
templateCode += `const figma = require('figma')\n\n`;
|
|
523
|
+
let nestedLayerCount = 0;
|
|
521
524
|
// Then we output `const propName = figma.properties.<kind>('propName')` calls
|
|
522
525
|
// for each referenced prop, so these are accessible to the template code.
|
|
523
526
|
if (propMappings && referencedProps.size > 0) {
|
|
@@ -529,7 +532,20 @@ function parseRenderFunction(exp, parserContext, propMappings) {
|
|
|
529
532
|
node: exp,
|
|
530
533
|
});
|
|
531
534
|
}
|
|
532
|
-
|
|
535
|
+
if (propMapping.kind === intrinsics_1.IntrinsicKind.NestedProps) {
|
|
536
|
+
// the actual layer name in figma could have a bunch of special characters in it,
|
|
537
|
+
// and if we try to normalize it to a valid JS identifier, it could conflict with
|
|
538
|
+
// other variables in the template code. So we generate a unique variable name
|
|
539
|
+
// for each nested layer reference instead.
|
|
540
|
+
const nestedLayerRef = `nestedLayer${nestedLayerCount++}`;
|
|
541
|
+
templateCode += `const ${nestedLayerRef} = figma.currentLayer.__find__("${propMapping.args.layer}")\n`;
|
|
542
|
+
templateCode += `const ${prop} = {
|
|
543
|
+
${Object.entries(propMapping.args.props).map(([key, intrinsic]) => `${key}: ${(0, intrinsics_1.intrinsicToString)(intrinsic, nestedLayerRef)}\n`)}
|
|
544
|
+
}\n`;
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
templateCode += `const ${prop} = ${(0, intrinsics_1.intrinsicToString)(propMapping)}\n`;
|
|
548
|
+
}
|
|
533
549
|
});
|
|
534
550
|
templateCode += '\n';
|
|
535
551
|
}
|
|
@@ -546,30 +562,6 @@ function parseRenderFunction(exp, parserContext, propMappings) {
|
|
|
546
562
|
};
|
|
547
563
|
}
|
|
548
564
|
exports.parseRenderFunction = parseRenderFunction;
|
|
549
|
-
/**
|
|
550
|
-
* This wrapper function ensures that property names are type checked in case
|
|
551
|
-
* we make changes to the `figma.connect()` interface.
|
|
552
|
-
*/
|
|
553
|
-
function makeConfigPropertyParser({ key, predicate, errorMessage, }) {
|
|
554
|
-
return (configArg, parserContext) => {
|
|
555
|
-
if (!configArg) {
|
|
556
|
-
return undefined;
|
|
557
|
-
}
|
|
558
|
-
return (0, compiler_1.parsePropertyOfType)({
|
|
559
|
-
objectLiteralNode: configArg,
|
|
560
|
-
propertyName: key,
|
|
561
|
-
predicate,
|
|
562
|
-
parserContext,
|
|
563
|
-
required: false,
|
|
564
|
-
errorMessage,
|
|
565
|
-
});
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
function makeFunctionArgumentParser({ index, predicate, required, errorMessage, }) {
|
|
569
|
-
return (node, parserContext) => {
|
|
570
|
-
return (0, compiler_1.parseFunctionArgument)(node, parserContext, index, predicate, required, errorMessage);
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
565
|
function followIdentifierToStringLiteralDeclaration(node, parserContext, errMessage) {
|
|
574
566
|
const { checker } = parserContext;
|
|
575
567
|
let result = node;
|
|
@@ -720,7 +712,7 @@ async function parseDoc(node, parserContext, repoUrl) {
|
|
|
720
712
|
// but I couldn't work out how to model that in TypeScript
|
|
721
713
|
const { propsArg, exampleArg, variantArg, linksArg, importsArg } = parseConfigObjectArg(configObjArg, parserContext);
|
|
722
714
|
let figmaNode = (0, compiler_1.stripQuotes)(figmaNodeUrlArg);
|
|
723
|
-
if (config
|
|
715
|
+
if (config.documentUrlSubstitutions) {
|
|
724
716
|
Object.entries(config.documentUrlSubstitutions).forEach(([from, to]) => {
|
|
725
717
|
figmaNode = figmaNode.replace(from, to);
|
|
726
718
|
});
|
|
@@ -728,7 +720,7 @@ async function parseDoc(node, parserContext, repoUrl) {
|
|
|
728
720
|
const metadata = componentArg
|
|
729
721
|
? await parseComponentMetadata(componentArg, parserContext)
|
|
730
722
|
: undefined;
|
|
731
|
-
const props = propsArg ? parsePropsObject(propsArg, parserContext) : undefined;
|
|
723
|
+
const props = propsArg ? (0, intrinsics_1.parsePropsObject)(propsArg, parserContext) : undefined;
|
|
732
724
|
const render = exampleArg ? parseRenderFunction(exampleArg, parserContext, props) : undefined;
|
|
733
725
|
const variant = variantArg ? parseVariant(variantArg, sourceFile, checker) : undefined;
|
|
734
726
|
const links = linksArg ? parseLinks(linksArg, parserContext) : undefined;
|
|
@@ -786,7 +778,7 @@ async function parseDoc(node, parserContext, repoUrl) {
|
|
|
786
778
|
language: 'typescript',
|
|
787
779
|
component: metadata?.component,
|
|
788
780
|
source: metadata?.source ? (0, project_1.getRemoteFileUrl)(metadata.source, repoUrl) : '',
|
|
789
|
-
sourceLocation: metadata?.line ? { line: metadata.line } : { line: -1 },
|
|
781
|
+
sourceLocation: metadata?.line !== undefined ? { line: metadata.line } : { line: -1 },
|
|
790
782
|
variant,
|
|
791
783
|
template,
|
|
792
784
|
templateData: {
|
|
@@ -803,7 +795,7 @@ async function parseDoc(node, parserContext, repoUrl) {
|
|
|
803
795
|
},
|
|
804
796
|
};
|
|
805
797
|
}
|
|
806
|
-
async function parse(program, file,
|
|
798
|
+
async function parse(program, file, config, absPath, repoUrl, debug) {
|
|
807
799
|
const sourceFile = program.getSourceFile(file);
|
|
808
800
|
if (!sourceFile) {
|
|
809
801
|
throw new InternalError(`Could not find source file for ${file}`);
|
|
@@ -812,6 +804,7 @@ async function parse(program, file, repoUrl, config, debug) {
|
|
|
812
804
|
checker: program.getTypeChecker(),
|
|
813
805
|
sourceFile,
|
|
814
806
|
config,
|
|
807
|
+
absPath,
|
|
815
808
|
};
|
|
816
809
|
const codeConnectObjects = [];
|
|
817
810
|
const nodes = [parserContext.sourceFile];
|