@sitecore-jss/sitecore-jss-dev-tools 21.2.0-canary.8 → 21.2.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 (43) hide show
  1. package/LICENSE.txt +202 -202
  2. package/README.md +7 -7
  3. package/dist/cjs/index.js +2 -3
  4. package/dist/cjs/templating/components.js +27 -0
  5. package/dist/cjs/templating/index.js +10 -0
  6. package/dist/cjs/templating/nextjs/generate-component-builder.js +61 -0
  7. package/dist/cjs/templating/nextjs/index.js +7 -0
  8. package/dist/cjs/templating/nextjs/templates/component-builder.js +54 -0
  9. package/dist/cjs/templating/plugins.js +78 -0
  10. package/dist/cjs/templating/react/generate-component-builder.js +56 -0
  11. package/dist/cjs/templating/react/index.js +7 -0
  12. package/dist/cjs/templating/react/templates/component-builder.js +48 -0
  13. package/dist/cjs/templating/scaffold.js +38 -0
  14. package/dist/cjs/templating/utils.js +56 -0
  15. package/dist/esm/index.js +1 -1
  16. package/dist/esm/templating/components.js +23 -0
  17. package/dist/esm/templating/index.js +3 -0
  18. package/dist/esm/templating/nextjs/generate-component-builder.js +52 -0
  19. package/dist/esm/templating/nextjs/index.js +2 -0
  20. package/dist/esm/templating/nextjs/templates/component-builder.js +50 -0
  21. package/dist/esm/templating/plugins.js +70 -0
  22. package/dist/esm/templating/react/generate-component-builder.js +47 -0
  23. package/dist/esm/templating/react/index.js +2 -0
  24. package/dist/esm/templating/react/templates/component-builder.js +41 -0
  25. package/dist/esm/templating/scaffold.js +30 -0
  26. package/dist/esm/templating/utils.js +48 -0
  27. package/nextjs.d.ts +1 -0
  28. package/nextjs.js +3 -0
  29. package/package.json +6 -4
  30. package/react.d.ts +1 -0
  31. package/react.js +3 -0
  32. package/types/index.d.ts +1 -1
  33. package/types/templating/components.d.ts +29 -0
  34. package/types/templating/index.d.ts +4 -0
  35. package/types/templating/nextjs/generate-component-builder.d.ts +39 -0
  36. package/types/templating/nextjs/index.d.ts +2 -0
  37. package/types/templating/nextjs/templates/component-builder.d.ts +7 -0
  38. package/types/templating/plugins.d.ts +67 -0
  39. package/types/templating/react/generate-component-builder.d.ts +25 -0
  40. package/types/templating/react/index.d.ts +2 -0
  41. package/types/templating/react/templates/component-builder.d.ts +8 -0
  42. package/types/templating/scaffold.d.ts +15 -0
  43. package/types/templating/utils.d.ts +38 -0
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generatePlugins = exports.getPluginList = exports.ModuleType = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const utils_1 = require("./utils");
10
+ /**
11
+ * Identifies the format of the module to be compiled
12
+ */
13
+ var ModuleType;
14
+ (function (ModuleType) {
15
+ ModuleType[ModuleType["CJS"] = 0] = "CJS";
16
+ ModuleType[ModuleType["ESM"] = 1] = "ESM";
17
+ })(ModuleType = exports.ModuleType || (exports.ModuleType = {}));
18
+ /**
19
+ * Get list of plugins from @var path
20
+ * Returns a list of plugins in the following format:
21
+ * {
22
+ * path: 'path/to/plugin/foo',
23
+ * name: 'fooPlugin'
24
+ * }
25
+ * @example getPluginList('src/foo/plugins', 'Foo')
26
+ * @param {Object} definition plugin definition
27
+ * @param {string} definition.path path to get plugin from
28
+ * @param {string} definition.pluginName plugin name
29
+ * @param {boolean} [definition.silent] whether to suppress console output
30
+ */
31
+ function getPluginList({ path, pluginName, silent = false, }) {
32
+ const plugins = (0, utils_1.getItems)({
33
+ path,
34
+ resolveItem: (path, name) => ({
35
+ path: `${path}/${name}`,
36
+ name: `${name.replace(/-./g, (x) => x[1].toUpperCase())}Plugin`,
37
+ }),
38
+ cb: (name) => !silent && console.debug(`Registering ${pluginName} plugin ${name}`),
39
+ });
40
+ return plugins;
41
+ }
42
+ exports.getPluginList = getPluginList;
43
+ /**
44
+ * Generates the plugins file and saves it to the filesystem.
45
+ * By convention, we expect to find plugins under {pluginName}/plugins/** (subfolders are searched recursively).
46
+ * generated file will be saved to @var {distPath} and will contain a list of plugins in the following format:
47
+ * CJS: exports.fooPlugin = require('{pluginPath}');
48
+ * ESM: export { fooPlugin } from '{pluginPath}';
49
+ * @example generatePlugins({ distPath: 'src/temp/foo-plugins.js', rootPath: 'src/foo/plugins', moduleType: ModuleType.CJS })
50
+ * @param {PluginDefinition} definition plugin definition
51
+ */
52
+ function generatePlugins(definition) {
53
+ const { rootPath, distPath, moduleType, relative = false, silent } = definition;
54
+ const segments = rootPath.split('/');
55
+ const pluginName = segments[segments.length - 2];
56
+ const plugins = getPluginList({ path: rootPath, pluginName, silent });
57
+ let fileContent = '';
58
+ fileContent = plugins
59
+ .map((plugin) => {
60
+ const sourcePath = relative
61
+ ? path_1.default.relative(path_1.default.dirname(distPath), plugin.path).replace(/\\/g, '/')
62
+ : plugin.path;
63
+ return moduleType === ModuleType.CJS
64
+ ? `exports.${plugin.name} = require('${sourcePath}');`
65
+ : `export { ${plugin.name} } from '${sourcePath}';`;
66
+ })
67
+ .join('\r\n')
68
+ .concat('\r\n');
69
+ if (!plugins.length) {
70
+ fileContent = moduleType === ModuleType.CJS ? 'module.exports = {};\r\n' : 'export {};\r\n';
71
+ }
72
+ const filePath = path_1.default.resolve(distPath);
73
+ !silent && console.log(`Writing ${pluginName} plugins to ${filePath}`);
74
+ fs_1.default.writeFileSync(filePath, fileContent, {
75
+ encoding: 'utf8',
76
+ });
77
+ }
78
+ exports.generatePlugins = generatePlugins;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.writeComponentBuilder = exports.watchComponentBuilder = exports.generateComponentBuilder = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const component_builder_1 = require("./templates/component-builder");
10
+ const components_1 = require("../components");
11
+ const utils_1 = require("../utils");
12
+ // Default destination path for component builder
13
+ const componentBuilderOutputPath = 'src/temp/componentBuilder.js';
14
+ const defaultComponentRootPath = 'src/components';
15
+ /**
16
+ * Generate component builder based on provided settings
17
+ * @param {Object} settings settings for component builder generation
18
+ * @param {string} settings.componentRootPath path to components root
19
+ * @param {PackageDefinition[]} settings.packages list of packages to include in component builder
20
+ * @param {boolean} settings.watch whether to watch for changes to component builder sources
21
+ */
22
+ function generateComponentBuilder({ componentRootPath = defaultComponentRootPath, packages, watch, }) {
23
+ if (watch) {
24
+ watchComponentBuilder(componentRootPath, packages);
25
+ }
26
+ else {
27
+ writeComponentBuilder(componentRootPath, packages);
28
+ }
29
+ }
30
+ exports.generateComponentBuilder = generateComponentBuilder;
31
+ /**
32
+ * Watch for changes to component builder sources
33
+ * @param {string} componentRootPath root path to components
34
+ * @param {PackageDefinition[]} [packages] packages to include in component builder
35
+ */
36
+ function watchComponentBuilder(componentRootPath, packages) {
37
+ console.log(`Watching for changes to component builder sources in ${componentRootPath}...`);
38
+ (0, utils_1.watchItems)([componentRootPath], writeComponentBuilder.bind(null, componentRootPath, packages));
39
+ }
40
+ exports.watchComponentBuilder = watchComponentBuilder;
41
+ /**
42
+ * Write component builder to file
43
+ * @param {string} componentRootPath root path to components
44
+ * @param {PackageDefinition[]} [packages] packages to include in component builder
45
+ */
46
+ function writeComponentBuilder(componentRootPath, packages = []) {
47
+ const components = (0, components_1.getComponentList)(componentRootPath);
48
+ components.unshift(...packages);
49
+ const componentBuilderPath = path_1.default.resolve(componentBuilderOutputPath);
50
+ const fileContent = (0, component_builder_1.getComponentBuilderTemplate)(components, componentBuilderPath);
51
+ console.log(`Writing component builder to ${componentBuilderPath}`);
52
+ fs_1.default.writeFileSync(componentBuilderPath, fileContent, {
53
+ encoding: 'utf8',
54
+ });
55
+ }
56
+ exports.writeComponentBuilder = writeComponentBuilder;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateComponentBuilder = exports.getComponentBuilderTemplate = void 0;
4
+ var component_builder_1 = require("./templates/component-builder");
5
+ Object.defineProperty(exports, "getComponentBuilderTemplate", { enumerable: true, get: function () { return component_builder_1.getComponentBuilderTemplate; } });
6
+ var generate_component_builder_1 = require("./generate-component-builder");
7
+ Object.defineProperty(exports, "generateComponentBuilder", { enumerable: true, get: function () { return generate_component_builder_1.generateComponentBuilder; } });
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getComponentBuilderTemplate = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ /**
9
+ * Generate component builder template
10
+ * @param {(PackageDefinition | ComponentFile)[]} components components to include in component builder
11
+ * @param {string} distPath destination path for component builder
12
+ * @returns generated component builder template
13
+ */
14
+ const getComponentBuilderTemplate = (components, distPath) => {
15
+ const componentFiles = components.filter((component) => component.componentName);
16
+ const packages = components.filter((component) => component.components);
17
+ return `/* eslint-disable */
18
+ // Do not edit this file, it is auto-generated at build time!
19
+ // See scripts/generate-component-builder/index.js to modify the generation of this file.
20
+
21
+ import { ComponentBuilder } from '@sitecore-jss/sitecore-jss-react';
22
+ ${packages
23
+ .map((pkg) => {
24
+ const list = pkg.components.map((c) => c.moduleName).join(', ');
25
+ return `import { ${list} } from '${pkg.name}'`;
26
+ })
27
+ .join('\n')}
28
+ ${componentFiles
29
+ .map((component) => {
30
+ const sourcePath = path_1.default.relative(path_1.default.dirname(distPath), component.path).replace(/\\/g, '/');
31
+ return `import ${component.moduleName} from '${sourcePath}';`;
32
+ })
33
+ .join('\n')}
34
+
35
+ const components = new Map();
36
+ ${packages
37
+ .map((p) => p.components.map((component) => `components.set('${component.componentName}', ${component.moduleName})`))
38
+ .join('\n')}
39
+ ${componentFiles
40
+ .map((component) => `components.set('${component.componentName}', ${component.moduleName});`)
41
+ .join('\n')}
42
+
43
+ const componentBuilder = new ComponentBuilder({ components });
44
+
45
+ export const componentFactory = componentBuilder.getComponentFactory();
46
+ `;
47
+ };
48
+ exports.getComponentBuilderTemplate = getComponentBuilderTemplate;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.scaffoldFile = exports.editLineEndings = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const path_1 = __importDefault(require("path"));
10
+ /**
11
+ * Force to use `crlf` line endings, we are using `crlf` across the project.
12
+ * Replace: `lf` (\n), `cr` (\r)
13
+ * @param {string} content
14
+ */
15
+ function editLineEndings(content) {
16
+ return content.replace(/\r|\n/gm, '\r\n');
17
+ }
18
+ exports.editLineEndings = editLineEndings;
19
+ /**
20
+ * Creates a file relative to the specified path if the file doesn't exist.
21
+ * Creates directories as needed.
22
+ * Does not overwrite existing files.
23
+ * @param {string} filePath - the file path
24
+ * @param {string} fileContent - the file content
25
+ * @returns {string} the file path if the file was created, otherwise null
26
+ */
27
+ function scaffoldFile(filePath, fileContent) {
28
+ const outputDir = path_1.default.dirname(filePath);
29
+ if (fs_1.default.existsSync(filePath)) {
30
+ console.log(chalk_1.default.red(`Skipping creating ${filePath}; already exists.`));
31
+ return null;
32
+ }
33
+ fs_1.default.mkdirSync(outputDir, { recursive: true });
34
+ fs_1.default.writeFileSync(filePath, editLineEndings(fileContent), 'utf8');
35
+ console.log(chalk_1.default.green(`File ${filePath} has been scaffolded.`));
36
+ return filePath;
37
+ }
38
+ exports.scaffoldFile = scaffoldFile;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.watchItems = exports.getItems = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const chokidar_1 = __importDefault(require("chokidar"));
9
+ /**
10
+ * Using @var path find all files and generate output using @var resolveItem function for each file
11
+ * Can be used to generate list of components, templates, etc.
12
+ * @param {GetItemsSettings} settings
13
+ * @returns {Item[]} list of items
14
+ */
15
+ function getItems(settings) {
16
+ const { recursive = true, path, resolveItem, cb, fileFormat = new RegExp(/(.+)(?<!\.d)\.[jt]sx?$/), } = settings;
17
+ const items = [];
18
+ const folders = [];
19
+ if (!fs_1.default.existsSync(path))
20
+ return [];
21
+ fs_1.default.readdirSync(path, { withFileTypes: true }).forEach((item) => {
22
+ if (item.isDirectory()) {
23
+ folders.push(item);
24
+ }
25
+ if (fileFormat.test(item.name)) {
26
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
27
+ const name = item.name.match(fileFormat)[1];
28
+ items.push(resolveItem(path, name));
29
+ cb && cb(name);
30
+ }
31
+ });
32
+ for (const folder of folders) {
33
+ recursive
34
+ ? items.push(...getItems({
35
+ path: `${path}/${folder.name}`,
36
+ resolveItem,
37
+ cb,
38
+ fileFormat,
39
+ }))
40
+ : items.push(resolveItem(`${path}/${folder.name}`, folder.name));
41
+ }
42
+ return items;
43
+ }
44
+ exports.getItems = getItems;
45
+ /**
46
+ * Run watch mode, watching on @var paths
47
+ * @param {string[]} paths paths to watch by chokidar
48
+ * @param {Function<void>} cb callback to run on file change
49
+ */
50
+ function watchItems(paths, cb) {
51
+ chokidar_1.default
52
+ .watch(paths, { ignoreInitial: true, awaitWriteFinish: true })
53
+ .on('add', cb)
54
+ .on('unlink', cb);
55
+ }
56
+ exports.watchItems = watchItems;
package/dist/esm/index.js CHANGED
@@ -12,7 +12,7 @@ export { createDisconnectedDictionaryService, } from './disconnected-server/dict
12
12
  export { createDefaultDocumentMiddleware, } from './disconnected-server/default-document';
