@plasmicapp/cli 0.1.162
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/.eslintrc.js +61 -0
- package/.idea/cli.iml +11 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/README +16 -0
- package/README.internal +46 -0
- package/README.md +17 -0
- package/build.sh +8 -0
- package/dist/__mocks__/api.d.ts +16 -0
- package/dist/__mocks__/api.js +297 -0
- package/dist/__tests__/code-utils-spec.d.ts +1 -0
- package/dist/__tests__/code-utils-spec.js +838 -0
- package/dist/__tests__/ftue-spec.d.ts +1 -0
- package/dist/__tests__/ftue-spec.js +39 -0
- package/dist/__tests__/project-api-token-spec.d.ts +1 -0
- package/dist/__tests__/project-api-token-spec.js +147 -0
- package/dist/__tests__/versioned-sync-spec.d.ts +1 -0
- package/dist/__tests__/versioned-sync-spec.js +145 -0
- package/dist/actions/auth.d.ts +8 -0
- package/dist/actions/auth.js +47 -0
- package/dist/actions/fix-imports.d.ts +4 -0
- package/dist/actions/fix-imports.js +25 -0
- package/dist/actions/init.d.ts +62 -0
- package/dist/actions/init.js +460 -0
- package/dist/actions/project-token.d.ts +6 -0
- package/dist/actions/project-token.js +42 -0
- package/dist/actions/sync-components.d.ts +10 -0
- package/dist/actions/sync-components.js +242 -0
- package/dist/actions/sync-global-variants.d.ts +3 -0
- package/dist/actions/sync-global-variants.js +89 -0
- package/dist/actions/sync-icons.d.ts +7 -0
- package/dist/actions/sync-icons.js +92 -0
- package/dist/actions/sync-images.d.ts +6 -0
- package/dist/actions/sync-images.js +137 -0
- package/dist/actions/sync-styles.d.ts +3 -0
- package/dist/actions/sync-styles.js +58 -0
- package/dist/actions/sync.d.ts +25 -0
- package/dist/actions/sync.js +417 -0
- package/dist/actions/upload-bundle.d.ts +15 -0
- package/dist/actions/upload-bundle.js +28 -0
- package/dist/actions/watch.d.ts +14 -0
- package/dist/actions/watch.js +90 -0
- package/dist/api.d.ts +182 -0
- package/dist/api.js +202 -0
- package/dist/deps.d.ts +2 -0
- package/dist/deps.js +20 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +247 -0
- package/dist/lib.d.ts +10 -0
- package/dist/lib.js +23 -0
- package/dist/migrations/0.1.110-fileLocks.d.ts +2 -0
- package/dist/migrations/0.1.110-fileLocks.js +15 -0
- package/dist/migrations/0.1.143-ensureImportModuleType.d.ts +2 -0
- package/dist/migrations/0.1.143-ensureImportModuleType.js +12 -0
- package/dist/migrations/0.1.146-addReactRuntime.d.ts +2 -0
- package/dist/migrations/0.1.146-addReactRuntime.js +10 -0
- package/dist/migrations/0.1.27-migrateInit.d.ts +1 -0
- package/dist/migrations/0.1.27-migrateInit.js +8 -0
- package/dist/migrations/0.1.28-tsToTsx.d.ts +3 -0
- package/dist/migrations/0.1.28-tsToTsx.js +33 -0
- package/dist/migrations/0.1.31-ensureProjectIcons.d.ts +2 -0
- package/dist/migrations/0.1.31-ensureProjectIcons.js +12 -0
- package/dist/migrations/0.1.42-ensureVersion.d.ts +2 -0
- package/dist/migrations/0.1.42-ensureVersion.js +12 -0
- package/dist/migrations/0.1.57-ensureJsBundleThemes.d.ts +2 -0
- package/dist/migrations/0.1.57-ensureJsBundleThemes.js +12 -0
- package/dist/migrations/0.1.64-imageFiles.d.ts +2 -0
- package/dist/migrations/0.1.64-imageFiles.js +17 -0
- package/dist/migrations/0.1.95-componentType.d.ts +2 -0
- package/dist/migrations/0.1.95-componentType.js +16 -0
- package/dist/migrations/migrations.d.ts +10 -0
- package/dist/migrations/migrations.js +119 -0
- package/dist/plasmic.schema.json +463 -0
- package/dist/test-common/fixtures.d.ts +13 -0
- package/dist/test-common/fixtures.js +165 -0
- package/dist/tsconfig-transform.json +68 -0
- package/dist/utils/auth-utils.d.ts +31 -0
- package/dist/utils/auth-utils.js +236 -0
- package/dist/utils/checksum.d.ts +4 -0
- package/dist/utils/checksum.js +63 -0
- package/dist/utils/code-utils.d.ts +46 -0
- package/dist/utils/code-utils.js +457 -0
- package/dist/utils/config-utils.d.ts +271 -0
- package/dist/utils/config-utils.js +178 -0
- package/dist/utils/envdetect.d.ts +4 -0
- package/dist/utils/envdetect.js +42 -0
- package/dist/utils/error.d.ts +14 -0
- package/dist/utils/error.js +42 -0
- package/dist/utils/file-utils.d.ts +71 -0
- package/dist/utils/file-utils.js +433 -0
- package/dist/utils/get-context.d.ts +40 -0
- package/dist/utils/get-context.js +339 -0
- package/dist/utils/help.d.ts +2 -0
- package/dist/utils/help.js +56 -0
- package/dist/utils/lang-utils.d.ts +10 -0
- package/dist/utils/lang-utils.js +52 -0
- package/dist/utils/npm-utils.d.ts +28 -0
- package/dist/utils/npm-utils.js +215 -0
- package/dist/utils/prompts.d.ts +6 -0
- package/dist/utils/prompts.js +23 -0
- package/dist/utils/resolve-utils.d.ts +13 -0
- package/dist/utils/resolve-utils.js +198 -0
- package/dist/utils/semver.d.ts +34 -0
- package/dist/utils/semver.js +61 -0
- package/dist/utils/test-utils.d.ts +22 -0
- package/dist/utils/test-utils.js +106 -0
- package/dist/utils/user-utils.d.ts +7 -0
- package/dist/utils/user-utils.js +48 -0
- package/jest.config.js +6 -0
- package/package.json +80 -0
- package/src/__mocks__/api.ts +394 -0
- package/src/__tests__/code-utils-spec.ts +881 -0
- package/src/__tests__/ftue-spec.ts +43 -0
- package/src/__tests__/project-api-token-spec.ts +208 -0
- package/src/__tests__/versioned-sync-spec.ts +176 -0
- package/src/actions/auth.ts +43 -0
- package/src/actions/fix-imports.ts +13 -0
- package/src/actions/init.ts +638 -0
- package/src/actions/project-token.ts +36 -0
- package/src/actions/sync-components.ts +405 -0
- package/src/actions/sync-global-variants.ts +129 -0
- package/src/actions/sync-icons.ts +135 -0
- package/src/actions/sync-images.ts +191 -0
- package/src/actions/sync-styles.ts +71 -0
- package/src/actions/sync.ts +747 -0
- package/src/actions/upload-bundle.ts +38 -0
- package/src/actions/watch.ts +95 -0
- package/src/api.ts +407 -0
- package/src/deps.ts +18 -0
- package/src/index.ts +300 -0
- package/src/lib.ts +10 -0
- package/src/migrations/0.1.110-fileLocks.ts +16 -0
- package/src/migrations/0.1.146-addReactRuntime.ts +8 -0
- package/src/migrations/0.1.27-migrateInit.ts +4 -0
- package/src/migrations/0.1.28-tsToTsx.ts +37 -0
- package/src/migrations/0.1.31-ensureProjectIcons.ts +10 -0
- package/src/migrations/0.1.42-ensureVersion.ts +10 -0
- package/src/migrations/0.1.57-ensureJsBundleThemes.ts +10 -0
- package/src/migrations/0.1.64-imageFiles.ts +15 -0
- package/src/migrations/0.1.95-componentType.ts +14 -0
- package/src/migrations/migrations.ts +147 -0
- package/src/test-common/fixtures.ts +178 -0
- package/src/utils/auth-utils.ts +276 -0
- package/src/utils/checksum.ts +106 -0
- package/src/utils/code-utils.ts +656 -0
- package/src/utils/config-utils.ts +551 -0
- package/src/utils/envdetect.ts +39 -0
- package/src/utils/error.ts +36 -0
- package/src/utils/file-utils.ts +526 -0
- package/src/utils/get-context.ts +451 -0
- package/src/utils/help.ts +75 -0
- package/src/utils/lang-utils.ts +52 -0
- package/src/utils/npm-utils.ts +223 -0
- package/src/utils/prompts.ts +22 -0
- package/src/utils/resolve-utils.ts +245 -0
- package/src/utils/semver.ts +67 -0
- package/src/utils/test-utils.ts +116 -0
- package/src/utils/user-utils.ts +37 -0
- package/testData/fixImports_plasmic.json +66 -0
- package/tsconfig-transform.json +68 -0
- package/tsconfig.json +67 -0
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import * as Sentry from "@sentry/node";
|
|
2
|
+
import L from "lodash";
|
|
3
|
+
import * as querystring from "querystring";
|
|
4
|
+
import path from "upath";
|
|
5
|
+
import { initPlasmic } from "../actions/init";
|
|
6
|
+
import { PlasmicApi } from "../api";
|
|
7
|
+
import { logger } from "../deps";
|
|
8
|
+
import { CommonArgs } from "../index";
|
|
9
|
+
import { runNecessaryMigrations } from "../migrations/migrations";
|
|
10
|
+
import { HandledError } from "../utils/error";
|
|
11
|
+
import { getCurrentAuth } from "./auth-utils";
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_HOST,
|
|
14
|
+
findConfigFile,
|
|
15
|
+
LOCK_FILE_NAME,
|
|
16
|
+
PlasmicConfig,
|
|
17
|
+
PlasmicContext,
|
|
18
|
+
PlasmicLock,
|
|
19
|
+
readConfig,
|
|
20
|
+
} from "./config-utils";
|
|
21
|
+
import {
|
|
22
|
+
buildBaseNameToFiles,
|
|
23
|
+
existsBuffered,
|
|
24
|
+
fileExists,
|
|
25
|
+
readFileText,
|
|
26
|
+
} from "./file-utils";
|
|
27
|
+
import { ensure } from "./lang-utils";
|
|
28
|
+
import { getCliVersion } from "./npm-utils";
|
|
29
|
+
import * as prompts from "./prompts";
|
|
30
|
+
|
|
31
|
+
function createPlasmicLock(): PlasmicLock {
|
|
32
|
+
return {
|
|
33
|
+
projects: [],
|
|
34
|
+
cliVersion: getCliVersion(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function readLock(lockFile: string): PlasmicLock {
|
|
39
|
+
if (!existsBuffered(lockFile)) {
|
|
40
|
+
return createPlasmicLock();
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const result = JSON.parse(readFileText(lockFile!)) as PlasmicLock;
|
|
44
|
+
return {
|
|
45
|
+
...result,
|
|
46
|
+
};
|
|
47
|
+
} catch (e) {
|
|
48
|
+
logger.error(
|
|
49
|
+
`Error encountered reading ${LOCK_FILE_NAME} at ${lockFile}: ${e}`
|
|
50
|
+
);
|
|
51
|
+
throw e;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function removeMissingFilesFromLock(
|
|
56
|
+
context: PlasmicContext,
|
|
57
|
+
config: PlasmicConfig,
|
|
58
|
+
lock: PlasmicLock
|
|
59
|
+
) {
|
|
60
|
+
const knownProjects = Object.fromEntries(
|
|
61
|
+
config.projects.map((project) => [project.projectId, project])
|
|
62
|
+
);
|
|
63
|
+
const knownGlobalVariants = Object.fromEntries(
|
|
64
|
+
context.config.globalVariants.variantGroups.map((vg) => [vg.projectId, vg])
|
|
65
|
+
);
|
|
66
|
+
lock.projects = lock.projects
|
|
67
|
+
.filter((project) => knownProjects[project.projectId])
|
|
68
|
+
.map((project) => {
|
|
69
|
+
const knownComponents = Object.fromEntries(
|
|
70
|
+
knownProjects[project.projectId].components.map((component) => [
|
|
71
|
+
component.id,
|
|
72
|
+
component,
|
|
73
|
+
])
|
|
74
|
+
);
|
|
75
|
+
const knownImages = Object.fromEntries(
|
|
76
|
+
knownProjects[project.projectId].images.map((image) => [
|
|
77
|
+
image.id,
|
|
78
|
+
image,
|
|
79
|
+
])
|
|
80
|
+
);
|
|
81
|
+
const knownIcons = Object.fromEntries(
|
|
82
|
+
knownProjects[project.projectId].images.map((icons) => [
|
|
83
|
+
icons.id,
|
|
84
|
+
icons,
|
|
85
|
+
])
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
project.fileLocks = project.fileLocks.filter((lock) => {
|
|
89
|
+
switch (lock.type) {
|
|
90
|
+
default:
|
|
91
|
+
return false;
|
|
92
|
+
case "projectCss":
|
|
93
|
+
return knownProjects[project.projectId].cssFilePath;
|
|
94
|
+
case "globalVariant":
|
|
95
|
+
return knownGlobalVariants[project.projectId];
|
|
96
|
+
case "cssRules":
|
|
97
|
+
case "renderModule":
|
|
98
|
+
return knownComponents[lock.assetId];
|
|
99
|
+
case "image":
|
|
100
|
+
return knownImages[lock.assetId];
|
|
101
|
+
case "icon":
|
|
102
|
+
return knownIcons[lock.assetId];
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
return project;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function attemptToRestoreFilePath(
|
|
111
|
+
context: PlasmicContext,
|
|
112
|
+
expectedPath: string,
|
|
113
|
+
baseNameToFiles: Record<string, string[]>
|
|
114
|
+
) {
|
|
115
|
+
// If the path is not set, always recreate.
|
|
116
|
+
if (expectedPath === "") {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (fileExists(context, expectedPath)) {
|
|
121
|
+
return expectedPath;
|
|
122
|
+
}
|
|
123
|
+
const fileName = path.basename(expectedPath);
|
|
124
|
+
if (!baseNameToFiles[fileName]) {
|
|
125
|
+
const answer = await prompts.askChoice({
|
|
126
|
+
message: `File ${path.join(
|
|
127
|
+
context.absoluteSrcDir,
|
|
128
|
+
expectedPath
|
|
129
|
+
)} not found. Do you want to recreate it?`,
|
|
130
|
+
choices: ["Yes", "No"],
|
|
131
|
+
defaultAnswer: "Yes",
|
|
132
|
+
hidePrompt: context.cliArgs.yes,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
if (answer === "No") {
|
|
136
|
+
throw new HandledError(
|
|
137
|
+
"Please add this file or update your plasmic.json by removing or changing this path and try again."
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (baseNameToFiles[fileName].length === 1) {
|
|
144
|
+
const newPath = path.relative(
|
|
145
|
+
context.absoluteSrcDir,
|
|
146
|
+
baseNameToFiles[fileName][0]
|
|
147
|
+
);
|
|
148
|
+
logger.info(`\tDetected file moved from ${expectedPath} to ${newPath}.`);
|
|
149
|
+
return newPath;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Multiple files
|
|
153
|
+
const none = "None.";
|
|
154
|
+
const answer = await prompts.askChoice({
|
|
155
|
+
message: `Cannot find expected file at ${expectedPath}. Please select one of the following matches:`,
|
|
156
|
+
choices: [...baseNameToFiles[fileName], none],
|
|
157
|
+
defaultAnswer: none,
|
|
158
|
+
hidePrompt: context.cliArgs.yes,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
if (answer === none) {
|
|
162
|
+
throw new HandledError(
|
|
163
|
+
"Please add this file or update your plasmic.json by removing or changing this path and try again."
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
return answer;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function resolveMissingFilesInConfig(
|
|
170
|
+
context: PlasmicContext,
|
|
171
|
+
config: PlasmicConfig
|
|
172
|
+
) {
|
|
173
|
+
const baseNameToFiles = buildBaseNameToFiles(context);
|
|
174
|
+
|
|
175
|
+
// Make sure all the files exist. Prompt the user / exit process if not.
|
|
176
|
+
async function filterFiles<T>(list: T[], pathProp: keyof T) {
|
|
177
|
+
const newList = [];
|
|
178
|
+
for (const item of list) {
|
|
179
|
+
const newPath = await attemptToRestoreFilePath(
|
|
180
|
+
context,
|
|
181
|
+
item[pathProp] as any,
|
|
182
|
+
baseNameToFiles
|
|
183
|
+
);
|
|
184
|
+
if (newPath) {
|
|
185
|
+
item[pathProp] = newPath as any;
|
|
186
|
+
newList.push(item);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return newList;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
context.config.globalVariants.variantGroups = await filterFiles(
|
|
193
|
+
context.config.globalVariants.variantGroups,
|
|
194
|
+
"contextFilePath"
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
context.config.style.defaultStyleCssFilePath =
|
|
198
|
+
(await attemptToRestoreFilePath(
|
|
199
|
+
context,
|
|
200
|
+
context.config.style.defaultStyleCssFilePath,
|
|
201
|
+
baseNameToFiles
|
|
202
|
+
)) || "";
|
|
203
|
+
|
|
204
|
+
for (const project of config.projects) {
|
|
205
|
+
project.cssFilePath =
|
|
206
|
+
(await attemptToRestoreFilePath(
|
|
207
|
+
context,
|
|
208
|
+
project.cssFilePath,
|
|
209
|
+
baseNameToFiles
|
|
210
|
+
)) || "";
|
|
211
|
+
|
|
212
|
+
project.images = await filterFiles(project.images, "filePath");
|
|
213
|
+
project.icons = await filterFiles(project.icons, "moduleFilePath");
|
|
214
|
+
project.jsBundleThemes = await filterFiles(
|
|
215
|
+
project.jsBundleThemes || [],
|
|
216
|
+
"themeFilePath"
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// For components, if they decide to recreate in any of the path (css, wrapper, or blackbox component)
|
|
220
|
+
// we'll delete existing files.
|
|
221
|
+
|
|
222
|
+
const newComponents = [];
|
|
223
|
+
for (const component of project.components) {
|
|
224
|
+
if (component.type === "mapped") {
|
|
225
|
+
// For components mapped to an external module, we skip restoring files on disk
|
|
226
|
+
newComponents.push(component);
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const newModulePath = await attemptToRestoreFilePath(
|
|
230
|
+
context,
|
|
231
|
+
component.importSpec.modulePath,
|
|
232
|
+
baseNameToFiles
|
|
233
|
+
);
|
|
234
|
+
if (!newModulePath) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const newRenderModulePath = await attemptToRestoreFilePath(
|
|
238
|
+
context,
|
|
239
|
+
component.renderModuleFilePath,
|
|
240
|
+
baseNameToFiles
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
if (!newRenderModulePath) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const newCssPath = await attemptToRestoreFilePath(
|
|
248
|
+
context,
|
|
249
|
+
component.cssFilePath,
|
|
250
|
+
baseNameToFiles
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
if (!newCssPath) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
component.importSpec.modulePath = newModulePath;
|
|
258
|
+
component.renderModuleFilePath = newRenderModulePath;
|
|
259
|
+
component.cssFilePath = newCssPath;
|
|
260
|
+
newComponents.push(component);
|
|
261
|
+
}
|
|
262
|
+
project.components = newComponents;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export async function getContext(
|
|
267
|
+
args: CommonArgs,
|
|
268
|
+
{ enableSkipAuth = false }: { enableSkipAuth?: boolean } = {}
|
|
269
|
+
): Promise<PlasmicContext> {
|
|
270
|
+
if (!args.baseDir) args.baseDir = process.cwd();
|
|
271
|
+
const auth = enableSkipAuth
|
|
272
|
+
? await getCurrentOrDefaultAuth(args)
|
|
273
|
+
: await getOrInitAuth(args);
|
|
274
|
+
|
|
275
|
+
/** Sentry */
|
|
276
|
+
if (auth.host.startsWith(DEFAULT_HOST)) {
|
|
277
|
+
// Production usage of cli
|
|
278
|
+
Sentry.init({
|
|
279
|
+
dsn:
|
|
280
|
+
"https://3ed4eb43d28646e381bf3c50cff24bd6@o328029.ingest.sentry.io/5285892",
|
|
281
|
+
});
|
|
282
|
+
Sentry.configureScope((scope) => {
|
|
283
|
+
if (auth.user) {
|
|
284
|
+
scope.setUser({ email: auth.user });
|
|
285
|
+
}
|
|
286
|
+
scope.setExtra("cliVersion", getCliVersion());
|
|
287
|
+
scope.setExtra("args", JSON.stringify(args));
|
|
288
|
+
scope.setExtra("host", auth.host);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/** PlasmicConfig **/
|
|
293
|
+
let configFile =
|
|
294
|
+
args.config || findConfigFile(args.baseDir, { traverseParents: true });
|
|
295
|
+
|
|
296
|
+
if (!configFile) {
|
|
297
|
+
await maybeRunPlasmicInit(args, "plasmic.json", enableSkipAuth);
|
|
298
|
+
configFile = findConfigFile(args.baseDir, { traverseParents: true });
|
|
299
|
+
if (!configFile) {
|
|
300
|
+
const err = new HandledError(
|
|
301
|
+
"No plasmic.json file found. Please run `plasmic init` first."
|
|
302
|
+
);
|
|
303
|
+
throw err;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const rootDir = path.dirname(configFile);
|
|
307
|
+
// plasmic.lock should be in the same directory as plasmic.json
|
|
308
|
+
const lockFile = path.join(rootDir, LOCK_FILE_NAME);
|
|
309
|
+
|
|
310
|
+
await runNecessaryMigrations(configFile, lockFile, args.baseDir, args.yes);
|
|
311
|
+
const config = readConfig(configFile, true);
|
|
312
|
+
|
|
313
|
+
/** PlasmicLock */
|
|
314
|
+
const lock = readLock(lockFile);
|
|
315
|
+
|
|
316
|
+
const context = {
|
|
317
|
+
config,
|
|
318
|
+
configFile,
|
|
319
|
+
lock,
|
|
320
|
+
lockFile,
|
|
321
|
+
rootDir,
|
|
322
|
+
absoluteSrcDir: path.isAbsolute(config.srcDir)
|
|
323
|
+
? config.srcDir
|
|
324
|
+
: path.resolve(rootDir, config.srcDir),
|
|
325
|
+
auth,
|
|
326
|
+
api: new PlasmicApi(auth),
|
|
327
|
+
cliArgs: args,
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
await resolveMissingFilesInConfig(context, config);
|
|
331
|
+
removeMissingFilesFromLock(context, config, lock);
|
|
332
|
+
|
|
333
|
+
return context;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Use empty user/token to signify no auth (only returning to provide a default host).
|
|
338
|
+
*/
|
|
339
|
+
async function getCurrentOrDefaultAuth(args: CommonArgs) {
|
|
340
|
+
const auth = await getCurrentAuth(args.auth);
|
|
341
|
+
if (auth) {
|
|
342
|
+
return auth;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return {
|
|
346
|
+
host: DEFAULT_HOST,
|
|
347
|
+
user: "",
|
|
348
|
+
token: "",
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async function getOrInitAuth(args: CommonArgs) {
|
|
353
|
+
const auth = await getCurrentAuth(args.auth);
|
|
354
|
+
|
|
355
|
+
if (auth) {
|
|
356
|
+
return auth;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (await maybeRunPlasmicInit(args, ".plasmic.auth")) {
|
|
360
|
+
return ensure(await getCurrentAuth());
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Could not find the authentication credentials and the user
|
|
364
|
+
// declined to run plasmic init.
|
|
365
|
+
throw new HandledError("Could not authenticate.");
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async function maybeRunPlasmicInit(
|
|
369
|
+
args: CommonArgs,
|
|
370
|
+
missingFile: string,
|
|
371
|
+
enableSkipAuth?: boolean
|
|
372
|
+
): Promise<boolean> {
|
|
373
|
+
if (!process.env.QUIET) {
|
|
374
|
+
logger.info(`No ${missingFile} file found. Initializing plasmic...`);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
await initPlasmic({
|
|
378
|
+
host: DEFAULT_HOST,
|
|
379
|
+
platform: "",
|
|
380
|
+
codeLang: "",
|
|
381
|
+
codeScheme: "",
|
|
382
|
+
styleScheme: "",
|
|
383
|
+
imagesScheme: "",
|
|
384
|
+
srcDir: "",
|
|
385
|
+
plasmicDir: "",
|
|
386
|
+
imagesPublicDir: "",
|
|
387
|
+
imagesPublicUrlPrefix: "",
|
|
388
|
+
enableSkipAuth,
|
|
389
|
+
...args,
|
|
390
|
+
});
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Table of where this metadata will be set
|
|
396
|
+
*
|
|
397
|
+
* Source | via |
|
|
398
|
+
* -------------------------------------------------------------------------
|
|
399
|
+
* cli | defaults | source=cli scheme=codegen command=sync|watch
|
|
400
|
+
* loader | defaults | source=loader scheme=loader command=sync|watch
|
|
401
|
+
* create-plasmic-app | env | source=create-plasmic-app
|
|
402
|
+
* plasmic-action | env | source=plasmic-action
|
|
403
|
+
*/
|
|
404
|
+
export interface Metadata {
|
|
405
|
+
platform?: string; // from plasmic.json
|
|
406
|
+
source?: "cli" | "loader" | "create-plasmic-app" | "plasmic-action";
|
|
407
|
+
scheme?: "codegen" | "loader";
|
|
408
|
+
command?: "sync" | "watch";
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Create a metadata bundle
|
|
413
|
+
* This will be used to tag Segment events (e.g. for codegen)
|
|
414
|
+
* Merges in:
|
|
415
|
+
* 1. defaults
|
|
416
|
+
* 2. PLASMIC_METADATA environment variable settings
|
|
417
|
+
* 3. arguments from the command-line
|
|
418
|
+
* to create a single Metadata object for Segment
|
|
419
|
+
* @param defaults
|
|
420
|
+
* @param fromArgs
|
|
421
|
+
*/
|
|
422
|
+
export function generateMetadata(
|
|
423
|
+
defaults: Metadata,
|
|
424
|
+
fromArgs?: string
|
|
425
|
+
): Metadata {
|
|
426
|
+
const fromEnv = process.env.PLASMIC_METADATA;
|
|
427
|
+
const metadataFromEnv = !fromEnv ? {} : { ...querystring.decode(fromEnv) };
|
|
428
|
+
const metadataFromArgs = !fromArgs ? {} : { ...querystring.decode(fromArgs) };
|
|
429
|
+
// Priority: 1. args 2. env 3. defaults
|
|
430
|
+
const metadata = L.assign({ ...defaults }, metadataFromEnv, metadataFromArgs);
|
|
431
|
+
|
|
432
|
+
return metadata;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* This is meant to be called from consumers of the CLI to set
|
|
437
|
+
* metadata into the PLASMIC_METADATA environment variable
|
|
438
|
+
* @param metadata
|
|
439
|
+
*/
|
|
440
|
+
export function setMetadataEnv(metadata: Metadata): void {
|
|
441
|
+
const fromEnv = process.env.PLASMIC_METADATA
|
|
442
|
+
? querystring.decode(process.env.PLASMIC_METADATA)
|
|
443
|
+
: {};
|
|
444
|
+
const env = { ...fromEnv };
|
|
445
|
+
L.toPairs(metadata).forEach(([k, v]) => {
|
|
446
|
+
if (!env[k]) {
|
|
447
|
+
env[k] = v;
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
process.env.PLASMIC_METADATA = querystring.encode(env);
|
|
451
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import L from "lodash";
|
|
3
|
+
import wrapAnsi from "wrap-ansi";
|
|
4
|
+
import { logger } from "../deps";
|
|
5
|
+
import { PlasmicContext } from "./config-utils";
|
|
6
|
+
import { ensure } from "./lang-utils";
|
|
7
|
+
|
|
8
|
+
function wrap(str: string) {
|
|
9
|
+
return wrapAnsi(str, 60);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function printFirstSyncInfo(context: PlasmicContext) {
|
|
13
|
+
const config = context.config;
|
|
14
|
+
if (config.code.scheme === "blackbox" && config.projects.length > 0) {
|
|
15
|
+
const project = ensure(L.last(config.projects));
|
|
16
|
+
logger.info(
|
|
17
|
+
`\nYour Plasmic project "${project.projectName}" has now been synced to disk.`
|
|
18
|
+
);
|
|
19
|
+
const exampleComponent = project.components[0];
|
|
20
|
+
if (exampleComponent) {
|
|
21
|
+
logger.info(
|
|
22
|
+
`
|
|
23
|
+
|
|
24
|
+
${chalk.bold("Using Plasmic Components")}
|
|
25
|
+
${chalk.bold("------------------------")}
|
|
26
|
+
|
|
27
|
+
${wrap(
|
|
28
|
+
`For each component, Plasmic generates two React components in two files. For example, for component ${chalk.bold(
|
|
29
|
+
exampleComponent.name
|
|
30
|
+
)}, there are:`
|
|
31
|
+
)}
|
|
32
|
+
|
|
33
|
+
* A ${chalk.bold("blackbox")} component at ${chalk.bold.underline(
|
|
34
|
+
exampleComponent.renderModuleFilePath
|
|
35
|
+
)}
|
|
36
|
+
${wrap(
|
|
37
|
+
`This is a blackbox, purely-presentational library component that you can use to render your designs. This file is owned by Plasmic, and you should not edit it -- it will be overwritten when the component design is updated. This component should only be used by the "wrapper" component (below).`
|
|
38
|
+
)}
|
|
39
|
+
|
|
40
|
+
* A ${chalk.bold("wrapper")} component at ${chalk.bold.underline(
|
|
41
|
+
exampleComponent.importSpec.modulePath
|
|
42
|
+
)}
|
|
43
|
+
${wrap(
|
|
44
|
+
`This component is owned and edited by you to instantiate the Plasmic${exampleComponent.name} component with desired variants, states, event handlers, and data. You have complete control over this file, and this is the actual component that should be used by the rest of the codebase.`
|
|
45
|
+
)}
|
|
46
|
+
|
|
47
|
+
Learn more at https://www.plasmic.app/learn/codegen-guide/
|
|
48
|
+
`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const exampleIcon = project.icons[0];
|
|
53
|
+
if (exampleIcon) {
|
|
54
|
+
logger.info(
|
|
55
|
+
`
|
|
56
|
+
${chalk.bold("Using Icons")}
|
|
57
|
+
${chalk.bold("-----------")}
|
|
58
|
+
|
|
59
|
+
${wrap(
|
|
60
|
+
`For each SVG icon, Plasmic also generates a React component. The component takes in all the usual props that you can pass to an svg element, and defaults to width/height of 1em.`
|
|
61
|
+
)}
|
|
62
|
+
|
|
63
|
+
For example, for the ${chalk.bold(
|
|
64
|
+
exampleIcon.name
|
|
65
|
+
)} icon at ${chalk.bold.underline(exampleIcon.moduleFilePath)},
|
|
66
|
+
instantiate it like:
|
|
67
|
+
|
|
68
|
+
${chalk.green(`<${exampleIcon.name} color="red" />`)}
|
|
69
|
+
|
|
70
|
+
Learn more at https://www.plasmic.app/learn/other-assets/#icons
|
|
71
|
+
`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import L from "lodash";
|
|
2
|
+
|
|
3
|
+
type StringGen = string | (() => string);
|
|
4
|
+
|
|
5
|
+
export function flatMap<T, U>(arr: T[], f: (x: T) => U[]) {
|
|
6
|
+
const r: U[] = [];
|
|
7
|
+
for (const x of arr) {
|
|
8
|
+
r.push(...f(x));
|
|
9
|
+
}
|
|
10
|
+
return r;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function ensure<T>(x: T | null | undefined, msg: StringGen = ""): T {
|
|
14
|
+
if (x === null || x === undefined) {
|
|
15
|
+
debugger;
|
|
16
|
+
msg = (L.isString(msg) ? msg : msg()) || "";
|
|
17
|
+
throw new Error(
|
|
18
|
+
`Value must not be undefined or null${msg ? `- ${msg}` : ""}`
|
|
19
|
+
);
|
|
20
|
+
} else {
|
|
21
|
+
return x;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function ensureString(x: any) {
|
|
26
|
+
if (L.isString(x)) {
|
|
27
|
+
return x;
|
|
28
|
+
} else {
|
|
29
|
+
throw new Error(`Expected ${x} to be a string`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class AssertionError extends Error {
|
|
34
|
+
constructor(msg = "Assertion failed") {
|
|
35
|
+
super(msg);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function assert<T>(
|
|
40
|
+
cond: T,
|
|
41
|
+
msg: StringGen = "Assertion failed"
|
|
42
|
+
): asserts cond {
|
|
43
|
+
if (!cond) {
|
|
44
|
+
// We always generate an non empty message so that it doesn't get swallowed
|
|
45
|
+
// by the async library.
|
|
46
|
+
msg = (L.isString(msg) ? msg : msg()) || "Assertion failed";
|
|
47
|
+
debugger;
|
|
48
|
+
throw new AssertionError(msg);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const tuple = <T extends any[]>(...args: T): T => args;
|