@sitecore-content-sdk/cli 1.3.0-canary.4 → 1.3.0-canary.6
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.
|
@@ -49,17 +49,19 @@ exports.unitMocks = void 0;
|
|
|
49
49
|
exports.args = args;
|
|
50
50
|
exports.builder = builder;
|
|
51
51
|
exports.handler = handler;
|
|
52
|
+
const fs_1 = __importDefault(require("fs"));
|
|
53
|
+
const path_1 = __importDefault(require("path"));
|
|
52
54
|
const chalk_1 = __importDefault(require("chalk"));
|
|
53
55
|
const child_process_1 = require("child_process");
|
|
54
56
|
const tools = __importStar(require("@sitecore-content-sdk/core/tools"));
|
|
55
57
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
56
|
-
const load_config_1 = __importDefault(require("../../../utils/load-config"));
|
|
57
58
|
const generate_map_1 = require("./generate-map");
|
|
58
|
-
|
|
59
|
+
const load_config_1 = __importDefault(require("../../../utils/load-config"));
|
|
60
|
+
let { getComponentSpec, getComponentList, getComponentSpecUrl } = tools;
|
|
59
61
|
const unitMocks = (toolsModule) => {
|
|
60
|
-
|
|
62
|
+
getComponentSpec = toolsModule.getComponentSpec;
|
|
61
63
|
getComponentList = toolsModule.getComponentList;
|
|
62
|
-
|
|
64
|
+
getComponentSpecUrl = toolsModule.getComponentSpecUrl;
|
|
63
65
|
};
|
|
64
66
|
exports.unitMocks = unitMocks;
|
|
65
67
|
/**
|
|
@@ -68,11 +70,11 @@ exports.unitMocks = unitMocks;
|
|
|
68
70
|
function args(yargs) {
|
|
69
71
|
/* istanbul ignore next */
|
|
70
72
|
return yargs
|
|
71
|
-
.positional('
|
|
73
|
+
.positional('componentId', {
|
|
72
74
|
requiresArg: true,
|
|
73
75
|
positional: true,
|
|
74
76
|
type: 'string',
|
|
75
|
-
describe: `The unique identifier of the newly created
|
|
77
|
+
describe: `The unique identifier of the newly created component.`,
|
|
76
78
|
})
|
|
77
79
|
.option('token', {
|
|
78
80
|
requiresArg: true,
|
|
@@ -83,7 +85,7 @@ function args(yargs) {
|
|
|
83
85
|
.option('target-path', {
|
|
84
86
|
requiresArg: false,
|
|
85
87
|
type: 'string',
|
|
86
|
-
describe: 'The target path for the component
|
|
88
|
+
describe: 'The relative target path for the component.\n(Example: components/Promo.WithText.ts)',
|
|
87
89
|
})
|
|
88
90
|
.option('skip-component-map', {
|
|
89
91
|
requiresArg: false,
|
|
@@ -108,16 +110,35 @@ function args(yargs) {
|
|
|
108
110
|
*/
|
|
109
111
|
function builder(yargs) {
|
|
110
112
|
/* istanbul ignore next */
|
|
111
|
-
return yargs.command('add <
|
|
113
|
+
return yargs.command('add <component-id>', 'Adds a component', args, handler);
|
|
112
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Validates the target path. If no target path is provided, returns true.
|
|
117
|
+
* @param {string} [targetPath] - The target path to validate.
|
|
118
|
+
* @returns {boolean | string} True if the target path is valid, the error message otherwise.
|
|
119
|
+
*/
|
|
120
|
+
const validateTargetPath = (targetPath) => {
|
|
121
|
+
if (!targetPath) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
// Check for unsafe absolute path starting with "/"
|
|
125
|
+
if (path_1.default.isAbsolute(targetPath)) {
|
|
126
|
+
return 'Target path cannot be an absolute path starting with "/"';
|
|
127
|
+
}
|
|
128
|
+
// Check for path traversal attempts
|
|
129
|
+
if (targetPath.includes('..')) {
|
|
130
|
+
return 'Target path cannot contain ".." (path traversal)';
|
|
131
|
+
}
|
|
132
|
+
return true;
|
|
133
|
+
};
|
|
113
134
|
/**
|
|
114
135
|
* Handler for the add command.
|
|
115
136
|
* @param {AddArgs} argv - The arguments passed to the command.
|
|
116
137
|
*/
|
|
117
138
|
function handler(argv) {
|
|
118
139
|
return __awaiter(this, void 0, void 0, function* () {
|
|
119
|
-
const {
|
|
120
|
-
console.log(chalk_1.default.green('Adding component
|
|
140
|
+
const { componentId, token, targetPath: targetPathArg, skipComponentMap, config, overwrite, } = argv;
|
|
141
|
+
console.log(chalk_1.default.green('Adding component'));
|
|
121
142
|
let targetPath = targetPathArg;
|
|
122
143
|
const cliConfig = (0, load_config_1.default)(config);
|
|
123
144
|
if (!cliConfig.config) {
|
|
@@ -125,10 +146,16 @@ function handler(argv) {
|
|
|
125
146
|
return;
|
|
126
147
|
}
|
|
127
148
|
const { edgeUrl } = cliConfig.config.api.edge;
|
|
149
|
+
let backupPath;
|
|
150
|
+
let resolvedFilePath;
|
|
128
151
|
try {
|
|
129
|
-
|
|
152
|
+
if (validateTargetPath(targetPath) !== true) {
|
|
153
|
+
console.error(chalk_1.default.red(validateTargetPath(targetPath)));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const spec = yield getComponentSpec({
|
|
130
157
|
edgeUrl,
|
|
131
|
-
|
|
158
|
+
componentId,
|
|
132
159
|
targetPath,
|
|
133
160
|
token,
|
|
134
161
|
});
|
|
@@ -155,29 +182,54 @@ function handler(argv) {
|
|
|
155
182
|
type: 'input',
|
|
156
183
|
name: 'targetPath',
|
|
157
184
|
required: true,
|
|
158
|
-
message: `Enter the target path for the component
|
|
185
|
+
message: `Enter the target path for the component.\n(Example: components/Promo.WithText.ts):`,
|
|
186
|
+
validate: validateTargetPath,
|
|
159
187
|
})
|
|
160
188
|
.then((answer) => answer.targetPath);
|
|
161
189
|
}
|
|
162
190
|
}
|
|
163
|
-
|
|
164
|
-
|
|
191
|
+
resolvedFilePath = path_1.default.resolve(process.cwd(), targetPath);
|
|
192
|
+
const isFileAlreadyExists = fs_1.default.existsSync(resolvedFilePath);
|
|
193
|
+
backupPath = `${resolvedFilePath}.backup`;
|
|
194
|
+
if (isFileAlreadyExists) {
|
|
195
|
+
if (!overwrite) {
|
|
196
|
+
const shouldOverwrite = yield inquirer_1.default.prompt({
|
|
197
|
+
type: 'confirm',
|
|
198
|
+
name: 'overwrite',
|
|
199
|
+
message: `File already exists: ${targetPath}. Overwrite?`,
|
|
200
|
+
default: false,
|
|
201
|
+
});
|
|
202
|
+
if (!shouldOverwrite.overwrite) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
fs_1.default.renameSync(resolvedFilePath, backupPath);
|
|
207
|
+
console.log(chalk_1.default.yellow(`Overwriting existing file: ${targetPath}`));
|
|
208
|
+
}
|
|
209
|
+
const componentSpecUrl = getComponentSpecUrl({
|
|
210
|
+
componentId,
|
|
165
211
|
targetPath: targetPath,
|
|
166
212
|
edgeUrl,
|
|
167
213
|
token,
|
|
168
214
|
});
|
|
169
|
-
(0, child_process_1.execSync)(`npx shadcn@^3.4.2 add "${
|
|
215
|
+
(0, child_process_1.execSync)(`npx shadcn@^3.4.2 add "${componentSpecUrl}"`, {
|
|
170
216
|
stdio: 'inherit',
|
|
171
217
|
cwd: process.cwd(),
|
|
172
218
|
});
|
|
219
|
+
if (isFileAlreadyExists) {
|
|
220
|
+
fs_1.default.unlinkSync(backupPath);
|
|
221
|
+
}
|
|
173
222
|
if (!skipComponentMap) {
|
|
174
223
|
(0, generate_map_1.handler)({ config });
|
|
175
224
|
}
|
|
176
|
-
console.log(chalk_1.default.green(`Component
|
|
225
|
+
console.log(chalk_1.default.green(`Component ${componentName} added successfully`));
|
|
177
226
|
}
|
|
178
227
|
catch (error) {
|
|
228
|
+
if (backupPath && resolvedFilePath && fs_1.default.existsSync(backupPath)) {
|
|
229
|
+
fs_1.default.renameSync(backupPath, resolvedFilePath);
|
|
230
|
+
}
|
|
179
231
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
180
|
-
console.error(chalk_1.default.red(`Failed to add component
|
|
232
|
+
console.error(chalk_1.default.red(`Failed to add component: ${errorMessage}`));
|
|
181
233
|
return;
|
|
182
234
|
}
|
|
183
235
|
});
|
|
@@ -7,17 +7,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
10
12
|
import chalk from 'chalk';
|
|
11
13
|
import { execSync } from 'child_process';
|
|
12
14
|
import * as tools from '@sitecore-content-sdk/core/tools';
|
|
13
15
|
import inquirer from 'inquirer';
|
|
14
|
-
import loadCliConfig from '../../../utils/load-config';
|
|
15
16
|
import { handler as generateMapHandler } from './generate-map';
|
|
16
|
-
|
|
17
|
+
import loadCliConfig from '../../../utils/load-config';
|
|
18
|
+
let { getComponentSpec, getComponentList, getComponentSpecUrl } = tools;
|
|
17
19
|
export const unitMocks = (toolsModule) => {
|
|
18
|
-
|
|
20
|
+
getComponentSpec = toolsModule.getComponentSpec;
|
|
19
21
|
getComponentList = toolsModule.getComponentList;
|
|
20
|
-
|
|
22
|
+
getComponentSpecUrl = toolsModule.getComponentSpecUrl;
|
|
21
23
|
};
|
|
22
24
|
/**
|
|
23
25
|
* @param {Argv} yargs
|
|
@@ -25,11 +27,11 @@ export const unitMocks = (toolsModule) => {
|
|
|
25
27
|
export function args(yargs) {
|
|
26
28
|
/* istanbul ignore next */
|
|
27
29
|
return yargs
|
|
28
|
-
.positional('
|
|
30
|
+
.positional('componentId', {
|
|
29
31
|
requiresArg: true,
|
|
30
32
|
positional: true,
|
|
31
33
|
type: 'string',
|
|
32
|
-
describe: `The unique identifier of the newly created
|
|
34
|
+
describe: `The unique identifier of the newly created component.`,
|
|
33
35
|
})
|
|
34
36
|
.option('token', {
|
|
35
37
|
requiresArg: true,
|
|
@@ -40,7 +42,7 @@ export function args(yargs) {
|
|
|
40
42
|
.option('target-path', {
|
|
41
43
|
requiresArg: false,
|
|
42
44
|
type: 'string',
|
|
43
|
-
describe: 'The target path for the component
|
|
45
|
+
describe: 'The relative target path for the component.\n(Example: components/Promo.WithText.ts)',
|
|
44
46
|
})
|
|
45
47
|
.option('skip-component-map', {
|
|
46
48
|
requiresArg: false,
|
|
@@ -65,16 +67,35 @@ export function args(yargs) {
|
|
|
65
67
|
*/
|
|
66
68
|
export function builder(yargs) {
|
|
67
69
|
/* istanbul ignore next */
|
|
68
|
-
return yargs.command('add <
|
|
70
|
+
return yargs.command('add <component-id>', 'Adds a component', args, handler);
|
|
69
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Validates the target path. If no target path is provided, returns true.
|
|
74
|
+
* @param {string} [targetPath] - The target path to validate.
|
|
75
|
+
* @returns {boolean | string} True if the target path is valid, the error message otherwise.
|
|
76
|
+
*/
|
|
77
|
+
const validateTargetPath = (targetPath) => {
|
|
78
|
+
if (!targetPath) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
// Check for unsafe absolute path starting with "/"
|
|
82
|
+
if (path.isAbsolute(targetPath)) {
|
|
83
|
+
return 'Target path cannot be an absolute path starting with "/"';
|
|
84
|
+
}
|
|
85
|
+
// Check for path traversal attempts
|
|
86
|
+
if (targetPath.includes('..')) {
|
|
87
|
+
return 'Target path cannot contain ".." (path traversal)';
|
|
88
|
+
}
|
|
89
|
+
return true;
|
|
90
|
+
};
|
|
70
91
|
/**
|
|
71
92
|
* Handler for the add command.
|
|
72
93
|
* @param {AddArgs} argv - The arguments passed to the command.
|
|
73
94
|
*/
|
|
74
95
|
export function handler(argv) {
|
|
75
96
|
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
-
const {
|
|
77
|
-
console.log(chalk.green('Adding component
|
|
97
|
+
const { componentId, token, targetPath: targetPathArg, skipComponentMap, config, overwrite, } = argv;
|
|
98
|
+
console.log(chalk.green('Adding component'));
|
|
78
99
|
let targetPath = targetPathArg;
|
|
79
100
|
const cliConfig = loadCliConfig(config);
|
|
80
101
|
if (!cliConfig.config) {
|
|
@@ -82,10 +103,16 @@ export function handler(argv) {
|
|
|
82
103
|
return;
|
|
83
104
|
}
|
|
84
105
|
const { edgeUrl } = cliConfig.config.api.edge;
|
|
106
|
+
let backupPath;
|
|
107
|
+
let resolvedFilePath;
|
|
85
108
|
try {
|
|
86
|
-
|
|
109
|
+
if (validateTargetPath(targetPath) !== true) {
|
|
110
|
+
console.error(chalk.red(validateTargetPath(targetPath)));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const spec = yield getComponentSpec({
|
|
87
114
|
edgeUrl,
|
|
88
|
-
|
|
115
|
+
componentId,
|
|
89
116
|
targetPath,
|
|
90
117
|
token,
|
|
91
118
|
});
|
|
@@ -112,29 +139,54 @@ export function handler(argv) {
|
|
|
112
139
|
type: 'input',
|
|
113
140
|
name: 'targetPath',
|
|
114
141
|
required: true,
|
|
115
|
-
message: `Enter the target path for the component
|
|
142
|
+
message: `Enter the target path for the component.\n(Example: components/Promo.WithText.ts):`,
|
|
143
|
+
validate: validateTargetPath,
|
|
116
144
|
})
|
|
117
145
|
.then((answer) => answer.targetPath);
|
|
118
146
|
}
|
|
119
147
|
}
|
|
120
|
-
|
|
121
|
-
|
|
148
|
+
resolvedFilePath = path.resolve(process.cwd(), targetPath);
|
|
149
|
+
const isFileAlreadyExists = fs.existsSync(resolvedFilePath);
|
|
150
|
+
backupPath = `${resolvedFilePath}.backup`;
|
|
151
|
+
if (isFileAlreadyExists) {
|
|
152
|
+
if (!overwrite) {
|
|
153
|
+
const shouldOverwrite = yield inquirer.prompt({
|
|
154
|
+
type: 'confirm',
|
|
155
|
+
name: 'overwrite',
|
|
156
|
+
message: `File already exists: ${targetPath}. Overwrite?`,
|
|
157
|
+
default: false,
|
|
158
|
+
});
|
|
159
|
+
if (!shouldOverwrite.overwrite) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
fs.renameSync(resolvedFilePath, backupPath);
|
|
164
|
+
console.log(chalk.yellow(`Overwriting existing file: ${targetPath}`));
|
|
165
|
+
}
|
|
166
|
+
const componentSpecUrl = getComponentSpecUrl({
|
|
167
|
+
componentId,
|
|
122
168
|
targetPath: targetPath,
|
|
123
169
|
edgeUrl,
|
|
124
170
|
token,
|
|
125
171
|
});
|
|
126
|
-
execSync(`npx shadcn@^3.4.2 add "${
|
|
172
|
+
execSync(`npx shadcn@^3.4.2 add "${componentSpecUrl}"`, {
|
|
127
173
|
stdio: 'inherit',
|
|
128
174
|
cwd: process.cwd(),
|
|
129
175
|
});
|
|
176
|
+
if (isFileAlreadyExists) {
|
|
177
|
+
fs.unlinkSync(backupPath);
|
|
178
|
+
}
|
|
130
179
|
if (!skipComponentMap) {
|
|
131
180
|
generateMapHandler({ config });
|
|
132
181
|
}
|
|
133
|
-
console.log(chalk.green(`Component
|
|
182
|
+
console.log(chalk.green(`Component ${componentName} added successfully`));
|
|
134
183
|
}
|
|
135
184
|
catch (error) {
|
|
185
|
+
if (backupPath && resolvedFilePath && fs.existsSync(backupPath)) {
|
|
186
|
+
fs.renameSync(backupPath, resolvedFilePath);
|
|
187
|
+
}
|
|
136
188
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
137
|
-
console.error(chalk.red(`Failed to add component
|
|
189
|
+
console.error(chalk.red(`Failed to add component: ${errorMessage}`));
|
|
138
190
|
return;
|
|
139
191
|
}
|
|
140
192
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sitecore-content-sdk/cli",
|
|
3
|
-
"version": "1.3.0-canary.
|
|
3
|
+
"version": "1.3.0-canary.6",
|
|
4
4
|
"description": "Sitecore Content SDK CLI",
|
|
5
5
|
"main": "dist/cjs/cli.js",
|
|
6
6
|
"module": "dist/esm/cli.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"url": "https://github.com/sitecore/content-sdk/issues"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@sitecore-content-sdk/core": "1.3.0-canary.
|
|
37
|
+
"@sitecore-content-sdk/core": "1.3.0-canary.6",
|
|
38
38
|
"chokidar": "^4.0.3",
|
|
39
39
|
"dotenv": "^16.5.0",
|
|
40
40
|
"dotenv-expand": "^12.0.2",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"ts-node": "^10.9.1",
|
|
72
72
|
"typescript": "~5.8.3"
|
|
73
73
|
},
|
|
74
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "d60fd135077312b8541f2a23892b02f4631bb0e1",
|
|
75
75
|
"files": [
|
|
76
76
|
"dist",
|
|
77
77
|
"types"
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { Argv } from 'yargs';
|
|
2
2
|
import * as tools from '@sitecore-content-sdk/core/tools';
|
|
3
|
-
export declare const unitMocks: (toolsModule: Pick<typeof tools, "
|
|
3
|
+
export declare const unitMocks: (toolsModule: Pick<typeof tools, "getComponentSpec" | "getComponentList" | "getComponentSpecUrl">) => void;
|
|
4
4
|
type AddArgs = {
|
|
5
5
|
/**
|
|
6
|
-
* The unique identifier of the newly created
|
|
6
|
+
* The unique identifier of the newly created component.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
componentId: string;
|
|
9
9
|
/**
|
|
10
10
|
* The authentication token.
|
|
11
11
|
*/
|
|
12
12
|
token: string;
|
|
13
13
|
/**
|
|
14
|
-
* The target path for the component
|
|
14
|
+
* The target path for the component.
|
|
15
15
|
*/
|
|
16
16
|
targetPath?: string;
|
|
17
17
|
/**
|
|
@@ -33,8 +33,8 @@ type AddArgs = {
|
|
|
33
33
|
/**
|
|
34
34
|
* @param {Argv} yargs
|
|
35
35
|
*/
|
|
36
|
-
export declare function args(yargs: Argv<AddArgs>): Argv<import("yargs").Omit<import("yargs").Omit<import("yargs").Omit<import("yargs").Omit<AddArgs, "
|
|
37
|
-
|
|
36
|
+
export declare function args(yargs: Argv<AddArgs>): Argv<import("yargs").Omit<import("yargs").Omit<import("yargs").Omit<import("yargs").Omit<AddArgs, "componentId"> & {
|
|
37
|
+
componentId: string | undefined;
|
|
38
38
|
}, "token"> & {
|
|
39
39
|
token: string;
|
|
40
40
|
} & {
|