@plasmicapp/cli 0.1.169 → 0.1.173

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.
@@ -249,6 +249,7 @@ class PlasmicApi {
249
249
  iconChecksums: [],
250
250
  globalVariantChecksums: [],
251
251
  projectCssChecksum: "",
252
+ globalContextsChecksum: "",
252
253
  },
253
254
  usedNpmPackages: [],
254
255
  externalCssImports: [],
@@ -281,7 +282,6 @@ class PlasmicApi {
281
282
  return "0.0.1";
282
283
  });
283
284
  }
284
- ;
285
285
  requiredPackages() {
286
286
  return __awaiter(this, void 0, void 0, function* () {
287
287
  return {
@@ -11,14 +11,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.fixImports = void 0;
13
13
  const code_utils_1 = require("../utils/code-utils");
14
- const file_utils_1 = require("../utils/file-utils");
14
+ const config_utils_1 = require("../utils/config-utils");
15
15
  const get_context_1 = require("../utils/get-context");
16
16
  function fixImports(opts) {
17
17
  return __awaiter(this, void 0, void 0, function* () {
18
18
  if (!opts.baseDir)
19
19
  opts.baseDir = process.cwd();
20
20
  const context = yield get_context_1.getContext(opts, { enableSkipAuth: true });
21
- yield file_utils_1.fixAllFilePaths(context, opts.baseDir);
21
+ yield config_utils_1.updateConfig(context, context.config, opts.baseDir);
22
22
  yield code_utils_1.fixAllImportStatements(context, opts.baseDir);
23
23
  });
24
24
  }
@@ -0,0 +1,5 @@
1
+ import { CommonArgs } from "..";
2
+ export interface InfoArgs extends CommonArgs {
3
+ projects: readonly string[];
4
+ }
5
+ export declare function printProjectInfo(opts: InfoArgs): Promise<void>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.printProjectInfo = void 0;
13
+ const deps_1 = require("../deps");
14
+ const get_context_1 = require("../utils/get-context");
15
+ function printProjectInfo(opts) {
16
+ var _a, _b;
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ let context = yield get_context_1.getContext(opts);
19
+ const results = yield Promise.all(opts.projects.map((p) => __awaiter(this, void 0, void 0, function* () { return yield context.api.projectMeta(p); })));
20
+ for (const meta of results) {
21
+ deps_1.logger.info(`Id: ${meta.id}`);
22
+ deps_1.logger.info(`Name: ${meta.name}`);
23
+ deps_1.logger.info(`Host URL: ${(_a = meta.hostUrl) !== null && _a !== void 0 ? _a : null}`);
24
+ deps_1.logger.info(`Last published version: ${(_b = meta.lastPublishedVersion) !== null && _b !== void 0 ? _b : null}`);
25
+ }
26
+ });
27
+ }
28
+ exports.printProjectInfo = printProjectInfo;
@@ -0,0 +1,4 @@
1
+ import { ChecksumBundle, ProjectMetaBundle } from "../api";
2
+ import { PlasmicContext, ProjectConfig, ProjectLock } from "../utils/config-utils";
3
+ export declare function syncGlobalContexts(context: PlasmicContext, projectMeta: ProjectMetaBundle, projectConfig: ProjectConfig, projectLock: ProjectLock, checksums: ChecksumBundle, baseDir: string): Promise<void>;
4
+ export declare function getGlobalContextsResourcePath(context: PlasmicContext, projectConfig: ProjectConfig): string;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.getGlobalContextsResourcePath = exports.syncGlobalContexts = void 0;
16
+ const deps_1 = require("../deps");
17
+ const code_utils_1 = require("../utils/code-utils");
18
+ const lodash_1 = __importDefault(require("lodash"));
19
+ const file_utils_1 = require("../utils/file-utils");
20
+ const COMPONENT_NAME = "PlasmicGlobalContextsProvider";
21
+ function syncGlobalContexts(context, projectMeta, projectConfig, projectLock, checksums, baseDir) {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ const resourcePath = getGlobalContextsResourcePath(context, projectConfig);
24
+ if (checksums.globalContextsChecksum && projectMeta.globalContextBundle) {
25
+ if (context.cliArgs.quiet !== true) {
26
+ deps_1.logger.info(`Syncing component: ${COMPONENT_NAME}@${projectLock.version}\t['${projectConfig.projectName}' ${projectConfig.projectId} ${projectConfig.version}]`);
27
+ }
28
+ if (context.config.code.lang === "js") {
29
+ projectMeta.globalContextBundle.contextModule = code_utils_1.formatScript(code_utils_1.tsxToJsx(projectMeta.globalContextBundle.contextModule), baseDir);
30
+ }
31
+ file_utils_1.writeFileContent(context, resourcePath, projectMeta.globalContextBundle.contextModule, { force: false });
32
+ projectConfig.globalContextsFilePath = resourcePath;
33
+ const fl = projectLock.fileLocks.find((fl) => fl.assetId === projectConfig.projectId && fl.type === "globalContexts");
34
+ if (fl) {
35
+ fl.checksum = checksums.globalContextsChecksum;
36
+ }
37
+ else {
38
+ projectLock.fileLocks.push({
39
+ assetId: projectConfig.projectId,
40
+ checksum: checksums.globalContextsChecksum,
41
+ type: "globalContexts",
42
+ });
43
+ }
44
+ }
45
+ else if (!checksums.globalContextsChecksum &&
46
+ !projectMeta.globalContextBundle) {
47
+ if (file_utils_1.fileExists(context, resourcePath)) {
48
+ file_utils_1.deleteFile(context, resourcePath);
49
+ }
50
+ projectConfig.globalContextsFilePath = "";
51
+ lodash_1.default.remove(projectLock.fileLocks, (fl) => fl.assetId === projectConfig.projectId && fl.type === "globalContexts");
52
+ }
53
+ });
54
+ }
55
+ exports.syncGlobalContexts = syncGlobalContexts;
56
+ function getGlobalContextsResourcePath(context, projectConfig) {
57
+ return projectConfig.globalContextsFilePath !== ""
58
+ ? projectConfig.globalContextsFilePath
59
+ : file_utils_1.defaultResourcePath(context, projectConfig, `${COMPONENT_NAME}.${context.config.code.lang === "ts" ? "tsx" : "jsx"}`);
60
+ }
61
+ exports.getGlobalContextsResourcePath = getGlobalContextsResourcePath;
@@ -54,6 +54,7 @@ const sync_global_variants_1 = require("./sync-global-variants");
54
54
  const sync_icons_1 = require("./sync-icons");
