@plasmicapp/cli 0.1.165 → 0.1.169
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/__mocks__/api.js +9 -1
- package/dist/__tests__/project-api-token-spec.js +4 -4
- package/dist/actions/sync.js +50 -7
- package/dist/api.d.ts +6 -0
- package/dist/api.js +9 -0
- package/dist/migrations/0.1.166-indirect.d.ts +2 -0
- package/dist/migrations/0.1.166-indirect.js +12 -0
- package/dist/migrations/migrations.js +2 -0
- package/dist/plasmic.schema.json +5 -0
- package/dist/test-common/fixtures.d.ts +3 -1
- package/dist/test-common/fixtures.js +5 -2
- package/dist/utils/config-utils.d.ts +7 -0
- package/dist/utils/config-utils.js +2 -0
- package/dist/utils/resolve-utils.js +51 -5
- package/package.json +1 -1
- package/src/__mocks__/api.ts +7 -0
- package/src/__tests__/project-api-token-spec.ts +8 -4
- package/src/actions/sync.ts +80 -8
- package/src/api.ts +15 -0
- package/src/migrations/0.1.166-indirect.ts +10 -0
- package/src/migrations/migrations.ts +2 -0
- package/src/test-common/fixtures.ts +7 -2
- package/src/utils/config-utils.ts +11 -0
- package/src/utils/npm-utils.ts +1 -1
- package/src/utils/resolve-utils.ts +77 -9
package/dist/__mocks__/api.js
CHANGED
|
@@ -50,7 +50,7 @@ function mockProjectToProjectVersionMeta(mock, componentIdOrNames) {
|
|
|
50
50
|
.filter((c) => !componentIdOrNames ||
|
|
51
51
|
componentIdOrNames.includes(c.name) ||
|
|
52
52
|
componentIdOrNames.includes(c.id))
|
|
53
|
-
.map((c) => c.id) });
|
|
53
|
+
.map((c) => c.id), indirect: false });
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Call this in test to setup the data model
|
|
@@ -250,6 +250,8 @@ class PlasmicApi {
|
|
|
250
250
|
globalVariantChecksums: [],
|
|
251
251
|
projectCssChecksum: "",
|
|
252
252
|
},
|
|
253
|
+
usedNpmPackages: [],
|
|
254
|
+
externalCssImports: [],
|
|
253
255
|
};
|
|
254
256
|
return result;
|
|
255
257
|
});
|
|
@@ -274,6 +276,12 @@ class PlasmicApi {
|
|
|
274
276
|
throw new Error("Unimplemented");
|
|
275
277
|
});
|
|
276
278
|
}
|
|
279
|
+
latestCodegenVersion() {
|
|
280
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
281
|
+
return "0.0.1";
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
;
|
|
277
285
|
requiredPackages() {
|
|
278
286
|
return __awaiter(this, void 0, void 0, function* () {
|
|
279
287
|
return {
|
|
@@ -51,20 +51,20 @@ describe("Project API tokens", () => {
|
|
|
51
51
|
fixtures_1.tmpRepo.writePlasmicJson(Object.assign(Object.assign({}, fixtures_1.defaultPlasmicJson), { projects: [Object.assign(Object.assign({}, fixtures_1.project1Config), { projectApiToken: "blah" })] }));
|
|
52
52
|
yield expect(sync_1.sync(fixtures_1.opts)).resolves.toBeUndefined();
|
|
53
53
|
fixtures_1.expectProject1Components();
|
|
54
|
-
fixtures_1.expectProject1PlasmicJson();
|
|
54
|
+
fixtures_1.expectProject1PlasmicJson({ projectApiToken: true });
|
|
55
55
|
// Re-run, this time with no auth.
|
|
56
56
|
removeAuth();
|
|
57
|
-
yield expect(sync_1.sync(fixtures_1.opts)).
|
|
57
|
+
yield expect(sync_1.sync(fixtures_1.opts)).rejects.toThrow("No user+token, and project API tokens don't match");
|
|
58
58
|
}));
|
|
59
59
|
test("is filled in by auth'd user if project exists but token was initially missing", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
60
|
fixtures_1.opts.projects = ["projectId1"];
|
|
61
61
|
fixtures_1.tmpRepo.writePlasmicJson(Object.assign(Object.assign({}, fixtures_1.defaultPlasmicJson), { projects: [fixtures_1.project1Config] }));
|
|
62
62
|
yield expect(sync_1.sync(fixtures_1.opts)).resolves.toBeUndefined();
|
|
63
63
|
fixtures_1.expectProject1Components();
|
|
64
|
-
fixtures_1.expectProject1PlasmicJson();
|
|
64
|
+
fixtures_1.expectProject1PlasmicJson({ projectApiToken: true });
|
|
65
65
|
// Re-run, this time with no auth.
|
|
66
66
|
removeAuth();
|
|
67
|
-
yield expect(sync_1.sync(fixtures_1.opts)).
|
|
67
|
+
yield expect(sync_1.sync(fixtures_1.opts)).rejects.toThrow("Unable to authenticate Plasmic. Please run 'plasmic auth' or check the projectApiTokens in your plasmic.json, and try again.");
|
|
68
68
|
}));
|
|
69
69
|
test("when not available, should prompt for auth", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
70
70
|
fixtures_1.opts.projects = ["projectId1"];
|
package/dist/actions/sync.js
CHANGED
|
@@ -150,6 +150,7 @@ function sync(opts, metadataDefaults) {
|
|
|
150
150
|
versionRange: versionRange || ((_a = projectConfigMap[projectId]) === null || _a === void 0 ? void 0 : _a.version) || "latest",
|
|
151
151
|
componentIdOrNames: undefined,
|
|
152
152
|
projectApiToken: projectApiToken || projectIdToToken.get(projectId),
|
|
153
|
+
indirect: false,
|
|
153
154
|
};
|
|
154
155
|
});
|
|
155
156
|
const projectSyncParams = projectWithVersion.length
|
|
@@ -159,6 +160,7 @@ function sync(opts, metadataDefaults) {
|
|
|
159
160
|
versionRange: p.version,
|
|
160
161
|
componentIdOrNames: undefined,
|
|
161
162
|
projectApiToken: p.projectApiToken,
|
|
163
|
+
indirect: !!p.indirect,
|
|
162
164
|
}));
|
|
163
165
|
// Short-circuit if nothing to sync
|
|
164
166
|
if (projectSyncParams.length === 0) {
|
|
@@ -206,13 +208,15 @@ function sync(opts, metadataDefaults) {
|
|
|
206
208
|
...versionResolution.dependencies,
|
|
207
209
|
].map((p) => lodash_1.default.pick(p, "projectId", "projectApiToken"));
|
|
208
210
|
context.api.attachProjectIdsAndTokens(projectIdsAndTokens);
|
|
211
|
+
const externalNpmPackages = new Set();
|
|
212
|
+
const externalCssImports = new Set();
|
|
209
213
|
// Perform the actual sync
|
|
210
214
|
yield file_utils_1.withBufferedFs(() => __awaiter(this, void 0, void 0, function* () {
|
|
211
215
|
var _b;
|
|
212
216
|
// Sync in sequence (no parallelism)
|
|
213
217
|
// going in reverse to get leaves of the dependency tree first
|
|
214
218
|
for (const projectMeta of projectsToSync) {
|
|
215
|
-
yield syncProject(context, opts, projectIdsAndTokens, projectMeta.projectId, projectMeta.componentIds, projectMeta.version, projectMeta.dependencies, summary, pendingMerge, metadataDefaults);
|
|
219
|
+
yield syncProject(context, opts, projectIdsAndTokens, projectMeta.projectId, projectMeta.componentIds, projectMeta.version, projectMeta.dependencies, summary, pendingMerge, projectMeta.indirect, externalNpmPackages, externalCssImports, metadataDefaults);
|
|
216
220
|
}
|
|
217
221
|
// Materialize scheme into each component config.
|
|
218
222
|
context.config.projects.forEach((p) => p.components.forEach((c) => {
|
|
@@ -221,11 +225,20 @@ function sync(opts, metadataDefaults) {
|
|
|
221
225
|
}
|
|
222
226
|
}));
|
|
223
227
|
yield syncStyleConfig(context, yield context.api.genStyleConfig(context.config.style));
|
|
224
|
-
// Update project version if specified and
|
|
228
|
+
// Update project version and indirect status if specified and
|
|
229
|
+
// successfully synced.
|
|
225
230
|
if (projectWithVersion.length) {
|
|
226
231
|
const versionMap = {};
|
|
227
232
|
projectWithVersion.forEach((p) => (versionMap[p.projectId] = p.versionRange));
|
|
228
|
-
|
|
233
|
+
const indirectMap = {};
|
|
234
|
+
projectsToSync.forEach((p) => (indirectMap[p.projectId] = p.indirect));
|
|
235
|
+
context.config.projects.forEach((p) => {
|
|
236
|
+
p.version = versionMap[p.projectId] || p.version;
|
|
237
|
+
// Only update `indirect` if it is set in current config.
|
|
238
|
+
if (p.projectId in indirectMap && p.indirect) {
|
|
239
|
+
p.indirect = indirectMap[p.projectId];
|
|
240
|
+
}
|
|
241
|
+
});
|
|
229
242
|
}
|
|
230
243
|
// Fix imports
|
|
231
244
|
const fixImportContext = code_utils_1.mkFixImportContext(context.config);
|
|
@@ -244,9 +257,22 @@ function sync(opts, metadataDefaults) {
|
|
|
244
257
|
const config = Object.assign(Object.assign({}, loaderConfig), { projects: lodash_1.default.sortBy(lodash_1.default.uniqBy([...freshIdsAndTokens, ...((_b = loaderConfig === null || loaderConfig === void 0 ? void 0 : loaderConfig.projects) !== null && _b !== void 0 ? _b : [])], (p) => p.projectId), (p) => p.projectId) });
|
|
245
258
|
writeLoaderConfig(opts, config);
|
|
246
259
|
}
|
|
260
|
+
const codegenVersion = yield context.api.latestCodegenVersion();
|
|
261
|
+
context.lock.projects.forEach(p => {
|
|
262
|
+
if (projectsToSync.some(syncedProject => syncedProject.projectId === p.projectId)) {
|
|
263
|
+
p.codegenVersion = codegenVersion;
|
|
264
|
+
}
|
|
265
|
+
});
|
|
247
266
|
// Write the new ComponentConfigs to disk
|
|
248
267
|
yield config_utils_1.updateConfig(context, context.config, baseDir);
|
|
249
268
|
}));
|
|
269
|
+
yield checkExternalPkgs(context, baseDir, opts, Array.from(externalNpmPackages.keys()));
|
|
270
|
+
if (!opts.quiet && externalCssImports.size > 0) {
|
|
271
|
+
deps_1.logger.info(`This project uses external packages and styles. Make sure to import the following global CSS: ` +
|
|
272
|
+
Array.from(externalCssImports.keys())
|
|
273
|
+
.map((stmt) => `"${stmt}"`)
|
|
274
|
+
.join(", "));
|
|
275
|
+
}
|
|
250
276
|
// Post-sync commands
|
|
251
277
|
if (!opts.ignorePostSync) {
|
|
252
278
|
for (const cmd of context.config.postSyncCommands || []) {
|
|
@@ -261,6 +287,20 @@ function sync(opts, metadataDefaults) {
|
|
|
261
287
|
});
|
|
262
288
|
}
|
|
263
289
|
exports.sync = sync;
|
|
290
|
+
function checkExternalPkgs(context, baseDir, opts, pkgs) {
|
|
291
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
292
|
+
const missingPkgs = pkgs.filter((pkg) => {
|
|
293
|
+
const installedPkg = npm_utils_1.findInstalledVersion(context, baseDir, pkg);
|
|
294
|
+
return !installedPkg;
|
|
295
|
+
});
|
|
296
|
+
if (missingPkgs.length > 0) {
|
|
297
|
+
const upgrade = yield user_utils_1.confirmWithUser(`The following packages aren't installed but are required by some projects, would you like to install them? ${missingPkgs.join(", ")}`, opts.yes);
|
|
298
|
+
if (upgrade) {
|
|
299
|
+
npm_utils_1.installUpgrade(missingPkgs.join(" "), baseDir);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
264
304
|
function maybeRenamePathExt(context, path, ext) {
|
|
265
305
|
if (!path) {
|
|
266
306
|
return path;
|
|
@@ -281,7 +321,7 @@ function fixFileExtension(context) {
|
|
|
281
321
|
});
|
|
282
322
|
});
|
|
283
323
|
}
|
|
284
|
-
function syncProject(context, opts, projectIdsAndTokens, projectId, componentIds, projectVersion, dependencies, summary, pendingMerge, metadataDefaults) {
|
|
324
|
+
function syncProject(context, opts, projectIdsAndTokens, projectId, componentIds, projectVersion, dependencies, summary, pendingMerge, indirect, externalNpmPackages, externalCssImports, metadataDefaults) {
|
|
285
325
|
var _a;
|
|
286
326
|
return __awaiter(this, void 0, void 0, function* () {
|
|
287
327
|
const newComponentScheme = opts.newComponentScheme || context.config.code.scheme;
|
|
@@ -301,6 +341,7 @@ function syncProject(context, opts, projectIdsAndTokens, projectId, componentIds
|
|
|
301
341
|
checksums: existingChecksums,
|
|
302
342
|
codeOpts: context.config.code,
|
|
303
343
|
metadata: get_context_1.generateMetadata(Object.assign(Object.assign({}, metadataDefaults), { platform: context.config.platform }), opts.metadata),
|
|
344
|
+
indirect,
|
|
304
345
|
});
|
|
305
346
|
// Convert from TSX => JSX
|
|
306
347
|
if (context.config.code.lang === "js") {
|
|
@@ -319,11 +360,13 @@ function syncProject(context, opts, projectIdsAndTokens, projectId, componentIds
|
|
|
319
360
|
});
|
|
320
361
|
}
|
|
321
362
|
yield sync_global_variants_1.syncGlobalVariants(context, projectBundle.projectConfig, projectBundle.globalVariants, projectBundle.checksums, opts.baseDir);
|
|
322
|
-
yield syncProjectConfig(context, projectBundle.projectConfig, projectApiToken, projectVersion, dependencies, projectBundle.components, opts.forceOverwrite, !!opts.appendJsxOnMissingBase, summary, pendingMerge, projectBundle.checksums, opts.baseDir);
|
|
363
|
+
yield syncProjectConfig(context, projectBundle.projectConfig, projectApiToken, projectVersion, dependencies, projectBundle.components, opts.forceOverwrite, !!opts.appendJsxOnMissingBase, summary, pendingMerge, projectBundle.checksums, opts.baseDir, indirect);
|
|
323
364
|
syncCodeComponentsMeta(context, projectId, projectBundle.codeComponentMetas);
|
|
324
365
|
yield sync_styles_1.upsertStyleTokens(context, projectBundle.usedTokens);
|
|
325
366
|
yield sync_icons_1.syncProjectIconAssets(context, projectId, projectVersion, projectBundle.iconAssets, projectBundle.checksums, opts.baseDir);
|
|
326
367
|
yield sync_images_1.syncProjectImageAssets(context, projectId, projectVersion, projectBundle.imageAssets, projectBundle.checksums);
|
|
368
|
+
(projectBundle.usedNpmPackages || []).forEach((pkg) => externalNpmPackages.add(pkg));
|
|
369
|
+
(projectBundle.externalCssImports || []).forEach((css) => externalCssImports.add(css));
|
|
327
370
|
});
|
|
328
371
|
}
|
|
329
372
|
function syncStyleConfig(context, response) {
|
|
@@ -336,7 +379,7 @@ function syncStyleConfig(context, response) {
|
|
|
336
379
|
});
|
|
337
380
|
});
|
|
338
381
|
}
|
|
339
|
-
function syncProjectConfig(context, projectBundle, projectApiToken, version, dependencies, componentBundles, forceOverwrite, appendJsxOnMissingBase, summary, pendingMerge, checksums, baseDir) {
|
|
382
|
+
function syncProjectConfig(context, projectBundle, projectApiToken, version, dependencies, componentBundles, forceOverwrite, appendJsxOnMissingBase, summary, pendingMerge, checksums, baseDir, indirect) {
|
|
340
383
|
return __awaiter(this, void 0, void 0, function* () {
|
|
341
384
|
const defaultCssFilePath = file_utils_1.defaultResourcePath(context, projectBundle.projectName, projectBundle.cssFileName);
|
|
342
385
|
const isNew = !context.config.projects.find((p) => p.projectId === projectBundle.projectId);
|
|
@@ -346,13 +389,13 @@ function syncProjectConfig(context, projectBundle, projectApiToken, version, dep
|
|
|
346
389
|
projectName: projectBundle.projectName,
|
|
347
390
|
version,
|
|
348
391
|
cssFilePath: defaultCssFilePath,
|
|
392
|
+
indirect,
|
|
349
393
|
}));
|
|
350
394
|
// Update missing/outdated props
|
|
351
395
|
projectConfig.projectName = projectBundle.projectName;
|
|
352
396
|
if (!projectConfig.cssFilePath) {
|
|
353
397
|
projectConfig.cssFilePath = defaultCssFilePath;
|
|
354
398
|
}
|
|
355
|
-
projectConfig.projectApiToken = projectApiToken;
|
|
356
399
|
// plasmic.lock
|
|
357
400
|
const projectLock = config_utils_1.getOrAddProjectLock(context, projectConfig.projectId);
|
|
358
401
|
projectLock.version = version;
|
package/dist/api.d.ts
CHANGED
|
@@ -58,6 +58,7 @@ export interface ProjectVersionMeta {
|
|
|
58
58
|
dependencies: {
|
|
59
59
|
[projectId: string]: string;
|
|
60
60
|
};
|
|
61
|
+
indirect: boolean;
|
|
61
62
|
}
|
|
62
63
|
export interface VersionResolution {
|
|
63
64
|
projects: ProjectVersionMeta[];
|
|
@@ -79,6 +80,8 @@ export interface ProjectBundle {
|
|
|
79
80
|
iconAssets: IconBundle[];
|
|
80
81
|
imageAssets: ImageBundle[];
|
|
81
82
|
checksums: ChecksumBundle;
|
|
83
|
+
usedNpmPackages: string[];
|
|
84
|
+
externalCssImports: string[];
|
|
82
85
|
}
|
|
83
86
|
export declare type ProjectMeta = Omit<ProjectBundle, "projectConfig">;
|
|
84
87
|
export interface StyleConfigResponse {
|
|
@@ -124,6 +127,7 @@ export interface ProjectIdAndToken {
|
|
|
124
127
|
}
|
|
125
128
|
export declare class PlasmicApi {
|
|
126
129
|
private auth;
|
|
130
|
+
private codegenVersion?;
|
|
127
131
|
constructor(auth: AuthConfig);
|
|
128
132
|
genStyleConfig(styleOpts?: StyleConfig): Promise<StyleConfigResponse>;
|
|
129
133
|
/**
|
|
@@ -143,6 +147,7 @@ export declare class PlasmicApi {
|
|
|
143
147
|
}[], recursive?: boolean): Promise<VersionResolution>;
|
|
144
148
|
getCurrentUser(): Promise<import("axios").AxiosResponse<any>>;
|
|
145
149
|
requiredPackages(): Promise<RequiredPackages>;
|
|
150
|
+
latestCodegenVersion(): Promise<string>;
|
|
146
151
|
/**
|
|
147
152
|
* Code-gen endpoint.
|
|
148
153
|
* This will fetch components at an exact specified version.
|
|
@@ -165,6 +170,7 @@ export declare class PlasmicApi {
|
|
|
165
170
|
stylesOpts: StyleConfig;
|
|
166
171
|
codeOpts: CodeConfig;
|
|
167
172
|
checksums: ChecksumBundle;
|
|
173
|
+
indirect: boolean;
|
|
168
174
|
metadata?: Metadata;
|
|
169
175
|
}): Promise<ProjectBundle>;
|
|
170
176
|
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>;
|
package/dist/api.js
CHANGED
|
@@ -66,6 +66,15 @@ class PlasmicApi {
|
|
|
66
66
|
return Object.assign({}, resp.data);
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
|
+
latestCodegenVersion() {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
if (!this.codegenVersion) {
|
|
72
|
+
const resp = yield this.post(`${this.codegenHost}/api/v1/code/latest-codegen-version`);
|
|
73
|
+
this.codegenVersion = resp.data;
|
|
74
|
+
}
|
|
75
|
+
return this.codegenVersion;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
69
78
|
/**
|
|
70
79
|
* Code-gen endpoint.
|
|
71
80
|
* This will fetch components at an exact specified version.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ensureIndirect = void 0;
|
|
4
|
+
function ensureIndirect(config) {
|
|
5
|
+
for (const p of config.projects) {
|
|
6
|
+
if (p.indirect === undefined) {
|
|
7
|
+
p.indirect = false;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return config;
|
|
11
|
+
}
|
|
12
|
+
exports.ensureIndirect = ensureIndirect;
|
|
@@ -40,6 +40,7 @@ const npm_utils_1 = require("../utils/npm-utils");
|
|
|
40
40
|
const user_utils_1 = require("../utils/user-utils");
|
|
41
41
|
const _0_1_110_fileLocks_1 = require("./0.1.110-fileLocks");
|
|
42
42
|
const _0_1_146_addReactRuntime_1 = require("./0.1.146-addReactRuntime");
|
|
43
|
+
const _0_1_166_indirect_1 = require("./0.1.166-indirect");
|
|
43
44
|
const _0_1_27_migrateInit_1 = require("./0.1.27-migrateInit");
|
|
44
45
|
const _0_1_28_tsToTsx_1 = require("./0.1.28-tsToTsx");
|
|
45
46
|
const _0_1_31_ensureProjectIcons_1 = require("./0.1.31-ensureProjectIcons");
|
|
@@ -56,6 +57,7 @@ exports.MIGRATIONS = {
|
|
|
56
57
|
"0.1.64": _0_1_64_imageFiles_1.ensureImageFiles,
|
|
57
58
|
"0.1.95": _0_1_95_componentType_1.ensureComponentType,
|
|
58
59
|
"0.1.146": _0_1_146_addReactRuntime_1.ensureReactRuntime,
|
|
60
|
+
"0.1.166": _0_1_166_indirect_1.ensureIndirect,
|
|
59
61
|
};
|
|
60
62
|
exports.LOCK_MIGRATIONS = {
|
|
61
63
|
"0.1.110": _0_1_110_fileLocks_1.ensureFileLocks,
|
package/dist/plasmic.schema.json
CHANGED
|
@@ -296,6 +296,10 @@
|
|
|
296
296
|
},
|
|
297
297
|
"type": "array"
|
|
298
298
|
},
|
|
299
|
+
"indirect": {
|
|
300
|
+
"description": "True if the project was installed indirectly (as a dependency); if set,\ncodegen will not generate pages.",
|
|
301
|
+
"type": "boolean"
|
|
302
|
+
},
|
|
299
303
|
"jsBundleThemes": {
|
|
300
304
|
"items": {
|
|
301
305
|
"$ref": "#/definitions/JsBundleThemeConfig"
|
|
@@ -324,6 +328,7 @@
|
|
|
324
328
|
"cssFilePath",
|
|
325
329
|
"icons",
|
|
326
330
|
"images",
|
|
331
|
+
"indirect",
|
|
327
332
|
"projectId",
|
|
328
333
|
"projectName",
|
|
329
334
|
"version"
|
|
@@ -9,5 +9,7 @@ export declare function standardTestSetup(includeDep?: boolean): void;
|
|
|
9
9
|
export declare function standardTestTeardown(): void;
|
|
10
10
|
export declare function expectProject1Components(): void;
|
|
11
11
|
export declare const project1Config: ProjectConfig;
|
|
12
|
-
export declare function expectProject1PlasmicJson(
|
|
12
|
+
export declare function expectProject1PlasmicJson(optional?: {
|
|
13
|
+
[k in keyof ProjectConfig]?: boolean;
|
|
14
|
+
}): void;
|
|
13
15
|
export declare function expectProjectAndDepPlasmicJson(): void;
|
|
@@ -138,12 +138,15 @@ exports.project1Config = {
|
|
|
138
138
|
icons: [],
|
|
139
139
|
images: [],
|
|
140
140
|
jsBundleThemes: [],
|
|
141
|
+
indirect: false,
|
|
141
142
|
};
|
|
142
|
-
function expectProject1PlasmicJson() {
|
|
143
|
+
function expectProject1PlasmicJson(optional) {
|
|
143
144
|
const plasmicJson = exports.tmpRepo.readPlasmicJson();
|
|
144
145
|
expect(plasmicJson.projects.length).toEqual(1);
|
|
145
146
|
const projectConfig = plasmicJson.projects[0];
|
|
146
|
-
|
|
147
|
+
if (!(optional === null || optional === void 0 ? void 0 : optional.projectApiToken)) {
|
|
148
|
+
expect(projectConfig.projectApiToken).toBe("abc");
|
|
149
|
+
}
|
|
147
150
|
expect(projectConfig.components.length).toEqual(2);
|
|
148
151
|
const componentNames = projectConfig.components.map((c) => c.name);
|
|
149
152
|
expect(componentNames).toContain("Button");
|
|
@@ -126,6 +126,11 @@ export interface ProjectConfig {
|
|
|
126
126
|
icons: IconConfig[];
|
|
127
127
|
/** Metadata for each synced image in this project */
|
|
128
128
|
images: ImageConfig[];
|
|
129
|
+
/**
|
|
130
|
+
* True if the project was installed indirectly (as a dependency); if set,
|
|
131
|
+
* codegen will not generate pages.
|
|
132
|
+
*/
|
|
133
|
+
indirect: boolean;
|
|
129
134
|
}
|
|
130
135
|
export declare function createProjectConfig(base: {
|
|
131
136
|
projectId: string;
|
|
@@ -133,6 +138,7 @@ export declare function createProjectConfig(base: {
|
|
|
133
138
|
projectName: string;
|
|
134
139
|
version: string;
|
|
135
140
|
cssFilePath: string;
|
|
141
|
+
indirect: boolean;
|
|
136
142
|
}): ProjectConfig;
|
|
137
143
|
export interface TokensConfig {
|
|
138
144
|
scheme: "theo";
|
|
@@ -219,6 +225,7 @@ export interface ProjectLock {
|
|
|
219
225
|
};
|
|
220
226
|
lang: "ts" | "js";
|
|
221
227
|
fileLocks: FileLock[];
|
|
228
|
+
codegenVersion?: string;
|
|
222
229
|
}
|
|
223
230
|
export interface PlasmicLock {
|
|
224
231
|
projects: ProjectLock[];
|
|
@@ -39,6 +39,7 @@ function createProjectConfig(base) {
|
|
|
39
39
|
components: [],
|
|
40
40
|
icons: [],
|
|
41
41
|
images: [],
|
|
42
|
+
indirect: base.indirect,
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
exports.createProjectConfig = createProjectConfig;
|
|
@@ -148,6 +149,7 @@ function getOrAddProjectConfig(context, projectId, base // if one doesn't exist,
|
|
|
148
149
|
icons: [],
|
|
149
150
|
images: [],
|
|
150
151
|
jsBundleThemes: [],
|
|
152
|
+
indirect: false,
|
|
151
153
|
};
|
|
152
154
|
context.config.projects.push(project);
|
|
153
155
|
}
|
|
@@ -47,6 +47,7 @@ const user_utils_1 = require("./user-utils");
|
|
|
47
47
|
* @param versionResolution
|
|
48
48
|
*/
|
|
49
49
|
function walkDependencyTree(root, available) {
|
|
50
|
+
root.indirect = false;
|
|
50
51
|
const queue = [root];
|
|
51
52
|
const result = [];
|
|
52
53
|
const getMeta = (projectId, version) => {
|
|
@@ -54,7 +55,7 @@ function walkDependencyTree(root, available) {
|
|
|
54
55
|
if (!meta) {
|
|
55
56
|
throw new Error(`Cannot find projectId=${projectId}, version=${version} in the sync resolution results.`);
|
|
56
57
|
}
|
|
57
|
-
return meta;
|
|
58
|
+
return Object.assign(Object.assign({}, meta), { indirect: meta.projectId !== root.projectId });
|
|
58
59
|
};
|
|
59
60
|
while (queue.length > 0) {
|
|
60
61
|
const curr = lang_utils_1.ensure(queue.shift());
|
|
@@ -73,6 +74,16 @@ function checkProjectMeta(meta, root, context, opts) {
|
|
|
73
74
|
const projectId = meta.projectId;
|
|
74
75
|
const projectName = meta.projectName;
|
|
75
76
|
const newVersion = meta.version;
|
|
77
|
+
const indirect = meta.indirect;
|
|
78
|
+
// If the codegen version on-disk is invalid, we will sync again the project.
|
|
79
|
+
const checkCodegenVersion = () => __awaiter(this, void 0, void 0, function* () {
|
|
80
|
+
const projectLock = context.lock.projects.find((p) => p.projectId === projectId);
|
|
81
|
+
if (!!(projectLock === null || projectLock === void 0 ? void 0 : projectLock.codegenVersion) && semver.gte(projectLock.codegenVersion, yield context.api.latestCodegenVersion())) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
});
|
|
86
|
+
const isOnDiskCodeInvalid = yield checkCodegenVersion();
|
|
76
87
|
// Checks newVersion against plasmic.lock
|
|
77
88
|
const checkVersionLock = () => __awaiter(this, void 0, void 0, function* () {
|
|
78
89
|
const projectLock = context.lock.projects.find((p) => p.projectId === projectId);
|
|
@@ -86,7 +97,9 @@ function checkProjectMeta(meta, root, context, opts) {
|
|
|
86
97
|
meta !== root) {
|
|
87
98
|
// If this is a dependency (not root), and we're dealing with latest dep version
|
|
88
99
|
// just skip, it's confusing
|
|
89
|
-
|
|
100
|
+
if (!isOnDiskCodeInvalid) {
|
|
101
|
+
deps_1.logger.warn(`'${root.projectName}' depends on ${projectName}@${newVersion}. To update this project, explicitly specify this project for sync. Skipping...`);
|
|
102
|
+
}
|
|
90
103
|
return false;
|
|
91
104
|
}
|
|
92
105
|
if (semver.isLatest(newVersion)) {
|
|
@@ -104,7 +117,9 @@ function checkProjectMeta(meta, root, context, opts) {
|
|
|
104
117
|
return true;
|
|
105
118
|
}
|
|
106
119
|
else {
|
|
107
|
-
|
|
120
|
+
if (!isOnDiskCodeInvalid) {
|
|
121
|
+
deps_1.logger.info(`Project '${projectName}'@${newVersion} is already up to date; skipping. (To force an update, run again with "--force")`);
|
|
122
|
+
}
|
|
108
123
|
return false;
|
|
109
124
|
}
|
|
110
125
|
}
|
|
@@ -145,6 +160,15 @@ function checkProjectMeta(meta, root, context, opts) {
|
|
|
145
160
|
deps_1.logger.warn(`${projectName}@${newVersion} falls outside the range specified in ${config_utils_1.CONFIG_FILE_NAME} (${versionRange})\nTip: To avoid this warning in the future, update your ${config_utils_1.CONFIG_FILE_NAME}.`);
|
|
146
161
|
return yield user_utils_1.confirmWithUser("Do you want to force it?", opts.force || opts.yes, "n");
|
|
147
162
|
});
|
|
163
|
+
const checkIndirect = () => __awaiter(this, void 0, void 0, function* () {
|
|
164
|
+
const projectConfig = context.config.projects.find((p) => p.projectId === projectId);
|
|
165
|
+
const configIndirect = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.indirect;
|
|
166
|
+
if (configIndirect && !indirect) {
|
|
167
|
+
deps_1.logger.warn(`'${projectName}' was synced indirectly before, but a direct sync was requested. If it has page components, they will be synced and saved to plasmic.json.`);
|
|
168
|
+
return yield user_utils_1.confirmWithUser("Do you want to confirm it?", opts.force || opts.yes, "n");
|
|
169
|
+
}
|
|
170
|
+
return true;
|
|
171
|
+
});
|
|
148
172
|
const projectIds = opts.projects.length > 0
|
|
149
173
|
? opts.projects
|
|
150
174
|
: context.config.projects.map((p) => p.projectId);
|
|
@@ -153,7 +177,24 @@ function checkProjectMeta(meta, root, context, opts) {
|
|
|
153
177
|
// we should always sync it, even if nothing has changed
|
|
154
178
|
return true;
|
|
155
179
|
}
|
|
156
|
-
|
|
180
|
+
const checkedVersion = (yield checkVersionLock()) &&
|
|
181
|
+
(yield checkVersionRange()) &&
|
|
182
|
+
(yield checkIndirect());
|
|
183
|
+
if (!checkedVersion && isOnDiskCodeInvalid) {
|
|
184
|
+
// sync, but try to keep the current version on disk
|
|
185
|
+
const projectLock = context.lock.projects.find((p) => p.projectId === projectId);
|
|
186
|
+
const versionOnDisk = projectLock === null || projectLock === void 0 ? void 0 : projectLock.version;
|
|
187
|
+
deps_1.logger.warn(`Project '${projectName}' was synced by an incompatible version of Plasmic Codegen. Syncing again on the same version ${projectName}@${versionOnDisk}`);
|
|
188
|
+
meta.version = versionOnDisk !== null && versionOnDisk !== void 0 ? versionOnDisk : meta.version;
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
else if (checkedVersion) {
|
|
192
|
+
// sync and upgrade the version
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
157
198
|
});
|
|
158
199
|
}
|
|
159
200
|
/**
|
|
@@ -175,13 +216,18 @@ function checkVersionResolution(versionResolution, context, opts) {
|
|
|
175
216
|
? [root]
|
|
176
217
|
: walkDependencyTree(root, versionResolution.dependencies).reverse();
|
|
177
218
|
for (const m of queue) {
|
|
178
|
-
// If we haven't seen this yet
|
|
179
219
|
if (!seen.find((p) => p.projectId === m.projectId)) {
|
|
180
220
|
if (yield checkProjectMeta(m, root, context, opts)) {
|
|
181
221
|
result.push(m);
|
|
182
222
|
}
|
|
183
223
|
seen.push(m);
|
|
184
224
|
}
|
|
225
|
+
else if (root.projectId === m.projectId) {
|
|
226
|
+
// If m is the root project and it was already seen (maybe as a dep
|
|
227
|
+
// for another project), set indirect = false.
|
|
228
|
+
const project = lang_utils_1.ensure(seen.find((p) => p.projectId === m.projectId));
|
|
229
|
+
project.indirect = false;
|
|
230
|
+
}
|
|
185
231
|
}
|
|
186
232
|
}
|
|
187
233
|
// Ignore repeats
|
package/package.json
CHANGED
package/src/__mocks__/api.ts
CHANGED
|
@@ -61,6 +61,7 @@ function mockProjectToProjectVersionMeta(
|
|
|
61
61
|
componentIdOrNames.includes(c.id)
|
|
62
62
|
)
|
|
63
63
|
.map((c) => c.id),
|
|
64
|
+
indirect: false,
|
|
64
65
|
};
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -339,6 +340,8 @@ class PlasmicApi {
|
|
|
339
340
|
globalVariantChecksums: [],
|
|
340
341
|
projectCssChecksum: "",
|
|
341
342
|
} as ChecksumBundle,
|
|
343
|
+
usedNpmPackages: [],
|
|
344
|
+
externalCssImports: [],
|
|
342
345
|
};
|
|
343
346
|
return result;
|
|
344
347
|
}
|
|
@@ -369,6 +372,10 @@ class PlasmicApi {
|
|
|
369
372
|
throw new Error("Unimplemented");
|
|
370
373
|
}
|
|
371
374
|
|
|
375
|
+
async latestCodegenVersion(): Promise<string> {
|
|
376
|
+
return "0.0.1";
|
|
377
|
+
};
|
|
378
|
+
|
|
372
379
|
async requiredPackages(): Promise<RequiredPackages> {
|
|
373
380
|
return {
|
|
374
381
|
"@plasmicapp/loader": "0.0.1",
|
|
@@ -71,11 +71,13 @@ describe("Project API tokens", () => {
|
|
|
71
71
|
|
|
72
72
|
expectProject1Components();
|
|
73
73
|
|
|
74
|
-
expectProject1PlasmicJson();
|
|
74
|
+
expectProject1PlasmicJson({ projectApiToken: true });
|
|
75
75
|
|
|
76
76
|
// Re-run, this time with no auth.
|
|
77
77
|
removeAuth();
|
|
78
|
-
await expect(sync(opts)).
|
|
78
|
+
await expect(sync(opts)).rejects.toThrow(
|
|
79
|
+
"No user+token, and project API tokens don't match"
|
|
80
|
+
);
|
|
79
81
|
});
|
|
80
82
|
|
|
81
83
|
test("is filled in by auth'd user if project exists but token was initially missing", async () => {
|
|
@@ -88,11 +90,13 @@ describe("Project API tokens", () => {
|
|
|
88
90
|
|
|
89
91
|
expectProject1Components();
|
|
90
92
|
|
|
91
|
-
expectProject1PlasmicJson();
|
|
93
|
+
expectProject1PlasmicJson({ projectApiToken: true });
|
|
92
94
|
|
|
93
95
|
// Re-run, this time with no auth.
|
|
94
96
|
removeAuth();
|
|
95
|
-
await expect(sync(opts)).
|
|
97
|
+
await expect(sync(opts)).rejects.toThrow(
|
|
98
|
+
"Unable to authenticate Plasmic. Please run 'plasmic auth' or check the projectApiTokens in your plasmic.json, and try again."
|
|
99
|
+
);
|
|
96
100
|
});
|
|
97
101
|
|
|
98
102
|
test("when not available, should prompt for auth", async () => {
|
package/src/actions/sync.ts
CHANGED
|
@@ -234,6 +234,7 @@ export async function sync(
|
|
|
234
234
|
versionRange || projectConfigMap[projectId]?.version || "latest",
|
|
235
235
|
componentIdOrNames: undefined, // Get all components!
|
|
236
236
|
projectApiToken: projectApiToken || projectIdToToken.get(projectId),
|
|
237
|
+
indirect: false,
|
|
237
238
|
};
|
|
238
239
|
});
|
|
239
240
|
|
|
@@ -244,6 +245,7 @@ export async function sync(
|
|
|
244
245
|
versionRange: p.version,
|
|
245
246
|
componentIdOrNames: undefined, // Get all components!
|
|
246
247
|
projectApiToken: p.projectApiToken,
|
|
248
|
+
indirect: !!p.indirect,
|
|
247
249
|
}));
|
|
248
250
|
|
|
249
251
|
// Short-circuit if nothing to sync
|
|
@@ -259,7 +261,7 @@ export async function sync(
|
|
|
259
261
|
try {
|
|
260
262
|
context = await getContext(opts);
|
|
261
263
|
} catch (e) {
|
|
262
|
-
if (e.message.includes("Unable to authenticate Plasmic")) {
|
|
264
|
+
if ((e as any).message.includes("Unable to authenticate Plasmic")) {
|
|
263
265
|
const configFileName = process.env.PLASMIC_LOADER
|
|
264
266
|
? LOADER_CONFIG_FILE_NAME
|
|
265
267
|
: CONFIG_FILE_NAME;
|
|
@@ -313,6 +315,8 @@ export async function sync(
|
|
|
313
315
|
].map((p) => L.pick(p, "projectId", "projectApiToken"));
|
|
314
316
|
|
|
315
317
|
context.api.attachProjectIdsAndTokens(projectIdsAndTokens);
|
|
318
|
+
const externalNpmPackages = new Set<string>();
|
|
319
|
+
const externalCssImports = new Set<string>();
|
|
316
320
|
|
|
317
321
|
// Perform the actual sync
|
|
318
322
|
await withBufferedFs(async () => {
|
|
@@ -329,6 +333,9 @@ export async function sync(
|
|
|
329
333
|
projectMeta.dependencies,
|
|
330
334
|
summary,
|
|
331
335
|
pendingMerge,
|
|
336
|
+
projectMeta.indirect,
|
|
337
|
+
externalNpmPackages,
|
|
338
|
+
externalCssImports,
|
|
332
339
|
metadataDefaults
|
|
333
340
|
);
|
|
334
341
|
}
|
|
@@ -347,15 +354,22 @@ export async function sync(
|
|
|
347
354
|
await context.api.genStyleConfig(context.config.style)
|
|
348
355
|
);
|
|
349
356
|
|
|
350
|
-
// Update project version if specified and
|
|
357
|
+
// Update project version and indirect status if specified and
|
|
358
|
+
// successfully synced.
|
|
351
359
|
if (projectWithVersion.length) {
|
|
352
360
|
const versionMap: Record<string, string> = {};
|
|
353
361
|
projectWithVersion.forEach(
|
|
354
362
|
(p) => (versionMap[p.projectId] = p.versionRange)
|
|
355
363
|
);
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
)
|
|
364
|
+
const indirectMap: Record<string, boolean> = {};
|
|
365
|
+
projectsToSync.forEach((p) => (indirectMap[p.projectId] = p.indirect));
|
|
366
|
+
context.config.projects.forEach((p) => {
|
|
367
|
+
p.version = versionMap[p.projectId] || p.version;
|
|
368
|
+
// Only update `indirect` if it is set in current config.
|
|
369
|
+
if (p.projectId in indirectMap && p.indirect) {
|
|
370
|
+
p.indirect = indirectMap[p.projectId];
|
|
371
|
+
}
|
|
372
|
+
});
|
|
359
373
|
}
|
|
360
374
|
|
|
361
375
|
// Fix imports
|
|
@@ -402,10 +416,32 @@ export async function sync(
|
|
|
402
416
|
writeLoaderConfig(opts, config);
|
|
403
417
|
}
|
|
404
418
|
|
|
419
|
+
const codegenVersion = await context.api.latestCodegenVersion();
|
|
420
|
+
context.lock.projects.forEach(p => {
|
|
421
|
+
if (projectsToSync.some(syncedProject => syncedProject.projectId === p.projectId)) {
|
|
422
|
+
p.codegenVersion = codegenVersion;
|
|
423
|
+
}
|
|
424
|
+
})
|
|
405
425
|
// Write the new ComponentConfigs to disk
|
|
406
426
|
await updateConfig(context, context.config, baseDir);
|
|
407
427
|
});
|
|
408
428
|
|
|
429
|
+
await checkExternalPkgs(
|
|
430
|
+
context,
|
|
431
|
+
baseDir,
|
|
432
|
+
opts,
|
|
433
|
+
Array.from(externalNpmPackages.keys())
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
if (!opts.quiet && externalCssImports.size > 0) {
|
|
437
|
+
logger.info(
|
|
438
|
+
`This project uses external packages and styles. Make sure to import the following global CSS: ` +
|
|
439
|
+
Array.from(externalCssImports.keys())
|
|
440
|
+
.map((stmt) => `"${stmt}"`)
|
|
441
|
+
.join(", ")
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
|
|
409
445
|
// Post-sync commands
|
|
410
446
|
if (!opts.ignorePostSync) {
|
|
411
447
|
for (const cmd of context.config.postSyncCommands || []) {
|
|
@@ -420,6 +456,30 @@ export async function sync(
|
|
|
420
456
|
}
|
|
421
457
|
}
|
|
422
458
|
|
|
459
|
+
async function checkExternalPkgs(
|
|
460
|
+
context: PlasmicContext,
|
|
461
|
+
baseDir: string,
|
|
462
|
+
opts: SyncArgs,
|
|
463
|
+
pkgs: string[]
|
|
464
|
+
) {
|
|
465
|
+
const missingPkgs = pkgs.filter((pkg) => {
|
|
466
|
+
const installedPkg = findInstalledVersion(context, baseDir, pkg);
|
|
467
|
+
return !installedPkg;
|
|
468
|
+
});
|
|
469
|
+
if (missingPkgs.length > 0) {
|
|
470
|
+
const upgrade = await confirmWithUser(
|
|
471
|
+
`The following packages aren't installed but are required by some projects, would you like to install them? ${missingPkgs.join(
|
|
472
|
+
", "
|
|
473
|
+
)}`,
|
|
474
|
+
opts.yes
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
if (upgrade) {
|
|
478
|
+
installUpgrade(missingPkgs.join(" "), baseDir);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
423
483
|
function maybeRenamePathExt(
|
|
424
484
|
context: PlasmicContext,
|
|
425
485
|
path: string,
|
|
@@ -469,6 +529,9 @@ async function syncProject(
|
|
|
469
529
|
dependencies: { [projectId: string]: string },
|
|
470
530
|
summary: Map<string, ComponentUpdateSummary>,
|
|
471
531
|
pendingMerge: ComponentPendingMerge[],
|
|
532
|
+
indirect: boolean,
|
|
533
|
+
externalNpmPackages: Set<string>,
|
|
534
|
+
externalCssImports: Set<string>,
|
|
472
535
|
metadataDefaults?: Metadata
|
|
473
536
|
): Promise<void> {
|
|
474
537
|
const newComponentScheme =
|
|
@@ -512,6 +575,7 @@ async function syncProject(
|
|
|
512
575
|
},
|
|
513
576
|
opts.metadata
|
|
514
577
|
),
|
|
578
|
+
indirect,
|
|
515
579
|
});
|
|
516
580
|
|
|
517
581
|
// Convert from TSX => JSX
|
|
@@ -570,7 +634,8 @@ async function syncProject(
|
|
|
570
634
|
summary,
|
|
571
635
|
pendingMerge,
|
|
572
636
|
projectBundle.checksums,
|
|
573
|
-
opts.baseDir
|
|
637
|
+
opts.baseDir,
|
|
638
|
+
indirect
|
|
574
639
|
);
|
|
575
640
|
syncCodeComponentsMeta(context, projectId, projectBundle.codeComponentMetas);
|
|
576
641
|
await upsertStyleTokens(context, projectBundle.usedTokens);
|
|
@@ -589,6 +654,12 @@ async function syncProject(
|
|
|
589
654
|
projectBundle.imageAssets,
|
|
590
655
|
projectBundle.checksums
|
|
591
656
|
);
|
|
657
|
+
(projectBundle.usedNpmPackages || []).forEach((pkg) =>
|
|
658
|
+
externalNpmPackages.add(pkg)
|
|
659
|
+
);
|
|
660
|
+
(projectBundle.externalCssImports || []).forEach((css) =>
|
|
661
|
+
externalCssImports.add(css)
|
|
662
|
+
);
|
|
592
663
|
}
|
|
593
664
|
|
|
594
665
|
async function syncStyleConfig(
|
|
@@ -619,7 +690,8 @@ async function syncProjectConfig(
|
|
|
619
690
|
summary: Map<string, ComponentUpdateSummary>,
|
|
620
691
|
pendingMerge: ComponentPendingMerge[],
|
|
621
692
|
checksums: ChecksumBundle,
|
|
622
|
-
baseDir: string
|
|
693
|
+
baseDir: string,
|
|
694
|
+
indirect: boolean
|
|
623
695
|
) {
|
|
624
696
|
const defaultCssFilePath = defaultResourcePath(
|
|
625
697
|
context,
|
|
@@ -639,6 +711,7 @@ async function syncProjectConfig(
|
|
|
639
711
|
projectName: projectBundle.projectName,
|
|
640
712
|
version,
|
|
641
713
|
cssFilePath: defaultCssFilePath,
|
|
714
|
+
indirect,
|
|
642
715
|
})
|
|
643
716
|
);
|
|
644
717
|
|
|
@@ -647,7 +720,6 @@ async function syncProjectConfig(
|
|
|
647
720
|
if (!projectConfig.cssFilePath) {
|
|
648
721
|
projectConfig.cssFilePath = defaultCssFilePath;
|
|
649
722
|
}
|
|
650
|
-
projectConfig.projectApiToken = projectApiToken;
|
|
651
723
|
|
|
652
724
|
// plasmic.lock
|
|
653
725
|
const projectLock = getOrAddProjectLock(context, projectConfig.projectId);
|
package/src/api.ts
CHANGED
|
@@ -76,6 +76,7 @@ export interface ProjectVersionMeta {
|
|
|
76
76
|
dependencies: {
|
|
77
77
|
[projectId: string]: string;
|
|
78
78
|
};
|
|
79
|
+
indirect: boolean;
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
export interface VersionResolution {
|
|
@@ -100,6 +101,8 @@ export interface ProjectBundle {
|
|
|
100
101
|
iconAssets: IconBundle[];
|
|
101
102
|
imageAssets: ImageBundle[];
|
|
102
103
|
checksums: ChecksumBundle;
|
|
104
|
+
usedNpmPackages: string[];
|
|
105
|
+
externalCssImports: string[];
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
export type ProjectMeta = Omit<ProjectBundle, "projectConfig">;
|
|
@@ -158,6 +161,7 @@ export interface ProjectIdAndToken {
|
|
|
158
161
|
}
|
|
159
162
|
|
|
160
163
|
export class PlasmicApi {
|
|
164
|
+
private codegenVersion?: string;
|
|
161
165
|
constructor(private auth: AuthConfig) {}
|
|
162
166
|
|
|
163
167
|
async genStyleConfig(styleOpts?: StyleConfig): Promise<StyleConfigResponse> {
|
|
@@ -210,6 +214,16 @@ export class PlasmicApi {
|
|
|
210
214
|
return { ...resp.data } as RequiredPackages;
|
|
211
215
|
}
|
|
212
216
|
|
|
217
|
+
async latestCodegenVersion(): Promise<string> {
|
|
218
|
+
if (!this.codegenVersion) {
|
|
219
|
+
const resp = await this.post(
|
|
220
|
+
`${this.codegenHost}/api/v1/code/latest-codegen-version`
|
|
221
|
+
);
|
|
222
|
+
this.codegenVersion = resp.data as string;
|
|
223
|
+
}
|
|
224
|
+
return this.codegenVersion;
|
|
225
|
+
}
|
|
226
|
+
|
|
213
227
|
/**
|
|
214
228
|
* Code-gen endpoint.
|
|
215
229
|
* This will fetch components at an exact specified version.
|
|
@@ -235,6 +249,7 @@ export class PlasmicApi {
|
|
|
235
249
|
stylesOpts: StyleConfig;
|
|
236
250
|
codeOpts: CodeConfig;
|
|
237
251
|
checksums: ChecksumBundle;
|
|
252
|
+
indirect: boolean;
|
|
238
253
|
metadata?: Metadata;
|
|
239
254
|
}
|
|
240
255
|
): Promise<ProjectBundle> {
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
import { confirmWithUser } from "../utils/user-utils";
|
|
36
36
|
import { ensureFileLocks } from "./0.1.110-fileLocks";
|
|
37
37
|
import { ensureReactRuntime } from "./0.1.146-addReactRuntime";
|
|
38
|
+
import { ensureIndirect } from "./0.1.166-indirect";
|
|
38
39
|
import { migrateInit } from "./0.1.27-migrateInit";
|
|
39
40
|
import { tsToTsx } from "./0.1.28-tsToTsx";
|
|
40
41
|
import { ensureProjectIcons } from "./0.1.31-ensureProjectIcons";
|
|
@@ -64,6 +65,7 @@ export const MIGRATIONS: Record<string, MigrateConfigFunc> = {
|
|
|
64
65
|
"0.1.64": ensureImageFiles,
|
|
65
66
|
"0.1.95": ensureComponentType,
|
|
66
67
|
"0.1.146": ensureReactRuntime,
|
|
68
|
+
"0.1.166": ensureIndirect,
|
|
67
69
|
};
|
|
68
70
|
|
|
69
71
|
export const LOCK_MIGRATIONS: Record<string, MigrateLockFunc> = {
|
|
@@ -147,13 +147,18 @@ export const project1Config: ProjectConfig = {
|
|
|
147
147
|
icons: [],
|
|
148
148
|
images: [],
|
|
149
149
|
jsBundleThemes: [],
|
|
150
|
+
indirect: false,
|
|
150
151
|
};
|
|
151
152
|
|
|
152
|
-
export function expectProject1PlasmicJson(
|
|
153
|
+
export function expectProject1PlasmicJson(
|
|
154
|
+
optional?: { [k in keyof ProjectConfig]?: boolean }
|
|
155
|
+
) {
|
|
153
156
|
const plasmicJson = tmpRepo.readPlasmicJson();
|
|
154
157
|
expect(plasmicJson.projects.length).toEqual(1);
|
|
155
158
|
const projectConfig = plasmicJson.projects[0];
|
|
156
|
-
|
|
159
|
+
if (!optional?.projectApiToken) {
|
|
160
|
+
expect(projectConfig.projectApiToken).toBe("abc");
|
|
161
|
+
}
|
|
157
162
|
expect(projectConfig.components.length).toEqual(2);
|
|
158
163
|
const componentNames = projectConfig.components.map((c) => c.name);
|
|
159
164
|
expect(componentNames).toContain("Button");
|
|
@@ -171,6 +171,12 @@ export interface ProjectConfig {
|
|
|
171
171
|
icons: IconConfig[];
|
|
172
172
|
/** Metadata for each synced image in this project */
|
|
173
173
|
images: ImageConfig[];
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* True if the project was installed indirectly (as a dependency); if set,
|
|
177
|
+
* codegen will not generate pages.
|
|
178
|
+
*/
|
|
179
|
+
indirect: boolean;
|
|
174
180
|
}
|
|
175
181
|
|
|
176
182
|
export function createProjectConfig(base: {
|
|
@@ -179,6 +185,7 @@ export function createProjectConfig(base: {
|
|
|
179
185
|
projectName: string;
|
|
180
186
|
version: string;
|
|
181
187
|
cssFilePath: string;
|
|
188
|
+
indirect: boolean;
|
|
182
189
|
}): ProjectConfig {
|
|
183
190
|
return {
|
|
184
191
|
projectId: base.projectId,
|
|
@@ -189,6 +196,7 @@ export function createProjectConfig(base: {
|
|
|
189
196
|
components: [],
|
|
190
197
|
icons: [],
|
|
191
198
|
images: [],
|
|
199
|
+
indirect: base.indirect,
|
|
192
200
|
};
|
|
193
201
|
}
|
|
194
202
|
|
|
@@ -310,6 +318,8 @@ export interface ProjectLock {
|
|
|
310
318
|
lang: "ts" | "js";
|
|
311
319
|
// One for each file whose checksum is computed
|
|
312
320
|
fileLocks: FileLock[];
|
|
321
|
+
// The version of Codegen when this project was written
|
|
322
|
+
codegenVersion?: string;
|
|
313
323
|
}
|
|
314
324
|
|
|
315
325
|
export interface PlasmicLock {
|
|
@@ -519,6 +529,7 @@ export function getOrAddProjectConfig(
|
|
|
519
529
|
icons: [],
|
|
520
530
|
images: [],
|
|
521
531
|
jsBundleThemes: [],
|
|
532
|
+
indirect: false,
|
|
522
533
|
};
|
|
523
534
|
context.config.projects.push(project);
|
|
524
535
|
}
|
package/src/utils/npm-utils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import L from "lodash";
|
|
2
|
+
import { InvalidatedProjectKind } from "typescript";
|
|
2
3
|
import { SyncArgs } from "../actions/sync";
|
|
3
4
|
import { ProjectVersionMeta, VersionResolution } from "../api";
|
|
4
5
|
import { logger } from "../deps";
|
|
@@ -19,6 +20,7 @@ function walkDependencyTree(
|
|
|
19
20
|
root: ProjectVersionMeta,
|
|
20
21
|
available: ProjectVersionMeta[]
|
|
21
22
|
): ProjectVersionMeta[] {
|
|
23
|
+
root.indirect = false;
|
|
22
24
|
const queue: ProjectVersionMeta[] = [root];
|
|
23
25
|
const result: ProjectVersionMeta[] = [];
|
|
24
26
|
|
|
@@ -31,7 +33,10 @@ function walkDependencyTree(
|
|
|
31
33
|
`Cannot find projectId=${projectId}, version=${version} in the sync resolution results.`
|
|
32
34
|
);
|
|
33
35
|
}
|
|
34
|
-
return
|
|
36
|
+
return {
|
|
37
|
+
...meta,
|
|
38
|
+
indirect: meta.projectId !== root.projectId,
|
|
39
|
+
};
|
|
35
40
|
};
|
|
36
41
|
|
|
37
42
|
while (queue.length > 0) {
|
|
@@ -61,6 +66,22 @@ async function checkProjectMeta(
|
|
|
61
66
|
const projectId = meta.projectId;
|
|
62
67
|
const projectName = meta.projectName;
|
|
63
68
|
const newVersion = meta.version;
|
|
69
|
+
const indirect = meta.indirect;
|
|
70
|
+
|
|
71
|
+
// If the codegen version on-disk is invalid, we will sync again the project.
|
|
72
|
+
const checkCodegenVersion = async (): Promise<boolean> => {
|
|
73
|
+
const projectLock = context.lock.projects.find(
|
|
74
|
+
(p) => p.projectId === projectId
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
if (!!projectLock?.codegenVersion && semver.gte(projectLock.codegenVersion, await context.api.latestCodegenVersion())) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return true;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const isOnDiskCodeInvalid = await checkCodegenVersion();
|
|
64
85
|
|
|
65
86
|
// Checks newVersion against plasmic.lock
|
|
66
87
|
const checkVersionLock = async (): Promise<boolean> => {
|
|
@@ -81,9 +102,11 @@ async function checkProjectMeta(
|
|
|
81
102
|
) {
|
|
82
103
|
// If this is a dependency (not root), and we're dealing with latest dep version
|
|
83
104
|
// just skip, it's confusing
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
105
|
+
if (!isOnDiskCodeInvalid) {
|
|
106
|
+
logger.warn(
|
|
107
|
+
`'${root.projectName}' depends on ${projectName}@${newVersion}. To update this project, explicitly specify this project for sync. Skipping...`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
87
110
|
return false;
|
|
88
111
|
}
|
|
89
112
|
|
|
@@ -105,9 +128,11 @@ async function checkProjectMeta(
|
|
|
105
128
|
);
|
|
106
129
|
return true;
|
|
107
130
|
} else {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
131
|
+
if (!isOnDiskCodeInvalid) {
|
|
132
|
+
logger.info(
|
|
133
|
+
`Project '${projectName}'@${newVersion} is already up to date; skipping. (To force an update, run again with "--force")`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
111
136
|
return false;
|
|
112
137
|
}
|
|
113
138
|
}
|
|
@@ -177,6 +202,24 @@ async function checkProjectMeta(
|
|
|
177
202
|
);
|
|
178
203
|
};
|
|
179
204
|
|
|
205
|
+
const checkIndirect = async (): Promise<boolean> => {
|
|
206
|
+
const projectConfig = context.config.projects.find(
|
|
207
|
+
(p) => p.projectId === projectId
|
|
208
|
+
);
|
|
209
|
+
const configIndirect = projectConfig?.indirect;
|
|
210
|
+
if (configIndirect && !indirect) {
|
|
211
|
+
logger.warn(
|
|
212
|
+
`'${projectName}' was synced indirectly before, but a direct sync was requested. If it has page components, they will be synced and saved to plasmic.json.`
|
|
213
|
+
);
|
|
214
|
+
return await confirmWithUser(
|
|
215
|
+
"Do you want to confirm it?",
|
|
216
|
+
opts.force || opts.yes,
|
|
217
|
+
"n"
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
};
|
|
222
|
+
|
|
180
223
|
const projectIds =
|
|
181
224
|
opts.projects.length > 0
|
|
182
225
|
? opts.projects
|
|
@@ -187,8 +230,29 @@ async function checkProjectMeta(
|
|
|
187
230
|
// we should always sync it, even if nothing has changed
|
|
188
231
|
return true;
|
|
189
232
|
}
|
|
233
|
+
const checkedVersion =
|
|
234
|
+
(await checkVersionLock()) &&
|
|
235
|
+
(await checkVersionRange()) &&
|
|
236
|
+
(await checkIndirect());
|
|
190
237
|
|
|
191
|
-
|
|
238
|
+
if(!checkedVersion && isOnDiskCodeInvalid) {
|
|
239
|
+
// sync, but try to keep the current version on disk
|
|
240
|
+
const projectLock = context.lock.projects.find(
|
|
241
|
+
(p) => p.projectId === projectId
|
|
242
|
+
);
|
|
243
|
+
const versionOnDisk = projectLock?.version;
|
|
244
|
+
logger.warn(
|
|
245
|
+
`Project '${projectName}' was synced by an incompatible version of Plasmic Codegen. Syncing again on the same version ${projectName}@${versionOnDisk}`
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
meta.version = versionOnDisk ?? meta.version;
|
|
249
|
+
return true;
|
|
250
|
+
} else if (checkedVersion) {
|
|
251
|
+
// sync and upgrade the version
|
|
252
|
+
return true;
|
|
253
|
+
} else {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
192
256
|
}
|
|
193
257
|
|
|
194
258
|
/**
|
|
@@ -216,12 +280,16 @@ export async function checkVersionResolution(
|
|
|
216
280
|
? [root]
|
|
217
281
|
: walkDependencyTree(root, versionResolution.dependencies).reverse();
|
|
218
282
|
for (const m of queue) {
|
|
219
|
-
// If we haven't seen this yet
|
|
220
283
|
if (!seen.find((p) => p.projectId === m.projectId)) {
|
|
221
284
|
if (await checkProjectMeta(m, root, context, opts)) {
|
|
222
285
|
result.push(m);
|
|
223
286
|
}
|
|
224
287
|
seen.push(m);
|
|
288
|
+
} else if (root.projectId === m.projectId) {
|
|
289
|
+
// If m is the root project and it was already seen (maybe as a dep
|
|
290
|
+
// for another project), set indirect = false.
|
|
291
|
+
const project = ensure(seen.find((p) => p.projectId === m.projectId));
|
|
292
|
+
project.indirect = false;
|
|
225
293
|
}
|
|
226
294
|
}
|
|
227
295
|
}
|