@embeddables/cli 0.5.1 → 0.6.0
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/cli.js +1 -1
- package/dist/commands/branch.d.ts.map +1 -1
- package/dist/commands/branch.js +5 -1
- package/dist/commands/build.d.ts +1 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +11 -1
- package/dist/commands/pull.d.ts +4 -2
- package/dist/commands/pull.d.ts.map +1 -1
- package/dist/commands/pull.js +116 -29
- package/dist/commands/save.d.ts.map +1 -1
- package/dist/commands/save.js +121 -9
- package/dist/compiler/index.d.ts.map +1 -1
- package/dist/compiler/index.js +4 -0
- package/dist/compiler/reverse.d.ts +5 -0
- package/dist/compiler/reverse.d.ts.map +1 -1
- package/dist/compiler/reverse.js +129 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -30,7 +30,7 @@ program
|
|
|
30
30
|
});
|
|
31
31
|
program
|
|
32
32
|
.command('build')
|
|
33
|
-
.
|
|
33
|
+
.option('-i, --id <id>', 'Embeddable ID (will prompt if not provided)')
|
|
34
34
|
.option('-p, --pages <glob>', 'Pages glob')
|
|
35
35
|
.option('-o, --out <path>', 'Output json path')
|
|
36
36
|
.option('--pageKeyFrom <mode>', 'filename|export', 'filename')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/commands/branch.ts"],"names":[],"mappings":"AAKA,wBAAsB,SAAS,CAAC,IAAI,EAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/commands/branch.ts"],"names":[],"mappings":"AAKA,wBAAsB,SAAS,CAAC,IAAI,EAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,iBAoDpD"}
|
package/dist/commands/branch.js
CHANGED
|
@@ -41,6 +41,10 @@ export async function runBranch(opts) {
|
|
|
41
41
|
else {
|
|
42
42
|
console.log(pc.cyan(`Switching to branch: ${selectedBranch.name}...`));
|
|
43
43
|
console.log('');
|
|
44
|
-
await runPull({
|
|
44
|
+
await runPull({
|
|
45
|
+
id: embeddableId,
|
|
46
|
+
branch: selectedBranch.id,
|
|
47
|
+
branchName: selectedBranch.name,
|
|
48
|
+
});
|
|
45
49
|
}
|
|
46
50
|
}
|
package/dist/commands/build.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAKA,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACnC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,UAAU,GAAG,QAAQ,CAAA;CACnC,iBA4BA"}
|
package/dist/commands/build.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { compileAllPages } from '../compiler/index.js';
|
|
3
3
|
import { formatError } from '../compiler/errors.js';
|
|
4
|
+
import { promptForLocalEmbeddable } from '../prompts/index.js';
|
|
4
5
|
export async function runBuild(opts) {
|
|
5
|
-
|
|
6
|
+
let embeddableId = opts.id;
|
|
7
|
+
if (!embeddableId) {
|
|
8
|
+
const selected = await promptForLocalEmbeddable({
|
|
9
|
+
message: 'Select an embeddable to build:',
|
|
10
|
+
});
|
|
11
|
+
if (!selected) {
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
embeddableId = selected;
|
|
15
|
+
}
|
|
6
16
|
const pagesGlob = opts.pages || `embeddables/${embeddableId}/pages/**/*.page.tsx`;
|
|
7
17
|
const outPath = opts.out || path.join('embeddables', embeddableId, '.generated', 'embeddable.json');
|
|
8
18
|
const stylesDir = path.join('embeddables', embeddableId, 'styles');
|
package/dist/commands/pull.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type RunPullOptions = {
|
|
2
2
|
id?: string;
|
|
3
3
|
out?: string;
|
|
4
4
|
branch?: string;
|
|
5
|
+
branchName?: string;
|
|
5
6
|
fix?: boolean;
|
|
6
|
-
}
|
|
7
|
+
};
|
|
8
|
+
export declare function runPull(opts: RunPullOptions): Promise<void>;
|
|
7
9
|
//# sourceMappingURL=pull.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAyEA,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,CAAC,EAAE,OAAO,CAAA;CACd,CAAA;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,cAAc,iBAkPjD"}
|
package/dist/commands/pull.js
CHANGED
|
@@ -6,6 +6,69 @@ import { reverseCompile } from '../compiler/reverse.js';
|
|
|
6
6
|
import { getAccessToken, isLoggedIn } from '../auth/index.js';
|
|
7
7
|
import { getProjectId, writeProjectConfig } from '../config/index.js';
|
|
8
8
|
import { promptForProject, promptForEmbeddable, fetchEmbeddableMetadata } from '../prompts/index.js';
|
|
9
|
+
/** Slug for branch name/id for use in filenames (e.g. "my branch" -> "my_branch"). */
|
|
10
|
+
function slugForBranch(nameOrId) {
|
|
11
|
+
return String(nameOrId).replace(/[^a-zA-Z0-9_.-]/g, '_').replace(/_+/g, '_') || 'main';
|
|
12
|
+
}
|
|
13
|
+
/** Versioned embeddable filename: embeddable-{branchSlug}@{version}.json */
|
|
14
|
+
function getVersionedBasename(version, branchSlug) {
|
|
15
|
+
const v = typeof version === 'number' ? version : String(version);
|
|
16
|
+
return `embeddable-${branchSlug}@${v}.json`;
|
|
17
|
+
}
|
|
18
|
+
/** Read current _branch_id and _branch_name from config (set when on a branch via `embeddables branch`). */
|
|
19
|
+
function getCurrentBranchFromConfig(embeddableId) {
|
|
20
|
+
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
21
|
+
if (!fs.existsSync(configPath))
|
|
22
|
+
return null;
|
|
23
|
+
try {
|
|
24
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
25
|
+
const branchId = config._branch_id;
|
|
26
|
+
if (typeof branchId !== 'string' || !branchId)
|
|
27
|
+
return null;
|
|
28
|
+
const branchName = config._branch_name;
|
|
29
|
+
return { branchId, branchName: typeof branchName === 'string' ? branchName : undefined };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Write _version, _branch_id, _branch_name to config.json. Called early and in finally so it always runs. */
|
|
36
|
+
function writePullMetadataToConfig(embeddableId, version, branch, branchName) {
|
|
37
|
+
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
38
|
+
let config = {};
|
|
39
|
+
try {
|
|
40
|
+
if (fs.existsSync(configPath)) {
|
|
41
|
+
try {
|
|
42
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
43
|
+
config = JSON.parse(content);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
/* use empty config */
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (version != null) {
|
|
50
|
+
const n = typeof version === 'number' ? version : parseInt(String(version), 10);
|
|
51
|
+
if (!isNaN(n))
|
|
52
|
+
config._version = n;
|
|
53
|
+
}
|
|
54
|
+
if (branch) {
|
|
55
|
+
config._branch_id = branch;
|
|
56
|
+
if (branchName)
|
|
57
|
+
config._branch_name = branchName;
|
|
58
|
+
else
|
|
59
|
+
delete config._branch_name;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
delete config._branch_id;
|
|
63
|
+
delete config._branch_name;
|
|
64
|
+
}
|
|
65
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
66
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
console.warn(pc.yellow(`Could not write config.json: ${err instanceof Error ? err.message : err}`));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
9
72
|
export async function runPull(opts) {
|
|
10
73
|
let embeddableId = opts.id;
|
|
11
74
|
// If no ID provided, try to get it interactively
|
|
@@ -34,7 +97,7 @@ export async function runPull(opts) {
|
|
|
34
97
|
project_id: projectId,
|
|
35
98
|
project_name: selectedProject.title || undefined,
|
|
36
99
|
});
|
|
37
|
-
console.log(pc.green(`✓
|
|
100
|
+
console.log(pc.green(`✓ Wrote project config to embeddables.json`));
|
|
38
101
|
console.log('');
|
|
39
102
|
}
|
|
40
103
|
console.log(pc.cyan('Fetching embeddables from project...'));
|
|
@@ -47,12 +110,23 @@ export async function runPull(opts) {
|
|
|
47
110
|
embeddableId = selected;
|
|
48
111
|
console.log('');
|
|
49
112
|
}
|
|
113
|
+
// Stay on current branch when no --branch: use config's _branch_id if set
|
|
114
|
+
const currentFromConfig = opts.branch == null ? getCurrentBranchFromConfig(embeddableId) : null;
|
|
115
|
+
const effectiveBranch = opts.branch ?? currentFromConfig?.branchId;
|
|
116
|
+
const effectiveBranchName = opts.branchName ?? currentFromConfig?.branchName;
|
|
50
117
|
let url = `https://engine.embeddables.com/${embeddableId}?version=latest`;
|
|
51
|
-
if (
|
|
52
|
-
url += `&embeddable_branch=${
|
|
118
|
+
if (effectiveBranch) {
|
|
119
|
+
url += `&embeddable_branch=${effectiveBranch}`;
|
|
53
120
|
}
|
|
54
121
|
const outPath = opts.out || path.join('embeddables', embeddableId, '.generated', 'embeddable.json');
|
|
122
|
+
const branchLabel = effectiveBranch
|
|
123
|
+
? effectiveBranchName
|
|
124
|
+
? `${effectiveBranchName} (${effectiveBranch})`
|
|
125
|
+
: effectiveBranch
|
|
126
|
+
: 'main';
|
|
127
|
+
console.log(pc.cyan(`Pulling branch: ${pc.bold(branchLabel)}`));
|
|
55
128
|
console.log(`Fetching embeddable from ${url}...`);
|
|
129
|
+
let pullVersion;
|
|
56
130
|
try {
|
|
57
131
|
// Add authentication header if available
|
|
58
132
|
const accessToken = getAccessToken();
|
|
@@ -75,24 +149,28 @@ export async function runPull(opts) {
|
|
|
75
149
|
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
76
150
|
const flowJson = JSON.stringify(flow, null, 2);
|
|
77
151
|
fs.writeFileSync(outPath, flowJson, 'utf8');
|
|
78
|
-
console.log(pc.cyan(`✓
|
|
79
|
-
// Also save version-specific file (e.g. embeddable-
|
|
80
|
-
|
|
152
|
+
console.log(pc.cyan(`✓ Wrote embeddable JSON to ${outPath}`));
|
|
153
|
+
// Also save version-specific file (e.g. embeddable-main@135.json or embeddable-my_branch@135.json)
|
|
154
|
+
pullVersion =
|
|
155
|
+
data.version ?? data.embeddable_version ?? flow.version;
|
|
156
|
+
const version = pullVersion;
|
|
157
|
+
const branchSlug = slugForBranch(effectiveBranchName ?? effectiveBranch ?? 'main');
|
|
81
158
|
if (version != null) {
|
|
82
159
|
const versionStr = typeof version === 'string' ? version : String(version);
|
|
83
|
-
const
|
|
84
|
-
const versionedBasename = `embeddable-${versionLabel}.json`;
|
|
160
|
+
const versionedBasename = getVersionedBasename(versionStr, branchSlug);
|
|
85
161
|
const versionedPath = path.join(path.dirname(outPath), versionedBasename);
|
|
86
162
|
fs.writeFileSync(versionedPath, flowJson, 'utf8');
|
|
87
|
-
console.log(pc.cyan(`✓
|
|
163
|
+
console.log(pc.cyan(`✓ Wrote versioned embeddable JSON to ${versionedPath}`));
|
|
88
164
|
}
|
|
165
|
+
// Persist _version and _branch_id in config.json immediately so they survive reverseCompile
|
|
166
|
+
writePullMetadataToConfig(embeddableId, version, effectiveBranch, effectiveBranchName);
|
|
89
167
|
// Fetch and save flow metadata from DB (title, archived, created_at)
|
|
90
168
|
const metadata = await fetchEmbeddableMetadata(embeddableId);
|
|
91
169
|
if (metadata) {
|
|
92
170
|
const metadataPath = path.join('embeddables', embeddableId, 'metadata.json');
|
|
93
171
|
fs.mkdirSync(path.dirname(metadataPath), { recursive: true });
|
|
94
172
|
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2) + '\n', 'utf8');
|
|
95
|
-
console.log(pc.cyan(`✓
|
|
173
|
+
console.log(pc.cyan(`✓ Wrote flow metadata to ${metadataPath}`));
|
|
96
174
|
}
|
|
97
175
|
// Clear existing pages, styles, computed-fields, actions, and global-components before generating new ones
|
|
98
176
|
const pagesDir = path.join('embeddables', embeddableId, 'pages');
|
|
@@ -137,9 +215,16 @@ export async function runPull(opts) {
|
|
|
137
215
|
}
|
|
138
216
|
console.log(`${pc.gray(`Cleared ${existingGlobalComponents.length} existing global component(s)`)}`);
|
|
139
217
|
}
|
|
140
|
-
// Run reverse compiler
|
|
218
|
+
// Run reverse compiler (pass pullMetadata so config.json gets _version and _branch_id even on fix retry)
|
|
219
|
+
const versionNum = version != null && !isNaN(Number(version)) ? Number(version) : undefined;
|
|
220
|
+
const pullMetadata = {
|
|
221
|
+
version: versionNum,
|
|
222
|
+
branchId: effectiveBranch,
|
|
223
|
+
branchName: effectiveBranchName,
|
|
224
|
+
};
|
|
225
|
+
let usedFix = opts.fix;
|
|
141
226
|
try {
|
|
142
|
-
await reverseCompile(flow, embeddableId, { fix: opts.fix });
|
|
227
|
+
await reverseCompile(flow, embeddableId, { fix: opts.fix, pullMetadata });
|
|
143
228
|
}
|
|
144
229
|
catch (compileError) {
|
|
145
230
|
// If fix mode wasn't already enabled, offer to retry with fix mode
|
|
@@ -159,10 +244,11 @@ export async function runPull(opts) {
|
|
|
159
244
|
},
|
|
160
245
|
});
|
|
161
246
|
if (response.fix) {
|
|
247
|
+
usedFix = true;
|
|
162
248
|
console.log('');
|
|
163
249
|
console.log(pc.cyan('Retrying with auto-fix enabled...'));
|
|
164
250
|
console.log('');
|
|
165
|
-
await reverseCompile(flow, embeddableId, { fix: true });
|
|
251
|
+
await reverseCompile(flow, embeddableId, { fix: true, pullMetadata });
|
|
166
252
|
}
|
|
167
253
|
else {
|
|
168
254
|
process.exit(1);
|
|
@@ -172,22 +258,17 @@ export async function runPull(opts) {
|
|
|
172
258
|
throw compileError;
|
|
173
259
|
}
|
|
174
260
|
}
|
|
175
|
-
//
|
|
176
|
-
if (
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
// Ignore errors updating config.json - versioned files are a fallback
|
|
189
|
-
}
|
|
190
|
-
}
|
|
261
|
+
// Persist mutated flow when fixes were applied (e.g. parent_key -> parent_id)
|
|
262
|
+
if (usedFix) {
|
|
263
|
+
const flowJson = JSON.stringify(flow, null, 2);
|
|
264
|
+
fs.writeFileSync(outPath, flowJson, 'utf8');
|
|
265
|
+
console.log(pc.cyan(`✓ Wrote embeddable JSON to ${outPath} (with fixes applied)`));
|
|
266
|
+
if (version != null) {
|
|
267
|
+
const versionStr = typeof version === 'string' ? version : String(version);
|
|
268
|
+
const versionedBasename = getVersionedBasename(versionStr, branchSlug);
|
|
269
|
+
const versionedPath = path.join(path.dirname(outPath), versionedBasename);
|
|
270
|
+
fs.writeFileSync(versionedPath, flowJson, 'utf8');
|
|
271
|
+
console.log(pc.cyan(`✓ Wrote versioned embeddable JSON to ${versionedPath} (with fixes applied)`));
|
|
191
272
|
}
|
|
192
273
|
}
|
|
193
274
|
}
|
|
@@ -195,4 +276,10 @@ export async function runPull(opts) {
|
|
|
195
276
|
console.error('Error pulling embeddable:', error);
|
|
196
277
|
process.exit(1);
|
|
197
278
|
}
|
|
279
|
+
finally {
|
|
280
|
+
// Always persist _version and _branch_id once we've fetched (so config is correct even if reverseCompile failed or was retried with fix)
|
|
281
|
+
if (embeddableId != null && pullVersion !== undefined) {
|
|
282
|
+
writePullMetadataToConfig(embeddableId, pullVersion, effectiveBranch, effectiveBranchName);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
198
285
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../../src/commands/save.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../../src/commands/save.ts"],"names":[],"mappings":"AA+OA,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,iBAoBA"}
|
package/dist/commands/save.js
CHANGED
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import pc from 'picocolors';
|
|
4
4
|
import prompts from 'prompts';
|
|
5
|
-
import { getAccessToken, isLoggedIn } from '../auth/index.js';
|
|
5
|
+
import { getAccessToken, getAuthenticatedSupabaseClient, isLoggedIn } from '../auth/index.js';
|
|
6
6
|
import { getProjectId, writeProjectConfig } from '../config/index.js';
|
|
7
7
|
import { compileAllPages } from '../compiler/index.js';
|
|
8
8
|
import { formatError } from '../compiler/errors.js';
|
|
@@ -69,6 +69,45 @@ function getVersionFromConfig(embeddableId) {
|
|
|
69
69
|
}
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Read `_branch_id` from config.json for the given embeddable (set when on a branch via `embeddables branch`).
|
|
74
|
+
*/
|
|
75
|
+
function getBranchFromConfig(embeddableId) {
|
|
76
|
+
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
77
|
+
if (!fs.existsSync(configPath)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
82
|
+
if (typeof config._branch_id === 'string' && config._branch_id) {
|
|
83
|
+
return config._branch_id;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Ignore parse errors
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
/** Slug for branch name/id for versioned filenames (e.g. "my branch" -> "my_branch"). */
|
|
92
|
+
function slugForBranch(nameOrId) {
|
|
93
|
+
return String(nameOrId).replace(/[^a-zA-Z0-9_.-]/g, '_').replace(/_+/g, '_') || 'main';
|
|
94
|
+
}
|
|
95
|
+
/** Get branch slug from config (_branch_name preferred, else _branch_id, else main). */
|
|
96
|
+
function getBranchSlugFromConfig(embeddableId) {
|
|
97
|
+
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
98
|
+
if (!fs.existsSync(configPath))
|
|
99
|
+
return 'main';
|
|
100
|
+
try {
|
|
101
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
102
|
+
const name = config._branch_name ?? config._branch_id;
|
|
103
|
+
if (typeof name === 'string' && name)
|
|
104
|
+
return slugForBranch(name);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
/* ignore */
|
|
108
|
+
}
|
|
109
|
+
return 'main';
|
|
110
|
+
}
|
|
72
111
|
/**
|
|
73
112
|
* Update `_version` in config.json for the given embeddable.
|
|
74
113
|
*/
|
|
@@ -87,7 +126,7 @@ function setVersionInConfig(embeddableId, version) {
|
|
|
87
126
|
}
|
|
88
127
|
}
|
|
89
128
|
/**
|
|
90
|
-
* Scan the .generated/ directory for versioned files (embeddable-v*.json)
|
|
129
|
+
* Scan the .generated/ directory for versioned files (embeddable-v*.json or embeddable-*@*.json)
|
|
91
130
|
* and return the highest version number found.
|
|
92
131
|
*/
|
|
93
132
|
function getLatestVersionFromFiles(generatedDir) {
|
|
@@ -95,10 +134,11 @@ function getLatestVersionFromFiles(generatedDir) {
|
|
|
95
134
|
return null;
|
|
96
135
|
}
|
|
97
136
|
const files = fs.readdirSync(generatedDir);
|
|
98
|
-
const
|
|
137
|
+
const legacyPattern = /^embeddable-v(\d+)\.json$/;
|
|
138
|
+
const branchPattern = /^embeddable-[^@]+@(\d+)\.json$/;
|
|
99
139
|
let maxVersion = null;
|
|
100
140
|
for (const file of files) {
|
|
101
|
-
const match = file.match(
|
|
141
|
+
const match = file.match(legacyPattern) ?? file.match(branchPattern);
|
|
102
142
|
if (match) {
|
|
103
143
|
const version = parseInt(match[1], 10);
|
|
104
144
|
if (maxVersion === null || version > maxVersion) {
|
|
@@ -108,6 +148,41 @@ function getLatestVersionFromFiles(generatedDir) {
|
|
|
108
148
|
}
|
|
109
149
|
return maxVersion;
|
|
110
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Fetch active drafts from other users on the same version (status=DRAFT, not saved/discarded).
|
|
153
|
+
* Used to warn before saving that others may have unsaved edits.
|
|
154
|
+
*/
|
|
155
|
+
async function fetchOtherUsersDrafts(supabase, flowId, versionNumber, branchId, currentUserId) {
|
|
156
|
+
try {
|
|
157
|
+
let query = supabase
|
|
158
|
+
.from('flow_versions')
|
|
159
|
+
.select('id, author_id, author_name')
|
|
160
|
+
.eq('flow_id', flowId)
|
|
161
|
+
.eq('status', 'DRAFT')
|
|
162
|
+
.eq('version_number', versionNumber)
|
|
163
|
+
.not('draft_saved', 'is', true)
|
|
164
|
+
.not('draft_discarded', 'is', true)
|
|
165
|
+
.neq('author_id', currentUserId);
|
|
166
|
+
if (branchId === null) {
|
|
167
|
+
query = query.is('branch_id', null);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
query = query.eq('branch_id', branchId);
|
|
171
|
+
}
|
|
172
|
+
const { data, error } = await query;
|
|
173
|
+
if (error) {
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
return (data || []).map((row) => ({
|
|
177
|
+
id: row.id,
|
|
178
|
+
author_id: row.author_id,
|
|
179
|
+
author_name: row.author_name ?? null,
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
111
186
|
export async function runSave(opts) {
|
|
112
187
|
try {
|
|
113
188
|
await runSaveInner(opts);
|
|
@@ -158,6 +233,8 @@ async function runSaveInner(opts) {
|
|
|
158
233
|
embeddableId = selected;
|
|
159
234
|
console.log('');
|
|
160
235
|
}
|
|
236
|
+
// Resolve branch: explicit -b flag wins, otherwise use current branch from config (set by `embeddables branch`)
|
|
237
|
+
const effectiveBranch = opts.branch ?? getBranchFromConfig(embeddableId) ?? undefined;
|
|
161
238
|
// 4. Get project ID (from config or interactive prompt)
|
|
162
239
|
let projectId = getProjectId();
|
|
163
240
|
if (!projectId) {
|
|
@@ -242,6 +319,39 @@ async function runSaveInner(opts) {
|
|
|
242
319
|
}
|
|
243
320
|
fromVersionNumber = detectedVersion;
|
|
244
321
|
}
|
|
322
|
+
// 7b. Check for other users' drafts on this version; warn and optionally abort
|
|
323
|
+
const supabase = await getAuthenticatedSupabaseClient();
|
|
324
|
+
if (supabase) {
|
|
325
|
+
const { data: { user }, } = await supabase.auth.getUser();
|
|
326
|
+
const currentUserId = user?.id;
|
|
327
|
+
if (currentUserId) {
|
|
328
|
+
const branchIdForDrafts = effectiveBranch ?? null;
|
|
329
|
+
const otherDrafts = await fetchOtherUsersDrafts(supabase, embeddableId, fromVersionNumber, branchIdForDrafts, currentUserId);
|
|
330
|
+
if (otherDrafts.length > 0) {
|
|
331
|
+
const names = otherDrafts
|
|
332
|
+
.map((d) => d.author_name?.trim() || d.author_id || 'Someone')
|
|
333
|
+
.filter((n, i, a) => a.indexOf(n) === i);
|
|
334
|
+
const namesText = names.length === 1 ? names[0] : `${names.slice(0, -1).join(', ')} and ${names[names.length - 1]}`;
|
|
335
|
+
console.log('');
|
|
336
|
+
console.warn(pc.yellow(`⚠ ${namesText} ${names.length === 1 ? 'has' : 'have'} unsaved edits on version ${fromVersionNumber}. Saving may cause conflicts.`));
|
|
337
|
+
const { proceed } = await prompts({
|
|
338
|
+
type: 'confirm',
|
|
339
|
+
name: 'proceed',
|
|
340
|
+
message: 'Save anyway?',
|
|
341
|
+
initial: false,
|
|
342
|
+
}, {
|
|
343
|
+
onCancel: () => {
|
|
344
|
+
process.exit(1);
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
if (!proceed) {
|
|
348
|
+
console.log(pc.gray('Save cancelled.'));
|
|
349
|
+
process.exit(0);
|
|
350
|
+
}
|
|
351
|
+
console.log('');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
245
355
|
// 8. POST to save-version API
|
|
246
356
|
console.log(pc.cyan(`Saving embeddable (based on v${fromVersionNumber})...`));
|
|
247
357
|
const body = {
|
|
@@ -253,8 +363,8 @@ async function runSaveInner(opts) {
|
|
|
253
363
|
if (opts.label) {
|
|
254
364
|
body.label = opts.label;
|
|
255
365
|
}
|
|
256
|
-
if (
|
|
257
|
-
body.branchId =
|
|
366
|
+
if (effectiveBranch) {
|
|
367
|
+
body.branchId = effectiveBranch;
|
|
258
368
|
}
|
|
259
369
|
const url = `${WEB_APP_BASE_URL}/api/embeddables/save-version`;
|
|
260
370
|
const headers = {
|
|
@@ -340,7 +450,8 @@ async function runSaveInner(opts) {
|
|
|
340
450
|
const { newVersionNumber } = forceResult.data;
|
|
341
451
|
console.log(pc.green(`✓ Saved as version ${newVersionNumber}`));
|
|
342
452
|
setVersionInConfig(embeddableId, newVersionNumber);
|
|
343
|
-
const
|
|
453
|
+
const branchSlug = getBranchSlugFromConfig(embeddableId);
|
|
454
|
+
const versionedPath = path.join(generatedDir, `embeddable-${branchSlug}@${newVersionNumber}.json`);
|
|
344
455
|
fs.mkdirSync(generatedDir, { recursive: true });
|
|
345
456
|
fs.writeFileSync(versionedPath, jsonContent, 'utf8');
|
|
346
457
|
console.log(pc.cyan(`✓ Saved version file to ${versionedPath}`));
|
|
@@ -358,8 +469,9 @@ async function runSaveInner(opts) {
|
|
|
358
469
|
console.log(pc.green(`✓ Saved as version ${newVersionNumber}`));
|
|
359
470
|
// Update _version in config.json so future saves know the base version
|
|
360
471
|
setVersionInConfig(embeddableId, newVersionNumber);
|
|
361
|
-
// Also save the versioned file to .generated/ as a snapshot
|
|
362
|
-
const
|
|
472
|
+
// Also save the versioned file to .generated/ as a snapshot (embeddable-{branch}@{version}.json)
|
|
473
|
+
const branchSlug = getBranchSlugFromConfig(embeddableId);
|
|
474
|
+
const versionedPath = path.join(generatedDir, `embeddable-${branchSlug}@${newVersionNumber}.json`);
|
|
363
475
|
fs.mkdirSync(generatedDir, { recursive: true });
|
|
364
476
|
fs.writeFileSync(versionedPath, jsonContent, 'utf8');
|
|
365
477
|
console.log(pc.cyan(`✓ Saved version file to ${versionedPath}`));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"AA+CA;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CA2DlF;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,UAAU,GAAG,QAAQ,CAAA;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"AA+CA;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CA2DlF;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,UAAU,GAAG,QAAQ,CAAA;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,iBAoXA"}
|
package/dist/compiler/index.js
CHANGED
|
@@ -333,6 +333,10 @@ export async function compileAllPages(opts) {
|
|
|
333
333
|
// Skip _version - this is CLI metadata (tracked version number), not part of the embeddable
|
|
334
334
|
continue;
|
|
335
335
|
}
|
|
336
|
+
else if (key === '_branch_id' || key === '_branch_name') {
|
|
337
|
+
// Skip _branch_id / _branch_name - CLI metadata (current branch), not part of the embeddable
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
336
340
|
else if (key === 'computedFields') {
|
|
337
341
|
// Replace computedFields with loaded computedFields (which include code)
|
|
338
342
|
if (computedFields.length > 0) {
|
|
@@ -9,6 +9,11 @@ export declare function reverseCompile(embeddable: {
|
|
|
9
9
|
[key: string]: any;
|
|
10
10
|
}, embeddableId: string, opts?: {
|
|
11
11
|
fix?: boolean;
|
|
12
|
+
pullMetadata?: {
|
|
13
|
+
version?: number;
|
|
14
|
+
branchId?: string;
|
|
15
|
+
branchName?: string;
|
|
16
|
+
};
|
|
12
17
|
}): Promise<void>;
|
|
13
18
|
/**
|
|
14
19
|
* Sanitizes a string to be safe for use as a filename.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reverse.d.ts","sourceRoot":"","sources":["../../src/compiler/reverse.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"reverse.d.ts","sourceRoot":"","sources":["../../src/compiler/reverse.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,YAAY,CAAA;AAqlBzD,wBAAsB,cAAc,CAClC,UAAU,EAAE;IACV,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B,cAAc,CAAC,EAAE,GAAG,EAAE,CAAA;IACtB,WAAW,CAAC,EAAE,GAAG,EAAE,CAAA;IACnB,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB,EACD,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE;IACL,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,YAAY,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAC5E,iBAmFF;AA+0CD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKpD"}
|
package/dist/compiler/reverse.js
CHANGED
|
@@ -284,6 +284,7 @@ function validateComponentProps(component, validProps) {
|
|
|
284
284
|
'tags',
|
|
285
285
|
'type',
|
|
286
286
|
'parent_id',
|
|
287
|
+
'parent_key',
|
|
287
288
|
'buttons',
|
|
288
289
|
...IGNORED_COMPONENT_PROPERTIES,
|
|
289
290
|
]);
|
|
@@ -424,6 +425,61 @@ function checkAndFixDuplicateIds(pages, fix) {
|
|
|
424
425
|
}
|
|
425
426
|
return idMapping;
|
|
426
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* Fixes deprecated parent_key: resolves to parent_id using first component with matching key,
|
|
430
|
+
* removes parent_key, and removes components that still have no parent_id after resolution.
|
|
431
|
+
* Only runs when fix is enabled.
|
|
432
|
+
*/
|
|
433
|
+
function fixParentKeyDeprecation(components, fix) {
|
|
434
|
+
if (!fix || components.length === 0)
|
|
435
|
+
return;
|
|
436
|
+
// Build key -> id map (first occurrence wins, exclude ignored types)
|
|
437
|
+
const keyToId = new Map();
|
|
438
|
+
for (const comp of components) {
|
|
439
|
+
if (comp.key &&
|
|
440
|
+
comp.id &&
|
|
441
|
+
!keyToId.has(comp.key) &&
|
|
442
|
+
comp.type &&
|
|
443
|
+
!IGNORED_COMPONENT_TYPES.has(comp.type)) {
|
|
444
|
+
keyToId.set(comp.key, comp.id);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
// Resolve parent_key -> parent_id, remove parent_key, track components to remove
|
|
448
|
+
const toRemove = new Map(); // id -> parent_key for warning
|
|
449
|
+
for (const comp of components) {
|
|
450
|
+
const parentKey = comp.parent_key;
|
|
451
|
+
if (!parentKey)
|
|
452
|
+
continue;
|
|
453
|
+
if (!comp.parent_id) {
|
|
454
|
+
const resolvedId = keyToId.get(parentKey);
|
|
455
|
+
if (resolvedId) {
|
|
456
|
+
comp.parent_id = resolvedId;
|
|
457
|
+
console.warn(`Fixed parent_key on component (id: ${comp.id}, key: ${comp.key}) – resolved parent_key "${parentKey}" to parent_id.`);
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
toRemove.set(comp.id, parentKey);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
console.warn(`Fixed parent_key on component (id: ${comp.id}, key: ${comp.key}) – removed deprecated parent_key (already has parent_id).`);
|
|
465
|
+
}
|
|
466
|
+
delete comp.parent_key;
|
|
467
|
+
}
|
|
468
|
+
// Remove components that couldn't resolve parent
|
|
469
|
+
if (toRemove.size > 0) {
|
|
470
|
+
let i = 0;
|
|
471
|
+
while (i < components.length) {
|
|
472
|
+
const comp = components[i];
|
|
473
|
+
if (toRemove.has(comp.id)) {
|
|
474
|
+
console.warn(`Removed component (id: ${comp.id}, key: ${comp.key}) – parent_key "${toRemove.get(comp.id)}" not found, no parent_id.`);
|
|
475
|
+
components.splice(i, 1);
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
i++;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
427
483
|
/**
|
|
428
484
|
* Applies the ID mapping to all pages, updating component IDs and button IDs.
|
|
429
485
|
* The mapping uses occurrence keys (pageKey:componentIndex or pageKey:componentIndex:buttonIndex).
|
|
@@ -461,14 +517,43 @@ function applyIdMapping(pages, idMapping) {
|
|
|
461
517
|
}
|
|
462
518
|
}
|
|
463
519
|
}
|
|
520
|
+
function hasDeprecatedParentKey(components) {
|
|
521
|
+
return components.some((comp) => comp.parent_key != null);
|
|
522
|
+
}
|
|
464
523
|
export async function reverseCompile(embeddable, embeddableId, opts) {
|
|
465
524
|
const fix = opts?.fix ?? false;
|
|
525
|
+
const pullMetadata = opts?.pullMetadata;
|
|
526
|
+
// When fix is disabled, throw on deprecated parent_key so user gets interactive retry prompt
|
|
527
|
+
if (!fix) {
|
|
528
|
+
for (const page of embeddable.pages) {
|
|
529
|
+
if (hasDeprecatedParentKey(page.components)) {
|
|
530
|
+
const count = page.components.filter((c) => c.parent_key != null).length;
|
|
531
|
+
throw new Error(`Found deprecated parent_key on ${count} component(s) in page "${page.key}". Run with --fix to resolve.`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
if (embeddable.components && Array.isArray(embeddable.components)) {
|
|
535
|
+
if (hasDeprecatedParentKey(embeddable.components)) {
|
|
536
|
+
const count = embeddable.components.filter((c) => c.parent_key != null).length;
|
|
537
|
+
throw new Error(`Found deprecated parent_key on ${count} global component(s). Run with --fix to resolve.`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
466
541
|
// Check for duplicate IDs across all pages and create a mapping
|
|
467
542
|
const idMapping = checkAndFixDuplicateIds(embeddable.pages, fix);
|
|
468
543
|
// Apply ID mapping to all pages
|
|
469
544
|
if (idMapping.size > 0) {
|
|
470
545
|
applyIdMapping(embeddable.pages, idMapping);
|
|
471
546
|
}
|
|
547
|
+
// Fix deprecated parent_key (resolve to parent_id, remove parent_key, drop orphans).
|
|
548
|
+
// Must run before extractGlobalComponents so resolved parent_id avoids "must have _location since it has no parent_id" errors.
|
|
549
|
+
if (fix) {
|
|
550
|
+
for (const page of embeddable.pages) {
|
|
551
|
+
fixParentKeyDeprecation(page.components, fix);
|
|
552
|
+
}
|
|
553
|
+
if (embeddable.components && Array.isArray(embeddable.components)) {
|
|
554
|
+
fixParentKeyDeprecation(embeddable.components, fix);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
472
557
|
// Generate TSX pages
|
|
473
558
|
for (const page of embeddable.pages) {
|
|
474
559
|
await generatePageFile(page, embeddableId, fix);
|
|
@@ -478,7 +563,7 @@ export async function reverseCompile(embeddable, embeddableId, opts) {
|
|
|
478
563
|
await generateStylesFile(embeddable.styles, embeddableId);
|
|
479
564
|
}
|
|
480
565
|
// Generate config.json
|
|
481
|
-
await generateConfigFile(embeddable, embeddableId);
|
|
566
|
+
await generateConfigFile(embeddable, embeddableId, pullMetadata);
|
|
482
567
|
// Extract computedFields to JS files
|
|
483
568
|
if (embeddable.computedFields && embeddable.computedFields.length > 0) {
|
|
484
569
|
await extractComputedFields(embeddable.computedFields, embeddableId);
|
|
@@ -758,6 +843,7 @@ function generateJSX(node, indent = 4, pageKey, componentId, nameMap) {
|
|
|
758
843
|
'tags',
|
|
759
844
|
'type',
|
|
760
845
|
'parent_id',
|
|
846
|
+
'parent_key',
|
|
761
847
|
'buttons',
|
|
762
848
|
'_location',
|
|
763
849
|
...IGNORED_COMPONENT_PROPERTIES,
|
|
@@ -1347,9 +1433,27 @@ function escapeStringForJS(str) {
|
|
|
1347
1433
|
* This file controls page ordering and stores embeddable-level metadata.
|
|
1348
1434
|
* Preserves the order of top-level properties from embeddable.json.
|
|
1349
1435
|
*/
|
|
1350
|
-
async function generateConfigFile(embeddable, embeddableId) {
|
|
1436
|
+
async function generateConfigFile(embeddable, embeddableId, pullMetadata) {
|
|
1351
1437
|
try {
|
|
1352
1438
|
const configPath = path.join('embeddables', embeddableId, 'config.json');
|
|
1439
|
+
// CLI-only fields: from pull (when branching/saving) or from existing config file.
|
|
1440
|
+
let preservedVersion;
|
|
1441
|
+
let preservedBranchId;
|
|
1442
|
+
let preservedBranchName;
|
|
1443
|
+
if (fs.existsSync(configPath)) {
|
|
1444
|
+
try {
|
|
1445
|
+
const existing = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
1446
|
+
if (typeof existing._version === 'number')
|
|
1447
|
+
preservedVersion = existing._version;
|
|
1448
|
+
if (typeof existing._branch_id === 'string' && existing._branch_id)
|
|
1449
|
+
preservedBranchId = existing._branch_id;
|
|
1450
|
+
if (typeof existing._branch_name === 'string' && existing._branch_name)
|
|
1451
|
+
preservedBranchName = existing._branch_name;
|
|
1452
|
+
}
|
|
1453
|
+
catch {
|
|
1454
|
+
/* ignore */
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1353
1457
|
// Preserve the order of top-level properties from embeddable
|
|
1354
1458
|
const embeddableKeys = Object.keys(embeddable);
|
|
1355
1459
|
// Extract page metadata and order (excluding components which are in TSX files)
|
|
@@ -1432,6 +1536,29 @@ async function generateConfigFile(embeddable, embeddableId) {
|
|
|
1432
1536
|
if (!config.id) {
|
|
1433
1537
|
config.id = embeddableId;
|
|
1434
1538
|
}
|
|
1539
|
+
// Restore CLI-only fields: prefer pullMetadata (passed by pull/branch) so branch is never lost.
|
|
1540
|
+
const versionToWrite = pullMetadata?.version ?? preservedVersion;
|
|
1541
|
+
if (versionToWrite !== undefined)
|
|
1542
|
+
config._version = versionToWrite;
|
|
1543
|
+
if (pullMetadata !== undefined) {
|
|
1544
|
+
if (pullMetadata.branchId !== undefined) {
|
|
1545
|
+
config._branch_id = pullMetadata.branchId;
|
|
1546
|
+
if (pullMetadata.branchName !== undefined)
|
|
1547
|
+
config._branch_name = pullMetadata.branchName;
|
|
1548
|
+
else
|
|
1549
|
+
delete config._branch_name;
|
|
1550
|
+
}
|
|
1551
|
+
else {
|
|
1552
|
+
delete config._branch_id;
|
|
1553
|
+
delete config._branch_name;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
else {
|
|
1557
|
+
if (preservedBranchId !== undefined)
|
|
1558
|
+
config._branch_id = preservedBranchId;
|
|
1559
|
+
if (preservedBranchName !== undefined)
|
|
1560
|
+
config._branch_name = preservedBranchName;
|
|
1561
|
+
}
|
|
1435
1562
|
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
1436
1563
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
1437
1564
|
console.log(`${pc.gray(`Generated ${configPath}`)}`);
|