13
13
  export { createDefaultDisconnectedServer, } from './disconnected-server/create-default-disconnected-server';
14
14
  export { resolveScJssConfig } from './resolve-scjssconfig';
15
- export { strip } from './templating/strip';
15
+ export * from './templating';
16
16
  export * from './manifest';
17
17
  export * from './pipelines';
18
18
  export * from './update';
@@ -0,0 +1,23 @@
1
+ import { getItems } from './utils';
2
+ /**
3
+ * Get list of components from @var path
4
+ * Returns a list of components in the following format:
5
+ * {
6
+ * path: 'path/to/component',
7
+ * componentName: 'ComponentName',
8
+ * moduleName: 'ComponentName'
9
+ * }
10
+ * @param {string} path path to search
11
+ */
12
+ export function getComponentList(path) {
13
+ const components = getItems({
14
+ path,
15
+ resolveItem: (path, name) => ({
16
+ path: `${path}/${name}`,
17
+ componentName: name,
18
+ moduleName: name.replace(/[^\w]+/g, ''),
19
+ }),
20
+ cb: (name) => console.debug(`Registering JSS component ${name}`),
21
+ });
22
+ return components;
23
+ }
@@ -0,0 +1,3 @@
1
+ export { generatePlugins, ModuleType } from './plugins';
2
+ export { scaffoldFile } from './scaffold';
3
+ export { strip } from './strip';
@@ -0,0 +1,52 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import { getComponentBuilderTemplate } from './templates/component-builder';
4
+ import { getComponentList } from '../components';
5
+ import { watchItems } from '../utils';
6
+ // Default destination path for component builder
7
+ const defaultComponentBuilderOutputPath = 'src/temp/componentBuilder.ts';
8
+ const defaultComponentRootPath = 'src/components';
9
+ /**
10
+ * Generate component builder based on provided settings
11
+ * @param {Object} [settings] settings for component builder generation
12
+ * @param {string} [settings.componentRootPath] path to components root
13
+ * @param {string} [settings.componentBuilderOutputPath] path to component builder output
14
+ * @param {PackageDefinition[]} [settings.packages] list of packages to include in component builder
15
+ * @param {boolean} [settings.watch] whether to watch for changes to component builder sources
16
+ */
17
+ export function generateComponentBuilder({ componentRootPath = defaultComponentRootPath, componentBuilderOutputPath = defaultComponentBuilderOutputPath, packages = [], watch, } = {}) {
18
+ if (watch) {
19
+ watchComponentBuilder({ componentRootPath, componentBuilderOutputPath, packages });
20
+ }
21
+ else {
22
+ writeComponentBuilder({ componentRootPath, componentBuilderOutputPath, packages });
23
+ }
24
+ }
25
+ /**
26
+ * Watch for changes to component builder sources
27
+ * @param {Object} settings settings for component builder generation
28
+ * @param {string} settings.componentRootPath path to components root
29
+ * @param {string} settings.componentBuilderOutputPath path to component builder output
30
+ * @param {PackageDefinition[]} settings.packages list of packages to include in component builder
31
+ */
32
+ export function watchComponentBuilder({ componentRootPath, componentBuilderOutputPath, packages, }) {
33
+ console.log(`Watching for changes to component builder sources in ${componentRootPath}...`);
34
+ watchItems([componentRootPath], writeComponentBuilder.bind(null, { componentRootPath, componentBuilderOutputPath, packages }));
35
+ }
36
+ /**
37
+ * Write component builder to file
38
+ * @param {Object} settings settings for component builder generation
39
+ * @param {string} settings.componentRootPath path to components root
40
+ * @param {string} settings.componentBuilderOutputPath path to component builder output
41
+ * @param {PackageDefinition[]} settings.packages list of packages to include in component builder
42
+ */
43
+ export function writeComponentBuilder({ componentRootPath, componentBuilderOutputPath, packages, }) {
44
+ const components = getComponentList(componentRootPath);
45
+ components.unshift(...packages);
46
+ const componentBuilderPath = path.resolve(componentBuilderOutputPath);
47
+ const fileContent = getComponentBuilderTemplate(components);
48
+ console.log(`Writing component builder to ${componentBuilderPath}`);
49
+ fs.writeFileSync(componentBuilderPath, fileContent, {
50
+ encoding: 'utf8',
51
+ });
52
+ }
@@ -0,0 +1,2 @@
1
+ export { generateComponentBuilder } from './generate-component-builder';
2
+ export { getComponentBuilderTemplate } from './templates/component-builder';
@@ -0,0 +1,50 @@
1
+ const isLazyLoadingModule = (componentPath) => componentPath.includes('.dynamic');
2
+ const removeDynamicModuleNameEnding = (moduleName) => moduleName.replace(/\.?dynamic$/i, '');
3
+ /**
4
+ * Generate component builder template
5
+ * @param {(PackageDefinition | ComponentFile)[]} components components to include in component builder
6
+ * @returns generated component builder template
7
+ */
8
+ export const getComponentBuilderTemplate = (components) => {
9
+ const componentFiles = components.filter((component) => component.componentName);
10
+ const packages = components.filter((component) => component.components);
11
+ const hasLazyModules = componentFiles.find((component) => isLazyLoadingModule(component.path));
12
+ return `/* eslint-disable */
13
+ // Do not edit this file, it is auto-generated at build time!
14
+ // See scripts/generate-component-builder/index.ts to modify the generation of this file.
15
+
16
+ ${hasLazyModules ? "import dynamic from 'next/dynamic';" : ''}
17
+ import { ComponentBuilder } from '@sitecore-jss/sitecore-jss-nextjs';
18
+
19
+ ${packages.map((pkg) => {
20
+ const list = pkg.components.map((c) => c.moduleName).join(', ');
21
+ return `import { ${list} } from '${pkg.name}'`;
22
+ })}
23
+ ${componentFiles
24
+ .map((component) => {
25
+ if (isLazyLoadingModule(component.path)) {
26
+ const moduleName = removeDynamicModuleNameEnding(component.moduleName);
27
+ return `const ${moduleName} = {
28
+ module: () => import('${component.path}'),
29
+ element: (isEditing?: boolean) => isEditing ? require('${component.path}')?.default : dynamic(${moduleName}.module)
30
+ }`;
31
+ }
32
+ return `import * as ${component.moduleName} from '${component.path}';`;
33
+ })
34
+ .join('\n')}
35
+
36
+ const components = new Map();
37
+ ${packages.map((p) => p.components.map((component) => `components.set('${component.componentName}', ${component.moduleName})`))}
38
+ ${componentFiles
39
+ .map((component) => `components.set('${isLazyLoadingModule(component.path)
40
+ ? removeDynamicModuleNameEnding(component.componentName)
41
+ : component.componentName}', ${isLazyLoadingModule(component.path)
42
+ ? removeDynamicModuleNameEnding(component.moduleName)
43
+ : component.moduleName});`)
44
+ .join('\n')}
45
+
46
+ export const componentBuilder = new ComponentBuilder({ components });
47
+
48
+ export const moduleFactory = componentBuilder.getModuleFactory();
49
+ `;
50
+ };
@@ -0,0 +1,70 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { getItems } from './utils';
4
+ /**
5
+ * Identifies the format of the module to be compiled
6
+ */
7
+ export var ModuleType;
8
+ (function (ModuleType) {
9
+ ModuleType[ModuleType["CJS"] = 0] = "CJS";
10
+ ModuleType[ModuleType["ESM"] = 1] = "ESM";
11
+ })(ModuleType || (ModuleType = {}));
12
+ /**
13
+ * Get list of plugins from @var path
14
+ * Returns a list of plugins in the following format:
15
+ * {
16
+ * path: 'path/to/plugin/foo',
17
+ * name: 'fooPlugin'
18
+ * }
19
+ * @example getPluginList('src/foo/plugins', 'Foo')
20
+ * @param {Object} definition plugin definition
21
+ * @param {string} definition.path path to get plugin from
22
+ * @param {string} definition.pluginName plugin name
23
+ * @param {boolean} [definition.silent] whether to suppress console output
24
+ */
25
+ export function getPluginList({ path, pluginName, silent = false, }) {
26
+ const plugins = getItems({
27
+ path,
28
+ resolveItem: (path, name) => ({
29
+ path: `${path}/${name}`,
30
+ name: `${name.replace(/-./g, (x) => x[1].toUpperCase())}Plugin`,
31
+ }),
32
+ cb: (name) => !silent && console.debug(`Registering ${pluginName} plugin ${name}`),
33
+ });
34
+ return plugins;
35
+ }
36
+ /**
37
+ * Generates the plugins file and saves it to the filesystem.
38
+ * By convention, we expect to find plugins under {pluginName}/plugins/** (subfolders are searched recursively).
39
+ * generated file will be saved to @var {distPath} and will contain a list of plugins in the following format:
40
+ * CJS: exports.fooPlugin = require('{pluginPath}');
41
+ * ESM: export { fooPlugin } from '{pluginPath}';
42
+ * @example generatePlugins({ distPath: 'src/temp/foo-plugins.js', rootPath: 'src/foo/plugins', moduleType: ModuleType.CJS })
43
+ * @param {PluginDefinition} definition plugin definition
44
+ */
45
+ export function generatePlugins(definition) {
46
+ const { rootPath, distPath, moduleType, relative = false, silent } = definition;
47
+ const segments = rootPath.split('/');
48
+ const pluginName = segments[segments.length - 2];
49
+ const plugins = getPluginList({ path: rootPath, pluginName, silent });
50
+ let fileContent = '';
51
+ fileContent = plugins
52
+ .map((plugin) => {
53
+ const sourcePath = relative
54
+ ? path.relative(path.dirname(distPath), plugin.path).replace(/\\/g, '/')
55
+ : plugin.path;
56
+ return moduleType === ModuleType.CJS
57
+ ? `exports.${plugin.name} = require('${sourcePath}');`
58
+ : `export { ${plugin.name} } from '${sourcePath}';`;
59
+ })
60
+ .join('\r\n')
61
+ .concat('\r\n');
62
+ if (!plugins.length) {
63
+ fileContent = moduleType === ModuleType.CJS ? 'module.exports = {};\r\n' : 'export {};\r\n';
64
+ }
65
+ const filePath = path.resolve(distPath);
66
+ !silent && console.log(`Writing ${pluginName} plugins to ${filePath}`);
67
+ fs.writeFileSync(filePath, fileContent, {
68
+ encoding: 'utf8',
69
+ });
70
+ }
@@ -0,0 +1,47 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import { getComponentBuilderTemplate } from './templates/component-builder';
4
+ import { getComponentList } from '../components';
5
+ import { watchItems } from '../utils';
6
+ // Default destination path for component builder
7
+ const componentBuilderOutputPath = 'src/temp/componentBuilder.js';
8
+ const defaultComponentRootPath = 'src/components';
9
+ /**
10
+ * Generate component builder based on provided settings
11
+ * @param {Object} settings settings for component builder generation
12
+ * @param {string} settings.componentRootPath path to components root
13
+ * @param {PackageDefinition[]} settings.packages list of packages to include in component builder
14
+ * @param {boolean} settings.watch whether to watch for changes to component builder sources
15
+ */
16
+ export function generateComponentBuilder({ componentRootPath = defaultComponentRootPath, packages, watch, }) {
17
+ if (watch) {
18
+ watchComponentBuilder(componentRootPath, packages);
19
+ }
20
+ else {
21
+ writeComponentBuilder(componentRootPath, packages);
22
+ }
23
+ }
24
+ /**
25
+ * Watch for changes to component builder sources
26
+ * @param {string} componentRootPath root path to components
27
+ * @param {PackageDefinition[]} [packages] packages to include in component builder
28
+ */
29
+ export function watchComponentBuilder(componentRootPath, packages) {
30
+ console.log(`Watching for changes to component builder sources in ${componentRootPath}...`);
31
+ watchItems([componentRootPath], writeComponentBuilder.bind(null, componentRootPath, packages));
32
+ }
33
+ /**
34
+ * Write component builder to file
35
+ * @param {string} componentRootPath root path to components
36
+ * @param {PackageDefinition[]} [packages] packages to include in component builder
37
+ */
38
+ export function writeComponentBuilder(componentRootPath, packages = []) {
39
+ const components = getComponentList(componentRootPath);
40
+ components.unshift(...packages);
41
+ const componentBuilderPath = path.resolve(componentBuilderOutputPath);
42
+ const fileContent = getComponentBuilderTemplate(components, componentBuilderPath);
43
+ console.log(`Writing component builder to ${componentBuilderPath}`);
44
+ fs.writeFileSync(componentBuilderPath, fileContent, {
45
+ encoding: 'utf8',
46
+ });
47
+ }
@@ -0,0 +1,2 @@
1
+ export { getComponentBuilderTemplate } from './templates/component-builder';
2
+ export { generateComponentBuilder } from './generate-component-builder';
@@ -0,0 +1,41 @@
1
+ import path from 'path';
2
+ /**
3
+ * Generate component builder template
4
+ * @param {(PackageDefinition | ComponentFile)[]} components components to include in component builder
5
+ * @param {string} distPath destination path for component builder
6
+ * @returns generated component builder template
7
+ */
8
+ export const getComponentBuilderTemplate = (components, distPath) => {
9
+ const componentFiles = components.filter((component) => component.componentName);
10
+ const packages = components.filter((component) => component.components);
11
+ return `/* eslint-disable */
12
+ // Do not edit this file, it is auto-generated at build time!
13
+ // See scripts/generate-component-builder/index.js to modify the generation of this file.
14
+
15
+ import { ComponentBuilder } from '@sitecore-jss/sitecore-jss-react';
16
+ ${packages
17
+ .map((pkg) => {
18
+ const list = pkg.components.map((c) => c.moduleName).join(', ');
19
+ return `import { ${list} } from '${pkg.name}'`;
20
+ })
21
+ .join('\n')}
22
+ ${componentFiles
23
+ .map((component) => {
24
+ const sourcePath = path.relative(path.dirname(distPath), component.path).replace(/\\/g, '/');
25
+ return `import ${component.moduleName} from '${sourcePath}';`;
26
+ })
27
+ .join('\n')}
28
+
29
+ const components = new Map();
30
+ ${packages
31
+ .map((p) => p.components.map((component) => `components.set('${component.componentName}', ${component.moduleName})`))
32
+ .join('\n')}
33
+ ${componentFiles
34
+ .map((component) => `components.set('${component.componentName}', ${component.moduleName});`)
35
+ .join('\n')}
36
+
37
+ const componentBuilder = new ComponentBuilder({ components });
38
+
39
+ export const componentFactory = componentBuilder.getComponentFactory();
40
+ `;
41
+ };
@@ -0,0 +1,30 @@
1
+ import fs from 'fs';
2
+ import chalk from 'chalk';
3
+ import path from 'path';
4
+ /**
5
+ * Force to use `crlf` line endings, we are using `crlf` across the project.
6
+ * Replace: `lf` (\n), `cr` (\r)
7
+ * @param {string} content
8
+ */
9
+ export function editLineEndings(content) {
10
+ return content.replace(/\r|\n/gm, '\r\n');
11
+ }
12
+ /**
13
+ * Creates a file relative to the specified path if the file doesn't exist.
14
+ * Creates directories as needed.
15
+ * Does not overwrite existing files.
16
+ * @param {string} filePath - the file path
17
+ * @param {string} fileContent - the file content
18
+ * @returns {string} the file path if the file was created, otherwise null
19
+ */
20
+ export function scaffoldFile(filePath, fileContent) {
21
+ const outputDir = path.dirname(filePath);
22
+ if (fs.existsSync(filePath)) {
23
+ console.log(chalk.red(`Skipping creating ${filePath}; already exists.`));
24
+ return null;
25
+ }
26
+ fs.mkdirSync(outputDir, { recursive: true });
27
+ fs.writeFileSync(filePath, editLineEndings(fileContent), 'utf8');
28
+ console.log(chalk.green(`File ${filePath} has been scaffolded.`));
29
+ return filePath;
30
+ }