@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,526 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import glob from "glob";
|
|
3
|
+
import L from "lodash";
|
|
4
|
+
import path from "upath";
|
|
5
|
+
import { ProjectMetaBundle } from "../api";
|
|
6
|
+
import { logger } from "../deps";
|
|
7
|
+
import { HandledError } from "../utils/error";
|
|
8
|
+
import { isLocalModulePath } from "./code-utils";
|
|
9
|
+
import {
|
|
10
|
+
ComponentConfig,
|
|
11
|
+
CONFIG_FILE_NAME,
|
|
12
|
+
PlasmicContext,
|
|
13
|
+
ProjectConfig,
|
|
14
|
+
updateConfig,
|
|
15
|
+
} from "./config-utils";
|
|
16
|
+
import { ensureString } from "./lang-utils";
|
|
17
|
+
import { confirmWithUser } from "./user-utils";
|
|
18
|
+
|
|
19
|
+
export function stripExtension(filename: string, removeComposedPath = false) {
|
|
20
|
+
const ext = removeComposedPath
|
|
21
|
+
? filename.substring(filename.indexOf("."))
|
|
22
|
+
: path.extname(filename);
|
|
23
|
+
if (!ext || filename === ext) {
|
|
24
|
+
return filename;
|
|
25
|
+
}
|
|
26
|
+
return filename.substring(0, filename.lastIndexOf(ext));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function writeFileContentRaw(
|
|
30
|
+
filePath: string,
|
|
31
|
+
content: string | Buffer,
|
|
32
|
+
opts?: { force?: boolean; yes?: boolean }
|
|
33
|
+
) {
|
|
34
|
+
opts = opts || {};
|
|
35
|
+
if (existsBuffered(filePath) && !opts.force) {
|
|
36
|
+
const overwrite = await confirmWithUser(
|
|
37
|
+
`File ${filePath} already exists. Do you want to overwrite?`,
|
|
38
|
+
opts.yes
|
|
39
|
+
);
|
|
40
|
+
if (!overwrite) {
|
|
41
|
+
throw new HandledError(
|
|
42
|
+
`Cannot write to ${filePath}; file already exists.`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
48
|
+
|
|
49
|
+
writeFileText(filePath, content);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function defaultResourcePath(
|
|
53
|
+
context: PlasmicContext,
|
|
54
|
+
project: ProjectConfig | ProjectMetaBundle | string,
|
|
55
|
+
...subpaths: string[]
|
|
56
|
+
) {
|
|
57
|
+
const projectName = L.isString(project) ? project : project.projectName;
|
|
58
|
+
return path.join(
|
|
59
|
+
context.config.defaultPlasmicDir,
|
|
60
|
+
L.snakeCase(projectName),
|
|
61
|
+
...subpaths
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function defaultPublicResourcePath(
|
|
66
|
+
context: PlasmicContext,
|
|
67
|
+
project: ProjectConfig,
|
|
68
|
+
...subpaths: string[]
|
|
69
|
+
) {
|
|
70
|
+
return path.join(
|
|
71
|
+
context.config.images.publicDir,
|
|
72
|
+
"plasmic",
|
|
73
|
+
L.snakeCase(project.projectName),
|
|
74
|
+
...subpaths
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function defaultPagePath(context: PlasmicContext, fileName: string) {
|
|
79
|
+
if (context.config.platform === "nextjs") {
|
|
80
|
+
return path.join(context.config.nextjsConfig?.pagesDir || "", fileName);
|
|
81
|
+
}
|
|
82
|
+
if (context.config.platform === "gatsby") {
|
|
83
|
+
return path.join(context.config.gatsbyConfig?.pagesDir || "", fileName);
|
|
84
|
+
}
|
|
85
|
+
return fileName;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function writeFileContent(
|
|
89
|
+
context: PlasmicContext,
|
|
90
|
+
srcDirFilePath: string,
|
|
91
|
+
content: string | Buffer,
|
|
92
|
+
opts: { force?: boolean } = {}
|
|
93
|
+
) {
|
|
94
|
+
const path = makeFilePath(context, srcDirFilePath);
|
|
95
|
+
await writeFileContentRaw(path, content, {
|
|
96
|
+
yes: context.cliArgs.yes,
|
|
97
|
+
...opts,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function readFileContent(
|
|
102
|
+
context: PlasmicContext,
|
|
103
|
+
srcDirFilePath: string
|
|
104
|
+
) {
|
|
105
|
+
const path = makeFilePath(context, srcDirFilePath);
|
|
106
|
+
return readFileText(path);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function deleteFile(context: PlasmicContext, srcDirFilePath: string) {
|
|
110
|
+
const path = makeFilePath(context, srcDirFilePath);
|
|
111
|
+
deleteFileBuffered(path);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function fileExists(context: PlasmicContext, srcDirFilePath: string) {
|
|
115
|
+
return existsBuffered(makeFilePath(context, srcDirFilePath));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function makeFilePath(context: PlasmicContext, filePath: string) {
|
|
119
|
+
return path.isAbsolute(filePath)
|
|
120
|
+
? filePath
|
|
121
|
+
: path.join(context.absoluteSrcDir, filePath);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function renameFile(
|
|
125
|
+
context: PlasmicContext,
|
|
126
|
+
oldPath: string,
|
|
127
|
+
newPath: string
|
|
128
|
+
) {
|
|
129
|
+
renameFileBuffered(
|
|
130
|
+
makeFilePath(context, oldPath),
|
|
131
|
+
makeFilePath(context, newPath)
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Returns absolute paths of all Plasmic managed files found, grouped by each basename
|
|
137
|
+
* for example:
|
|
138
|
+
* {
|
|
139
|
+
* "file.txt": [ "/path1/file.txt", "/path2.txt" ]
|
|
140
|
+
* ...
|
|
141
|
+
* }
|
|
142
|
+
* @param {PlasmicContext} context
|
|
143
|
+
* @returns {Record<string, string[]>}
|
|
144
|
+
**/
|
|
145
|
+
export function buildBaseNameToFiles(
|
|
146
|
+
context: PlasmicContext
|
|
147
|
+
): Record<string, string[]> {
|
|
148
|
+
const srcDir = context.absoluteSrcDir;
|
|
149
|
+
const scriptFileExt = context.config.code.lang === "ts" ? "tsx" : "jsx";
|
|
150
|
+
const allFiles = glob.sync(`${srcDir}/**/*.+(ts|css|${scriptFileExt}|json)`, {
|
|
151
|
+
ignore: [`${srcDir}/**/node_modules/**/*`],
|
|
152
|
+
});
|
|
153
|
+
return L.groupBy(allFiles, (f) => path.basename(f));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Tries to find the file at `srcDir/expectedPath`. If it's not there, tries to detect if it has
|
|
158
|
+
* been moved to a different location. Returns the found location relative to the `srcDir`.
|
|
159
|
+
*
|
|
160
|
+
* If `expectedPath` doesn't exist, but there's more than one file of that name in `baseNameToFiles`, then
|
|
161
|
+
* error and quit. If no file of that name can be found, `expectedPath` is returned.
|
|
162
|
+
*/
|
|
163
|
+
export function findSrcDirPath(
|
|
164
|
+
absoluteSrcDir: string,
|
|
165
|
+
expectedPath: string,
|
|
166
|
+
baseNameToFiles: Record<string, string[]>
|
|
167
|
+
): string {
|
|
168
|
+
if (!path.isAbsolute(absoluteSrcDir)) {
|
|
169
|
+
throw new HandledError("Cannot find srcDir. Please check plasmic.json.");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const fileName = path.basename(expectedPath);
|
|
173
|
+
if (existsBuffered(path.join(absoluteSrcDir, expectedPath))) {
|
|
174
|
+
return expectedPath;
|
|
175
|
+
} else if (!(fileName in baseNameToFiles)) {
|
|
176
|
+
return expectedPath;
|
|
177
|
+
} else if (baseNameToFiles[fileName].length === 1) {
|
|
178
|
+
// There's only one file of the same name, so maybe we've been moved there?
|
|
179
|
+
const newPath = path.relative(absoluteSrcDir, baseNameToFiles[fileName][0]);
|
|
180
|
+
logger.info(`\tDetected file moved from ${expectedPath} to ${newPath}`);
|
|
181
|
+
return newPath;
|
|
182
|
+
} else {
|
|
183
|
+
throw new HandledError(
|
|
184
|
+
`Cannot find expected file at ${expectedPath}, and found multiple possible matching files ${baseNameToFiles[fileName]}. Please update plasmic.config with the real location for ${fileName}.`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Finds the full path to the first file satisfying `pred` in `dir`. If
|
|
191
|
+
* `opts.traverseParents` is set to true, then will also look in ancestor
|
|
192
|
+
* directories until the plasmic.json file is found. If none is found,
|
|
193
|
+
* returns undefined.
|
|
194
|
+
*/
|
|
195
|
+
export function findFile(
|
|
196
|
+
dir: string,
|
|
197
|
+
pred: (name: string) => boolean,
|
|
198
|
+
opts: {
|
|
199
|
+
traverseParents?: boolean;
|
|
200
|
+
}
|
|
201
|
+
): string | undefined {
|
|
202
|
+
const files = fs.readdirSync(dir);
|
|
203
|
+
const found = files.find((f) => pred(f));
|
|
204
|
+
if (found) {
|
|
205
|
+
return path.join(dir, found);
|
|
206
|
+
}
|
|
207
|
+
if (!opts.traverseParents) {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
const parent = path.dirname(dir);
|
|
211
|
+
if (parent === dir) {
|
|
212
|
+
// We've hit the root dir already
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
return findFile(path.dirname(dir), pred, opts);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
type BundleKeyPair = {
|
|
219
|
+
bundle: Record<string, any>;
|
|
220
|
+
key: string;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Parses a configuration and returns file/dir paths in it (in the format
|
|
225
|
+
* BundleKeyPair to allow the caller to change these paths).
|
|
226
|
+
*/
|
|
227
|
+
function getAllPaths(context: PlasmicContext): BundleKeyPair[] {
|
|
228
|
+
const config = context.config;
|
|
229
|
+
|
|
230
|
+
const pairs: BundleKeyPair[] = [];
|
|
231
|
+
const pushPath = (bundle: Record<string, any>, key: string) => {
|
|
232
|
+
pairs.push({ bundle, key });
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const pushComponent = (comp: ComponentConfig) => {
|
|
236
|
+
pushPath(comp, "renderModuleFilePath");
|
|
237
|
+
pushPath(comp, "cssFilePath");
|
|
238
|
+
if (isLocalModulePath(comp.importSpec.modulePath)) {
|
|
239
|
+
pushPath(comp.importSpec, "modulePath");
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const pushProject = (proj: ProjectConfig) => {
|
|
244
|
+
pushPath(proj, "cssFilePath");
|
|
245
|
+
for (const component of proj.components) {
|
|
246
|
+
pushComponent(component);
|
|
247
|
+
}
|
|
248
|
+
for (const icon of proj.icons) {
|
|
249
|
+
pushPath(icon, "moduleFilePath");
|
|
250
|
+
}
|
|
251
|
+
for (const image of proj.images) {
|
|
252
|
+
pushPath(image, "filePath");
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
for (const project of config.projects) {
|
|
257
|
+
pushProject(project);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
for (const bundle of config.globalVariants.variantGroups) {
|
|
261
|
+
pushPath(bundle, "contextFilePath");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
pushPath(config.tokens, "tokensFilePath");
|
|
265
|
+
pushPath(config.style, "defaultStyleCssFilePath");
|
|
266
|
+
|
|
267
|
+
pushPath(config, "defaultPlasmicDir");
|
|
268
|
+
if (config.images.publicDir) {
|
|
269
|
+
pushPath(config.images, "publicDir");
|
|
270
|
+
}
|
|
271
|
+
if (config.gatsbyConfig) {
|
|
272
|
+
pushPath(config.gatsbyConfig, "pagesDir");
|
|
273
|
+
}
|
|
274
|
+
if (config.nextjsConfig) {
|
|
275
|
+
pushPath(config.nextjsConfig, "pagesDir");
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return pairs;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Fixes all src-relative file paths in PlasmicConfig by detecting file
|
|
283
|
+
* movement on disk.
|
|
284
|
+
*/
|
|
285
|
+
export async function fixAllFilePaths(context: PlasmicContext, baseDir: string) {
|
|
286
|
+
const baseNameToFiles = buildBaseNameToFiles(context);
|
|
287
|
+
let changed = false;
|
|
288
|
+
|
|
289
|
+
const paths = getAllPaths(context);
|
|
290
|
+
for (const { bundle, key } of paths) {
|
|
291
|
+
const known = bundle[key];
|
|
292
|
+
// Check null and undefined
|
|
293
|
+
if (known == null) {
|
|
294
|
+
throw new HandledError(
|
|
295
|
+
`"${key} is required, but missing in ${CONFIG_FILE_NAME}. Please restore the file or delete from ${CONFIG_FILE_NAME} and run plasmic sync: ${bundle}"`
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
// Check falsey values (e.g. "")
|
|
299
|
+
if (!known) {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const found = findSrcDirPath(
|
|
303
|
+
context.absoluteSrcDir,
|
|
304
|
+
known,
|
|
305
|
+
baseNameToFiles
|
|
306
|
+
);
|
|
307
|
+
if (known !== found) {
|
|
308
|
+
bundle[key] = found;
|
|
309
|
+
changed = true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (changed) {
|
|
314
|
+
await updateConfig(context, context.config, baseDir);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Throws an error if some file in PlasmicConfig is not inside the root
|
|
320
|
+
* directory (i.e., the directory containing plasmic.json).
|
|
321
|
+
*/
|
|
322
|
+
export function assertAllPathsInRootDir(context: PlasmicContext) {
|
|
323
|
+
// Do not run this check when running in PlasmicLoader environment
|
|
324
|
+
if (process.env.PLASMIC_LOADER) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (!context.absoluteSrcDir.startsWith(context.rootDir)) {
|
|
329
|
+
throw new HandledError(
|
|
330
|
+
`"srcDir" in ${CONFIG_FILE_NAME} is outside of ${context.rootDir}`
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const paths = getAllPaths(context);
|
|
335
|
+
for (const { bundle, key } of paths) {
|
|
336
|
+
const relPath = bundle[key];
|
|
337
|
+
if (!relPath) {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const absPath = path.resolve(context.absoluteSrcDir, relPath);
|
|
342
|
+
if (!absPath.startsWith(context.rootDir)) {
|
|
343
|
+
throw new HandledError(
|
|
344
|
+
`The path "${relPath}" in ${CONFIG_FILE_NAME} is outside of ${context.rootDir}`
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/** Whether we're currently recording to the buffer. */
|
|
351
|
+
let buffering = false;
|
|
352
|
+
|
|
353
|
+
interface BufferCreateFile {
|
|
354
|
+
type: "create";
|
|
355
|
+
content: string | Buffer;
|
|
356
|
+
}
|
|
357
|
+
interface BufferRenameFile {
|
|
358
|
+
type: "rename";
|
|
359
|
+
newPath: string;
|
|
360
|
+
}
|
|
361
|
+
interface BufferDeleteFile {
|
|
362
|
+
type: "delete";
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** List of buffer actions. */
|
|
366
|
+
const buffer = new Map<
|
|
367
|
+
string,
|
|
368
|
+
BufferCreateFile | BufferRenameFile | BufferDeleteFile
|
|
369
|
+
>();
|
|
370
|
+
const renamedFiles = new Map<string, string>();
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* This turns on buffering of file writes/reads.
|
|
374
|
+
*
|
|
375
|
+
* This is useful for reducing the extent to which our file updates are scattered over time, which can cause webpack
|
|
376
|
+
* dev server to trip up.
|
|
377
|
+
*
|
|
378
|
+
* This also has the side benefit of making our CLI commands more atomic, in case of failure partway through a sync.
|
|
379
|
+
*/
|
|
380
|
+
export async function withBufferedFs(f: () => Promise<void>) {
|
|
381
|
+
buffering = true;
|
|
382
|
+
buffer.clear();
|
|
383
|
+
renamedFiles.clear();
|
|
384
|
+
try {
|
|
385
|
+
await f();
|
|
386
|
+
for (const [filePath, action] of buffer.entries()) {
|
|
387
|
+
switch (action.type) {
|
|
388
|
+
case "create":
|
|
389
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
390
|
+
// eslint-disable-next-line no-restricted-properties
|
|
391
|
+
fs.writeFileSync(filePath, action.content);
|
|
392
|
+
break;
|
|
393
|
+
case "rename":
|
|
394
|
+
fs.mkdirSync(path.dirname(action.newPath), { recursive: true });
|
|
395
|
+
// eslint-disable-next-line no-restricted-properties
|
|
396
|
+
fs.renameSync(filePath, action.newPath);
|
|
397
|
+
break;
|
|
398
|
+
case "delete":
|
|
399
|
+
// eslint-disable-next-line no-restricted-properties
|
|
400
|
+
fs.unlinkSync(filePath);
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
} finally {
|
|
405
|
+
buffering = false;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export function writeFileText(path: string, content: string | Buffer) {
|
|
410
|
+
if (buffering) {
|
|
411
|
+
buffer.set(path, { type: "create", content });
|
|
412
|
+
} else {
|
|
413
|
+
// eslint-disable-next-line no-restricted-properties
|
|
414
|
+
fs.writeFileSync(path, content, "utf8");
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
export function readFileText(path: string): string {
|
|
419
|
+
if (buffering) {
|
|
420
|
+
const action = buffer.get(path);
|
|
421
|
+
if (action) {
|
|
422
|
+
switch (action.type) {
|
|
423
|
+
case "create":
|
|
424
|
+
return ensureString(action.content);
|
|
425
|
+
case "rename":
|
|
426
|
+
return readFileText(action.newPath);
|
|
427
|
+
case "delete":
|
|
428
|
+
throw new HandledError("File does not exists");
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// eslint-disable-next-line no-restricted-properties
|
|
434
|
+
return fs.readFileSync(path, "utf8");
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export function renameFileBuffered(oldPath: string, newPath: string) {
|
|
438
|
+
if (oldPath === newPath) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (buffering) {
|
|
443
|
+
if (!existsBuffered(oldPath)) {
|
|
444
|
+
throw new HandledError("File does not exists");
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const action = buffer.get(oldPath);
|
|
448
|
+
|
|
449
|
+
if (action) {
|
|
450
|
+
switch (action.type) {
|
|
451
|
+
case "create":
|
|
452
|
+
buffer.set(newPath, action);
|
|
453
|
+
buffer.delete(oldPath);
|
|
454
|
+
break;
|
|
455
|
+
case "rename":
|
|
456
|
+
throw new HandledError("File does not exists");
|
|
457
|
+
case "delete":
|
|
458
|
+
throw new HandledError("File does not exists");
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const renamedFile = renamedFiles.get(oldPath);
|
|
463
|
+
if (renamedFile !== undefined) {
|
|
464
|
+
oldPath = renamedFile;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
buffer.set(oldPath, { type: "rename", newPath });
|
|
468
|
+
renamedFiles.set(newPath, oldPath);
|
|
469
|
+
} else {
|
|
470
|
+
fs.mkdirSync(path.dirname(newPath), { recursive: true });
|
|
471
|
+
// eslint-disable-next-line no-restricted-properties
|
|
472
|
+
fs.renameSync(oldPath, newPath);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export function deleteFileBuffered(path: string) {
|
|
477
|
+
if (buffering) {
|
|
478
|
+
if (!existsBuffered(path)) {
|
|
479
|
+
throw new HandledError("File does not exists");
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const action = buffer.get(path);
|
|
483
|
+
|
|
484
|
+
if (action) {
|
|
485
|
+
switch (action.type) {
|
|
486
|
+
case "create":
|
|
487
|
+
buffer.delete(path);
|
|
488
|
+
break;
|
|
489
|
+
case "rename":
|
|
490
|
+
throw new HandledError("File does not exists");
|
|
491
|
+
case "delete":
|
|
492
|
+
throw new HandledError("File does not exists");
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
buffer.set(path, { type: "delete" });
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
renamedFiles.delete(path);
|
|
499
|
+
} else {
|
|
500
|
+
// eslint-disable-next-line no-restricted-properties
|
|
501
|
+
fs.unlinkSync(path);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export function existsBuffered(path: string): boolean {
|
|
506
|
+
if (buffering) {
|
|
507
|
+
if (renamedFiles.has(path)) {
|
|
508
|
+
return true;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const action = buffer.get(path);
|
|
512
|
+
if (action) {
|
|
513
|
+
switch (action.type) {
|
|
514
|
+
case "create":
|
|
515
|
+
return true;
|
|
516
|
+
case "rename":
|
|
517
|
+
return false;
|
|
518
|
+
case "delete":
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// eslint-disable-next-line no-restricted-properties
|
|
525
|
+
return fs.existsSync(path);
|
|
526
|
+
}
|