@sitecore-content-sdk/cli 1.3.0-canary.7 → 1.3.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.
Files changed (50) hide show
  1. package/LICENSE.txt +202 -202
  2. package/README.md +5 -5
  3. package/dist/cjs/bin/sitecore-tools.js +77 -77
  4. package/dist/cjs/cli.js +69 -69
  5. package/dist/cjs/scripts/index.js +40 -40
  6. package/dist/cjs/scripts/project/build.js +42 -42
  7. package/dist/cjs/scripts/project/component/add.js +241 -236
  8. package/dist/cjs/scripts/project/component/generate-map.js +70 -68
  9. package/dist/cjs/scripts/project/component/index.js +57 -57
  10. package/dist/cjs/scripts/project/component/scaffold.js +69 -66
  11. package/dist/cjs/scripts/project/index.js +56 -56
  12. package/dist/cjs/utils/load-config.js +42 -42
  13. package/dist/cjs/utils/process-env.js +70 -70
  14. package/dist/cjs/utils/watch-items.js +18 -18
  15. package/dist/esm/cli.js +63 -63
  16. package/dist/esm/scripts/index.js +4 -4
  17. package/dist/esm/scripts/project/build.js +35 -35
  18. package/dist/esm/scripts/project/component/add.js +198 -193
  19. package/dist/esm/scripts/project/component/generate-map.js +62 -60
  20. package/dist/esm/scripts/project/component/index.js +21 -21
  21. package/dist/esm/scripts/project/component/scaffold.js +61 -58
  22. package/dist/esm/scripts/project/index.js +20 -20
  23. package/dist/esm/utils/load-config.js +36 -36
  24. package/dist/esm/utils/process-env.js +31 -31
  25. package/dist/esm/utils/watch-items.js +12 -12
  26. package/package.json +79 -79
  27. package/types/bin/sitecore-tools.d.ts +3 -2
  28. package/types/bin/sitecore-tools.d.ts.map +1 -0
  29. package/types/cli.d.ts +14 -13
  30. package/types/cli.d.ts.map +1 -0
  31. package/types/scripts/index.d.ts +3 -2
  32. package/types/scripts/index.d.ts.map +1 -0
  33. package/types/scripts/project/build.d.ts +25 -24
  34. package/types/scripts/project/build.d.ts.map +1 -0
  35. package/types/scripts/project/component/add.d.ts +59 -58
  36. package/types/scripts/project/component/add.d.ts.map +1 -0
  37. package/types/scripts/project/component/generate-map.d.ts +33 -32
  38. package/types/scripts/project/component/generate-map.d.ts.map +1 -0
  39. package/types/scripts/project/component/index.d.ts +6 -5
  40. package/types/scripts/project/component/index.d.ts.map +1 -0
  41. package/types/scripts/project/component/scaffold.d.ts +45 -44
  42. package/types/scripts/project/component/scaffold.d.ts.map +1 -0
  43. package/types/scripts/project/index.d.ts +6 -5
  44. package/types/scripts/project/index.d.ts.map +1 -0
  45. package/types/utils/load-config.d.ts +9 -8
  46. package/types/utils/load-config.d.ts.map +1 -0
  47. package/types/utils/process-env.d.ts +9 -8
  48. package/types/utils/process-env.d.ts.map +1 -0
  49. package/types/utils/watch-items.d.ts +7 -6
  50. package/types/utils/watch-items.d.ts.map +1 -0