55
55
  const sync_images_1 = require("./sync-images");
56
56
  const sync_styles_1 = require("./sync-styles");
57
+ const sync_global_contexts_1 = require("./sync-global-contexts");
57
58
  function ensureRequiredPackages(context, baseDir, yes) {
58
59
  return __awaiter(this, void 0, void 0, function* () {
59
60
  const requireds = yield context.api.requiredPackages();
@@ -258,8 +259,8 @@ function sync(opts, metadataDefaults) {
258
259
  writeLoaderConfig(opts, config);
259
260
  }
260
261
  const codegenVersion = yield context.api.latestCodegenVersion();
261
- context.lock.projects.forEach(p => {
262
- if (projectsToSync.some(syncedProject => syncedProject.projectId === p.projectId)) {
262
+ context.lock.projects.forEach((p) => {
263
+ if (projectsToSync.some((syncedProject) => syncedProject.projectId === p.projectId)) {
263
264
  p.codegenVersion = codegenVersion;
264
265
  }
265
266
  });
@@ -444,6 +445,7 @@ function syncProjectConfig(context, projectBundle, projectApiToken, version, dep
444
445
  projectConfig.jsBundleThemes.length === 0) {
445
446
  delete projectConfig.jsBundleThemes;
446
447
  }
448
+ yield sync_global_contexts_1.syncGlobalContexts(context, projectBundle, projectConfig, projectLock, checksums, baseDir);
447
449
  // Write out components
448
450
  yield sync_components_1.syncProjectComponents(context, projectConfig, version, componentBundles, forceOverwrite, appendJsxOnMissingBase, summary, pendingMerge, projectLock, checksums, baseDir);
449
451
  });
package/dist/api.d.ts CHANGED
@@ -25,6 +25,10 @@ export interface GlobalVariantBundle {
25
25
  contextModule: string;
26
26
  contextFileName: string;
27
27
  }
28
+ export interface GlobalContextBundle {
29
+ id: string;
30
+ contextModule: string;
31
+ }
28
32
  export interface JsBundleTheme {
29
33
  themeFileName: string;
30
34
  themeModule: string;
@@ -36,6 +40,7 @@ export interface ProjectMetaBundle {
36
40
  cssFileName: string;
37
41
  cssRules: string;
38
42
  jsBundleThemes?: JsBundleTheme[];
43
+ globalContextBundle?: GlobalContextBundle;
39
44
  }
40
45
  export interface IconBundle {
41
46
  id: string;
@@ -71,6 +76,13 @@ export interface RequiredPackages {
71
76
  "@plasmicapp/react-web": string;
72
77
  "@plasmicapp/react-web-runtime": string;
73
78
  }
79
+ export interface ProjectMetaInfo {
80
+ id: string;
81
+ name: string;
82
+ workspaceId?: string;
83
+ hostUrl?: string;
84
+ lastPublishedVersion?: string;
85
+ }
74
86
  export interface ProjectBundle {
75
87
  components: ComponentBundle[];
76
88
  codeComponentMetas: CodeComponentMeta[];
@@ -111,6 +123,7 @@ export interface ChecksumBundle {
111
123
  iconChecksums: Array<[string, string]>;
112
124
  globalVariantChecksums: Array<[string, string]>;
113
125
  projectCssChecksum: string;
126
+ globalContextsChecksum: string;
114
127
  }
115
128
  export interface CodeComponentMeta {
116
129
  id: string;
@@ -173,6 +186,7 @@ export declare class PlasmicApi {
173
186
  indirect: boolean;
174
187
  metadata?: Metadata;
175
188
  }): Promise<ProjectBundle>;
189
+ projectMeta(projectId: string): Promise<ProjectMetaInfo>;
176
190
  uploadBundle(projectId: string, bundleName: string, bundleJs: string, css: string[], metaJson: string, genModulePath: string | undefined, genCssPaths: string[], pkgVersion: string | undefined, extraPropMetaJson: string | undefined, themeProviderWrapper: string | undefined, themeModule: string | undefined): Promise<StyleTokensMap>;
177
191
  projectStyleTokens(projectId: string, versionRange?: string): Promise<StyleTokensMap>;
178
192
  projectIcons(projectId: string, versionRange?: string, iconIds?: string[]): Promise<ProjectIconsResponse>;
package/dist/api.js CHANGED
@@ -93,6 +93,12 @@ class PlasmicApi {
93
93
  return result.data;
94
94
  });
95
95
  }
96
+ projectMeta(projectId) {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ const result = yield this.post(`${this.codegenHost}/api/v1/projects/${projectId}/code/meta`);
99
+ return result.data;
100
+ });
101
+ }
96
102
  uploadBundle(projectId, bundleName, bundleJs, css, metaJson, genModulePath, genCssPaths, pkgVersion, extraPropMetaJson, themeProviderWrapper, themeModule) {
97
103
  return __awaiter(this, void 0, void 0, function* () {
98
104
  const result = yield this.post(`${this.codegenHost}/api/v1/projects/${projectId}/jsbundle/upload`, {
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ const update_notifier_1 = __importDefault(require("update-notifier"));
28
28
  const yargs_1 = __importDefault(require("yargs"));
29
29
  const auth = __importStar(require("./actions/auth"));
30
30
  const fix_imports_1 = require("./actions/fix-imports");
31
+ const info_1 = require("./actions/info");
31
32
  const init_1 = require("./actions/init");
32
33
  const projectToken = __importStar(require("./actions/project-token"));
33
34
  const sync_1 = require("./actions/sync");
@@ -118,6 +119,14 @@ yargs_1.default
118
119
  }));
119
120
  })
120
121
  .command("fix-imports", "Fixes import paths after you've moved around Plasmic blackbox files", (yags) => 0, (argv) => error_1.handleError(fix_imports_1.fixImports(argv)))
122
+ .command("info", "Fetches metadata for projects", (yags) => yags.option("projects", {
123
+ alias: "p",
124
+ describe: "ID of plasmic project to check",
125
+ type: "array",
126
+ default: [],
127
+ }), (argv) => {
128
+ error_1.handleError(info_1.printProjectInfo(argv));
129
+ })
121
130
  .command("upload-bundle", false, (yargs) => yargs
122
131
  .option("project", {
123
132
  alias: "p",
@@ -0,0 +1,2 @@
1
+ import { PlasmicConfig } from "../utils/config-utils";
2
+ export declare function ensureImportModuleType(config: PlasmicConfig): PlasmicConfig;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureImportModuleType = void 0;
4
+ function ensureImportModuleType(config) {
5
+ for (const project of config.projects) {
6
+ for (const component of project.components) {
7
+ component.importSpec.moduleType = "local";
8
+ }
9
+ }
10
+ return config;
11
+ }
12
+ exports.ensureImportModuleType = ensureImportModuleType;
@@ -282,6 +282,10 @@
282
282
  "description": "File location for the project-wide css styles. Relative to srcDir",
283
283
  "type": "string"
284
284
  },
285
+ "globalContextsFilePath": {
286
+ "description": "File location for the project-wide global contexts. Relative to srcDir",
287
+ "type": "string"
288
+ },
285
289
  "icons": {
286
290
  "description": "Metadata for each synced icon in this project",
287
291
  "items": {
@@ -326,6 +330,7 @@
326
330
  "required": [
327
331
  "components",
328
332
  "cssFilePath",
333
+ "globalContextsFilePath",
329
334
  "icons",
330
335
  "images",
331
336
  "indirect",
@@ -348,6 +353,9 @@
348
353
  "css-modules"
349
354
  ],
350
355
  "type": "string"
356
+ },
357
+ "skipGlobalCssImport": {
358
+ "type": "boolean"
351
359
  }
352
360
  },
353
361
  "required": [
@@ -139,6 +139,7 @@ exports.project1Config = {
139
139
  images: [],
140
140
  jsBundleThemes: [],
141
141
  indirect: false,
142
+ globalContextsFilePath: "",
142
143
  };
143
144
  function expectProject1PlasmicJson(optional) {
144
145
  const plasmicJson = exports.tmpRepo.readPlasmicJson();
@@ -13,6 +13,7 @@ function getChecksums(context, opts, projectId, componentIds) {
13
13
  cssRulesChecksums: [],
14
14
  globalVariantChecksums: [],
15
15
  projectCssChecksum: "",
16
+ globalContextsChecksum: "",
16
17
  };
17
18
  }
18
19
  const fileLocks = projectLock.fileLocks;
@@ -51,6 +52,11 @@ function getChecksums(context, opts, projectId, componentIds) {
51
52
  const projectCssChecksums = fileLocks.filter((fileLock) => fileLock.type === "projectCss");
52
53
  lang_utils_1.assert(projectCssChecksums.length < 2);
53
54
  const projectCssChecksum = projectCssChecksums.length > 0 ? projectCssChecksums[0].checksum : "";
55
+ const globalContextsChecksums = fileLocks.filter((fileLock) => fileLock.type === "globalContexts" && fileLock.assetId === projectId);
56
+ lang_utils_1.assert(globalContextsChecksums.length < 2);
57
+ const globalContextsChecksum = globalContextsChecksums.length > 0
58
+ ? globalContextsChecksums[0].checksum
59
+ : "";
54
60
  return {
55
61
  imageChecksums,
56
62
  iconChecksums,
@@ -58,6 +64,7 @@ function getChecksums(context, opts, projectId, componentIds) {
58
64
  cssRulesChecksums,
59
65
  globalVariantChecksums,
60
66
  projectCssChecksum,
67
+ globalContextsChecksum,
61
68
  };
62
69
  }
63
70
  exports.getChecksums = getChecksums;
@@ -41,9 +41,11 @@ const Prettier = __importStar(require("prettier"));
41
41
  const prettier_1 = require("prettier");
42
42
  const ts = __importStar(require("typescript"));
43
43
  const upath_1 = __importDefault(require("upath"));
44
+ const sync_global_contexts_1 = require("../actions/sync-global-contexts");
44
45
  const sync_images_1 = require("../actions/sync-images");
45
46
  const deps_1 = require("../deps");
46
47
  const error_1 = require("../utils/error");
48
+ const config_utils_1 = require("./config-utils");
47
49
  const file_utils_1 = require("./file-utils");
48
50
  const lang_utils_1 = require("./lang-utils");
49
51
  exports.formatAsLocal = (content, filePath, baseDir, defaultOpts = {}) => {
@@ -341,13 +343,15 @@ function fixAllImportStatements(context, baseDir, summary) {
341
343
  }
342
344
  }
343
345
  }
346
+ fixGlobalContextImportStatements(context, fixImportContext, baseDir);
344
347
  });
345
348
  }
346
349
  exports.fixAllImportStatements = fixAllImportStatements;
347
350
  function fixComponentImportStatements(context, compConfig, fixImportContext, fixSkeletonModule, baseDir) {
348
351
  return __awaiter(this, void 0, void 0, function* () {
349
352
  // If ComponentConfig.importPath is still a local file, we best-effort also fix up the import statements there.
350
- if (isLocalModulePath(compConfig.importSpec.modulePath) &&
353
+ if (compConfig.type !== "mapped" &&
354
+ isLocalModulePath(compConfig.importSpec.modulePath) &&
351
355
  fixSkeletonModule) {
352
356
  yield fixFileImportStatements(context, compConfig.importSpec.modulePath, fixImportContext, true, baseDir);
353
357
  }
@@ -455,3 +459,26 @@ exports.formatScript = (code, baseDir) => {
455
459
  useTabs: false,
456
460
  });
457
461
  };
462
+ function fixGlobalContextImportStatements(context, fixImportContext, baseDir) {
463
+ return __awaiter(this, void 0, void 0, function* () {
464
+ for (const project of context.config.projects) {
465
+ if (!project.globalContextsFilePath)
466
+ continue;
467
+ const resourcePath = sync_global_contexts_1.getGlobalContextsResourcePath(context, project);
468
+ let prevContent;
469
+ try {
470
+ prevContent = file_utils_1.readFileText(file_utils_1.makeFilePath(context, resourcePath)).toString();
471
+ }
472
+ catch (e) {
473
+ deps_1.logger.warn(`${resourcePath} is missing. If you deleted this component, remember to remove the component from ${config_utils_1.CONFIG_FILE_NAME}`);
474
+ throw e;
475
+ }
476
+ const newContent = replaceImports(context, prevContent, resourcePath, fixImportContext, false, baseDir, true);
477
+ if (prevContent !== newContent) {
478
+ yield file_utils_1.writeFileContent(context, resourcePath, newContent, {
479
+ force: true,
480
+ });
481
+ }
482
+ }
483
+ });
484
+ }
@@ -73,6 +73,7 @@ export interface StyleConfig {
73
73
  scheme: "css" | "css-modules";
74
74
  /** File location for global css styles shared by all components. Relative to srcDir */
75
75
  defaultStyleCssFilePath: string;
76
+ skipGlobalCssImport?: boolean;
76
77
  }
77
78
  export interface ImagesConfig {
78
79
  /**
@@ -118,6 +119,8 @@ export interface ProjectConfig {
118
119
  version: string;
119
120
  /** File location for the project-wide css styles. Relative to srcDir */
120
121
  cssFilePath: string;
122
+ /** File location for the project-wide global contexts. Relative to srcDir */
123
+ globalContextsFilePath: string;
121
124
  jsBundleThemes?: JsBundleThemeConfig[];
122
125
  codeComponents?: CodeComponentConfig[];
123
126
  /** Metadata for each synced component in this project. */
@@ -213,7 +216,7 @@ export interface GlobalVariantGroupConfig {
213
216
  contextFilePath: string;
214
217
  }
215
218
  export interface FileLock {
216
- type: "renderModule" | "cssRules" | "icon" | "image" | "projectCss" | "globalVariant";
219
+ type: "renderModule" | "cssRules" | "icon" | "image" | "projectCss" | "globalVariant" | "globalContexts";
217
220
  checksum: string;
218
221
  assetId: string;
219
222
  }
@@ -40,6 +40,7 @@ function createProjectConfig(base) {
40
40
  icons: [],
41
41
  images: [],
42
42
  indirect: base.indirect,
43
+ globalContextsFilePath: "",
43
44
  };
44
45
  }
45
46
  exports.createProjectConfig = createProjectConfig;
@@ -150,6 +151,7 @@ function getOrAddProjectConfig(context, projectId, base // if one doesn't exist,
150
151
  images: [],
151
152
  jsBundleThemes: [],
152
153
  indirect: false,
154
+ globalContextsFilePath: "",
153
155
  };
154
156
  context.config.projects.push(project);
155
157
  }
@@ -45,11 +45,6 @@ export declare function findSrcDirPath(absoluteSrcDir: string, expectedPath: str
45
45
  export declare function findFile(dir: string, pred: (name: string) => boolean, opts: {
46
46
  traverseParents?: boolean;
47
47
  }): string | undefined;
48
- /**
49
- * Fixes all src-relative file paths in PlasmicConfig by detecting file
50
- * movement on disk.
51
- */
52
- export declare function fixAllFilePaths(context: PlasmicContext, baseDir: string): Promise<void>;
53
48
  /**
54
49
  * Throws an error if some file in PlasmicConfig is not inside the root
55
50
  * directory (i.e., the directory containing plasmic.json).
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.existsBuffered = exports.deleteFileBuffered = exports.renameFileBuffered = exports.readFileText = exports.writeFileText = exports.withBufferedFs = exports.assertAllPathsInRootDir = exports.fixAllFilePaths = exports.findFile = exports.findSrcDirPath = exports.buildBaseNameToFiles = exports.renameFile = exports.makeFilePath = exports.fileExists = exports.deleteFile = exports.readFileContent = exports.writeFileContent = exports.defaultPagePath = exports.defaultPublicResourcePath = exports.defaultResourcePath = exports.writeFileContentRaw = exports.stripExtension = void 0;
15
+ exports.existsBuffered = exports.deleteFileBuffered = exports.renameFileBuffered = exports.readFileText = exports.writeFileText = exports.withBufferedFs = exports.assertAllPathsInRootDir = exports.findFile = exports.findSrcDirPath = exports.buildBaseNameToFiles = exports.renameFile = exports.makeFilePath = exports.fileExists = exports.deleteFile = exports.readFileContent = exports.writeFileContent = exports.defaultPagePath = exports.defaultPublicResourcePath = exports.defaultResourcePath = exports.writeFileContentRaw = exports.stripExtension = void 0;
16
16
  const fs_1 = __importDefault(require("fs"));
17
17
  const glob_1 = __importDefault(require("glob"));
18
18
  const lodash_1 = __importDefault(require("lodash"));
@@ -188,6 +188,7 @@ function getAllPaths(context) {
188
188
  };
189
189
  const pushProject = (proj) => {
190
190
  pushPath(proj, "cssFilePath");
191
+ pushPath(proj, "globalContextsFilePath");
191
192
  for (const component of proj.components) {
192
193
  pushComponent(component);
193
194
  }
@@ -218,37 +219,6 @@ function getAllPaths(context) {
218
219
  }
219
220
  return pairs;
220
221
  }
221
- /**
222
- * Fixes all src-relative file paths in PlasmicConfig by detecting file
223
- * movement on disk.
224
- */
225
- function fixAllFilePaths(context, baseDir) {
226
- return __awaiter(this, void 0, void 0, function* () {
227
- const baseNameToFiles = buildBaseNameToFiles(context);
228
- let changed = false;
229
- const paths = getAllPaths(context);
230
- for (const { bundle, key } of paths) {
231
- const known = bundle[key];
232
- // Check null and undefined
233
- if (known == null) {
234
- throw new error_1.HandledError(`"${key} is required, but missing in ${config_utils_1.CONFIG_FILE_NAME}. Please restore the file or delete from ${config_utils_1.CONFIG_FILE_NAME} and run plasmic sync: ${bundle}"`);
235
- }
236
- // Check falsey values (e.g. "")
237
- if (!known) {
238
- continue;
239
- }
240
- const found = findSrcDirPath(context.absoluteSrcDir, known, baseNameToFiles);
241
- if (known !== found) {
242
- bundle[key] = found;
243
- changed = true;
244
- }
245
- }
246
- if (changed) {
247
- yield config_utils_1.updateConfig(context, context.config, baseDir);
248
- }
249
- });
250
- }
251
- exports.fixAllFilePaths = fixAllFilePaths;
252
222
  /**
253
223
  * Throws an error if some file in PlasmicConfig is not inside the root
254
224
  * directory (i.e., the directory containing plasmic.json).
@@ -81,10 +81,7 @@ function removeMissingFilesFromLock(context, config, lock) {
81
81
  image.id,
82
82
  image,
83
83
  ]));
84
- const knownIcons = Object.fromEntries(knownProjects[project.projectId].icons.map((icons) => [
85
- icons.id,
86
- icons,
87
- ]));
84
+ const knownIcons = Object.fromEntries(knownProjects[project.projectId].icons.map((icons) => [icons.id, icons]));
88
85
  project.fileLocks = project.fileLocks.filter((lock) => {
89
86
  switch (lock.type) {
90
87
  default:
@@ -100,6 +97,8 @@ function removeMissingFilesFromLock(context, config, lock) {
100
97
  return knownImages[lock.assetId];
101
98
  case "icon":
102
99
  return knownIcons[lock.assetId];
100
+ case "globalContexts":
101
+ return knownProjects[project.projectId].globalContextsFilePath;
103
102
  }
104
103
  });
105
104
  return project;
@@ -169,6 +168,11 @@ function resolveMissingFilesInConfig(context, config) {
169
168
  for (const project of config.projects) {
170
169
  project.cssFilePath =
171
170
  (yield attemptToRestoreFilePath(context, project.cssFilePath, baseNameToFiles)) || "";
171
+ if (!project.globalContextsFilePath) {
172
+ project.globalContextsFilePath = "";
173
+ }
174
+ project.globalContextsFilePath =
175
+ (yield attemptToRestoreFilePath(context, project.globalContextsFilePath, baseNameToFiles)) || "";
172
176
  project.images = yield filterFiles(project.images, "filePath");
173
177
  project.icons = yield filterFiles(project.icons, "moduleFilePath");
174
178
  project.jsBundleThemes = yield filterFiles(project.jsBundleThemes || [], "themeFilePath");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plasmicapp/cli",
3
- "version": "0.1.169",
3
+ "version": "0.1.173",
4
4
  "description": "plasmic cli for syncing local code with Plasmic designs",
5
5
  "engines": {
6
6
  "node": ">=12"
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "devDependencies": {
22
22
  "@babel/preset-typescript": "^7.12.1",
23
- "@plasmicapp/react-web": "^0.2.18",
23
+ "@plasmicapp/react-web": "^0.2.91",
24
24
  "@types/findup-sync": "^2.0.2",
25
25
  "@types/glob": "^7.1.3",
26
26
  "@types/inquirer": "^6.5.0",
@@ -339,6 +339,7 @@ class PlasmicApi {
339
339
  iconChecksums: [],
340
340
  globalVariantChecksums: [],
341
341
  projectCssChecksum: "",
342
+ globalContextsChecksum: "",
342
343
  } as ChecksumBundle,
343
344
  usedNpmPackages: [],
344
345
  externalCssImports: [],
@@ -374,7 +375,7 @@ class PlasmicApi {
374
375
 
375
376
  async latestCodegenVersion(): Promise<string> {
376
377
  return "0.0.1";
377
- };
378
+ }
378
379
 
379
380
  async requiredPackages(): Promise<RequiredPackages> {
380
381
  return {
@@ -1,13 +1,12 @@
1
1
  import { CommonArgs } from "..";
2
2
  import { fixAllImportStatements } from "../utils/code-utils";
3
- import { fixAllFilePaths } from "../utils/file-utils";
3
+ import { updateConfig } from "../utils/config-utils";
4
4
  import { getContext } from "../utils/get-context";
5
5
 
6
6
  export interface FixImportsArgs extends CommonArgs {}
7
7
  export async function fixImports(opts: FixImportsArgs) {
8
8
  if (!opts.baseDir) opts.baseDir = process.cwd();
9
9
  const context = await getContext(opts, { enableSkipAuth: true });
10
-
11
- await fixAllFilePaths(context, opts.baseDir);
10
+ await updateConfig(context, context.config, opts.baseDir);
12
11
  await fixAllImportStatements(context, opts.baseDir);
13
12
  }
@@ -0,0 +1,20 @@
1
+ import { CommonArgs } from "..";
2
+ import { logger } from "../deps";
3
+ import { getContext } from "../utils/get-context";
4
+
5
+ export interface InfoArgs extends CommonArgs {
6
+ projects: readonly string[];
7
+ }
8
+
9
+ export async function printProjectInfo(opts: InfoArgs): Promise<void> {
10
+ let context = await getContext(opts);
11
+ const results = await Promise.all(
12
+ opts.projects.map(async (p) => await context.api.projectMeta(p))
13
+ );
14
+ for (const meta of results) {
15
+ logger.info(`Id: ${meta.id}`);
16
+ logger.info(`Name: ${meta.name}`);
17
+ logger.info(`Host URL: ${meta.hostUrl ?? null}`);
18
+ logger.info(`Last published version: ${meta.lastPublishedVersion ?? null}`);
19
+ }
20
+ }
@@ -0,0 +1,87 @@
1
+ import { ChecksumBundle, ProjectMetaBundle } from "../api";
2
+ import { logger } from "../deps";
3
+ import { formatScript, tsxToJsx } from "../utils/code-utils";
4
+ import L from "lodash";
5
+ import {
6
+ PlasmicContext,
7
+ ProjectConfig,
8
+ ProjectLock,
9
+ } from "../utils/config-utils";
10
+ import {
11
+ defaultResourcePath,
12
+ deleteFile,
13
+ fileExists,
14
+ writeFileContent,
15
+ } from "../utils/file-utils";
16
+
17
+ const COMPONENT_NAME = "PlasmicGlobalContextsProvider";
18
+
19
+ export async function syncGlobalContexts(
20
+ context: PlasmicContext,
21
+ projectMeta: ProjectMetaBundle,
22
+ projectConfig: ProjectConfig,
23
+ projectLock: ProjectLock,
24
+ checksums: ChecksumBundle,
25
+ baseDir: string
26
+ ) {
27
+ const resourcePath = getGlobalContextsResourcePath(context, projectConfig);
28
+ if (checksums.globalContextsChecksum && projectMeta.globalContextBundle) {
29
+ if (context.cliArgs.quiet !== true) {
30
+ logger.info(
31
+ `Syncing component: ${COMPONENT_NAME}@${projectLock.version}\t['${projectConfig.projectName}' ${projectConfig.projectId} ${projectConfig.version}]`
32
+ );
33
+ }
34
+ if (context.config.code.lang === "js") {
35
+ projectMeta.globalContextBundle.contextModule = formatScript(
36
+ tsxToJsx(projectMeta.globalContextBundle.contextModule),
37
+ baseDir
38
+ );
39
+ }
40
+ writeFileContent(
41
+ context,
42
+ resourcePath,
43
+ projectMeta.globalContextBundle.contextModule,
44
+ { force: false }
45
+ );
46
+ projectConfig.globalContextsFilePath = resourcePath;
47
+ const fl = projectLock.fileLocks.find(
48
+ (fl) =>
49
+ fl.assetId === projectConfig.projectId && fl.type === "globalContexts"
50
+ );
51
+ if (fl) {
52
+ fl.checksum = checksums.globalContextsChecksum;
53
+ } else {
54
+ projectLock.fileLocks.push({
55
+ assetId: projectConfig.projectId,
56
+ checksum: checksums.globalContextsChecksum,
57
+ type: "globalContexts",
58
+ });
59
+ }
60
+ } else if (
61
+ !checksums.globalContextsChecksum &&
62
+ !projectMeta.globalContextBundle
63
+ ) {
64
+ if (fileExists(context, resourcePath)) {
65
+ deleteFile(context, resourcePath);
66
+ }
67
+ projectConfig.globalContextsFilePath = "";
68
+ L.remove(
69
+ projectLock.fileLocks,
70
+ (fl) =>
71
+ fl.assetId === projectConfig.projectId && fl.type === "globalContexts"
72
+ );
73
+ }
74
+ }
75
+
76
+ export function getGlobalContextsResourcePath(
77
+ context: PlasmicContext,
78
+ projectConfig: ProjectConfig
79
+ ) {
80
+ return projectConfig.globalContextsFilePath !== ""
81
+ ? projectConfig.globalContextsFilePath
82
+ : defaultResourcePath(
83
+ context,
84
+ projectConfig,
85
+ `${COMPONENT_NAME}.${context.config.code.lang === "ts" ? "tsx" : "jsx"}`
86
+ );
87
+ }
@@ -64,6 +64,7 @@ import { syncGlobalVariants } from "./sync-global-variants";
64
64
  import { syncProjectIconAssets } from "./sync-icons";
65
65
  import { syncProjectImageAssets } from "./sync-images";
66
66
  import { upsertStyleTokens } from "./sync-styles";
67
+ import { syncGlobalContexts } from "./sync-global-contexts";
67
68
 
68
69
  export interface SyncArgs extends CommonArgs {
69
70
  projects: readonly string[];
@@ -417,11 +418,15 @@ export async function sync(
417
418
  }
418
419
 
419
420
  const codegenVersion = await context.api.latestCodegenVersion();
420
- context.lock.projects.forEach(p => {
421
- if (projectsToSync.some(syncedProject => syncedProject.projectId === p.projectId)) {
421
+ context.lock.projects.forEach((p) => {
422
+ if (
423
+ projectsToSync.some(
424
+ (syncedProject) => syncedProject.projectId === p.projectId
425
+ )
426
+ ) {
422
427
  p.codegenVersion = codegenVersion;
423
428
  }
424
- })
429
+ });
425
430
  // Write the new ComponentConfigs to disk
426
431
  await updateConfig(context, context.config, baseDir);
427
432
  });
@@ -787,6 +792,15 @@ async function syncProjectConfig(
787
792
  delete projectConfig.jsBundleThemes;
788
793
  }
789
794
 
795
+ await syncGlobalContexts(
796
+ context,
797
+ projectBundle,
798
+ projectConfig,
799
+ projectLock,
800
+ checksums,
801
+ baseDir
802
+ );
803
+
790
804
  // Write out components
791
805
  await syncProjectComponents(
792
806
  context,
package/src/api.ts CHANGED
@@ -39,6 +39,11 @@ export interface GlobalVariantBundle {
39
39
  contextFileName: string;
40
40
  }
41
41
 
42
+ export interface GlobalContextBundle {
43
+ id: string;
44
+ contextModule: string;
45
+ }
46
+
42
47
  export interface JsBundleTheme {
43
48
  themeFileName: string;
44
49
  themeModule: string;
@@ -51,6 +56,7 @@ export interface ProjectMetaBundle {
51
56
  cssFileName: string;
52
57
  cssRules: string;
53
58
  jsBundleThemes?: JsBundleTheme[];
59
+ globalContextBundle?: GlobalContextBundle;
54
60
  }
55
61
 
56
62
  export interface IconBundle {
@@ -92,6 +98,14 @@ export interface RequiredPackages {
92
98
  "@plasmicapp/react-web-runtime": string;
93
99
  }
94
100
 
101
+ export interface ProjectMetaInfo {
102
+ id: string;
103
+ name: string;
104
+ workspaceId?: string;
105
+ hostUrl?: string;
106
+ lastPublishedVersion?: string;
107
+ }
108
+
95
109
  export interface ProjectBundle {
96
110
  components: ComponentBundle[];
97
111
  codeComponentMetas: CodeComponentMeta[];
@@ -142,6 +156,8 @@ export interface ChecksumBundle {
142
156
  globalVariantChecksums: Array<[string, string]>;
143
157
  // Checksum of projectCss file
144
158
  projectCssChecksum: string;
159
+ // Checksum of project global contexts
160
+ globalContextsChecksum: string;
145
161
  }
146
162
 
147
163
  export interface CodeComponentMeta {
@@ -262,6 +278,13 @@ export class PlasmicApi {
262
278
  return result.data as ProjectBundle;
263
279
  }
264
280
 
281
+ async projectMeta(projectId: string) {
282
+ const result = await this.post(
283
+ `${this.codegenHost}/api/v1/projects/${projectId}/code/meta`
284
+ );
285
+ return result.data as ProjectMetaInfo;
286
+ }
287
+
265
288
  async uploadBundle(
266
289
  projectId: string,
267
290
  bundleName: string,
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ import updateNotifier from "update-notifier";
4
4
  import yargs from "yargs";
5
5
  import * as auth from "./actions/auth";
6
6
  import { fixImports, FixImportsArgs } from "./actions/fix-imports";
7
+ import { InfoArgs, printProjectInfo } from "./actions/info";
7
8
  import { getYargsOption, InitArgs, initPlasmic } from "./actions/init";
8
9
  import * as projectToken from "./actions/project-token";
9
10
  import { sync, SyncArgs } from "./actions/sync";
@@ -134,6 +135,20 @@ yargs
134
135
  (yags) => 0,
135
136
  (argv) => handleError(fixImports(argv))
136
137
  )
138
+ .command<InfoArgs>(
139
+ "info",
140
+ "Fetches metadata for projects",
141
+ (yags) =>
142
+ yags.option("projects", {
143
+ alias: "p",
144
+ describe: "ID of plasmic project to check",
145
+ type: "array",
146
+ default: [],
147
+ }),
148
+ (argv) => {
149
+ handleError(printProjectInfo(argv));
150
+ }
151
+ )
137
152
  .command<UploadBundleArgs>(
138
153
  "upload-bundle",
139
154
  false,
@@ -148,6 +148,7 @@ export const project1Config: ProjectConfig = {
148
148
  images: [],
149
149
  jsBundleThemes: [],
150
150
  indirect: false,
151
+ globalContextsFilePath: "",
151
152
  };
152
153
 
153
154
  export function expectProject1PlasmicJson(
@@ -25,6 +25,7 @@ export function getChecksums(
25
25
  cssRulesChecksums: [],
26
26
  globalVariantChecksums: [],
27
27
  projectCssChecksum: "",
28
+ globalContextsChecksum: "",
28
29
  };
29
30
  }
30
31
 
@@ -95,6 +96,16 @@ export function getChecksums(
95
96
  const projectCssChecksum =
96
97
  projectCssChecksums.length > 0 ? projectCssChecksums[0].checksum : "";
97
98
 
99
+ const globalContextsChecksums = fileLocks.filter(
100
+ (fileLock) =>
101
+ fileLock.type === "globalContexts" && fileLock.assetId === projectId
102
+ );
103
+ assert(globalContextsChecksums.length < 2);
104
+ const globalContextsChecksum =
105
+ globalContextsChecksums.length > 0
106
+ ? globalContextsChecksums[0].checksum
107
+ : "";
108
+
98
109
  return {
99
110
  imageChecksums,
100
111
  iconChecksums,
@@ -102,5 +113,6 @@ export function getChecksums(
102
113
  cssRulesChecksums,
103
114
  globalVariantChecksums,
104
115
  projectCssChecksum,
116
+ globalContextsChecksum,
105
117
  };
106
118
  }
@@ -8,6 +8,7 @@ import * as Prettier from "prettier";
8
8
  import { Options, resolveConfig } from "prettier";
9
9
  import * as ts from "typescript";
10
10
  import path from "upath";
11
+ import { getGlobalContextsResourcePath } from "../actions/sync-global-contexts";
11
12
  import {
12
13
  fixComponentCssReferences,
13
14
  fixComponentImagesReferences,
@@ -17,6 +18,7 @@ import { HandledError } from "../utils/error";
17
18
  import {
18
19
  CodeComponentConfig,
19
20
  ComponentConfig,
21
+ CONFIG_FILE_NAME,
20
22
  GlobalVariantGroupConfig,
21
23
  IconConfig,
22
24
  ImageConfig,
@@ -473,6 +475,7 @@ export async function fixAllImportStatements(
473
475
  }
474
476
  }
475
477
  }
478
+ fixGlobalContextImportStatements(context, fixImportContext, baseDir);
476
479
  }
477
480
 
478
481
  async function fixComponentImportStatements(
@@ -484,6 +487,7 @@ async function fixComponentImportStatements(
484
487
  ) {
485
488
  // If ComponentConfig.importPath is still a local file, we best-effort also fix up the import statements there.
486
489
  if (
490
+ compConfig.type !== "mapped" &&
487
491
  isLocalModulePath(compConfig.importSpec.modulePath) &&
488
492
  fixSkeletonModule
489
493
  ) {
@@ -654,3 +658,42 @@ export const formatScript = (code: string, baseDir: string) => {
654
658
  useTabs: false,
655
659
  });
656
660
  };
661
+
662
+ async function fixGlobalContextImportStatements(
663
+ context: PlasmicContext,
664
+ fixImportContext: FixImportContext,
665
+ baseDir: string
666
+ ) {
667
+ for (const project of context.config.projects) {
668
+ if (!project.globalContextsFilePath) continue;
669
+ const resourcePath = getGlobalContextsResourcePath(context, project);
670
+
671
+ let prevContent: string;
672
+ try {
673
+ prevContent = readFileText(
674
+ makeFilePath(context, resourcePath)
675
+ ).toString();
676
+ } catch (e) {
677
+ logger.warn(
678
+ `${resourcePath} is missing. If you deleted this component, remember to remove the component from ${CONFIG_FILE_NAME}`
679
+ );
680
+ throw e;
681
+ }
682
+
683
+ const newContent = replaceImports(
684
+ context,
685
+ prevContent,
686
+ resourcePath,
687
+ fixImportContext,
688
+ false,
689
+ baseDir,
690
+ true
691
+ );
692
+
693
+ if (prevContent !== newContent) {
694
+ await writeFileContent(context, resourcePath, newContent, {
695
+ force: true,
696
+ });
697
+ }
698
+ }
699
+ }
@@ -108,6 +108,8 @@ export interface StyleConfig {
108
108
 
109
109
  /** File location for global css styles shared by all components. Relative to srcDir */
110
110
  defaultStyleCssFilePath: string;
111
+
112
+ skipGlobalCssImport?: boolean;
111
113
  }
112
114
 
113
115
  export interface ImagesConfig {
@@ -159,6 +161,8 @@ export interface ProjectConfig {
159
161
  version: string;
160
162
  /** File location for the project-wide css styles. Relative to srcDir */
161
163
  cssFilePath: string;
164
+ /** File location for the project-wide global contexts. Relative to srcDir */
165
+ globalContextsFilePath: string;
162
166
 
163
167
  // Code-component-related fields can be treated as optional not to be shown
164
168
  // to the users nor appear to be missing in the documentation.
@@ -197,6 +201,7 @@ export function createProjectConfig(base: {
197
201
  icons: [],
198
202
  images: [],
199
203
  indirect: base.indirect,
204
+ globalContextsFilePath: "",
200
205
  };
201
206
  }
202
207
 
@@ -299,7 +304,8 @@ export interface FileLock {
299
304
  | "icon"
300
305
  | "image"
301
306
  | "projectCss"
302
- | "globalVariant";
307
+ | "globalVariant"
308
+ | "globalContexts";
303
309
  // The checksum value for the file
304
310
  checksum: string;
305
311
  // The component id, or the image asset id
@@ -530,6 +536,7 @@ export function getOrAddProjectConfig(
530
536
  images: [],
531
537
  jsBundleThemes: [],
532
538
  indirect: false,
539
+ globalContextsFilePath: "",
533
540
  };
534
541
  context.config.projects.push(project);
535
542
  }
@@ -11,7 +11,6 @@ import {
11
11
  CONFIG_FILE_NAME,
12
12
  PlasmicContext,
13
13
  ProjectConfig,
14
- updateConfig,
15
14
  } from "./config-utils";
16
15
  import { ensureString } from "./lang-utils";
17
16
  import { confirmWithUser } from "./user-utils";
@@ -242,6 +241,7 @@ function getAllPaths(context: PlasmicContext): BundleKeyPair[] {
242
241
 
243
242
  const pushProject = (proj: ProjectConfig) => {
244
243
  pushPath(proj, "cssFilePath");
244
+ pushPath(proj, "globalContextsFilePath");
245
245
  for (const component of proj.components) {
246
246
  pushComponent(component);
247
247
  }
@@ -278,43 +278,6 @@ function getAllPaths(context: PlasmicContext): BundleKeyPair[] {
278
278
  return pairs;
279
279
  }
280
280
 
281
- /**
282
- * Fixes all src-relative file paths in PlasmicConfig by detecting file
283
- * movement on disk.
284
- */
285
- export async function fixAllFilePaths(context: PlasmicContext, baseDir: string) {
286
- const baseNameToFiles = buildBaseNameToFiles(context);
287
- let changed = false;
288
-
289
- const paths = getAllPaths(context);
290
- for (const { bundle, key } of paths) {
291
- const known = bundle[key];
292
- // Check null and undefined
293
- if (known == null) {
294
- throw new HandledError(
295
- `"${key} is required, but missing in ${CONFIG_FILE_NAME}. Please restore the file or delete from ${CONFIG_FILE_NAME} and run plasmic sync: ${bundle}"`
296
- );
297
- }
298
- // Check falsey values (e.g. "")
299
- if (!known) {
300
- continue;
301
- }
302
- const found = findSrcDirPath(
303
- context.absoluteSrcDir,
304
- known,
305
- baseNameToFiles
306
- );
307
- if (known !== found) {
308
- bundle[key] = found;
309
- changed = true;
310
- }
311
- }
312
-
313
- if (changed) {
314
- await updateConfig(context, context.config, baseDir);
315
- }
316
- }
317
-
318
281
  /**
319
282
  * Throws an error if some file in PlasmicConfig is not inside the root
320
283
  * directory (i.e., the directory containing plasmic.json).
@@ -79,10 +79,7 @@ function removeMissingFilesFromLock(
79
79
  ])
80
80
  );
81
81
  const knownIcons = Object.fromEntries(
82
- knownProjects[project.projectId].icons.map((icons) => [
83
- icons.id,
84
- icons,
85
- ])
82
+ knownProjects[project.projectId].icons.map((icons) => [icons.id, icons])
86
83
  );
87
84
 
88
85
  project.fileLocks = project.fileLocks.filter((lock) => {
@@ -100,6 +97,8 @@ function removeMissingFilesFromLock(
100
97
  return knownImages[lock.assetId];
101
98
  case "icon":
102
99
  return knownIcons[lock.assetId];
100
+ case "globalContexts":
101
+ return knownProjects[project.projectId].globalContextsFilePath;
103
102
  }
104
103
  });
105
104
 
@@ -209,6 +208,16 @@ async function resolveMissingFilesInConfig(
209
208
  baseNameToFiles
210
209
  )) || "";
211
210
 
211
+ if (!project.globalContextsFilePath) {
212
+ project.globalContextsFilePath = "";
213
+ }
214
+ project.globalContextsFilePath =
215
+ (await attemptToRestoreFilePath(
216
+ context,
217
+ project.globalContextsFilePath,
218
+ baseNameToFiles
219
+ )) || "";
220
+
212
221
  project.images = await filterFiles(project.images, "filePath");
213
222
  project.icons = await filterFiles(project.icons, "moduleFilePath");
214
223
  project.jsBundleThemes = await filterFiles(