@plasmicapp/cli 0.1.163 → 0.1.167
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 +3 -1
- package/dist/__tests__/project-api-token-spec.js +4 -4
- package/dist/actions/sync.js +47 -12
- package/dist/api.d.ts +4 -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 +6 -0
- package/dist/utils/config-utils.js +2 -0
- package/dist/utils/npm-utils.d.ts +2 -2
- package/dist/utils/npm-utils.js +30 -8
- package/dist/utils/resolve-utils.js +21 -3
- package/package.json +4 -2
- package/src/__mocks__/api.ts +3 -0
- package/src/__tests__/project-api-token-spec.ts +8 -4
- package/src/actions/sync.ts +78 -13
- package/src/api.ts +4 -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 +9 -0
- package/src/utils/npm-utils.ts +38 -8
- package/src/utils/resolve-utils.ts +35 -3
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
|
});
|
|
@@ -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
|
@@ -82,14 +82,14 @@ function ensureRequiredPackages(context, baseDir, yes) {
|
|
|
82
82
|
// Exit so the user can run again with the new cli
|
|
83
83
|
throw new error_1.HandledError();
|
|
84
84
|
}
|
|
85
|
-
const reactWebVersion = npm_utils_1.findInstalledVersion(context, "@plasmicapp/react-web");
|
|
85
|
+
const reactWebVersion = npm_utils_1.findInstalledVersion(context, baseDir, "@plasmicapp/react-web");
|
|
86
86
|
if (!reactWebVersion ||
|
|
87
87
|
semver.gt(requireds["@plasmicapp/react-web"], reactWebVersion)) {
|
|
88
88
|
yield confirmInstall("@plasmicapp/react-web", requireds["@plasmicapp/react-web"], { global: false, dev: false });
|
|
89
89
|
}
|
|
90
90
|
if (context.config.code.reactRuntime === "automatic") {
|
|
91
91
|
// Using automatic runtime requires installing the @plasmicapp/react-web-runtime package
|
|
92
|
-
const runtimeVersion = npm_utils_1.findInstalledVersion(context, "@plasmicapp/react-web-runtime");
|
|
92
|
+
const runtimeVersion = npm_utils_1.findInstalledVersion(context, baseDir, "@plasmicapp/react-web-runtime");
|
|
93
93
|
if (!runtimeVersion ||
|
|
94
94
|
semver.gt(requireds["@plasmicapp/react-web-runtime"], runtimeVersion)) {
|
|
95
95
|
yield confirmInstall("@plasmicapp/react-web-runtime", requireds["@plasmicapp/react-web-runtime"], { global: false, dev: false });
|
|
@@ -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);
|
|
@@ -247,6 +260,13 @@ function sync(opts, metadataDefaults) {
|
|
|
247
260
|
// Write the new ComponentConfigs to disk
|
|
248
261
|
yield config_utils_1.updateConfig(context, context.config, baseDir);
|
|
249
262
|
}));
|
|
263
|
+
yield checkExternalPkgs(context, baseDir, opts, Array.from(externalNpmPackages.keys()));
|
|
264
|
+
if (!opts.quiet && externalCssImports.size > 0) {
|
|
265
|
+
deps_1.logger.info(`This project uses external packages and styles. Make sure to import the following global CSS: ` +
|
|
266
|
+
Array.from(externalCssImports.keys())
|
|
267
|
+
.map((stmt) => `"${stmt}"`)
|
|
268
|
+
.join(", "));
|
|
269
|
+
}
|
|
250
270
|
// Post-sync commands
|
|
251
271
|
if (!opts.ignorePostSync) {
|
|
252
272
|
for (const cmd of context.config.postSyncCommands || []) {
|
|
@@ -261,6 +281,20 @@ function sync(opts, metadataDefaults) {
|
|
|
261
281
|
});
|
|
262
282
|
}
|
|
263
283
|
exports.sync = sync;
|
|
284
|
+
function checkExternalPkgs(context, baseDir, opts, pkgs) {
|
|
285
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
286
|
+
const missingPkgs = pkgs.filter((pkg) => {
|
|
287
|
+
const installedPkg = npm_utils_1.findInstalledVersion(context, baseDir, pkg);
|
|
288
|
+
return !installedPkg;
|
|
289
|
+
});
|
|
290
|
+
if (missingPkgs.length > 0) {
|
|
291
|
+
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);
|
|
292
|
+
if (upgrade) {
|
|
293
|
+
npm_utils_1.installUpgrade(missingPkgs.join(" "), baseDir);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
}
|
|
264
298
|
function maybeRenamePathExt(context, path, ext) {
|
|
265
299
|
if (!path) {
|
|
266
300
|
return path;
|
|
@@ -281,7 +315,7 @@ function fixFileExtension(context) {
|
|
|
281
315
|
});
|
|
282
316
|
});
|
|
283
317
|
}
|
|
284
|
-
function syncProject(context, opts, projectIdsAndTokens, projectId, componentIds, projectVersion, dependencies, summary, pendingMerge, metadataDefaults) {
|
|
318
|
+
function syncProject(context, opts, projectIdsAndTokens, projectId, componentIds, projectVersion, dependencies, summary, pendingMerge, indirect, externalNpmPackages, externalCssImports, metadataDefaults) {
|
|
285
319
|
var _a;
|
|
286
320
|
return __awaiter(this, void 0, void 0, function* () {
|
|
287
321
|
const newComponentScheme = opts.newComponentScheme || context.config.code.scheme;
|
|
@@ -301,6 +335,7 @@ function syncProject(context, opts, projectIdsAndTokens, projectId, componentIds
|
|
|
301
335
|
checksums: existingChecksums,
|
|
302
336
|
codeOpts: context.config.code,
|
|
303
337
|
metadata: get_context_1.generateMetadata(Object.assign(Object.assign({}, metadataDefaults), { platform: context.config.platform }), opts.metadata),
|
|
338
|
+
indirect,
|
|
304
339
|
});
|
|
305
340
|
// Convert from TSX => JSX
|
|
306
341
|
if (context.config.code.lang === "js") {
|
|
@@ -319,11 +354,13 @@ function syncProject(context, opts, projectIdsAndTokens, projectId, componentIds
|
|
|
319
354
|
});
|
|
320
355
|
}
|
|
321
356
|
yield sync_global_variants_1.syncGlobalVariants(context, projectBundle.projectConfig, projectBundle.globalVariants, projectBundle.checksums, opts.baseDir);
|
|
357
|
+
yield syncProjectConfig(context, projectBundle.projectConfig, projectApiToken, projectVersion, dependencies, projectBundle.components, opts.forceOverwrite, !!opts.appendJsxOnMissingBase, summary, pendingMerge, projectBundle.checksums, opts.baseDir, indirect);
|
|
322
358
|
syncCodeComponentsMeta(context, projectId, projectBundle.codeComponentMetas);
|
|
323
|
-
yield syncProjectConfig(context, projectBundle.projectConfig, projectApiToken, projectVersion, dependencies, projectBundle.components, opts.forceOverwrite, !!opts.appendJsxOnMissingBase, summary, pendingMerge, projectBundle.checksums, opts.baseDir);
|
|
324
359
|
yield sync_styles_1.upsertStyleTokens(context, projectBundle.usedTokens);
|
|
325
360
|
yield sync_icons_1.syncProjectIconAssets(context, projectId, projectVersion, projectBundle.iconAssets, projectBundle.checksums, opts.baseDir);
|
|
326
361
|
yield sync_images_1.syncProjectImageAssets(context, projectId, projectVersion, projectBundle.imageAssets, projectBundle.checksums);
|
|
362
|
+
(projectBundle.usedNpmPackages || []).forEach((pkg) => externalNpmPackages.add(pkg));
|
|
363
|
+
(projectBundle.externalCssImports || []).forEach((css) => externalCssImports.add(css));
|
|
327
364
|
});
|
|
328
365
|
}
|
|
329
366
|
function syncStyleConfig(context, response) {
|
|
@@ -336,25 +373,23 @@ function syncStyleConfig(context, response) {
|
|
|
336
373
|
});
|
|
337
374
|
});
|
|
338
375
|
}
|
|
339
|
-
function syncProjectConfig(context, projectBundle, projectApiToken, version, dependencies, componentBundles, forceOverwrite, appendJsxOnMissingBase, summary, pendingMerge, checksums, baseDir) {
|
|
376
|
+
function syncProjectConfig(context, projectBundle, projectApiToken, version, dependencies, componentBundles, forceOverwrite, appendJsxOnMissingBase, summary, pendingMerge, checksums, baseDir, indirect) {
|
|
340
377
|
return __awaiter(this, void 0, void 0, function* () {
|
|
341
378
|
const defaultCssFilePath = file_utils_1.defaultResourcePath(context, projectBundle.projectName, projectBundle.cssFileName);
|
|
342
379
|
const isNew = !context.config.projects.find((p) => p.projectId === projectBundle.projectId);
|
|
343
|
-
// If latest, use that as the range, otherwise set to latest published (>=0.0.0)
|
|
344
|
-
const versionRange = semver.isLatest(version) ? version : ">=0.0.0";
|
|
345
380
|
const projectConfig = config_utils_1.getOrAddProjectConfig(context, projectBundle.projectId, config_utils_1.createProjectConfig({
|
|
346
381
|
projectId: projectBundle.projectId,
|
|
347
382
|
projectApiToken,
|
|
348
383
|
projectName: projectBundle.projectName,
|
|
349
|
-
version
|
|
384
|
+
version,
|
|
350
385
|
cssFilePath: defaultCssFilePath,
|
|
386
|
+
indirect,
|
|
351
387
|
}));
|
|
352
388
|
// Update missing/outdated props
|
|
353
389
|
projectConfig.projectName = projectBundle.projectName;
|
|
354
390
|
if (!projectConfig.cssFilePath) {
|
|
355
391
|
projectConfig.cssFilePath = defaultCssFilePath;
|
|
356
392
|
}
|
|
357
|
-
projectConfig.projectApiToken = projectApiToken;
|
|
358
393
|
// plasmic.lock
|
|
359
394
|
const projectLock = config_utils_1.getOrAddProjectLock(context, projectConfig.projectId);
|
|
360
395
|
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 {
|
|
@@ -165,6 +168,7 @@ export declare class PlasmicApi {
|
|
|
165
168
|
stylesOpts: StyleConfig;
|
|
166
169
|
codeOpts: CodeConfig;
|
|
167
170
|
checksums: ChecksumBundle;
|
|
171
|
+
indirect: boolean;
|
|
168
172
|
metadata?: Metadata;
|
|
169
173
|
}): Promise<ProjectBundle>;
|
|
170
174
|
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>;
|
|
@@ -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";
|
|
@@ -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
|
}
|
|
@@ -10,7 +10,7 @@ export declare function warnLatest(context: PlasmicContext, pkg: string, baseDir
|
|
|
10
10
|
requiredMsg: () => string;
|
|
11
11
|
updateMsg: (curVersion: string, latestVersion: string) => string;
|
|
12
12
|
}, yes?: boolean): Promise<void>;
|
|
13
|
-
export declare function findInstalledVersion(context: PlasmicContext, pkg: string):
|
|
13
|
+
export declare function findInstalledVersion(context: PlasmicContext, baseDir: string, pkg: string): any;
|
|
14
14
|
/**
|
|
15
15
|
* Detects if the cli is globally installed. `rootDir` is the folder
|
|
16
16
|
* where plasmic.json is
|
|
@@ -25,4 +25,4 @@ export declare function installCommand(pkg: string, baseDir: string, opts?: {
|
|
|
25
25
|
global?: boolean;
|
|
26
26
|
dev?: boolean;
|
|
27
27
|
}): string;
|
|
28
|
-
export declare function detectPackageManager(baseDir: string): "yarn" | "npm";
|
|
28
|
+
export declare function detectPackageManager(baseDir: string): "yarn2" | "yarn" | "npm";
|
package/dist/utils/npm-utils.js
CHANGED
|
@@ -60,7 +60,7 @@ exports.getParsedPackageJson = getParsedPackageJson;
|
|
|
60
60
|
// @TODO: is this function still used?
|
|
61
61
|
function warnLatest(context, pkg, baseDir, msgs, yes) {
|
|
62
62
|
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
-
const check = yield checkVersion(context, pkg);
|
|
63
|
+
const check = yield checkVersion(context, baseDir, pkg);
|
|
64
64
|
if (check.type === "up-to-date") {
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
@@ -76,7 +76,7 @@ function warnLatest(context, pkg, baseDir, msgs, yes) {
|
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
exports.warnLatest = warnLatest;
|
|
79
|
-
function checkVersion(context, pkg) {
|
|
79
|
+
function checkVersion(context, baseDir, pkg) {
|
|
80
80
|
return __awaiter(this, void 0, void 0, function* () {
|
|
81
81
|
// Try to get the latest version from npm
|
|
82
82
|
let last = null;
|
|
@@ -87,7 +87,7 @@ function checkVersion(context, pkg) {
|
|
|
87
87
|
// This is likely because .npmrc is set to a different registry
|
|
88
88
|
return { type: "wrong-npm-registry" };
|
|
89
89
|
}
|
|
90
|
-
const cur = findInstalledVersion(context, pkg);
|
|
90
|
+
const cur = findInstalledVersion(context, baseDir, pkg);
|
|
91
91
|
if (!cur) {
|
|
92
92
|
return { type: "not-installed" };
|
|
93
93
|
}
|
|
@@ -101,7 +101,18 @@ function checkVersion(context, pkg) {
|
|
|
101
101
|
return { type: "up-to-date" };
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
|
-
function findInstalledVersion(context, pkg) {
|
|
104
|
+
function findInstalledVersion(context, baseDir, pkg) {
|
|
105
|
+
var _a;
|
|
106
|
+
const pm = detectPackageManager(baseDir);
|
|
107
|
+
if (pm === "yarn2") {
|
|
108
|
+
try {
|
|
109
|
+
const pkgInfo = JSON.parse(child_process_1.execSync(`yarn info --json ${pkg}`).toString().trim());
|
|
110
|
+
return (_a = pkgInfo === null || pkgInfo === void 0 ? void 0 : pkgInfo.children) === null || _a === void 0 ? void 0 : _a.Version;
|
|
111
|
+
}
|
|
112
|
+
catch (_) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
105
116
|
const filename = findInstalledPackageJsonFile(context, pkg);
|
|
106
117
|
if (filename) {
|
|
107
118
|
const json = parsePackageJson(filename);
|
|
@@ -190,6 +201,18 @@ function installCommand(pkg, baseDir, opts = {}) {
|
|
|
190
201
|
return `yarn add --ignore-scripts -W ${pkg}`;
|
|
191
202
|
}
|
|
192
203
|
}
|
|
204
|
+
else if (mgr === "yarn2") {
|
|
205
|
+
if (opts.global) {
|
|
206
|
+
// yarn2 does not support global.
|
|
207
|
+
return `npm install -g ${pkg}`;
|
|
208
|
+
}
|
|
209
|
+
else if (opts.dev) {
|
|
210
|
+
return `yarn add -D ${pkg}`;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
return `yarn add ${pkg}`;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
193
216
|
else {
|
|
194
217
|
if (opts.global) {
|
|
195
218
|
return `npm install -g ${pkg}`;
|
|
@@ -206,10 +229,9 @@ exports.installCommand = installCommand;
|
|
|
206
229
|
function detectPackageManager(baseDir) {
|
|
207
230
|
const yarnLock = findup_sync_1.default("yarn.lock", { cwd: baseDir });
|
|
208
231
|
if (yarnLock) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
else {
|
|
212
|
-
return "npm";
|
|
232
|
+
const yarnVersion = child_process_1.execSync(`yarn --version`).toString().trim();
|
|
233
|
+
return semver_1.default.gte(yarnVersion, "2.0.0") ? "yarn2" : "yarn";
|
|
213
234
|
}
|
|
235
|
+
return "npm";
|
|
214
236
|
}
|
|
215
237
|
exports.detectPackageManager = detectPackageManager;
|
|
@@ -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,7 @@ 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;
|
|
76
78
|
// Checks newVersion against plasmic.lock
|
|
77
79
|
const checkVersionLock = () => __awaiter(this, void 0, void 0, function* () {
|
|
78
80
|
const projectLock = context.lock.projects.find((p) => p.projectId === projectId);
|
|
@@ -145,6 +147,15 @@ function checkProjectMeta(meta, root, context, opts) {
|
|
|
145
147
|
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
148
|
return yield user_utils_1.confirmWithUser("Do you want to force it?", opts.force || opts.yes, "n");
|
|
147
149
|
});
|
|
150
|
+
const checkIndirect = () => __awaiter(this, void 0, void 0, function* () {
|
|
151
|
+
const projectConfig = context.config.projects.find((p) => p.projectId === projectId);
|
|
152
|
+
const configIndirect = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.indirect;
|
|
153
|
+
if (configIndirect && !indirect) {
|
|
154
|
+
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.`);
|
|
155
|
+
return yield user_utils_1.confirmWithUser("Do you want to confirm it?", opts.force || opts.yes, "n");
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
});
|
|
148
159
|
const projectIds = opts.projects.length > 0
|
|
149
160
|
? opts.projects
|
|
150
161
|
: context.config.projects.map((p) => p.projectId);
|
|
@@ -153,7 +164,9 @@ function checkProjectMeta(meta, root, context, opts) {
|
|
|
153
164
|
// we should always sync it, even if nothing has changed
|
|
154
165
|
return true;
|
|
155
166
|
}
|
|
156
|
-
return (yield checkVersionLock()) &&
|
|
167
|
+
return ((yield checkVersionLock()) &&
|
|
168
|
+
(yield checkVersionRange()) &&
|
|
169
|
+
(yield checkIndirect()));
|
|
157
170
|
});
|
|
158
171
|
}
|
|
159
172
|
/**
|
|
@@ -175,13 +188,18 @@ function checkVersionResolution(versionResolution, context, opts) {
|
|
|
175
188
|
? [root]
|
|
176
189
|
: walkDependencyTree(root, versionResolution.dependencies).reverse();
|
|
177
190
|
for (const m of queue) {
|
|
178
|
-
// If we haven't seen this yet
|
|
179
191
|
if (!seen.find((p) => p.projectId === m.projectId)) {
|
|
180
192
|
if (yield checkProjectMeta(m, root, context, opts)) {
|
|
181
193
|
result.push(m);
|
|
182
194
|
}
|
|
183
195
|
seen.push(m);
|
|
184
196
|
}
|
|
197
|
+
else if (root.projectId === m.projectId) {
|
|
198
|
+
// If m is the root project and it was already seen (maybe as a dep
|
|
199
|
+
// for another project), set indirect = false.
|
|
200
|
+
const project = lang_utils_1.ensure(seen.find((p) => p.projectId === m.projectId));
|
|
201
|
+
project.indirect = false;
|
|
202
|
+
}
|
|
185
203
|
}
|
|
186
204
|
}
|
|
187
205
|
// Ignore repeats
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plasmicapp/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.167",
|
|
4
4
|
"description": "plasmic cli for syncing local code with Plasmic designs",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=12"
|
|
@@ -49,7 +49,9 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@babel/core": "^7.12.3",
|
|
51
51
|
"@babel/generator": "^7.12.1",
|
|
52
|
-
"@
|
|
52
|
+
"@babel/parser": "^7.12.3",
|
|
53
|
+
"@babel/traverse": "^7.12.1",
|
|
54
|
+
"@plasmicapp/code-merger": "^0.0.33",
|
|
53
55
|
"@sentry/node": "^5.19.2",
|
|
54
56
|
"@types/socket.io-client": "^1.4.34",
|
|
55
57
|
"axios": "^0.21.1",
|
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
|
}
|
|
@@ -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
|
@@ -128,6 +128,7 @@ async function ensureRequiredPackages(
|
|
|
128
128
|
|
|
129
129
|
const reactWebVersion = findInstalledVersion(
|
|
130
130
|
context,
|
|
131
|
+
baseDir,
|
|
131
132
|
"@plasmicapp/react-web"
|
|
132
133
|
);
|
|
133
134
|
if (
|
|
@@ -145,6 +146,7 @@ async function ensureRequiredPackages(
|
|
|
145
146
|
// Using automatic runtime requires installing the @plasmicapp/react-web-runtime package
|
|
146
147
|
const runtimeVersion = findInstalledVersion(
|
|
147
148
|
context,
|
|
149
|
+
baseDir,
|
|
148
150
|
"@plasmicapp/react-web-runtime"
|
|
149
151
|
);
|
|
150
152
|
if (
|
|
@@ -232,6 +234,7 @@ export async function sync(
|
|
|
232
234
|
versionRange || projectConfigMap[projectId]?.version || "latest",
|
|
233
235
|
componentIdOrNames: undefined, // Get all components!
|
|
234
236
|
projectApiToken: projectApiToken || projectIdToToken.get(projectId),
|
|
237
|
+
indirect: false,
|
|
235
238
|
};
|
|
236
239
|
});
|
|
237
240
|
|
|
@@ -242,6 +245,7 @@ export async function sync(
|
|
|
242
245
|
versionRange: p.version,
|
|
243
246
|
componentIdOrNames: undefined, // Get all components!
|
|
244
247
|
projectApiToken: p.projectApiToken,
|
|
248
|
+
indirect: !!p.indirect,
|
|
245
249
|
}));
|
|
246
250
|
|
|
247
251
|
// Short-circuit if nothing to sync
|
|
@@ -257,7 +261,7 @@ export async function sync(
|
|
|
257
261
|
try {
|
|
258
262
|
context = await getContext(opts);
|
|
259
263
|
} catch (e) {
|
|
260
|
-
if (e.message.includes("Unable to authenticate Plasmic")) {
|
|
264
|
+
if ((e as any).message.includes("Unable to authenticate Plasmic")) {
|
|
261
265
|
const configFileName = process.env.PLASMIC_LOADER
|
|
262
266
|
? LOADER_CONFIG_FILE_NAME
|
|
263
267
|
: CONFIG_FILE_NAME;
|
|
@@ -311,6 +315,8 @@ export async function sync(
|
|
|
311
315
|
].map((p) => L.pick(p, "projectId", "projectApiToken"));
|
|
312
316
|
|
|
313
317
|
context.api.attachProjectIdsAndTokens(projectIdsAndTokens);
|
|
318
|
+
const externalNpmPackages = new Set<string>();
|
|
319
|
+
const externalCssImports = new Set<string>();
|
|
314
320
|
|
|
315
321
|
// Perform the actual sync
|
|
316
322
|
await withBufferedFs(async () => {
|
|
@@ -327,6 +333,9 @@ export async function sync(
|
|
|
327
333
|
projectMeta.dependencies,
|
|
328
334
|
summary,
|
|
329
335
|
pendingMerge,
|
|
336
|
+
projectMeta.indirect,
|
|
337
|
+
externalNpmPackages,
|
|
338
|
+
externalCssImports,
|
|
330
339
|
metadataDefaults
|
|
331
340
|
);
|
|
332
341
|
}
|
|
@@ -345,15 +354,22 @@ export async function sync(
|
|
|
345
354
|
await context.api.genStyleConfig(context.config.style)
|
|
346
355
|
);
|
|
347
356
|
|
|
348
|
-
// Update project version if specified and
|
|
357
|
+
// Update project version and indirect status if specified and
|
|
358
|
+
// successfully synced.
|
|
349
359
|
if (projectWithVersion.length) {
|
|
350
360
|
const versionMap: Record<string, string> = {};
|
|
351
361
|
projectWithVersion.forEach(
|
|
352
362
|
(p) => (versionMap[p.projectId] = p.versionRange)
|
|
353
363
|
);
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
)
|
|
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
|
+
});
|
|
357
373
|
}
|
|
358
374
|
|
|
359
375
|
// Fix imports
|
|
@@ -404,6 +420,22 @@ export async function sync(
|
|
|
404
420
|
await updateConfig(context, context.config, baseDir);
|
|
405
421
|
});
|
|
406
422
|
|
|
423
|
+
await checkExternalPkgs(
|
|
424
|
+
context,
|
|
425
|
+
baseDir,
|
|
426
|
+
opts,
|
|
427
|
+
Array.from(externalNpmPackages.keys())
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
if (!opts.quiet && externalCssImports.size > 0) {
|
|
431
|
+
logger.info(
|
|
432
|
+
`This project uses external packages and styles. Make sure to import the following global CSS: ` +
|
|
433
|
+
Array.from(externalCssImports.keys())
|
|
434
|
+
.map((stmt) => `"${stmt}"`)
|
|
435
|
+
.join(", ")
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
|
|
407
439
|
// Post-sync commands
|
|
408
440
|
if (!opts.ignorePostSync) {
|
|
409
441
|
for (const cmd of context.config.postSyncCommands || []) {
|
|
@@ -418,6 +450,30 @@ export async function sync(
|
|
|
418
450
|
}
|
|
419
451
|
}
|
|
420
452
|
|
|
453
|
+
async function checkExternalPkgs(
|
|
454
|
+
context: PlasmicContext,
|
|
455
|
+
baseDir: string,
|
|
456
|
+
opts: SyncArgs,
|
|
457
|
+
pkgs: string[]
|
|
458
|
+
) {
|
|
459
|
+
const missingPkgs = pkgs.filter((pkg) => {
|
|
460
|
+
const installedPkg = findInstalledVersion(context, baseDir, pkg);
|
|
461
|
+
return !installedPkg;
|
|
462
|
+
});
|
|
463
|
+
if (missingPkgs.length > 0) {
|
|
464
|
+
const upgrade = await confirmWithUser(
|
|
465
|
+
`The following packages aren't installed but are required by some projects, would you like to install them? ${missingPkgs.join(
|
|
466
|
+
", "
|
|
467
|
+
)}`,
|
|
468
|
+
opts.yes
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
if (upgrade) {
|
|
472
|
+
installUpgrade(missingPkgs.join(" "), baseDir);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
421
477
|
function maybeRenamePathExt(
|
|
422
478
|
context: PlasmicContext,
|
|
423
479
|
path: string,
|
|
@@ -467,6 +523,9 @@ async function syncProject(
|
|
|
467
523
|
dependencies: { [projectId: string]: string },
|
|
468
524
|
summary: Map<string, ComponentUpdateSummary>,
|
|
469
525
|
pendingMerge: ComponentPendingMerge[],
|
|
526
|
+
indirect: boolean,
|
|
527
|
+
externalNpmPackages: Set<string>,
|
|
528
|
+
externalCssImports: Set<string>,
|
|
470
529
|
metadataDefaults?: Metadata
|
|
471
530
|
): Promise<void> {
|
|
472
531
|
const newComponentScheme =
|
|
@@ -510,6 +569,7 @@ async function syncProject(
|
|
|
510
569
|
},
|
|
511
570
|
opts.metadata
|
|
512
571
|
),
|
|
572
|
+
indirect,
|
|
513
573
|
});
|
|
514
574
|
|
|
515
575
|
// Convert from TSX => JSX
|
|
@@ -556,8 +616,6 @@ async function syncProject(
|
|
|
556
616
|
opts.baseDir
|
|
557
617
|
);
|
|
558
618
|
|
|
559
|
-
syncCodeComponentsMeta(context, projectId, projectBundle.codeComponentMetas);
|
|
560
|
-
|
|
561
619
|
await syncProjectConfig(
|
|
562
620
|
context,
|
|
563
621
|
projectBundle.projectConfig,
|
|
@@ -570,8 +628,10 @@ async function syncProject(
|
|
|
570
628
|
summary,
|
|
571
629
|
pendingMerge,
|
|
572
630
|
projectBundle.checksums,
|
|
573
|
-
opts.baseDir
|
|
631
|
+
opts.baseDir,
|
|
632
|
+
indirect
|
|
574
633
|
);
|
|
634
|
+
syncCodeComponentsMeta(context, projectId, projectBundle.codeComponentMetas);
|
|
575
635
|
await upsertStyleTokens(context, projectBundle.usedTokens);
|
|
576
636
|
await syncProjectIconAssets(
|
|
577
637
|
context,
|
|
@@ -588,6 +648,12 @@ async function syncProject(
|
|
|
588
648
|
projectBundle.imageAssets,
|
|
589
649
|
projectBundle.checksums
|
|
590
650
|
);
|
|
651
|
+
(projectBundle.usedNpmPackages || []).forEach((pkg) =>
|
|
652
|
+
externalNpmPackages.add(pkg)
|
|
653
|
+
);
|
|
654
|
+
(projectBundle.externalCssImports || []).forEach((css) =>
|
|
655
|
+
externalCssImports.add(css)
|
|
656
|
+
);
|
|
591
657
|
}
|
|
592
658
|
|
|
593
659
|
async function syncStyleConfig(
|
|
@@ -618,7 +684,8 @@ async function syncProjectConfig(
|
|
|
618
684
|
summary: Map<string, ComponentUpdateSummary>,
|
|
619
685
|
pendingMerge: ComponentPendingMerge[],
|
|
620
686
|
checksums: ChecksumBundle,
|
|
621
|
-
baseDir: string
|
|
687
|
+
baseDir: string,
|
|
688
|
+
indirect: boolean
|
|
622
689
|
) {
|
|
623
690
|
const defaultCssFilePath = defaultResourcePath(
|
|
624
691
|
context,
|
|
@@ -629,8 +696,6 @@ async function syncProjectConfig(
|
|
|
629
696
|
(p) => p.projectId === projectBundle.projectId
|
|
630
697
|
);
|
|
631
698
|
|
|
632
|
-
// If latest, use that as the range, otherwise set to latest published (>=0.0.0)
|
|
633
|
-
const versionRange = semver.isLatest(version) ? version : ">=0.0.0";
|
|
634
699
|
const projectConfig = getOrAddProjectConfig(
|
|
635
700
|
context,
|
|
636
701
|
projectBundle.projectId,
|
|
@@ -638,8 +703,9 @@ async function syncProjectConfig(
|
|
|
638
703
|
projectId: projectBundle.projectId,
|
|
639
704
|
projectApiToken,
|
|
640
705
|
projectName: projectBundle.projectName,
|
|
641
|
-
version
|
|
706
|
+
version,
|
|
642
707
|
cssFilePath: defaultCssFilePath,
|
|
708
|
+
indirect,
|
|
643
709
|
})
|
|
644
710
|
);
|
|
645
711
|
|
|
@@ -648,7 +714,6 @@ async function syncProjectConfig(
|
|
|
648
714
|
if (!projectConfig.cssFilePath) {
|
|
649
715
|
projectConfig.cssFilePath = defaultCssFilePath;
|
|
650
716
|
}
|
|
651
|
-
projectConfig.projectApiToken = projectApiToken;
|
|
652
717
|
|
|
653
718
|
// plasmic.lock
|
|
654
719
|
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">;
|
|
@@ -235,6 +238,7 @@ export class PlasmicApi {
|
|
|
235
238
|
stylesOpts: StyleConfig;
|
|
236
239
|
codeOpts: CodeConfig;
|
|
237
240
|
checksums: ChecksumBundle;
|
|
241
|
+
indirect: boolean;
|
|
238
242
|
metadata?: Metadata;
|
|
239
243
|
}
|
|
240
244
|
): 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
|
|
|
@@ -519,6 +527,7 @@ export function getOrAddProjectConfig(
|
|
|
519
527
|
icons: [],
|
|
520
528
|
images: [],
|
|
521
529
|
jsBundleThemes: [],
|
|
530
|
+
indirect: false,
|
|
522
531
|
};
|
|
523
532
|
context.config.projects.push(project);
|
|
524
533
|
}
|
package/src/utils/npm-utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spawnSync } from "child_process";
|
|
1
|
+
import { execSync, spawnSync } from "child_process";
|
|
2
2
|
import glob from "fast-glob";
|
|
3
3
|
import findupSync from "findup-sync";
|
|
4
4
|
import latest from "latest-version";
|
|
@@ -54,7 +54,7 @@ export async function warnLatest(
|
|
|
54
54
|
},
|
|
55
55
|
yes?: boolean
|
|
56
56
|
) {
|
|
57
|
-
const check = await checkVersion(context, pkg);
|
|
57
|
+
const check = await checkVersion(context, baseDir, pkg);
|
|
58
58
|
if (check.type === "up-to-date") {
|
|
59
59
|
return;
|
|
60
60
|
} else if (check.type === "wrong-npm-registry") {
|
|
@@ -80,7 +80,11 @@ export async function warnLatest(
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
async function checkVersion(
|
|
83
|
+
async function checkVersion(
|
|
84
|
+
context: PlasmicContext,
|
|
85
|
+
baseDir: string,
|
|
86
|
+
pkg: string
|
|
87
|
+
) {
|
|
84
88
|
// Try to get the latest version from npm
|
|
85
89
|
let last = null;
|
|
86
90
|
try {
|
|
@@ -90,7 +94,7 @@ async function checkVersion(context: PlasmicContext, pkg: string) {
|
|
|
90
94
|
return { type: "wrong-npm-registry" } as const;
|
|
91
95
|
}
|
|
92
96
|
|
|
93
|
-
const cur = findInstalledVersion(context, pkg);
|
|
97
|
+
const cur = findInstalledVersion(context, baseDir, pkg);
|
|
94
98
|
if (!cur) {
|
|
95
99
|
return { type: "not-installed" } as const;
|
|
96
100
|
}
|
|
@@ -104,7 +108,23 @@ async function checkVersion(context: PlasmicContext, pkg: string) {
|
|
|
104
108
|
return { type: "up-to-date" } as const;
|
|
105
109
|
}
|
|
106
110
|
|
|
107
|
-
export function findInstalledVersion(
|
|
111
|
+
export function findInstalledVersion(
|
|
112
|
+
context: PlasmicContext,
|
|
113
|
+
baseDir: string,
|
|
114
|
+
pkg: string
|
|
115
|
+
) {
|
|
116
|
+
const pm = detectPackageManager(baseDir);
|
|
117
|
+
if (pm === "yarn2") {
|
|
118
|
+
try {
|
|
119
|
+
const pkgInfo = JSON.parse(
|
|
120
|
+
execSync(`yarn info --json ${pkg}`).toString().trim()
|
|
121
|
+
);
|
|
122
|
+
return pkgInfo?.children?.Version;
|
|
123
|
+
} catch (_) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
108
128
|
const filename = findInstalledPackageJsonFile(context, pkg);
|
|
109
129
|
if (filename) {
|
|
110
130
|
const json = parsePackageJson(filename);
|
|
@@ -202,6 +222,15 @@ export function installCommand(
|
|
|
202
222
|
} else {
|
|
203
223
|
return `yarn add --ignore-scripts -W ${pkg}`;
|
|
204
224
|
}
|
|
225
|
+
} else if (mgr === "yarn2") {
|
|
226
|
+
if (opts.global) {
|
|
227
|
+
// yarn2 does not support global.
|
|
228
|
+
return `npm install -g ${pkg}`;
|
|
229
|
+
} else if (opts.dev) {
|
|
230
|
+
return `yarn add -D ${pkg}`;
|
|
231
|
+
} else {
|
|
232
|
+
return `yarn add ${pkg}`;
|
|
233
|
+
}
|
|
205
234
|
} else {
|
|
206
235
|
if (opts.global) {
|
|
207
236
|
return `npm install -g ${pkg}`;
|
|
@@ -216,8 +245,9 @@ export function installCommand(
|
|
|
216
245
|
export function detectPackageManager(baseDir: string) {
|
|
217
246
|
const yarnLock = findupSync("yarn.lock", { cwd: baseDir });
|
|
218
247
|
if (yarnLock) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
return "npm";
|
|
248
|
+
const yarnVersion = execSync(`yarn --version`).toString().trim();
|
|
249
|
+
return semver.gte(yarnVersion, "2.0.0") ? "yarn2" : "yarn";
|
|
222
250
|
}
|
|
251
|
+
|
|
252
|
+
return "npm";
|
|
223
253
|
}
|
|
@@ -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,7 @@ 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;
|
|
64
70
|
|
|
65
71
|
// Checks newVersion against plasmic.lock
|
|
66
72
|
const checkVersionLock = async (): Promise<boolean> => {
|
|
@@ -177,6 +183,24 @@ async function checkProjectMeta(
|
|
|
177
183
|
);
|
|
178
184
|
};
|
|
179
185
|
|
|
186
|
+
const checkIndirect = async (): Promise<boolean> => {
|
|
187
|
+
const projectConfig = context.config.projects.find(
|
|
188
|
+
(p) => p.projectId === projectId
|
|
189
|
+
);
|
|
190
|
+
const configIndirect = projectConfig?.indirect;
|
|
191
|
+
if (configIndirect && !indirect) {
|
|
192
|
+
logger.warn(
|
|
193
|
+
`'${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.`
|
|
194
|
+
);
|
|
195
|
+
return await confirmWithUser(
|
|
196
|
+
"Do you want to confirm it?",
|
|
197
|
+
opts.force || opts.yes,
|
|
198
|
+
"n"
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
return true;
|
|
202
|
+
};
|
|
203
|
+
|
|
180
204
|
const projectIds =
|
|
181
205
|
opts.projects.length > 0
|
|
182
206
|
? opts.projects
|
|
@@ -188,7 +212,11 @@ async function checkProjectMeta(
|
|
|
188
212
|
return true;
|
|
189
213
|
}
|
|
190
214
|
|
|
191
|
-
return (
|
|
215
|
+
return (
|
|
216
|
+
(await checkVersionLock()) &&
|
|
217
|
+
(await checkVersionRange()) &&
|
|
218
|
+
(await checkIndirect())
|
|
219
|
+
);
|
|
192
220
|
}
|
|
193
221
|
|
|
194
222
|
/**
|
|
@@ -216,12 +244,16 @@ export async function checkVersionResolution(
|
|
|
216
244
|
? [root]
|
|
217
245
|
: walkDependencyTree(root, versionResolution.dependencies).reverse();
|
|
218
246
|
for (const m of queue) {
|
|
219
|
-
// If we haven't seen this yet
|
|
220
247
|
if (!seen.find((p) => p.projectId === m.projectId)) {
|
|
221
248
|
if (await checkProjectMeta(m, root, context, opts)) {
|
|
222
249
|
result.push(m);
|
|
223
250
|
}
|
|
224
251
|
seen.push(m);
|
|
252
|
+
} else if (root.projectId === m.projectId) {
|
|
253
|
+
// If m is the root project and it was already seen (maybe as a dep
|
|
254
|
+
// for another project), set indirect = false.
|
|
255
|
+
const project = ensure(seen.find((p) => p.projectId === m.projectId));
|
|
256
|
+
project.indirect = false;
|
|
225
257
|
}
|
|
226
258
|
}
|
|
227
259
|
}
|