package/dist/esm/cli.js CHANGED
@@ -1,63 +1,63 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import yargs from 'yargs';
11
- // Makes the script crash on unhandled rejections instead of silently
12
- // ignoring them. In the future, promise rejections that are not handled will
13
- // terminate the Node.js process with a non-zero exit code.
14
- process.on('unhandledRejection', (err) => {
15
- throw err;
16
- });
17
- /**
18
- * Initializes and configures the CLI application using yargs.
19
- * This function registers commands, sets up argument parsing, and handles command execution.
20
- * @param {object} commands - An object containing command modules to be registered with yargs.
21
- * Each key in the object represents a command name, and the value is a `CommandModule` object
22
- * that defines the command's behavior, arguments, and options.
23
- */
24
- export default function cli(commands) {
25
- return __awaiter(this, void 0, void 0, function* () {
26
- let appCommands = yargs.usage('$0 <command>');
27
- appCommands = appCommands.scriptName('sitecore-tools');
28
- // Register commands if available
29
- if (commands && Object.keys(commands).length > 0) {
30
- for (const cmd of Object.keys(commands)) {
31
- const commandObject = commands[cmd];
32
- if (typeof commandObject.builder === 'function') {
33
- appCommands = yield commandObject.builder(appCommands);
34
- }
35
- if (typeof commandObject.builder === 'object') {
36
- const ogBuilder = commandObject.builder;
37
- const builderFunc = commandObject.disableStrictArgs
38
- ? (yarrrrg) => yarrrrg.options(ogBuilder)
39
- : (yarrrrg) => yarrrrg.options(ogBuilder).strict();
40
- commandObject.builder = builderFunc;
41
- appCommands = appCommands.command(commandObject);
42
- }
43
- }
44
- }
45
- appCommands
46
- .command({
47
- command: '*',
48
- handler: (argv) => {
49
- if (argv._.length > 0) {
50
- console.error(`Command not found: "${argv._[0]}"`);
51
- }
52
- else {
53
- console.error('No command provided');
54
- }
55
- yargs.showHelp();
56
- process.exit(1);
57
- },
58
- })
59
- .demandCommand(1, 'You need to specify a command to run')
60
- .strict();
61
- yield appCommands.argv;
62
- });
63
- }
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import yargs from 'yargs';
11
+ // Makes the script crash on unhandled rejections instead of silently
12
+ // ignoring them. In the future, promise rejections that are not handled will
13
+ // terminate the Node.js process with a non-zero exit code.
14
+ process.on('unhandledRejection', (err) => {
15
+ throw err;
16
+ });
17
+ /**
18
+ * Initializes and configures the CLI application using yargs.
19
+ * This function registers commands, sets up argument parsing, and handles command execution.
20
+ * @param {object} commands - An object containing command modules to be registered with yargs.
21
+ * Each key in the object represents a command name, and the value is a `CommandModule` object
22
+ * that defines the command's behavior, arguments, and options.
23
+ */
24
+ export default function cli(commands) {
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ let appCommands = yargs.usage('$0 <command>');
27
+ appCommands = appCommands.scriptName('sitecore-tools');
28
+ // Register commands if available
29
+ if (commands && Object.keys(commands).length > 0) {
30
+ for (const cmd of Object.keys(commands)) {
31
+ const commandObject = commands[cmd];
32
+ if (typeof commandObject.builder === 'function') {
33
+ appCommands = yield commandObject.builder(appCommands);
34
+ }
35
+ if (typeof commandObject.builder === 'object') {
36
+ const ogBuilder = commandObject.builder;
37
+ const builderFunc = commandObject.disableStrictArgs
38
+ ? (yarrrrg) => yarrrrg.options(ogBuilder)
39
+ : (yarrrrg) => yarrrrg.options(ogBuilder).strict();
40
+ commandObject.builder = builderFunc;
41
+ appCommands = appCommands.command(commandObject);
42
+ }
43
+ }
44
+ }
45
+ appCommands
46
+ .command({
47
+ command: '*',
48
+ handler: (argv) => {
49
+ if (argv._.length > 0) {
50
+ console.error(`Command not found: "${argv._[0]}"`);
51
+ }
52
+ else {
53
+ console.error('No command provided');
54
+ }
55
+ yargs.showHelp();
56
+ process.exit(1);
57
+ },
58
+ })
59
+ .demandCommand(1, 'You need to specify a command to run')
60
+ .strict();
61
+ yield appCommands.argv;
62
+ });
63
+ }
@@ -1,4 +1,4 @@
1
- // commands available when running from an app location (with CLI installed to local node_modules)
2
- // e.g. setup, deploy
3
- import * as project from './project';
4
- export { project };
1
+ // commands available when running from an app location (with CLI installed to local node_modules)
2
+ // e.g. setup, deploy
3
+ import * as project from './project';
4
+ export { project };
@@ -1,35 +1,35 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import loadCliConfig from '../../utils/load-config';
11
- export const command = 'build';
12
- export const describe = 'Performs build time automation';
13
- export const builder = {
14
- config: {
15
- requiresArg: false,
16
- type: 'string',
17
- describe: 'Path to the `sitecore.cli.config` file. Supports both JavaScript (`.js`) and TypeScript (`.ts`) formats.',
18
- },
19
- };
20
- /**
21
- * Handler for the build command.
22
- * @param {BuildArgs} argv - The arguments passed to the command.
23
- */
24
- export function handler(argv) {
25
- return __awaiter(this, void 0, void 0, function* () {
26
- const cliConfig = loadCliConfig(argv.config);
27
- if (cliConfig.build && Array.isArray(cliConfig.build.commands)) {
28
- for (const command of cliConfig.build.commands) {
29
- yield command({ scConfig: cliConfig.config });
30
- }
31
- }
32
- // Exit the process to avoid hanging the process by custom build commands
33
- process.exit(0);
34
- });
35
- }
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import loadCliConfig from '../../utils/load-config';
11
+ export const command = ['build', 'b'];
12
+ export const describe = 'Performs build time automation';
13
+ export const builder = {
14
+ config: {
15
+ requiresArg: false,
16
+ type: 'string',
17
+ describe: 'Path to the `sitecore.cli.config` file. Supports both JavaScript (`.js`) and TypeScript (`.ts`) formats.',
18
+ },
19
+ };
20
+ /**
21
+ * Handler for the build command.
22
+ * @param {BuildArgs} argv - The arguments passed to the command.
23
+ */
24
+ export function handler(argv) {
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ const cliConfig = loadCliConfig(argv.config);
27
+ if (cliConfig.build && Array.isArray(cliConfig.build.commands)) {
28
+ for (const command of cliConfig.build.commands) {
29
+ yield command({ scConfig: cliConfig.config });
30
+ }
31
+ }
32
+ // Exit the process to avoid hanging the process by custom build commands
33
+ process.exit(0);
34
+ });
35
+ }
@@ -1,193 +1,198 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import fs from 'fs';
11
- import path from 'path';
12
- import chalk from 'chalk';
13
- import { execSync } from 'child_process';
14
- import * as tools from '@sitecore-content-sdk/core/tools';
15
- import inquirer from 'inquirer';
16
- import { handler as generateMapHandler } from './generate-map';
17
- import loadCliConfig from '../../../utils/load-config';
18
- let { getComponentSpec, getComponentList, getComponentSpecUrl } = tools;
19
- export const unitMocks = (toolsModule) => {
20
- getComponentSpec = toolsModule.getComponentSpec;
21
- getComponentList = toolsModule.getComponentList;
22
- getComponentSpecUrl = toolsModule.getComponentSpecUrl;
23
- };
24
- /**
25
- * @param {Argv} yargs
26
- */
27
- export function args(yargs) {
28
- /* istanbul ignore next */
29
- return yargs
30
- .positional('componentId', {
31
- requiresArg: true,
32
- positional: true,
33
- type: 'string',
34
- describe: `The unique identifier of the newly created component.`,
35
- })
36
- .option('token', {
37
- requiresArg: true,
38
- type: 'string',
39
- describe: 'The authentication token.',
40
- demandOption: true,
41
- })
42
- .option('target-path', {
43
- requiresArg: false,
44
- type: 'string',
45
- describe: 'The relative target path for the component.\n(Example: components/Promo.WithText.ts)',
46
- })
47
- .option('skip-component-map', {
48
- requiresArg: false,
49
- type: 'boolean',
50
- describe: 'If true, skips the component map generation.',
51
- default: false,
52
- })
53
- .option('overwrite', {
54
- requiresArg: false,
55
- type: 'boolean',
56
- describe: 'If true, overwrites the existing component.',
57
- default: false,
58
- })
59
- .option('config', {
60
- requiresArg: false,
61
- type: 'string',
62
- describe: 'Path to the `sitecore.cli.config` file. Supports both JavaScript (`.js`) and TypeScript (`.ts`) formats',
63
- });
64
- }
65
- /**
66
- * @param {Argv} yargs
67
- */
68
- export function builder(yargs) {
69
- /* istanbul ignore next */
70
- return yargs.command('add <component-id>', 'Adds a component', args, handler);
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
- };
91
- /**
92
- * Handler for the add command.
93
- * @param {AddArgs} argv - The arguments passed to the command.
94
- */
95
- export function handler(argv) {
96
- return __awaiter(this, void 0, void 0, function* () {
97
- const { componentId, token, targetPath: targetPathArg, skipComponentMap, config, overwrite, } = argv;
98
- console.log(chalk.green('Adding component'));
99
- let targetPath = targetPathArg;
100
- const cliConfig = loadCliConfig(config);
101
- if (!cliConfig.config) {
102
- console.error('The `sitecore.cli.config` file is missing a `config`. Please add it to use this command.');
103
- return;
104
- }
105
- const { edgeUrl } = cliConfig.config.api.edge;
106
- let backupPath;
107
- let resolvedFilePath;
108
- try {
109
- if (validateTargetPath(targetPath) !== true) {
110
- console.error(chalk.red(validateTargetPath(targetPath)));
111
- return;
112
- }
113
- const spec = yield getComponentSpec({
114
- edgeUrl,
115
- componentId,
116
- targetPath,
117
- token,
118
- });
119
- const componentType = spec.meta['contentsdk-component-type'];
120
- const componentName = spec.meta['contentsdk-component-name'];
121
- const variantName = spec.meta['contentsdk-component-variant-name'];
122
- const title = spec.title;
123
- if (componentType !== 'variant') {
124
- console.error(chalk.red(`The component "${title}" is not a content-sdk variant. Please, select a content-sdk variant to use this command.`));
125
- return;
126
- }
127
- if (!targetPath) {
128
- const { paths, exclude } = cliConfig.componentMap;
129
- const components = getComponentList(paths, exclude, true);
130
- const registeredComponent = components.find((c) => c.componentName === componentName);
131
- if (registeredComponent) {
132
- targetPath = registeredComponent.filePath
133
- .replace(/\\/g, '/')
134
- .replace(/([^/]+)\.([^.]+)$/, `$1.${variantName}.$2`);
135
- }
136
- else {
137
- targetPath = yield inquirer
138
- .prompt({
139
- type: 'input',
140
- name: 'targetPath',
141
- required: true,
142
- message: `Enter the target path for the component.\n(Example: components/Promo.WithText.ts):`,
143
- validate: validateTargetPath,
144
- })
145
- .then((answer) => answer.targetPath);
146
- }
147
- }
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,
168
- targetPath: targetPath,
169
- edgeUrl,
170
- token,
171
- });
172
- execSync(`npx shadcn@^3.4.2 add "${componentSpecUrl}"`, {
173
- stdio: 'inherit',
174
- cwd: process.cwd(),
175
- });
176
- if (isFileAlreadyExists) {
177
- fs.unlinkSync(backupPath);
178
- }
179
- if (!skipComponentMap) {
180
- generateMapHandler({ config });
181
- }
182
- console.log(chalk.green(`Component ${componentName} added successfully`));
183
- }
184
- catch (error) {
185
- if (backupPath && resolvedFilePath && fs.existsSync(backupPath)) {
186
- fs.renameSync(backupPath, resolvedFilePath);
187
- }
188
- const errorMessage = error instanceof Error ? error.message : String(error);
189
- console.error(chalk.red(`Failed to add component: ${errorMessage}`));
190
- return;
191
- }
192
- });
193
- }
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import chalk from 'chalk';
13
+ import { execSync } from 'child_process';
14
+ import * as tools from '@sitecore-content-sdk/core/tools';
15
+ import inquirer from 'inquirer';
16
+ import { handler as generateMapHandler } from './generate-map';
17
+ import loadCliConfig from '../../../utils/load-config';
18
+ let { getComponentSpec, getComponentList, getComponentSpecUrl } = tools;
19
+ export const unitMocks = (toolsModule) => {
20
+ getComponentSpec = toolsModule.getComponentSpec;
21
+ getComponentList = toolsModule.getComponentList;
22
+ getComponentSpecUrl = toolsModule.getComponentSpecUrl;
23
+ };
24
+ /**
25
+ * @param {Argv} yargs
26
+ */
27
+ export function args(yargs) {
28
+ /* istanbul ignore next */
29
+ return yargs
30
+ .positional('componentId', {
31
+ requiresArg: true,
32
+ positional: true,
33
+ type: 'string',
34
+ describe: `The unique identifier of the newly created component.`,
35
+ })
36
+ .option('token', {
37
+ requiresArg: true,
38
+ type: 'string',
39
+ describe: 'The authentication token.',
40
+ demandOption: true,
41
+ alias: 't',
42
+ })
43
+ .option('target-path', {
44
+ requiresArg: false,
45
+ type: 'string',
46
+ describe: 'The relative target path for the component.\n(Example: components/Promo.WithText.ts)',
47
+ alias: 'p',
48
+ })
49
+ .option('skip-component-map', {
50
+ requiresArg: false,
51
+ type: 'boolean',
52
+ describe: 'If true, skips the component map generation.',
53
+ default: false,
54
+ alias: 's',
55
+ })
56
+ .option('overwrite', {
57
+ requiresArg: false,
58
+ type: 'boolean',
59
+ describe: 'If true, overwrites the existing component.',
60
+ default: false,
61
+ alias: 'o',
62
+ })
63
+ .option('config', {
64
+ requiresArg: false,
65
+ type: 'string',
66
+ describe: 'Path to the `sitecore.cli.config` file. Supports both JavaScript (`.js`) and TypeScript (`.ts`) formats',
67
+ alias: 'c',
68
+ });
69
+ }
70
+ /**
71
+ * @param {Argv} yargs
72
+ */
73
+ export function builder(yargs) {
74
+ /* istanbul ignore next */
75
+ return yargs.command(['add <component-id>', 'a <component-id>'], 'Adds a component', args, handler);
76
+ }
77
+ /**
78
+ * Validates the target path. If no target path is provided, returns true.
79
+ * @param {string} [targetPath] - The target path to validate.
80
+ * @returns {boolean | string} True if the target path is valid, the error message otherwise.
81
+ */
82
+ const validateTargetPath = (targetPath) => {
83
+ if (!targetPath) {
84
+ return true;
85
+ }
86
+ // Check for unsafe absolute path starting with "/"
87
+ if (path.isAbsolute(targetPath)) {
88
+ return 'Target path cannot be an absolute path starting with "/"';
89
+ }
90
+ // Check for path traversal attempts
91
+ if (targetPath.includes('..')) {
92
+ return 'Target path cannot contain ".." (path traversal)';
93
+ }
94
+ return true;
95
+ };
96
+ /**
97
+ * Handler for the add command.
98
+ * @param {AddArgs} argv - The arguments passed to the command.
99
+ */
100
+ export function handler(argv) {
101
+ return __awaiter(this, void 0, void 0, function* () {
102
+ const { componentId, token, targetPath: targetPathArg, skipComponentMap, config, overwrite, } = argv;
103
+ console.log(chalk.green('Adding component'));
104
+ let targetPath = targetPathArg;
105
+ const cliConfig = loadCliConfig(config);
106
+ if (!cliConfig.config) {
107
+ console.error('The `sitecore.cli.config` file is missing a `config`. Please add it to use this command.');
108
+ return;
109
+ }
110
+ const { edgeUrl } = cliConfig.config.api.edge;
111
+ let backupPath;
112
+ let resolvedFilePath;
113
+ try {
114
+ if (validateTargetPath(targetPath) !== true) {
115
+ console.error(chalk.red(validateTargetPath(targetPath)));
116
+ return;
117
+ }
118
+ const spec = yield getComponentSpec({
119
+ edgeUrl,
120
+ componentId,
121
+ targetPath,
122
+ token,
123
+ });
124
+ const componentType = spec.meta['contentsdk-component-type'];
125
+ const componentName = spec.meta['contentsdk-component-name'];
126
+ const variantName = spec.meta['contentsdk-component-variant-name'];
127
+ const title = spec.title;
128
+ if (componentType !== 'variant') {
129
+ console.error(chalk.red(`The component "${title}" is not a content-sdk variant. Please, select a content-sdk variant to use this command.`));
130
+ return;
131
+ }
132
+ if (!targetPath) {
133
+ const { paths, exclude } = cliConfig.componentMap;
134
+ const components = getComponentList(paths, exclude, true);
135
+ const registeredComponent = components.find((c) => c.componentName === componentName);
136
+ if (registeredComponent) {
137
+ targetPath = registeredComponent.filePath
138
+ .replace(/\\/g, '/')
139
+ .replace(/([^/]+)\.([^.]+)$/, `$1.${variantName}.$2`);
140
+ }
141
+ else {
142
+ targetPath = yield inquirer
143
+ .prompt({
144
+ type: 'input',
145
+ name: 'targetPath',
146
+ required: true,
147
+ message: `Enter the target path for the component.\n(Example: components/Promo.WithText.ts):`,
148
+ validate: validateTargetPath,
149
+ })
150
+ .then((answer) => answer.targetPath);
151
+ }
152
+ }
153
+ resolvedFilePath = path.resolve(process.cwd(), targetPath);
154
+ const isFileAlreadyExists = fs.existsSync(resolvedFilePath);
155
+ backupPath = `${resolvedFilePath}.backup`;
156
+ if (isFileAlreadyExists) {
157
+ if (!overwrite) {
158
+ const shouldOverwrite = yield inquirer.prompt({
159
+ type: 'confirm',
160
+ name: 'overwrite',
161
+ message: `File already exists: ${targetPath}. Overwrite?`,
162
+ default: false,
163
+ });
164
+ if (!shouldOverwrite.overwrite) {
165
+ return;
166
+ }
167
+ }
168
+ fs.renameSync(resolvedFilePath, backupPath);
169
+ console.log(chalk.yellow(`Overwriting existing file: ${targetPath}`));
170
+ }
171
+ const componentSpecUrl = getComponentSpecUrl({
172
+ componentId,
173
+ targetPath: targetPath,
174
+ edgeUrl,
175
+ token,
176
+ });
177
+ execSync(`npx shadcn@^3.4.2 add "${componentSpecUrl}"`, {
178
+ stdio: 'inherit',
179
+ cwd: process.cwd(),
180
+ });
181
+ if (isFileAlreadyExists) {
182
+ fs.unlinkSync(backupPath);
183
+ }
184
+ if (!skipComponentMap) {
185
+ generateMapHandler({ config });
186
+ }
187
+ console.log(chalk.green(`Component ${componentName} added successfully`));
188
+ }
189
+ catch (error) {
190
+ if (backupPath && resolvedFilePath && fs.existsSync(backupPath)) {
191
+ fs.renameSync(backupPath, resolvedFilePath);
192
+ }
193
+ const errorMessage = error instanceof Error ? error.message : String(error);
194
+ console.error(chalk.red(`Failed to add component: ${errorMessage}`));
195
+ return;
196
+ }
197
+ });
198
+ }