@plasmicapp/cli 0.1.304 → 0.1.306

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/dist/lib.js CHANGED
@@ -731091,6 +731091,12 @@ function eqPagePath(a, b) {
731091
731091
  if (a === b) {
731092
731092
  return true;
731093
731093
  }
731094
+ const normPagePathBrackets = (p) => {
731095
+ return p.replace("[[", "[").replace("]]", "]");
731096
+ };
731097
+ if (normPagePathBrackets(a) === normPagePathBrackets(b)) {
731098
+ return true;
731099
+ }
731094
731100
  if (!a.endsWith("/index") && `${a}/index` === b) {
731095
731101
  return true;
731096
731102
  }
@@ -731539,7 +731545,7 @@ var handleError = (p) => {
731539
731545
  return p.catch((e) => {
731540
731546
  if (e.message) {
731541
731547
  logger.error(
731542
- import_chalk.default.bold(import_chalk.default.redBright("\nPlasmic error: ")) + e.message
731548
+ import_chalk.default.bold(import_chalk.default.redBright("\nPlasmic error: ")) + e.message + e.stack
731543
731549
  );
731544
731550
  }
731545
731551
  if (checkEngineStrict()) {
@@ -731557,7 +731563,6 @@ var DEFAULT_HOST = process.env.PLASMIC_DEFAULT_HOST || "https://studio.plasmic.a
731557
731563
  var AUTH_FILE_NAME = ".plasmic.auth";
731558
731564
  var CONFIG_FILE_NAME = "plasmic.json";
731559
731565
  var LOCK_FILE_NAME = "plasmic.lock";
731560
- var LOADER_CONFIG_FILE_NAME = "plasmic-loader.json";
731561
731566
  var ENV_AUTH_HOST = "PLASMIC_AUTH_HOST";
731562
731567
  var ENV_AUTH_USER = "PLASMIC_AUTH_USER";
731563
731568
  var ENV_AUTH_TOKEN = "PLASMIC_AUTH_TOKEN";
@@ -731782,6 +731787,20 @@ var PlasmicApi = class {
731782
731787
  );
731783
731788
  return result.data;
731784
731789
  }
731790
+ /**
731791
+ * Code-gen endpoint.
731792
+ * This will fetch components from a given branch at an exact specified version
731793
+ * using the "plain" scheme
731794
+ */
731795
+ async exportProject(projectId, branchName, opts) {
731796
+ const result = await this.post(
731797
+ `${this.codegenHost}/api/v1/projects/${projectId}/code/components?branchName=${branchName}&export=true`,
731798
+ {
731799
+ ...opts
731800
+ }
731801
+ );
731802
+ return result.data;
731803
+ }
731785
731804
  async projectMeta(projectId) {
731786
731805
  const result = await this.post(
731787
731806
  `${this.codegenHost}/api/v1/projects/${projectId}/code/meta`
@@ -733060,7 +733079,8 @@ async function resolveMissingFilesInConfig(context, config) {
733060
733079
  }
733061
733080
  async function getContext(args, {
733062
733081
  enableSkipAuth = false,
733063
- skipMissingFiles = false
733082
+ skipMissingFiles = false,
733083
+ skipInit = false
733064
733084
  } = {}) {
733065
733085
  if (!args.baseDir)
733066
733086
  args.baseDir = process.cwd();
@@ -734149,25 +734169,7 @@ async function ensureRequiredPackages(context, baseDir, yes) {
734149
734169
  }
734150
734170
  }
734151
734171
  }
734152
- function getLoaderConfigPath(opts) {
734153
- return opts.loaderConfig || LOADER_CONFIG_FILE_NAME;
734154
- }
734155
- function maybeReadLoaderConfig(opts) {
734156
- const path14 = getLoaderConfigPath(opts);
734157
- if (!existsBuffered(path14)) {
734158
- return {};
734159
- }
734160
- return JSON.parse(readFileText(path14));
734161
- }
734162
- function writeLoaderConfig(opts, config) {
734163
- const loaderConfigPath = getLoaderConfigPath(opts);
734164
- writeFileText(
734165
- loaderConfigPath,
734166
- formatAsLocal(JSON.stringify(config), loaderConfigPath, opts.baseDir)
734167
- );
734168
- }
734169
734172
  async function sync(opts, metadataDefaults) {
734170
- var _a;
734171
734173
  if (!opts.baseDir)
734172
734174
  opts.baseDir = process.cwd();
734173
734175
  const baseDir = opts.baseDir;
@@ -734181,18 +734183,17 @@ async function sync(opts, metadataDefaults) {
734181
734183
  }
734182
734184
  fixFileExtension(context);
734183
734185
  assertAllPathsInRootDir(context);
734184
- const loaderConfig = process.env.PLASMIC_LOADER ? maybeReadLoaderConfig(opts) : {};
734185
734186
  const projectIdToToken = new Map(
734186
- [...context.config.projects, ...(_a = loaderConfig == null ? void 0 : loaderConfig.projects) != null ? _a : []].filter((p) => p.projectApiToken).map((p) => tuple(p.projectId, p.projectApiToken))
734187
+ [...context.config.projects].filter((p) => p.projectApiToken).map((p) => tuple(p.projectId, p.projectApiToken))
734187
734188
  );
734188
734189
  const projectConfigMap = import_lodash17.default.keyBy(context.config.projects, (p) => p.projectId);
734189
734190
  const projectWithVersion = opts.projects.map((p) => {
734190
- var _a2, _b, _c;
734191
+ var _a, _b, _c;
734191
734192
  const [projectIdToken, versionRange] = p.split("@");
734192
734193
  const [projectId, projectApiToken] = projectIdToken.split(":");
734193
734194
  return {
734194
734195
  projectId,
734195
- branchName: (_b = (_a2 = projectConfigMap[projectId]) == null ? void 0 : _a2.projectBranchName) != null ? _b : "main",
734196
+ branchName: (_b = (_a = projectConfigMap[projectId]) == null ? void 0 : _a.projectBranchName) != null ? _b : "main",
734196
734197
  versionRange: versionRange || ((_c = projectConfigMap[projectId]) == null ? void 0 : _c.version) || "latest",
734197
734198
  componentIdOrNames: void 0,
734198
734199
  // Get all components!
@@ -734201,10 +734202,10 @@ async function sync(opts, metadataDefaults) {
734201
734202
  };
734202
734203
  });
734203
734204
  const projectSyncParams = projectWithVersion.length ? projectWithVersion : context.config.projects.map((p) => {
734204
- var _a2;
734205
+ var _a;
734205
734206
  return {
734206
734207
  projectId: p.projectId,
734207
- branchName: (_a2 = p.projectBranchName) != null ? _a2 : "main",
734208
+ branchName: (_a = p.projectBranchName) != null ? _a : "main",
734208
734209
  versionRange: p.version,
734209
734210
  componentIdOrNames: void 0,
734210
734211
  // Get all components!
@@ -734222,7 +734223,7 @@ async function sync(opts, metadataDefaults) {
734222
734223
  context = await getContext(opts);
734223
734224
  } catch (e) {
734224
734225
  if (e.message.includes("Unable to authenticate Plasmic")) {
734225
- const configFileName = process.env.PLASMIC_LOADER ? LOADER_CONFIG_FILE_NAME : CONFIG_FILE_NAME;
734226
+ const configFileName = CONFIG_FILE_NAME;
734226
734227
  throw new HandledError(
734227
734228
  `Unable to authenticate Plasmic. Please run 'plasmic auth' or check the projectApiTokens in your ${configFileName}, and try again.`
734228
734229
  );
@@ -734259,7 +734260,6 @@ async function sync(opts, metadataDefaults) {
734259
734260
  const externalNpmPackages = /* @__PURE__ */ new Set();
734260
734261
  const externalCssImports = /* @__PURE__ */ new Set();
734261
734262
  const doSync = async () => {
734262
- var _a2;
734263
734263
  for (const projectMeta of projectsToSync) {
734264
734264
  await syncProject(
734265
734265
  context,
@@ -734303,21 +734303,6 @@ async function sync(opts, metadataDefaults) {
734303
734303
  });
734304
734304
  }
734305
734305
  await fixAllImportStatements(context, opts.baseDir, summary);
734306
- if (process.env.PLASMIC_LOADER) {
734307
- const rootProjectIds = new Set(projectSyncParams.map((p) => p.projectId));
734308
- const freshIdsAndTokens = projectIdsAndTokens.filter((p) => rootProjectIds.has(p.projectId)).map((p) => import_lodash17.default.pick(p, "projectId", "projectApiToken"));
734309
- const config = {
734310
- ...loaderConfig,
734311
- projects: import_lodash17.default.sortBy(
734312
- import_lodash17.default.uniqBy(
734313
- [...freshIdsAndTokens, ...(_a2 = loaderConfig == null ? void 0 : loaderConfig.projects) != null ? _a2 : []],
734314
- (p) => p.projectId
734315
- ),
734316
- (p) => p.projectId
734317
- )
734318
- };
734319
- writeLoaderConfig(opts, config);
734320
- }
734321
734306
  const codegenVersion = await context.api.latestCodegenVersion();
734322
734307
  context.lock.projects.forEach((p) => {
734323
734308
  if (projectsToSync.some(
@@ -1,23 +1,13 @@
1
1
  import { DeepPartial } from "utility-types";
2
- import { PlasmicApi, ProjectIdAndToken } from "../api";
2
+ import { PlasmicApi } from "../api";
3
3
  export declare const DEFAULT_HOST: string;
4
4
  export declare const AUTH_FILE_NAME = ".plasmic.auth";
5
5
  export declare const CONFIG_FILE_NAME = "plasmic.json";
6
6
  export declare const LOCK_FILE_NAME = "plasmic.lock";
7
- export declare const LOADER_CONFIG_FILE_NAME = "plasmic-loader.json";
8
7
  export declare const CONFIG_SCHEMA_FILE_NAME = "plasmic.schema.json";
9
8
  export declare const ENV_AUTH_HOST = "PLASMIC_AUTH_HOST";
10
9
  export declare const ENV_AUTH_USER = "PLASMIC_AUTH_USER";
11
10
  export declare const ENV_AUTH_TOKEN = "PLASMIC_AUTH_TOKEN";
12
- export interface PlasmicLoaderConfig {
13
- projects: ProjectIdAndToken[];
14
- aboutThisFile: string;
15
- dir: string;
16
- plasmicDir: string;
17
- pageDir: string;
18
- initArgs: Record<string, string>;
19
- substitutions?: Record<string, any>;
20
- }
21
11
  export interface PlasmicConfig {
22
12
  /** Target platform to generate code for */
23
13
  platform: "react" | "nextjs" | "gatsby";
@@ -1,10 +1,15 @@
1
1
  import { CommonArgs } from "../index";
2
2
  import { PlasmicContext, PlasmicLock } from "./config-utils";
3
3
  export declare function readLock(lockFile: string): PlasmicLock;
4
- export declare function getContext(args: CommonArgs, { enableSkipAuth, skipMissingFiles, }?: {
4
+ export declare function getContext(args: CommonArgs, { enableSkipAuth, skipMissingFiles, skipInit, }?: {
5
5
  enableSkipAuth?: boolean;
6
6
  skipMissingFiles?: boolean;
7
+ skipInit?: boolean;
7
8
  }): Promise<PlasmicContext>;
9
+ /**
10
+ * Use empty user/token to signify no auth (only returning to provide a default host).
11
+ */
12
+ export declare function getCurrentOrDefaultAuth(args: CommonArgs): Promise<import("./config-utils").AuthConfig>;
8
13
  /**
9
14
  * Table of where this metadata will be set
10
15
  *
@@ -1,5 +1,5 @@
1
1
  import * as tmp from "tmp";
2
- import { AuthConfig, PlasmicConfig, PlasmicLoaderConfig } from "../utils/config-utils";
2
+ import { AuthConfig, PlasmicConfig } from "../utils/config-utils";
3
3
  export declare class TempRepo {
4
4
  tmpDir: tmp.DirResult;
5
5
  constructor();
@@ -17,6 +17,4 @@ export declare class TempRepo {
17
17
  readPlasmicJson(): PlasmicConfig;
18
18
  writePlasmicJson(json: PlasmicConfig): void;
19
19
  deletePlasmicJson(): void;
20
- plasmicLoaderJsonPath(): string;
21
- readPlasmicLoaderJson(): PlasmicLoaderConfig;
22
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plasmicapp/cli",
3
- "version": "0.1.304",
3
+ "version": "0.1.306",
4
4
  "description": "plasmic cli for syncing local code with Plasmic designs",
5
5
  "engines": {
6
6
  "node": ">=12"
@@ -78,5 +78,5 @@
78
78
  "wrap-ansi": "^7.0.0",
79
79
  "yargs": "^15.4.1"
80
80
  },
81
- "gitHead": "7569dd15624b746deaea9cf9631a43961a30f52f"
81
+ "gitHead": "cd709d627ae388ad77010119787ecef6d555362b"
82
82
  }
@@ -158,55 +158,4 @@ describe("Project API tokens", () => {
158
158
  });
159
159
  await expect(sync(opts)).rejects.toThrow("Unable to authenticate");
160
160
  });
161
-
162
- test("should use plasmic-loader.json for API tokens in loader mode", async () => {
163
- process.env.PLASMIC_LOADER = "1";
164
-
165
- opts.projects = ["projectId1"];
166
- await expect(sync(opts)).resolves.toBeUndefined();
167
-
168
- const loaderConfig = tmpRepo.readPlasmicLoaderJson();
169
- expect(loaderConfig).toEqual({
170
- projects: [
171
- {
172
- projectId: "projectId1",
173
- projectApiToken: "abc",
174
- },
175
- ],
176
- });
177
-
178
- // Re-run, this time with no auth and no tokens in plasmic.json, only in plasmic-loader.json.
179
- removeAuth();
180
- tmpRepo.writePlasmicJson(defaultPlasmicJson);
181
- await expect(sync(opts)).resolves.toBeUndefined();
182
-
183
- delete process.env["PLASMIC_LOADER"];
184
- });
185
-
186
- test("works in PlasmicLoader mode even if root project was determined to not need an update", async () => {
187
- process.env.PLASMIC_LOADER = "1";
188
-
189
- // Make project1 have a dependency.
190
- standardTestSetup();
191
-
192
- // Explicitly sync both - we had a bug writing back the plasmic-loader.json in this case.
193
- opts.projects = ["projectId1", "dependencyId1"];
194
- await expect(sync(opts)).resolves.toBeUndefined();
195
-
196
- // We sync project1 which got updated, but the dependency is still same version.
197
- opts.force = false;
198
- removeAuth();
199
- mockApi.getMockProject("projectId1", "main", "1.2.3").version = "1.2.4";
200
- await expect(sync(opts)).resolves.toBeUndefined();
201
- });
202
-
203
- test("should fail in loader mode if not available", async () => {
204
- process.env.PLASMIC_LOADER = "1";
205
-
206
- opts.projects = ["projectId1"];
207
- removeAuth();
208
- await expect(sync(opts)).rejects.toThrow();
209
-
210
- delete process.env["PLASMIC_LOADER"];
211
- });
212
161
  });
@@ -0,0 +1,326 @@
1
+ import { keyBy, snakeCase } from "lodash";
2
+ import { CommonArgs } from "..";
3
+ import { ComponentBundle, PlasmicApi, ProjectBundle } from "../api";
4
+ import {
5
+ CodeConfig,
6
+ I18NConfig,
7
+ ImagesConfig,
8
+ PlasmicConfig,
9
+ StyleConfig,
10
+ findConfigFile,
11
+ } from "../utils/config-utils";
12
+ import { getContext, getCurrentOrDefaultAuth } from "../utils/get-context";
13
+ import { tuple } from "../utils/lang-utils";
14
+ import {
15
+ fixAllImportStatements,
16
+ formatAsLocal,
17
+ maybeConvertTsxToJsx,
18
+ } from "../utils/code-utils";
19
+ import { promises as fs, write } from "fs";
20
+ import path from "path";
21
+ import { DEFAULT_GLOBAL_CONTEXTS_NAME } from "./sync-global-contexts";
22
+ import { ensureImageAssetContents } from "./sync-images";
23
+ import { logger } from "../deps";
24
+
25
+ export interface ExportArgs extends CommonArgs {
26
+ projects: readonly string[];
27
+ platform: "" | "react" | "nextjs" | "gatsby";
28
+ codeLang: "" | "ts" | "js";
29
+ styleScheme: "" | "css" | "css-modules";
30
+ imagesScheme: "" | "inlined" | "files" | "public-files";
31
+ imagesPublicDir: string;
32
+ imagesPublicUrlPrefix: string;
33
+ i18nKeyScheme: "" | I18NConfig["keyScheme"];
34
+ i18nTagPrefix: "" | I18NConfig["tagPrefix"];
35
+
36
+ skipFormatting?: boolean;
37
+
38
+ outDir: string;
39
+ }
40
+
41
+ export async function exportProjectsCli(opts: ExportArgs): Promise<void> {
42
+ if (!opts.baseDir) opts.baseDir = process.cwd();
43
+ let configFile =
44
+ opts.config || findConfigFile(opts.baseDir, { traverseParents: true });
45
+ let context = configFile
46
+ ? await getContext(opts, { enableSkipAuth: true })
47
+ : undefined;
48
+ const projectConfigMap = keyBy(
49
+ context?.config.projects ?? [],
50
+ (p) => p.projectId
51
+ );
52
+ const projectIdToToken = new Map(
53
+ [...(context?.config.projects ?? [])]
54
+ .filter((p) => p.projectApiToken)
55
+ .map((p) => tuple(p.projectId, p.projectApiToken))
56
+ );
57
+ const projectWithVersion = opts.projects.map((p) => {
58
+ const [projectIdToken, versionRange] = p.split("@");
59
+ const [projectId, projectApiToken] = projectIdToken.split(":");
60
+ return {
61
+ projectId,
62
+ branchName: projectConfigMap[projectId]?.projectBranchName ?? "main",
63
+ versionRange:
64
+ versionRange || projectConfigMap[projectId]?.version || "latest",
65
+ componentIdOrNames: undefined, // Get all components!
66
+ projectApiToken: projectApiToken || projectIdToToken.get(projectId),
67
+ indirect: false,
68
+ };
69
+ });
70
+
71
+ const auth = await getCurrentOrDefaultAuth(opts);
72
+ const api = new PlasmicApi(auth);
73
+ const result = await exportProjects(api, {
74
+ projects: projectWithVersion.map((p) => ({
75
+ id: p.projectId,
76
+ token: p.projectApiToken,
77
+ branchName: p.branchName,
78
+ version: p.versionRange,
79
+ })),
80
+ platform: opts.platform || "react",
81
+ codeOpts: { lang: opts.codeLang || "ts" },
82
+ stylesOpts: { scheme: opts.styleScheme || "css-modules" },
83
+ imageOpts: { scheme: opts.imagesScheme || "files" },
84
+ i18nOpts: opts.i18nKeyScheme
85
+ ? { keyScheme: opts.i18nKeyScheme, tagPrefix: opts.i18nTagPrefix }
86
+ : undefined,
87
+ });
88
+
89
+ const extx = opts.codeLang === "js" ? "jsx" : "tsx";
90
+
91
+ const writeProj = async (bundle: ProjectBundle) => {
92
+ await ensureImageAssetContents(bundle.imageAssets);
93
+ const outPath = path.resolve(opts.outDir);
94
+ const promises: Promise<void>[] = [];
95
+ const writeFile = (fileName: string, content: string | Buffer) => {
96
+ if (typeof content === "string" && !opts.skipFormatting) {
97
+ content = formatAsLocal(content, fileName, opts.outDir);
98
+ }
99
+ const projectName = snakeCase(bundle.projectConfig.projectName);
100
+ promises.push(
101
+ (async () => {
102
+ await fs.mkdir(path.join(outPath, projectName), { recursive: true });
103
+ await fs.writeFile(
104
+ path.join(outPath, projectName, fileName),
105
+ content
106
+ );
107
+ })()
108
+ );
109
+ };
110
+ for (const comp of bundle.components) {
111
+ writeFile(comp.skeletonModuleFileName, comp.skeletonModule);
112
+ writeFile(comp.cssFileName, comp.cssRules);
113
+ }
114
+ for (const icon of bundle.iconAssets) {
115
+ writeFile(icon.fileName, icon.module);
116
+ }
117
+ for (const gv of bundle.globalVariants) {
118
+ writeFile(gv.contextFileName, gv.contextModule);
119
+ }
120
+
121
+ for (const img of bundle.imageAssets) {
122
+ writeFile(img.fileName, Buffer.from(img.blob, "base64"));
123
+ }
124
+
125
+ writeFile(bundle.projectConfig.cssFileName, bundle.projectConfig.cssRules);
126
+ if (bundle.projectConfig.globalContextBundle) {
127
+ writeFile(
128
+ `${DEFAULT_GLOBAL_CONTEXTS_NAME}.${extx}`,
129
+ bundle.projectConfig.globalContextBundle.contextModule
130
+ );
131
+ }
132
+
133
+ await Promise.all(promises);
134
+ };
135
+
136
+ await Promise.all(result.map((res) => writeProj(res)));
137
+
138
+ await fixAllImportStatements(
139
+ {
140
+ configFile: "",
141
+ lockFile: "",
142
+ rootDir: path.resolve(opts.outDir),
143
+ absoluteSrcDir: path.resolve(opts.outDir),
144
+ config: {
145
+ platform: opts.platform || "react",
146
+ srcDir: "./",
147
+ defaultPlasmicDir: "./",
148
+ code: {
149
+ lang: opts.codeLang || "ts",
150
+ scheme: "blackbox",
151
+ reactRuntime: "classic",
152
+ },
153
+ images: {
154
+ scheme: opts.imagesScheme || "files",
155
+ publicDir: opts.imagesPublicDir,
156
+ publicUrlPrefix: opts.imagesPublicUrlPrefix,
157
+ },
158
+ style: {
159
+ scheme: opts.styleScheme || "css-modules",
160
+ defaultStyleCssFilePath: "",
161
+ },
162
+ tokens: {} as any,
163
+ globalVariants: {
164
+ variantGroups: result.flatMap((bundle) => {
165
+ const projectName = snakeCase(bundle.projectConfig.projectName);
166
+ return bundle.globalVariants.map((gv) => ({
167
+ id: gv.id,
168
+ name: gv.name,
169
+ projectId: bundle.projectConfig.projectId,
170
+ contextFilePath: `./${projectName}/${gv.contextFileName}`,
171
+ }));
172
+ }),
173
+ },
174
+ projects: result.map((bundle) => {
175
+ const projectName = snakeCase(bundle.projectConfig.projectName);
176
+ return {
177
+ projectId: bundle.projectConfig.projectId,
178
+ projectName: bundle.projectConfig.projectName,
179
+ version: "latest",
180
+ cssFilePath: `${projectName}/${bundle.projectConfig.cssFileName}`,
181
+ globalContextsFilePath: bundle.projectConfig.globalContextBundle
182
+ ? `${projectName}/${DEFAULT_GLOBAL_CONTEXTS_NAME}.${extx}`
183
+ : "",
184
+ components: bundle.components.map((comp) => ({
185
+ id: comp.id,
186
+ name: comp.componentName,
187
+ projectId: bundle.projectConfig.projectId,
188
+ type: "managed",
189
+ importSpec: {
190
+ modulePath: `${projectName}/${comp.skeletonModuleFileName}`,
191
+ },
192
+ renderModuleFilePath: `${projectName}/${comp.skeletonModuleFileName}`,
193
+ cssFilePath: `${projectName}/${comp.cssFileName}`,
194
+ scheme: "blackbox",
195
+ componentType: `${comp.isPage ? "page" : "component"}`,
196
+ plumeType: comp.plumeType,
197
+ })),
198
+ codeComponents: bundle.codeComponentMetas.map((comp) => ({
199
+ id: comp.id,
200
+ name: comp.name,
201
+ displayName: comp.displayName,
202
+ componentImportPath: comp.importPath,
203
+ helper: comp.helper,
204
+ })),
205
+ icons: bundle.iconAssets.map((icon) => ({
206
+ id: icon.id,
207
+ name: icon.name,
208
+ moduleFilePath: `${projectName}/${icon.fileName}`,
209
+ })),
210
+ images: bundle.imageAssets.map((image) => ({
211
+ id: image.id,
212
+ name: image.name,
213
+ filePath: `${projectName}/${image.fileName}`,
214
+ })),
215
+ indirect: false,
216
+ };
217
+ }),
218
+ wrapPagesWithGlobalContexts: true,
219
+ },
220
+ lock: {} as any,
221
+ auth: {} as any,
222
+ api: api,
223
+ cliArgs: {} as any,
224
+ },
225
+ opts.outDir
226
+ );
227
+ }
228
+
229
+ interface ExportOpts {
230
+ projects: {
231
+ id: string;
232
+ token?: string;
233
+ branchName?: string;
234
+ version?: string;
235
+ }[];
236
+ platform?: PlasmicConfig["platform"];
237
+ imageOpts?: ImagesConfig;
238
+ stylesOpts?: Omit<StyleConfig, "defaultStyleCssFilePath">;
239
+ i18nOpts?: I18NConfig;
240
+ codeOpts?: Omit<CodeConfig, "scheme" | "reactRuntime">;
241
+ }
242
+
243
+ async function exportProjects(api: PlasmicApi, opts: ExportOpts) {
244
+ api.attachProjectIdsAndTokens(
245
+ opts.projects.map((proj) => ({
246
+ projectId: proj.id,
247
+ projectApiToken: proj.token,
248
+ }))
249
+ );
250
+
251
+ const versionResolution = await api.resolveSync(
252
+ opts.projects.map((p) => ({
253
+ projectId: p.id,
254
+ branchName: p.branchName ?? "main",
255
+ versionRange: p.version,
256
+ componentIdOrNames: undefined,
257
+ projectApiToken: p.token,
258
+ indirect: false,
259
+ })),
260
+ true
261
+ );
262
+
263
+ const versionsToSync = [
264
+ ...versionResolution.dependencies,
265
+ ...versionResolution.projects,
266
+ ];
267
+
268
+ const result = await Promise.all(
269
+ versionsToSync.map(async (v) => {
270
+ return api.exportProject(v.projectId, v.branchName, {
271
+ platform: opts.platform ?? "react",
272
+ platformOptions: {},
273
+ version: v.version,
274
+ imageOpts: opts.imageOpts ?? {
275
+ scheme: "files",
276
+ },
277
+ stylesOpts: {
278
+ defaultStyleCssFilePath: "",
279
+ scheme: "css-modules",
280
+ ...opts.stylesOpts,
281
+ },
282
+ i18nOpts: opts.i18nOpts,
283
+ codeOpts: opts.codeOpts ?? { lang: "ts" },
284
+ indirect: v.indirect,
285
+ wrapPagesWithGlobalContexts: true,
286
+ });
287
+ })
288
+ );
289
+
290
+ if (opts.codeOpts?.lang === "js") {
291
+ for (const proj of result) {
292
+ for (const comp of proj.components) {
293
+ [comp.skeletonModuleFileName, comp.skeletonModule] =
294
+ maybeConvertTsxToJsx(
295
+ comp.skeletonModuleFileName,
296
+ comp.skeletonModule,
297
+ "."
298
+ );
299
+ }
300
+ for (const icon of proj.iconAssets) {
301
+ [icon.fileName, icon.module] = maybeConvertTsxToJsx(
302
+ icon.fileName,
303
+ icon.module,
304
+ "."
305
+ );
306
+ }
307
+ for (const gv of proj.globalVariants) {
308
+ [gv.contextFileName, gv.contextModule] = maybeConvertTsxToJsx(
309
+ gv.contextFileName,
310
+ gv.contextModule,
311
+ "."
312
+ );
313
+ }
314
+ if (proj.projectConfig.globalContextBundle) {
315
+ const res = maybeConvertTsxToJsx(
316
+ `${DEFAULT_GLOBAL_CONTEXTS_NAME}.tsx`,
317
+ proj.projectConfig.globalContextBundle.contextModule,
318
+ "."
319
+ );
320
+ proj.projectConfig.globalContextBundle.contextModule = res[1];
321
+ }
322
+ }
323
+ }
324
+
325
+ return result;
326
+ }
@@ -22,6 +22,25 @@ export interface LocalizationStringsArgs extends CommonArgs {
22
22
  excludeDeps: boolean | undefined;
23
23
  }
24
24
 
25
+ export function getLocalizationYargs(key: "key-scheme" | "tag-prefix") {
26
+ if (key === "key-scheme") {
27
+ return {
28
+ describe:
29
+ "What value to use as message keys; `content` uses the message content itself, `hash` uses a hash of the content, and `path` uses a a hierarchical string containing the project id, component name, element name, and related variants, and does not encode the text content in the key. Defaults to whatever is specified in plasmic.json, or `content`",
30
+ type: "string" as const,
31
+ choices: ["content", "hash", "path"],
32
+ };
33
+ } else if (key === "tag-prefix") {
34
+ return {
35
+ describe:
36
+ "By default, rich text with markup tags look like '<0>hello</0>'. If your localization framework requires num-numeric tags, then specify a prefix; for example a prefix of 'n' turns it into '<n0>hello</n0>'.",
37
+ type: "string" as const,
38
+ };
39
+ } else {
40
+ throw new Error(`Unexpected localization option ${key}`);
41
+ }
42
+ }
43
+
25
44
  export async function localizationStrings(
26
45
  opts: LocalizationStringsArgs
27
46
  ): Promise<void> {
@@ -233,7 +233,7 @@ export async function syncProjectComponents(
233
233
 
234
234
  compConfig.plumeType = plumeType;
235
235
 
236
- if (scheme === "direct") {
236
+ if ((scheme as any) === "direct") {
237
237
  throw new Error(`Direct update codegen scheme is no longer supported`);
238
238
  } else if (/\/\/\s*plasmic-managed-jsx\/\d+/.test(editedFile)) {
239
239
  if (forceOverwrite) {
@@ -15,6 +15,7 @@ import {
15
15
  } from "../utils/file-utils";
16
16
 
17
17
  const COMPONENT_NAME = "PlasmicGlobalContextsProvider";
18
+ export const DEFAULT_GLOBAL_CONTEXTS_NAME = COMPONENT_NAME;
18
19
 
19
20
  export async function syncGlobalContexts(
20
21
  context: PlasmicContext,
@@ -130,7 +130,7 @@ export async function syncProjectImageAssets(
130
130
  );
131
131
  }
132
132
 
133
- async function ensureImageAssetContents(bundles: ImageBundle[]) {
133
+ export async function ensureImageAssetContents(bundles: ImageBundle[]) {
134
134
  // The server may send images as a url instead of a base64 blob. In that
135
135
  // case, we fetch the images here in the cli, instead of on the server.
136
136
  // If you have a lot of images, this moves the expensive / long fetch