@tridion-sites/extensions-cli 0.3.2 → 0.3.4

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 CHANGED
@@ -6,276 +6,274 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, createWriteStream }
6
6
  import { resolve, dirname, basename } from 'node:path';
7
7
  import Handlebars from 'handlebars';
8
8
  import { fileURLToPath } from 'node:url';
9
- import { r as readJsonFile, A as AddonManifest } from './addonManifest-30c25a45.js';
9
+ import { r as readJsonFile, A as AddonManifest } from './addonManifest-45b9450a.js';
10
10
  import inquirer from 'inquirer';
11
11
  import isValidFilename from 'valid-filename';
12
12
  import archiver from 'archiver';
13
13
 
14
- const installDependencies = (cwd) => {
15
- spawn.sync('npm', ['install'], {
16
- stdio: 'inherit',
17
- cwd,
18
- });
14
+ const installDependencies = (cwd) => {
15
+ spawn.sync('npm', ['install'], {
16
+ stdio: 'inherit',
17
+ cwd,
18
+ });
19
19
  };
20
20
 
21
- const runLinters = (cwd) => {
22
- spawn.sync('npm', ['run', 'lint'], {
23
- stdio: 'inherit',
24
- cwd,
25
- });
21
+ const runLinters = (cwd) => {
22
+ spawn.sync('npm', ['run', 'lint'], {
23
+ stdio: 'inherit',
24
+ cwd,
25
+ });
26
26
  };
27
27
 
28
- const createFolder = (parentFolder, folderName) => {
29
- const path = resolve(parentFolder, folderName);
30
- if (!existsSync(path)) {
31
- mkdirSync(path);
32
- }
33
- return path;
28
+ const createFolder = (parentFolder, folderName) => {
29
+ const path = resolve(parentFolder, folderName);
30
+ if (!existsSync(path)) {
31
+ mkdirSync(path);
32
+ }
33
+ return path;
34
34
  };
35
35
 
36
- const createFileFromTemplate = (templateFilePath, destinationFilePath, templateParams) => {
37
- const templateFile = readFileSync(templateFilePath, 'utf-8');
38
- const template = Handlebars.compile(templateFile);
39
- const file = template(templateParams);
40
- mkdirSync(dirname(destinationFilePath), { recursive: true });
41
- writeFileSync(destinationFilePath, file);
36
+ const createFileFromTemplate = (templateFilePath, destinationFilePath, templateParams) => {
37
+ const templateFile = readFileSync(templateFilePath, 'utf-8');
38
+ const template = Handlebars.compile(templateFile);
39
+ const file = template(templateParams);
40
+ mkdirSync(dirname(destinationFilePath), { recursive: true });
41
+ writeFileSync(destinationFilePath, file);
42
42
  };
43
43
 
44
- /**
45
- * Return the path to currently executing binary (in node_modules)
46
- * @note This function is going to return an incorrect path if
47
- * a build does not bundle all files into a single javascript file!
48
- */
49
- const getBinaryPath = () => {
50
- const filepath = fileURLToPath(import.meta.url);
51
- const binaryPath = dirname(filepath);
52
- return binaryPath;
44
+ /**
45
+ * Return the path to currently executing binary (in node_modules)
46
+ * @note This function is going to return an incorrect path if
47
+ * a build does not bundle all files into a single javascript file!
48
+ */
49
+ const getBinaryPath = () => {
50
+ const filepath = fileURLToPath(import.meta.url);
51
+ const binaryPath = dirname(filepath);
52
+ return binaryPath;
53
53
  };
54
54
 
55
- const getPackageJson = () => {
56
- const binaryPath = getBinaryPath();
57
- const packageJsonPath = resolve(binaryPath, '../package.json');
58
- const packageJson = readJsonFile(packageJsonPath);
59
- return packageJson;
55
+ const getPackageJson = () => {
56
+ const binaryPath = getBinaryPath();
57
+ const packageJsonPath = resolve(binaryPath, '../package.json');
58
+ const packageJson = readJsonFile(packageJsonPath);
59
+ return packageJson;
60
60
  };
61
61
 
62
- const copyTemplate = ({ addonId, addonRootFolderPath, author, extensionDescription, extensionName, extensionRootFolderPath, sitesUrl, }) => {
63
- const binaryPath = getBinaryPath();
64
- const templatePath = resolve(binaryPath, 'addon/template');
65
- const packageJson = getPackageJson();
66
- createFileFromTemplate(resolve(templatePath, 'addonId.config.json.hbs'), resolve(addonRootFolderPath, `${addonId}.config.json`), {
67
- extensionName,
68
- });
69
- [
70
- '.browserslistrc',
71
- '.editorconfig',
72
- '.eslintrc.json',
73
- '.gitignore',
74
- '.prettierrc',
75
- 'babel.config.js',
76
- 'devServer.js',
77
- 'tsconfig.json',
78
- 'src/globals.ts',
79
- 'src/index.css',
80
- 'src/index.tsx',
81
- 'types/css.d.ts',
82
- ].forEach(fileName => {
83
- createFileFromTemplate(resolve(templatePath, `extension/${fileName}.hbs`), resolve(extensionRootFolderPath, fileName));
84
- });
85
- createFileFromTemplate(resolve(templatePath, 'extension/package.json.hbs'), resolve(extensionRootFolderPath, 'package.json'), {
86
- extensionName,
87
- extensionDescription,
88
- author,
89
- addonId,
90
- sitesUrl,
91
- extensionsApiVersion: packageJson.dependencies['@tridion-sites/extensions'],
92
- modelsVersion: packageJson.dependencies['@tridion-sites/models'],
93
- openApiClientVersion: packageJson.dependencies['@tridion-sites/open-api-client'],
94
- extensionsCliVersion: packageJson.version,
95
- });
96
- createFileFromTemplate(resolve(templatePath, 'extension/webpack.dev.config.js.hbs'), resolve(extensionRootFolderPath, 'webpack.dev.config.js'), {
97
- extensionName,
98
- });
99
- createFileFromTemplate(resolve(templatePath, 'extension/webpack.prod.config.js.hbs'), resolve(extensionRootFolderPath, 'webpack.prod.config.js'), {
100
- extensionName,
101
- });
62
+ const copyTemplate = ({ addonId, addonRootFolderPath, author, extensionDescription, extensionName, extensionRootFolderPath, sitesUrl, }) => {
63
+ const binaryPath = getBinaryPath();
64
+ const templatePath = resolve(binaryPath, 'addon/template');
65
+ const packageJson = getPackageJson();
66
+ createFileFromTemplate(resolve(templatePath, 'addonId.config.json.hbs'), resolve(addonRootFolderPath, `${addonId}.config.json`), {
67
+ extensionName,
68
+ });
69
+ [
70
+ '.browserslistrc',
71
+ '.editorconfig',
72
+ '.eslintrc.json',
73
+ '.gitignore',
74
+ '.prettierrc',
75
+ 'babel.config.js',
76
+ 'devServer.js',
77
+ 'tsconfig.json',
78
+ 'src/globals.ts',
79
+ 'src/index.tsx',
80
+ ].forEach(fileName => {
81
+ createFileFromTemplate(resolve(templatePath, `extension/${fileName}.hbs`), resolve(extensionRootFolderPath, fileName));
82
+ });
83
+ createFileFromTemplate(resolve(templatePath, 'extension/package.json.hbs'), resolve(extensionRootFolderPath, 'package.json'), {
84
+ extensionName,
85
+ extensionDescription,
86
+ author,
87
+ addonId,
88
+ sitesUrl,
89
+ extensionsApiVersion: packageJson.dependencies['@tridion-sites/extensions'],
90
+ modelsVersion: packageJson.dependencies['@tridion-sites/models'],
91
+ openApiClientVersion: packageJson.dependencies['@tridion-sites/open-api-client'],
92
+ extensionsCliVersion: packageJson.version,
93
+ });
94
+ createFileFromTemplate(resolve(templatePath, 'extension/webpack.dev.config.js.hbs'), resolve(extensionRootFolderPath, 'webpack.dev.config.js'), {
95
+ extensionName,
96
+ });
97
+ createFileFromTemplate(resolve(templatePath, 'extension/webpack.prod.config.js.hbs'), resolve(extensionRootFolderPath, 'webpack.prod.config.js'), {
98
+ extensionName,
99
+ });
102
100
  };
103
101
 
104
- const createAddonPrompt = async () => {
105
- return inquirer.prompt([
106
- {
107
- type: 'input',
108
- name: 'addonId',
109
- message: 'Provide id of the addon:',
110
- default: 'my-addon',
111
- validate: (input) => {
112
- if (/\s+/g.test(input)) {
113
- return "Addon id can't have whitespace";
114
- }
115
- if (!isValidFilename(input)) {
116
- return "Addon id can't have reserved symbols";
117
- }
118
- return true;
119
- },
120
- },
121
- {
122
- type: 'input',
123
- name: 'addonName',
124
- message: 'Provide name of the addon:',
125
- default: 'My addon',
126
- },
127
- {
128
- type: 'input',
129
- name: 'addonDescription',
130
- message: 'Provide description of the addon:',
131
- default: 'My addon for Tridion Experience Space',
132
- },
133
- {
134
- type: 'input',
135
- name: 'author',
136
- message: `Provide author's name:`,
137
- default: 'RWS',
138
- },
139
- {
140
- type: 'input',
141
- name: 'extensionName',
142
- message: 'Provide the name of the frontend extension:',
143
- default: 'my-extension',
144
- validate: (input) => {
145
- if (!/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(input)) {
146
- return 'Extension name should adhere to package.json name requirements!';
147
- }
148
- return true;
149
- },
150
- },
151
- {
152
- type: 'input',
153
- name: 'extensionDescription',
154
- message: 'Provide description of the extension:',
155
- default: 'My first extension',
156
- },
157
- {
158
- type: 'input',
159
- name: 'url',
160
- message: `Provide the url to Tridion Sites:`,
161
- validate: (input) => {
162
- if (!/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}(\.[a-zA-Z0-9()]{1,6})?\b([-a-zA-Z0-9()@:%_\+.~#?&\/=]*)/gm.test(input)) {
163
- return `Make sure it's a valid URL`;
164
- }
165
- return true;
166
- },
167
- },
168
- ]);
102
+ const createAddonPrompt = async () => {
103
+ return inquirer.prompt([
104
+ {
105
+ type: 'input',
106
+ name: 'addonId',
107
+ message: 'Provide id of the addon:',
108
+ default: 'my-addon',
109
+ validate: (input) => {
110
+ if (/\s+/g.test(input)) {
111
+ return "Addon id can't have whitespace";
112
+ }
113
+ if (!isValidFilename(input)) {
114
+ return "Addon id can't have reserved symbols";
115
+ }
116
+ return true;
117
+ },
118
+ },
119
+ {
120
+ type: 'input',
121
+ name: 'addonName',
122
+ message: 'Provide name of the addon:',
123
+ default: 'My addon',
124
+ },
125
+ {
126
+ type: 'input',
127
+ name: 'addonDescription',
128
+ message: 'Provide description of the addon:',
129
+ default: 'My addon for Tridion Experience Space',
130
+ },
131
+ {
132
+ type: 'input',
133
+ name: 'author',
134
+ message: `Provide author's name:`,
135
+ default: 'RWS',
136
+ },
137
+ {
138
+ type: 'input',
139
+ name: 'extensionName',
140
+ message: 'Provide the name of the frontend extension:',
141
+ default: 'my-extension',
142
+ validate: (input) => {
143
+ if (!/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(input)) {
144
+ return 'Extension name should adhere to package.json name requirements!';
145
+ }
146
+ return true;
147
+ },
148
+ },
149
+ {
150
+ type: 'input',
151
+ name: 'extensionDescription',
152
+ message: 'Provide description of the extension:',
153
+ default: 'My first extension',
154
+ },
155
+ {
156
+ type: 'input',
157
+ name: 'url',
158
+ message: `Provide the url to Tridion Sites:`,
159
+ validate: (input) => {
160
+ if (!/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}(\.[a-zA-Z0-9()]{1,6})?\b([-a-zA-Z0-9()@:%_\+.~#?&\/=]*)/gm.test(input)) {
161
+ return `Make sure it's a valid URL`;
162
+ }
163
+ return true;
164
+ },
165
+ },
166
+ ]);
169
167
  };
170
168
 
171
- const createAddonRootFolder = ({ path, addonDescription, addonId, addonName, author, extensionName, }) => {
172
- const addonFolderPath = createFolder(path, addonId);
173
- const manifest = new AddonManifest({
174
- version: '1.0.0',
175
- id: addonId,
176
- name: addonName,
177
- description: addonDescription,
178
- author: author,
179
- });
180
- manifest.addFrontendExtension(extensionName, [`dist\\${extensionName}\\main.js`, `dist\\${extensionName}\\main.css`], `dist\\${extensionName}\\main.js`);
181
- manifest.writeFile(addonFolderPath);
182
- return addonFolderPath;
169
+ const createAddonRootFolder = ({ path, addonDescription, addonId, addonName, author, extensionName, }) => {
170
+ const addonFolderPath = createFolder(path, addonId);
171
+ const manifest = new AddonManifest({
172
+ version: '1.0.0',
173
+ id: addonId,
174
+ name: addonName,
175
+ description: addonDescription,
176
+ author: author,
177
+ });
178
+ manifest.addFrontendExtension(extensionName, [`dist\\${extensionName}\\main.js`], `dist\\${extensionName}\\main.js`);
179
+ manifest.writeFile(addonFolderPath);
180
+ return addonFolderPath;
183
181
  };
184
182
 
185
- const createAddon = async (path) => {
186
- const answers = await createAddonPrompt();
187
- const addonRootFolderPath = createAddonRootFolder({
188
- path,
189
- addonId: answers.addonId,
190
- addonName: answers.addonName,
191
- addonDescription: answers.addonDescription,
192
- author: answers.author,
193
- extensionName: answers.extensionName,
194
- });
195
- const extensionRootFolderPath = createFolder(addonRootFolderPath, answers.extensionName);
196
- copyTemplate({
197
- addonRootFolderPath,
198
- extensionRootFolderPath,
199
- addonId: answers.addonId,
200
- author: answers.author,
201
- extensionDescription: answers.extensionDescription,
202
- extensionName: answers.extensionName,
203
- sitesUrl: answers.url,
204
- });
205
- return {
206
- addonFolderPath: addonRootFolderPath,
207
- extensionFolderPath: extensionRootFolderPath,
208
- };
183
+ const createAddon = async (path) => {
184
+ const answers = await createAddonPrompt();
185
+ const addonRootFolderPath = createAddonRootFolder({
186
+ path,
187
+ addonId: answers.addonId,
188
+ addonName: answers.addonName,
189
+ addonDescription: answers.addonDescription,
190
+ author: answers.author,
191
+ extensionName: answers.extensionName,
192
+ });
193
+ const extensionRootFolderPath = createFolder(addonRootFolderPath, answers.extensionName);
194
+ copyTemplate({
195
+ addonRootFolderPath,
196
+ extensionRootFolderPath,
197
+ addonId: answers.addonId,
198
+ author: answers.author,
199
+ extensionDescription: answers.extensionDescription,
200
+ extensionName: answers.extensionName,
201
+ sitesUrl: answers.url,
202
+ });
203
+ return {
204
+ addonFolderPath: addonRootFolderPath,
205
+ extensionFolderPath: extensionRootFolderPath,
206
+ };
209
207
  };
210
208
 
211
- const configureHandlebars = () => {
212
- Handlebars.registerHelper('camelCase', (text) => {
213
- return text.replace(/^./gm, match => match.toLowerCase());
214
- });
215
- Handlebars.registerHelper('kebabCase', (text) => {
216
- return text.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
217
- });
209
+ const configureHandlebars = () => {
210
+ Handlebars.registerHelper('camelCase', (text) => {
211
+ return text.replace(/^./gm, match => match.toLowerCase());
212
+ });
213
+ Handlebars.registerHelper('kebabCase', (text) => {
214
+ return text.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
215
+ });
218
216
  };
219
217
 
220
- configureHandlebars();
221
- const createCommand = async () => {
222
- const currentProcessPath = process.cwd();
223
- console.info(chalk.green(`Creating a new addon at: ${currentProcessPath}`));
224
- const { extensionFolderPath } = await createAddon(currentProcessPath);
225
- console.info(chalk.green(`Installing dependencies`));
226
- installDependencies(extensionFolderPath);
227
- console.info(chalk.green(`Running linters`));
228
- runLinters(extensionFolderPath);
229
- console.info(chalk.green('🎉️️ All done! Happy hacking!'));
230
- console.info(chalk.green(`Your extension is available at: ${extensionFolderPath}`));
218
+ configureHandlebars();
219
+ const createCommand = async () => {
220
+ const currentProcessPath = process.cwd();
221
+ console.info(chalk.green(`Creating a new addon at: ${currentProcessPath}`));
222
+ const { extensionFolderPath } = await createAddon(currentProcessPath);
223
+ console.info(chalk.green(`Installing dependencies`));
224
+ installDependencies(extensionFolderPath);
225
+ console.info(chalk.green(`Running linters`));
226
+ runLinters(extensionFolderPath);
227
+ console.info(chalk.green('🎉️️ All done! Happy hacking!'));
228
+ console.info(chalk.green(`Your extension is available at: ${extensionFolderPath}`));
231
229
  };
232
230
 
233
- const packCommand = ({ inputFilesPath, manifestPath, outputPath }) => {
234
- console.info(chalk.green(`Creating an addon package from folder: ${inputFilesPath}`));
235
- console.info(chalk.green(`Manifest file path: ${manifestPath}`));
236
- const manifest = AddonManifest.fromFile(manifestPath);
237
- const packageName = `${manifest.id}-${manifest.version}.zip`;
238
- const archive = archiver('zip');
239
- const zipPath = resolve(outputPath, packageName);
240
- const stream = createWriteStream(zipPath);
241
- stream.on('close', () => {
242
- console.info(chalk.green(`Addon package "${packageName}" has been created at: ${zipPath}.`));
243
- console.info(chalk.green('It can be uploaded into Addon Manager now.'));
244
- });
245
- archive.on('error', error => {
246
- console.warn('We were unable to create a package.');
247
- throw error;
248
- });
249
- archive.pipe(stream);
250
- archive.file(manifestPath, { name: basename(manifestPath) });
251
- archive.directory(inputFilesPath, basename(resolve(inputFilesPath)));
252
- archive.finalize();
231
+ const packCommand = ({ inputFilesPath, manifestPath, outputPath }) => {
232
+ console.info(chalk.green(`Creating an addon package from folder: ${inputFilesPath}`));
233
+ console.info(chalk.green(`Manifest file path: ${manifestPath}`));
234
+ const manifest = AddonManifest.fromFile(manifestPath);
235
+ const packageName = `${manifest.id}-${manifest.version}.zip`;
236
+ const archive = archiver('zip');
237
+ const zipPath = resolve(outputPath, packageName);
238
+ const stream = createWriteStream(zipPath);
239
+ stream.on('close', () => {
240
+ console.info(chalk.green(`Addon package "${packageName}" has been created at: ${zipPath}.`));
241
+ console.info(chalk.green('It can be uploaded into Addon Manager now.'));
242
+ });
243
+ archive.on('error', error => {
244
+ console.warn('We were unable to create a package.');
245
+ throw error;
246
+ });
247
+ archive.pipe(stream);
248
+ archive.file(manifestPath, { name: basename(manifestPath) });
249
+ archive.directory(inputFilesPath, basename(resolve(inputFilesPath)));
250
+ archive.finalize();
253
251
  };
254
252
 
255
- const packageJson = getPackageJson();
256
- const program = new Command();
257
- const programName = Object.keys(packageJson.bin)[0];
258
- program
259
- .name(programName)
260
- .description('Provides helpers to build, run and deploy addons for Tridion Experience Space')
261
- .version(packageJson.version);
262
- program
263
- .command('create')
264
- .description('Create new Tridion Experience Space addon')
265
- .usage(`${programName} create`)
266
- .action(createCommand);
267
- program
268
- .command('pack')
269
- .description('Creates a package ready to be used in Addon Manager')
270
- .usage(`${programName} pack`)
271
- .requiredOption('-i, --input <string>', 'path to the directory with addon files')
272
- .requiredOption('-m, --manifest <string>', 'path to the addon manifest file')
273
- .requiredOption('-o, --output <string>', 'path where to output the package')
274
- .action(args => {
275
- packCommand({
276
- inputFilesPath: args.input,
277
- manifestPath: args.manifest,
278
- outputPath: args.output,
279
- });
280
- });
253
+ const packageJson = getPackageJson();
254
+ const program = new Command();
255
+ const programName = Object.keys(packageJson.bin)[0];
256
+ program
257
+ .name(programName)
258
+ .description('Provides helpers to build, run and deploy addons for Tridion Experience Space')
259
+ .version(packageJson.version);
260
+ program
261
+ .command('create')
262
+ .description('Create new Tridion Experience Space addon')
263
+ .usage(`${programName} create`)
264
+ .action(createCommand);
265
+ program
266
+ .command('pack')
267
+ .description('Creates a package ready to be used in Addon Manager')
268
+ .usage(`${programName} pack`)
269
+ .requiredOption('-i, --input <string>', 'path to the directory with addon files')
270
+ .requiredOption('-m, --manifest <string>', 'path to the addon manifest file')
271
+ .requiredOption('-o, --output <string>', 'path where to output the package')
272
+ .action(args => {
273
+ packCommand({
274
+ inputFilesPath: args.input,
275
+ manifestPath: args.manifest,
276
+ outputPath: args.output,
277
+ });
278
+ });
281
279
  program.parse(process.argv);