@plasmicapp/cli 0.1.162
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +61 -0
- package/.idea/cli.iml +11 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/README +16 -0
- package/README.internal +46 -0
- package/README.md +17 -0
- package/build.sh +8 -0
- package/dist/__mocks__/api.d.ts +16 -0
- package/dist/__mocks__/api.js +297 -0
- package/dist/__tests__/code-utils-spec.d.ts +1 -0
- package/dist/__tests__/code-utils-spec.js +838 -0
- package/dist/__tests__/ftue-spec.d.ts +1 -0
- package/dist/__tests__/ftue-spec.js +39 -0
- package/dist/__tests__/project-api-token-spec.d.ts +1 -0
- package/dist/__tests__/project-api-token-spec.js +147 -0
- package/dist/__tests__/versioned-sync-spec.d.ts +1 -0
- package/dist/__tests__/versioned-sync-spec.js +145 -0
- package/dist/actions/auth.d.ts +8 -0
- package/dist/actions/auth.js +47 -0
- package/dist/actions/fix-imports.d.ts +4 -0
- package/dist/actions/fix-imports.js +25 -0
- package/dist/actions/init.d.ts +62 -0
- package/dist/actions/init.js +460 -0
- package/dist/actions/project-token.d.ts +6 -0
- package/dist/actions/project-token.js +42 -0
- package/dist/actions/sync-components.d.ts +10 -0
- package/dist/actions/sync-components.js +242 -0
- package/dist/actions/sync-global-variants.d.ts +3 -0
- package/dist/actions/sync-global-variants.js +89 -0
- package/dist/actions/sync-icons.d.ts +7 -0
- package/dist/actions/sync-icons.js +92 -0
- package/dist/actions/sync-images.d.ts +6 -0
- package/dist/actions/sync-images.js +137 -0
- package/dist/actions/sync-styles.d.ts +3 -0
- package/dist/actions/sync-styles.js +58 -0
- package/dist/actions/sync.d.ts +25 -0
- package/dist/actions/sync.js +417 -0
- package/dist/actions/upload-bundle.d.ts +15 -0
- package/dist/actions/upload-bundle.js +28 -0
- package/dist/actions/watch.d.ts +14 -0
- package/dist/actions/watch.js +90 -0
- package/dist/api.d.ts +182 -0
- package/dist/api.js +202 -0
- package/dist/deps.d.ts +2 -0
- package/dist/deps.js +20 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +247 -0
- package/dist/lib.d.ts +10 -0
- package/dist/lib.js +23 -0
- package/dist/migrations/0.1.110-fileLocks.d.ts +2 -0
- package/dist/migrations/0.1.110-fileLocks.js +15 -0
- package/dist/migrations/0.1.143-ensureImportModuleType.d.ts +2 -0
- package/dist/migrations/0.1.143-ensureImportModuleType.js +12 -0
- package/dist/migrations/0.1.146-addReactRuntime.d.ts +2 -0
- package/dist/migrations/0.1.146-addReactRuntime.js +10 -0
- package/dist/migrations/0.1.27-migrateInit.d.ts +1 -0
- package/dist/migrations/0.1.27-migrateInit.js +8 -0
- package/dist/migrations/0.1.28-tsToTsx.d.ts +3 -0
- package/dist/migrations/0.1.28-tsToTsx.js +33 -0
- package/dist/migrations/0.1.31-ensureProjectIcons.d.ts +2 -0
- package/dist/migrations/0.1.31-ensureProjectIcons.js +12 -0
- package/dist/migrations/0.1.42-ensureVersion.d.ts +2 -0
- package/dist/migrations/0.1.42-ensureVersion.js +12 -0
- package/dist/migrations/0.1.57-ensureJsBundleThemes.d.ts +2 -0
- package/dist/migrations/0.1.57-ensureJsBundleThemes.js +12 -0
- package/dist/migrations/0.1.64-imageFiles.d.ts +2 -0
- package/dist/migrations/0.1.64-imageFiles.js +17 -0
- package/dist/migrations/0.1.95-componentType.d.ts +2 -0
- package/dist/migrations/0.1.95-componentType.js +16 -0
- package/dist/migrations/migrations.d.ts +10 -0
- package/dist/migrations/migrations.js +119 -0
- package/dist/plasmic.schema.json +463 -0
- package/dist/test-common/fixtures.d.ts +13 -0
- package/dist/test-common/fixtures.js +165 -0
- package/dist/tsconfig-transform.json +68 -0
- package/dist/utils/auth-utils.d.ts +31 -0
- package/dist/utils/auth-utils.js +236 -0
- package/dist/utils/checksum.d.ts +4 -0
- package/dist/utils/checksum.js +63 -0
- package/dist/utils/code-utils.d.ts +46 -0
- package/dist/utils/code-utils.js +457 -0
- package/dist/utils/config-utils.d.ts +271 -0
- package/dist/utils/config-utils.js +178 -0
- package/dist/utils/envdetect.d.ts +4 -0
- package/dist/utils/envdetect.js +42 -0
- package/dist/utils/error.d.ts +14 -0
- package/dist/utils/error.js +42 -0
- package/dist/utils/file-utils.d.ts +71 -0
- package/dist/utils/file-utils.js +433 -0
- package/dist/utils/get-context.d.ts +40 -0
- package/dist/utils/get-context.js +339 -0
- package/dist/utils/help.d.ts +2 -0
- package/dist/utils/help.js +56 -0
- package/dist/utils/lang-utils.d.ts +10 -0
- package/dist/utils/lang-utils.js +52 -0
- package/dist/utils/npm-utils.d.ts +28 -0
- package/dist/utils/npm-utils.js +215 -0
- package/dist/utils/prompts.d.ts +6 -0
- package/dist/utils/prompts.js +23 -0
- package/dist/utils/resolve-utils.d.ts +13 -0
- package/dist/utils/resolve-utils.js +198 -0
- package/dist/utils/semver.d.ts +34 -0
- package/dist/utils/semver.js +61 -0
- package/dist/utils/test-utils.d.ts +22 -0
- package/dist/utils/test-utils.js +106 -0
- package/dist/utils/user-utils.d.ts +7 -0
- package/dist/utils/user-utils.js +48 -0
- package/jest.config.js +6 -0
- package/package.json +80 -0
- package/src/__mocks__/api.ts +394 -0
- package/src/__tests__/code-utils-spec.ts +881 -0
- package/src/__tests__/ftue-spec.ts +43 -0
- package/src/__tests__/project-api-token-spec.ts +208 -0
- package/src/__tests__/versioned-sync-spec.ts +176 -0
- package/src/actions/auth.ts +43 -0
- package/src/actions/fix-imports.ts +13 -0
- package/src/actions/init.ts +638 -0
- package/src/actions/project-token.ts +36 -0
- package/src/actions/sync-components.ts +405 -0
- package/src/actions/sync-global-variants.ts +129 -0
- package/src/actions/sync-icons.ts +135 -0
- package/src/actions/sync-images.ts +191 -0
- package/src/actions/sync-styles.ts +71 -0
- package/src/actions/sync.ts +747 -0
- package/src/actions/upload-bundle.ts +38 -0
- package/src/actions/watch.ts +95 -0
- package/src/api.ts +407 -0
- package/src/deps.ts +18 -0
- package/src/index.ts +300 -0
- package/src/lib.ts +10 -0
- package/src/migrations/0.1.110-fileLocks.ts +16 -0
- package/src/migrations/0.1.146-addReactRuntime.ts +8 -0
- package/src/migrations/0.1.27-migrateInit.ts +4 -0
- package/src/migrations/0.1.28-tsToTsx.ts +37 -0
- package/src/migrations/0.1.31-ensureProjectIcons.ts +10 -0
- package/src/migrations/0.1.42-ensureVersion.ts +10 -0
- package/src/migrations/0.1.57-ensureJsBundleThemes.ts +10 -0
- package/src/migrations/0.1.64-imageFiles.ts +15 -0
- package/src/migrations/0.1.95-componentType.ts +14 -0
- package/src/migrations/migrations.ts +147 -0
- package/src/test-common/fixtures.ts +178 -0
- package/src/utils/auth-utils.ts +276 -0
- package/src/utils/checksum.ts +106 -0
- package/src/utils/code-utils.ts +656 -0
- package/src/utils/config-utils.ts +551 -0
- package/src/utils/envdetect.ts +39 -0
- package/src/utils/error.ts +36 -0
- package/src/utils/file-utils.ts +526 -0
- package/src/utils/get-context.ts +451 -0
- package/src/utils/help.ts +75 -0
- package/src/utils/lang-utils.ts +52 -0
- package/src/utils/npm-utils.ts +223 -0
- package/src/utils/prompts.ts +22 -0
- package/src/utils/resolve-utils.ts +245 -0
- package/src/utils/semver.ts +67 -0
- package/src/utils/test-utils.ts +116 -0
- package/src/utils/user-utils.ts +37 -0
- package/testData/fixImports_plasmic.json +66 -0
- package/tsconfig-transform.json +68 -0
- package/tsconfig.json +67 -0
|
@@ -0,0 +1,747 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { spawnSync } from "child_process";
|
|
3
|
+
import L from "lodash";
|
|
4
|
+
import path from "upath";
|
|
5
|
+
import { CommonArgs } from "..";
|
|
6
|
+
import {
|
|
7
|
+
ChecksumBundle,
|
|
8
|
+
CodeComponentMeta,
|
|
9
|
+
ComponentBundle,
|
|
10
|
+
ProjectIdAndToken,
|
|
11
|
+
ProjectMetaBundle,
|
|
12
|
+
StyleConfigResponse,
|
|
13
|
+
} from "../api";
|
|
14
|
+
import { logger } from "../deps";
|
|
15
|
+
import { getChecksums } from "../utils/checksum";
|
|
16
|
+
import {
|
|
17
|
+
ComponentUpdateSummary,
|
|
18
|
+
fixAllImportStatements,
|
|
19
|
+
formatAsLocal,
|
|
20
|
+
maybeConvertTsxToJsx,
|
|
21
|
+
mkFixImportContext,
|
|
22
|
+
replaceImports,
|
|
23
|
+
} from "../utils/code-utils";
|
|
24
|
+
import {
|
|
25
|
+
CONFIG_FILE_NAME,
|
|
26
|
+
createProjectConfig,
|
|
27
|
+
getOrAddProjectConfig,
|
|
28
|
+
getOrAddProjectLock,
|
|
29
|
+
LOADER_CONFIG_FILE_NAME,
|
|
30
|
+
PlasmicContext,
|
|
31
|
+
PlasmicLoaderConfig,
|
|
32
|
+
updateConfig,
|
|
33
|
+
} from "../utils/config-utils";
|
|
34
|
+
import { HandledError } from "../utils/error";
|
|
35
|
+
import {
|
|
36
|
+
assertAllPathsInRootDir,
|
|
37
|
+
defaultResourcePath,
|
|
38
|
+
existsBuffered,
|
|
39
|
+
readFileText,
|
|
40
|
+
renameFile,
|
|
41
|
+
stripExtension,
|
|
42
|
+
withBufferedFs,
|
|
43
|
+
writeFileContent,
|
|
44
|
+
writeFileText,
|
|
45
|
+
} from "../utils/file-utils";
|
|
46
|
+
import { generateMetadata, getContext, Metadata } from "../utils/get-context";
|
|
47
|
+
import { printFirstSyncInfo } from "../utils/help";
|
|
48
|
+
import { ensure, tuple } from "../utils/lang-utils";
|
|
49
|
+
import {
|
|
50
|
+
findInstalledVersion,
|
|
51
|
+
getCliVersion,
|
|
52
|
+
installCommand,
|
|
53
|
+
installUpgrade,
|
|
54
|
+
isCliGloballyInstalled,
|
|
55
|
+
} from "../utils/npm-utils";
|
|
56
|
+
import { checkVersionResolution } from "../utils/resolve-utils";
|
|
57
|
+
import * as semver from "../utils/semver";
|
|
58
|
+
import { confirmWithUser } from "../utils/user-utils";
|
|
59
|
+
import {
|
|
60
|
+
ComponentPendingMerge,
|
|
61
|
+
syncProjectComponents,
|
|
62
|
+
} from "./sync-components";
|
|
63
|
+
import { syncGlobalVariants } from "./sync-global-variants";
|
|
64
|
+
import { syncProjectIconAssets } from "./sync-icons";
|
|
65
|
+
import { syncProjectImageAssets } from "./sync-images";
|
|
66
|
+
import { upsertStyleTokens } from "./sync-styles";
|
|
67
|
+
|
|
68
|
+
export interface SyncArgs extends CommonArgs {
|
|
69
|
+
projects: readonly string[];
|
|
70
|
+
forceOverwrite: boolean;
|
|
71
|
+
newComponentScheme?: "blackbox" | "direct";
|
|
72
|
+
appendJsxOnMissingBase?: boolean;
|
|
73
|
+
yes?: boolean;
|
|
74
|
+
force?: boolean;
|
|
75
|
+
nonRecursive?: boolean;
|
|
76
|
+
skipUpgradeCheck?: boolean;
|
|
77
|
+
ignorePostSync?: boolean;
|
|
78
|
+
quiet?: boolean;
|
|
79
|
+
metadata?: string;
|
|
80
|
+
allFiles?: boolean;
|
|
81
|
+
loaderConfig?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function ensureRequiredPackages(
|
|
85
|
+
context: PlasmicContext,
|
|
86
|
+
baseDir: string,
|
|
87
|
+
yes?: boolean
|
|
88
|
+
) {
|
|
89
|
+
const requireds = await context.api.requiredPackages();
|
|
90
|
+
|
|
91
|
+
const confirmInstall = async (
|
|
92
|
+
pkg: string,
|
|
93
|
+
requiredVersion: string,
|
|
94
|
+
opts: { global: boolean; dev: boolean }
|
|
95
|
+
) => {
|
|
96
|
+
let success = false;
|
|
97
|
+
const command = installCommand(pkg, baseDir, opts);
|
|
98
|
+
const upgrade = await confirmWithUser(
|
|
99
|
+
`A more recent version of ${pkg} >=${requiredVersion} is required. Would you like to upgrade via "${command}"?`,
|
|
100
|
+
yes
|
|
101
|
+
);
|
|
102
|
+
if (upgrade) {
|
|
103
|
+
success = installUpgrade(pkg, baseDir, opts);
|
|
104
|
+
} else {
|
|
105
|
+
success = false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!success) {
|
|
109
|
+
throw new HandledError(`Upgrading ${pkg} is required to continue.`);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const cliVersion = getCliVersion();
|
|
114
|
+
if (!cliVersion || semver.gt(requireds["@plasmicapp/cli"], cliVersion)) {
|
|
115
|
+
const isGlobal = isCliGloballyInstalled(context.rootDir);
|
|
116
|
+
await confirmInstall("@plasmicapp/cli", requireds["@plasmicapp/cli"], {
|
|
117
|
+
global: isGlobal,
|
|
118
|
+
dev: true,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
logger.info(
|
|
122
|
+
chalk.bold("@plasmicapp/cli has been upgraded; please try again!")
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Exit so the user can run again with the new cli
|
|
126
|
+
throw new HandledError();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const reactWebVersion = findInstalledVersion(
|
|
130
|
+
context,
|
|
131
|
+
"@plasmicapp/react-web"
|
|
132
|
+
);
|
|
133
|
+
if (
|
|
134
|
+
!reactWebVersion ||
|
|
135
|
+
semver.gt(requireds["@plasmicapp/react-web"], reactWebVersion)
|
|
136
|
+
) {
|
|
137
|
+
await confirmInstall(
|
|
138
|
+
"@plasmicapp/react-web",
|
|
139
|
+
requireds["@plasmicapp/react-web"],
|
|
140
|
+
{ global: false, dev: false }
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (context.config.code.reactRuntime === "automatic") {
|
|
145
|
+
// Using automatic runtime requires installing the @plasmicapp/react-web-runtime package
|
|
146
|
+
const runtimeVersion = findInstalledVersion(
|
|
147
|
+
context,
|
|
148
|
+
"@plasmicapp/react-web-runtime"
|
|
149
|
+
);
|
|
150
|
+
if (
|
|
151
|
+
!runtimeVersion ||
|
|
152
|
+
semver.gt(requireds["@plasmicapp/react-web-runtime"], runtimeVersion)
|
|
153
|
+
) {
|
|
154
|
+
await confirmInstall(
|
|
155
|
+
"@plasmicapp/react-web-runtime",
|
|
156
|
+
requireds["@plasmicapp/react-web-runtime"],
|
|
157
|
+
{ global: false, dev: false }
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function getLoaderConfigPath(opts: SyncArgs) {
|
|
164
|
+
return opts.loaderConfig || LOADER_CONFIG_FILE_NAME;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function maybeReadLoaderConfig(opts: SyncArgs): Partial<PlasmicLoaderConfig> {
|
|
168
|
+
const path = getLoaderConfigPath(opts);
|
|
169
|
+
if (!existsBuffered(path)) {
|
|
170
|
+
return {};
|
|
171
|
+
}
|
|
172
|
+
return JSON.parse(readFileText(path!));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function writeLoaderConfig(
|
|
176
|
+
opts: SyncArgs,
|
|
177
|
+
config: Partial<PlasmicLoaderConfig>
|
|
178
|
+
) {
|
|
179
|
+
const loaderConfigPath = getLoaderConfigPath(opts);
|
|
180
|
+
|
|
181
|
+
writeFileText(
|
|
182
|
+
loaderConfigPath,
|
|
183
|
+
formatAsLocal(JSON.stringify(config), loaderConfigPath, opts.baseDir)
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Sync will always try to sync down a set of components that are version-consistent among specified projects.
|
|
189
|
+
* (we only allow 1 version per projectId).
|
|
190
|
+
* NOTE: the repo/plasmic.json might include projects with conflicting versions in its dependency tree.
|
|
191
|
+
* We leave it to the user to sync all projects if they want us to catch/prevent this.
|
|
192
|
+
* @param opts
|
|
193
|
+
*/
|
|
194
|
+
export async function sync(
|
|
195
|
+
opts: SyncArgs,
|
|
196
|
+
metadataDefaults?: Metadata
|
|
197
|
+
): Promise<void> {
|
|
198
|
+
// Initially allow for a missing auth. Only require an auth once we need to fetch new or updated API tokens for any
|
|
199
|
+
// projects.
|
|
200
|
+
|
|
201
|
+
if (!opts.baseDir) opts.baseDir = process.cwd();
|
|
202
|
+
const baseDir = opts.baseDir;
|
|
203
|
+
let context = await getContext(opts, { enableSkipAuth: true });
|
|
204
|
+
|
|
205
|
+
const isFirstRun = context.config.projects.length === 0;
|
|
206
|
+
|
|
207
|
+
if (!opts.skipUpgradeCheck) {
|
|
208
|
+
await ensureRequiredPackages(context, opts.baseDir, opts.yes);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
fixFileExtension(context);
|
|
212
|
+
assertAllPathsInRootDir(context);
|
|
213
|
+
|
|
214
|
+
const loaderConfig: Partial<PlasmicLoaderConfig> = process.env.PLASMIC_LOADER
|
|
215
|
+
? maybeReadLoaderConfig(opts)
|
|
216
|
+
: {};
|
|
217
|
+
|
|
218
|
+
const projectIdToToken = new Map(
|
|
219
|
+
[...context.config.projects, ...(loaderConfig?.projects ?? [])]
|
|
220
|
+
.filter((p) => p.projectApiToken)
|
|
221
|
+
.map((p) => tuple(p.projectId, p.projectApiToken))
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
// Resolve what will be synced
|
|
225
|
+
const projectConfigMap = L.keyBy(context.config.projects, (p) => p.projectId);
|
|
226
|
+
const projectWithVersion = opts.projects.map((p) => {
|
|
227
|
+
const [projectIdToken, versionRange] = p.split("@");
|
|
228
|
+
const [projectId, projectApiToken] = projectIdToken.split(":");
|
|
229
|
+
return {
|
|
230
|
+
projectId,
|
|
231
|
+
versionRange:
|
|
232
|
+
versionRange || projectConfigMap[projectId]?.version || "latest",
|
|
233
|
+
componentIdOrNames: undefined, // Get all components!
|
|
234
|
+
projectApiToken: projectApiToken || projectIdToToken.get(projectId),
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const projectSyncParams = projectWithVersion.length
|
|
239
|
+
? projectWithVersion
|
|
240
|
+
: context.config.projects.map((p) => ({
|
|
241
|
+
projectId: p.projectId,
|
|
242
|
+
versionRange: p.version,
|
|
243
|
+
componentIdOrNames: undefined, // Get all components!
|
|
244
|
+
projectApiToken: p.projectApiToken,
|
|
245
|
+
}));
|
|
246
|
+
|
|
247
|
+
// Short-circuit if nothing to sync
|
|
248
|
+
if (projectSyncParams.length === 0) {
|
|
249
|
+
throw new HandledError(
|
|
250
|
+
"Don't know which projects to sync. Please specify via --projects"
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// If there are any missing projectApiTokens, reload the context, this time requiring auth, so that we can fetch the
|
|
255
|
+
// projectApiTokens from the server (as a user that has permission to do so).
|
|
256
|
+
if (projectSyncParams.some((p) => !p.projectApiToken)) {
|
|
257
|
+
try {
|
|
258
|
+
context = await getContext(opts);
|
|
259
|
+
} catch (e) {
|
|
260
|
+
if (e.message.includes("Unable to authenticate Plasmic")) {
|
|
261
|
+
const configFileName = process.env.PLASMIC_LOADER
|
|
262
|
+
? LOADER_CONFIG_FILE_NAME
|
|
263
|
+
: CONFIG_FILE_NAME;
|
|
264
|
+
throw new HandledError(
|
|
265
|
+
`Unable to authenticate Plasmic. Please run 'plasmic auth' or check the projectApiTokens in your ${configFileName}, and try again.`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Pass just the root IDs and tokens that we do have for the resolve call. (In reality it doesn't need any of this
|
|
272
|
+
// because it only consults the projectApiToken within projectSyncParams; we could just attach [].)
|
|
273
|
+
context.api.attachProjectIdsAndTokens(
|
|
274
|
+
projectSyncParams.flatMap((p) =>
|
|
275
|
+
p.projectApiToken
|
|
276
|
+
? [{ projectId: p.projectId, projectApiToken: p.projectApiToken }]
|
|
277
|
+
: []
|
|
278
|
+
)
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
const versionResolution = await context.api.resolveSync(
|
|
282
|
+
projectSyncParams,
|
|
283
|
+
true // we always want to get dependency data
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
// Make sure the resolution is compatible with plasmic.json and plasmic.lock
|
|
287
|
+
const projectsToSync = await checkVersionResolution(
|
|
288
|
+
versionResolution,
|
|
289
|
+
context,
|
|
290
|
+
opts
|
|
291
|
+
);
|
|
292
|
+
if (projectsToSync.length <= 0) {
|
|
293
|
+
logger.info(
|
|
294
|
+
"Your projects are up-to-date with respect to your specified version ranges. Nothing to sync."
|
|
295
|
+
);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const summary = new Map<string, ComponentUpdateSummary>();
|
|
299
|
+
const pendingMerge = new Array<ComponentPendingMerge>();
|
|
300
|
+
|
|
301
|
+
// The resolveSync call returns the project API tokens for all relevant projects (sources and dependencies).
|
|
302
|
+
// resolveSync is what does this because it's what is computing all concrete versions to sync, and the dependency
|
|
303
|
+
// graph can change with any version. Subsequent API calls require the exact API tokens, not to redo this work on each
|
|
304
|
+
// call. Only resolveSync accepts just the API tokens for the root projects.
|
|
305
|
+
//
|
|
306
|
+
// We shouldn't simply use projectsToSync, because this list excludes up-to-date projects, but syncing a dependent
|
|
307
|
+
// project still requires tokens to the dependencies.
|
|
308
|
+
const projectIdsAndTokens = [
|
|
309
|
+
...versionResolution.projects,
|
|
310
|
+
...versionResolution.dependencies,
|
|
311
|
+
].map((p) => L.pick(p, "projectId", "projectApiToken"));
|
|
312
|
+
|
|
313
|
+
context.api.attachProjectIdsAndTokens(projectIdsAndTokens);
|
|
314
|
+
|
|
315
|
+
// Perform the actual sync
|
|
316
|
+
await withBufferedFs(async () => {
|
|
317
|
+
// Sync in sequence (no parallelism)
|
|
318
|
+
// going in reverse to get leaves of the dependency tree first
|
|
319
|
+
for (const projectMeta of projectsToSync) {
|
|
320
|
+
await syncProject(
|
|
321
|
+
context,
|
|
322
|
+
opts,
|
|
323
|
+
projectIdsAndTokens,
|
|
324
|
+
projectMeta.projectId,
|
|
325
|
+
projectMeta.componentIds,
|
|
326
|
+
projectMeta.version,
|
|
327
|
+
projectMeta.dependencies,
|
|
328
|
+
summary,
|
|
329
|
+
pendingMerge,
|
|
330
|
+
metadataDefaults
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Materialize scheme into each component config.
|
|
335
|
+
context.config.projects.forEach((p) =>
|
|
336
|
+
p.components.forEach((c) => {
|
|
337
|
+
if (c.type === "managed" && !c.scheme) {
|
|
338
|
+
c.scheme = context.config.code.scheme;
|
|
339
|
+
}
|
|
340
|
+
})
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
await syncStyleConfig(
|
|
344
|
+
context,
|
|
345
|
+
await context.api.genStyleConfig(context.config.style)
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
// Update project version if specified and successfully synced.
|
|
349
|
+
if (projectWithVersion.length) {
|
|
350
|
+
const versionMap: Record<string, string> = {};
|
|
351
|
+
projectWithVersion.forEach(
|
|
352
|
+
(p) => (versionMap[p.projectId] = p.versionRange)
|
|
353
|
+
);
|
|
354
|
+
context.config.projects.forEach(
|
|
355
|
+
(p) => (p.version = versionMap[p.projectId] || p.version)
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Fix imports
|
|
360
|
+
const fixImportContext = mkFixImportContext(context.config);
|
|
361
|
+
for (const m of pendingMerge) {
|
|
362
|
+
const resolvedEditedFile = replaceImports(
|
|
363
|
+
context,
|
|
364
|
+
m.editedSkeletonFile,
|
|
365
|
+
m.skeletonModulePath,
|
|
366
|
+
fixImportContext,
|
|
367
|
+
true,
|
|
368
|
+
baseDir
|
|
369
|
+
);
|
|
370
|
+
const resolvedNewFile = replaceImports(
|
|
371
|
+
context,
|
|
372
|
+
m.newSkeletonFile,
|
|
373
|
+
m.skeletonModulePath,
|
|
374
|
+
fixImportContext,
|
|
375
|
+
true,
|
|
376
|
+
baseDir
|
|
377
|
+
);
|
|
378
|
+
await m.merge(resolvedNewFile, resolvedEditedFile);
|
|
379
|
+
}
|
|
380
|
+
// Now we know config.components are all correct, so we can go ahead and fix up all the import statements
|
|
381
|
+
await fixAllImportStatements(context, opts.baseDir, summary);
|
|
382
|
+
|
|
383
|
+
if (process.env.PLASMIC_LOADER) {
|
|
384
|
+
const rootProjectIds = new Set(projectSyncParams.map((p) => p.projectId));
|
|
385
|
+
const freshIdsAndTokens = projectIdsAndTokens
|
|
386
|
+
.filter((p) => rootProjectIds.has(p.projectId))
|
|
387
|
+
.map((p) => L.pick(p, "projectId", "projectApiToken"));
|
|
388
|
+
|
|
389
|
+
const config: Partial<PlasmicLoaderConfig> = {
|
|
390
|
+
...loaderConfig,
|
|
391
|
+
projects: L.sortBy(
|
|
392
|
+
L.uniqBy(
|
|
393
|
+
[...freshIdsAndTokens, ...(loaderConfig?.projects ?? [])],
|
|
394
|
+
(p) => p.projectId
|
|
395
|
+
),
|
|
396
|
+
(p) => p.projectId
|
|
397
|
+
),
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
writeLoaderConfig(opts, config);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Write the new ComponentConfigs to disk
|
|
404
|
+
await updateConfig(context, context.config, baseDir);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Post-sync commands
|
|
408
|
+
if (!opts.ignorePostSync) {
|
|
409
|
+
for (const cmd of context.config.postSyncCommands || []) {
|
|
410
|
+
spawnSync(cmd, { shell: true, stdio: "inherit" });
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (isFirstRun) {
|
|
415
|
+
if (!process.env.QUIET) {
|
|
416
|
+
printFirstSyncInfo(context);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function maybeRenamePathExt(
|
|
422
|
+
context: PlasmicContext,
|
|
423
|
+
path: string,
|
|
424
|
+
ext: string
|
|
425
|
+
) {
|
|
426
|
+
if (!path) {
|
|
427
|
+
return path;
|
|
428
|
+
}
|
|
429
|
+
const correctPath = `${stripExtension(path, true)}${ext}`;
|
|
430
|
+
if (path !== correctPath) {
|
|
431
|
+
renameFile(context, path, correctPath);
|
|
432
|
+
}
|
|
433
|
+
return correctPath;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function fixFileExtension(context: PlasmicContext) {
|
|
437
|
+
const cssExt =
|
|
438
|
+
context.config.style.scheme === "css-modules" ? ".module.css" : ".css";
|
|
439
|
+
context.config.style.defaultStyleCssFilePath = maybeRenamePathExt(
|
|
440
|
+
context,
|
|
441
|
+
context.config.style.defaultStyleCssFilePath,
|
|
442
|
+
cssExt
|
|
443
|
+
);
|
|
444
|
+
context.config.projects.forEach((project) => {
|
|
445
|
+
project.cssFilePath = maybeRenamePathExt(
|
|
446
|
+
context,
|
|
447
|
+
project.cssFilePath,
|
|
448
|
+
cssExt
|
|
449
|
+
);
|
|
450
|
+
project.components.forEach((component) => {
|
|
451
|
+
component.cssFilePath = maybeRenamePathExt(
|
|
452
|
+
context,
|
|
453
|
+
component.cssFilePath,
|
|
454
|
+
cssExt
|
|
455
|
+
);
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
async function syncProject(
|
|
461
|
+
context: PlasmicContext,
|
|
462
|
+
opts: SyncArgs,
|
|
463
|
+
projectIdsAndTokens: ProjectIdAndToken[],
|
|
464
|
+
projectId: string,
|
|
465
|
+
componentIds: string[],
|
|
466
|
+
projectVersion: string,
|
|
467
|
+
dependencies: { [projectId: string]: string },
|
|
468
|
+
summary: Map<string, ComponentUpdateSummary>,
|
|
469
|
+
pendingMerge: ComponentPendingMerge[],
|
|
470
|
+
metadataDefaults?: Metadata
|
|
471
|
+
): Promise<void> {
|
|
472
|
+
const newComponentScheme =
|
|
473
|
+
opts.newComponentScheme || context.config.code.scheme;
|
|
474
|
+
const existingProject = context.config.projects.find(
|
|
475
|
+
(p) => p.projectId === projectId
|
|
476
|
+
);
|
|
477
|
+
const existingCompScheme: Array<[string, "blackbox" | "direct"]> = (
|
|
478
|
+
existingProject?.components || []
|
|
479
|
+
).map((c) => [c.id, c.scheme]);
|
|
480
|
+
|
|
481
|
+
const projectApiToken = ensure(
|
|
482
|
+
projectIdsAndTokens.find((p) => p.projectId === projectId)?.projectApiToken,
|
|
483
|
+
`Could not find the API token for project ${projectId} in list: ${JSON.stringify(
|
|
484
|
+
projectIdsAndTokens
|
|
485
|
+
)}`
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
const existingChecksums = getChecksums(
|
|
489
|
+
context,
|
|
490
|
+
opts,
|
|
491
|
+
projectId,
|
|
492
|
+
componentIds
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
// Server-side code-gen
|
|
496
|
+
const projectBundle = await context.api.projectComponents(projectId, {
|
|
497
|
+
platform: context.config.platform,
|
|
498
|
+
newCompScheme: newComponentScheme,
|
|
499
|
+
existingCompScheme,
|
|
500
|
+
componentIdOrNames: componentIds,
|
|
501
|
+
version: projectVersion,
|
|
502
|
+
imageOpts: context.config.images,
|
|
503
|
+
stylesOpts: context.config.style,
|
|
504
|
+
checksums: existingChecksums,
|
|
505
|
+
codeOpts: context.config.code,
|
|
506
|
+
metadata: generateMetadata(
|
|
507
|
+
{
|
|
508
|
+
...metadataDefaults,
|
|
509
|
+
platform: context.config.platform,
|
|
510
|
+
},
|
|
511
|
+
opts.metadata
|
|
512
|
+
),
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
// Convert from TSX => JSX
|
|
516
|
+
if (context.config.code.lang === "js") {
|
|
517
|
+
projectBundle.components.forEach((c) => {
|
|
518
|
+
[c.renderModuleFileName, c.renderModule] = maybeConvertTsxToJsx(
|
|
519
|
+
c.renderModuleFileName,
|
|
520
|
+
c.renderModule,
|
|
521
|
+
opts.baseDir
|
|
522
|
+
);
|
|
523
|
+
[c.skeletonModuleFileName, c.skeletonModule] = maybeConvertTsxToJsx(
|
|
524
|
+
c.skeletonModuleFileName,
|
|
525
|
+
c.skeletonModule,
|
|
526
|
+
opts.baseDir
|
|
527
|
+
);
|
|
528
|
+
});
|
|
529
|
+
projectBundle.iconAssets.forEach((icon) => {
|
|
530
|
+
[icon.fileName, icon.module] = maybeConvertTsxToJsx(
|
|
531
|
+
icon.fileName,
|
|
532
|
+
icon.module,
|
|
533
|
+
opts.baseDir
|
|
534
|
+
);
|
|
535
|
+
});
|
|
536
|
+
projectBundle.globalVariants.forEach((gv) => {
|
|
537
|
+
[gv.contextFileName, gv.contextModule] = maybeConvertTsxToJsx(
|
|
538
|
+
gv.contextFileName,
|
|
539
|
+
gv.contextModule,
|
|
540
|
+
opts.baseDir
|
|
541
|
+
);
|
|
542
|
+
});
|
|
543
|
+
(projectBundle.projectConfig.jsBundleThemes || []).forEach((theme) => {
|
|
544
|
+
[theme.themeFileName, theme.themeModule] = maybeConvertTsxToJsx(
|
|
545
|
+
theme.themeFileName,
|
|
546
|
+
theme.themeModule,
|
|
547
|
+
opts.baseDir
|
|
548
|
+
);
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
await syncGlobalVariants(
|
|
552
|
+
context,
|
|
553
|
+
projectBundle.projectConfig,
|
|
554
|
+
projectBundle.globalVariants,
|
|
555
|
+
projectBundle.checksums,
|
|
556
|
+
opts.baseDir
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
syncCodeComponentsMeta(context, projectId, projectBundle.codeComponentMetas);
|
|
560
|
+
|
|
561
|
+
await syncProjectConfig(
|
|
562
|
+
context,
|
|
563
|
+
projectBundle.projectConfig,
|
|
564
|
+
projectApiToken,
|
|
565
|
+
projectVersion,
|
|
566
|
+
dependencies,
|
|
567
|
+
projectBundle.components,
|
|
568
|
+
opts.forceOverwrite,
|
|
569
|
+
!!opts.appendJsxOnMissingBase,
|
|
570
|
+
summary,
|
|
571
|
+
pendingMerge,
|
|
572
|
+
projectBundle.checksums,
|
|
573
|
+
opts.baseDir
|
|
574
|
+
);
|
|
575
|
+
await upsertStyleTokens(context, projectBundle.usedTokens);
|
|
576
|
+
await syncProjectIconAssets(
|
|
577
|
+
context,
|
|
578
|
+
projectId,
|
|
579
|
+
projectVersion,
|
|
580
|
+
projectBundle.iconAssets,
|
|
581
|
+
projectBundle.checksums,
|
|
582
|
+
opts.baseDir
|
|
583
|
+
);
|
|
584
|
+
await syncProjectImageAssets(
|
|
585
|
+
context,
|
|
586
|
+
projectId,
|
|
587
|
+
projectVersion,
|
|
588
|
+
projectBundle.imageAssets,
|
|
589
|
+
projectBundle.checksums
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
async function syncStyleConfig(
|
|
594
|
+
context: PlasmicContext,
|
|
595
|
+
response: StyleConfigResponse
|
|
596
|
+
) {
|
|
597
|
+
const expectedPath =
|
|
598
|
+
context.config.style.defaultStyleCssFilePath ||
|
|
599
|
+
path.join(
|
|
600
|
+
context.config.defaultPlasmicDir,
|
|
601
|
+
response.defaultStyleCssFileName
|
|
602
|
+
);
|
|
603
|
+
context.config.style.defaultStyleCssFilePath = expectedPath;
|
|
604
|
+
await writeFileContent(context, expectedPath, response.defaultStyleCssRules, {
|
|
605
|
+
force: true,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
async function syncProjectConfig(
|
|
610
|
+
context: PlasmicContext,
|
|
611
|
+
projectBundle: ProjectMetaBundle,
|
|
612
|
+
projectApiToken: string,
|
|
613
|
+
version: string,
|
|
614
|
+
dependencies: { [projectId: string]: string },
|
|
615
|
+
componentBundles: ComponentBundle[],
|
|
616
|
+
forceOverwrite: boolean,
|
|
617
|
+
appendJsxOnMissingBase: boolean,
|
|
618
|
+
summary: Map<string, ComponentUpdateSummary>,
|
|
619
|
+
pendingMerge: ComponentPendingMerge[],
|
|
620
|
+
checksums: ChecksumBundle,
|
|
621
|
+
baseDir: string
|
|
622
|
+
) {
|
|
623
|
+
const defaultCssFilePath = defaultResourcePath(
|
|
624
|
+
context,
|
|
625
|
+
projectBundle.projectName,
|
|
626
|
+
projectBundle.cssFileName
|
|
627
|
+
);
|
|
628
|
+
const isNew = !context.config.projects.find(
|
|
629
|
+
(p) => p.projectId === projectBundle.projectId
|
|
630
|
+
);
|
|
631
|
+
|
|
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
|
+
const projectConfig = getOrAddProjectConfig(
|
|
635
|
+
context,
|
|
636
|
+
projectBundle.projectId,
|
|
637
|
+
createProjectConfig({
|
|
638
|
+
projectId: projectBundle.projectId,
|
|
639
|
+
projectApiToken,
|
|
640
|
+
projectName: projectBundle.projectName,
|
|
641
|
+
version: versionRange,
|
|
642
|
+
cssFilePath: defaultCssFilePath,
|
|
643
|
+
})
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
// Update missing/outdated props
|
|
647
|
+
projectConfig.projectName = projectBundle.projectName;
|
|
648
|
+
if (!projectConfig.cssFilePath) {
|
|
649
|
+
projectConfig.cssFilePath = defaultCssFilePath;
|
|
650
|
+
}
|
|
651
|
+
projectConfig.projectApiToken = projectApiToken;
|
|
652
|
+
|
|
653
|
+
// plasmic.lock
|
|
654
|
+
const projectLock = getOrAddProjectLock(context, projectConfig.projectId);
|
|
655
|
+
projectLock.version = version;
|
|
656
|
+
projectLock.dependencies = dependencies;
|
|
657
|
+
projectLock.lang = context.config.code.lang;
|
|
658
|
+
|
|
659
|
+
if (projectBundle.cssRules) {
|
|
660
|
+
const formattedCssRules = formatAsLocal(
|
|
661
|
+
projectBundle.cssRules,
|
|
662
|
+
projectConfig.cssFilePath,
|
|
663
|
+
baseDir
|
|
664
|
+
);
|
|
665
|
+
|
|
666
|
+
// Write out project css
|
|
667
|
+
await writeFileContent(
|
|
668
|
+
context,
|
|
669
|
+
projectConfig.cssFilePath,
|
|
670
|
+
formattedCssRules,
|
|
671
|
+
{
|
|
672
|
+
force: !isNew,
|
|
673
|
+
}
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
projectLock.fileLocks = projectLock.fileLocks.filter(
|
|
677
|
+
(fileLock) => fileLock.type !== "projectCss"
|
|
678
|
+
);
|
|
679
|
+
projectLock.fileLocks.push({
|
|
680
|
+
assetId: projectConfig.projectId,
|
|
681
|
+
type: "projectCss",
|
|
682
|
+
checksum: checksums.projectCssChecksum,
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
/*
|
|
686
|
+
for (const theme of projectBundle.jsBundleThemes) {
|
|
687
|
+
if (!projectConfig.jsBundleThemes) {
|
|
688
|
+
projectConfig.jsBundleThemes = [];
|
|
689
|
+
}
|
|
690
|
+
let themeConfig = projectConfig.jsBundleThemes.find(
|
|
691
|
+
(c) => c.bundleName === theme.bundleName
|
|
692
|
+
);
|
|
693
|
+
if (!themeConfig) {
|
|
694
|
+
const themeFilePath = defaultResourcePath(
|
|
695
|
+
context,
|
|
696
|
+
projectConfig,
|
|
697
|
+
theme.themeFileName
|
|
698
|
+
);
|
|
699
|
+
themeConfig = { themeFilePath, bundleName: theme.bundleName };
|
|
700
|
+
projectConfig.jsBundleThemes.push(themeConfig);
|
|
701
|
+
}
|
|
702
|
+
const formatted = formatAsLocal(
|
|
703
|
+
theme.themeModule,
|
|
704
|
+
themeConfig.themeFilePath
|
|
705
|
+
);
|
|
706
|
+
await writeFileContent(context, themeConfig.themeFilePath, formatted, {
|
|
707
|
+
force: true,
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
*/
|
|
711
|
+
|
|
712
|
+
if (
|
|
713
|
+
projectConfig.jsBundleThemes &&
|
|
714
|
+
projectConfig.jsBundleThemes.length === 0
|
|
715
|
+
) {
|
|
716
|
+
delete projectConfig.jsBundleThemes;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Write out components
|
|
720
|
+
await syncProjectComponents(
|
|
721
|
+
context,
|
|
722
|
+
projectConfig,
|
|
723
|
+
version,
|
|
724
|
+
componentBundles,
|
|
725
|
+
forceOverwrite,
|
|
726
|
+
appendJsxOnMissingBase,
|
|
727
|
+
summary,
|
|
728
|
+
pendingMerge,
|
|
729
|
+
projectLock,
|
|
730
|
+
checksums,
|
|
731
|
+
baseDir
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
function syncCodeComponentsMeta(
|
|
736
|
+
context: PlasmicContext,
|
|
737
|
+
projectId: string,
|
|
738
|
+
codeComponentBundles: CodeComponentMeta[]
|
|
739
|
+
) {
|
|
740
|
+
const projectConfig = getOrAddProjectConfig(context, projectId);
|
|
741
|
+
|
|
742
|
+
projectConfig.codeComponents = codeComponentBundles.map((meta) => ({
|
|
743
|
+
id: meta.id,
|
|
744
|
+
name: meta.name,
|
|
745
|
+
componentImportPath: meta.importPath,
|
|
746
|
+
}));
|
|
747
|
+
}
|