@sitecore-jss/sitecore-jss-dev-tools 22.0.0-canary.9 → 22.1.0-canary.2

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 (52) hide show
  1. package/README.md +7 -2
  2. package/dist/cjs/index.js +2 -3
  3. package/dist/cjs/pipelines/runner.js +2 -2
  4. package/dist/cjs/templating/components.js +27 -0
  5. package/dist/cjs/templating/index.js +14 -0
  6. package/dist/cjs/templating/metadata.js +32 -0
  7. package/dist/cjs/templating/nextjs/component-props.loader.js +91 -0
  8. package/dist/cjs/templating/nextjs/generate-component-builder.js +72 -0
  9. package/dist/cjs/templating/nextjs/index.js +7 -0
  10. package/dist/cjs/templating/nextjs/templates/component-builder.js +59 -0
  11. package/dist/cjs/templating/plugins.js +78 -0
  12. package/dist/cjs/templating/react/generate-component-builder.js +64 -0
  13. package/dist/cjs/templating/react/index.js +7 -0
  14. package/dist/cjs/templating/react/templates/component-builder.js +49 -0
  15. package/dist/cjs/templating/scaffold.js +38 -0
  16. package/dist/cjs/templating/utils.js +56 -0
  17. package/dist/esm/index.js +1 -1
  18. package/dist/esm/pipelines/runner.js +2 -2
  19. package/dist/esm/templating/components.js +23 -0
  20. package/dist/esm/templating/index.js +5 -0
  21. package/dist/esm/templating/metadata.js +25 -0
  22. package/dist/esm/templating/nextjs/component-props.loader.js +65 -0
  23. package/dist/esm/templating/nextjs/generate-component-builder.js +63 -0
  24. package/dist/esm/templating/nextjs/index.js +2 -0
  25. package/dist/esm/templating/nextjs/templates/component-builder.js +55 -0
  26. package/dist/esm/templating/plugins.js +70 -0
  27. package/dist/esm/templating/react/generate-component-builder.js +55 -0
  28. package/dist/esm/templating/react/index.js +2 -0
  29. package/dist/esm/templating/react/templates/component-builder.js +42 -0
  30. package/dist/esm/templating/scaffold.js +30 -0
  31. package/dist/esm/templating/utils.js +48 -0
  32. package/nextjs-component-props-loader.d.ts +1 -0
  33. package/nextjs-component-props-loader.js +3 -0
  34. package/nextjs.d.ts +1 -0
  35. package/nextjs.js +3 -0
  36. package/package.json +12 -8
  37. package/react.d.ts +1 -0
  38. package/react.js +3 -0
  39. package/types/index.d.ts +2 -1
  40. package/types/templating/components.d.ts +29 -0
  41. package/types/templating/index.d.ts +5 -0
  42. package/types/templating/metadata.d.ts +5 -0
  43. package/types/templating/nextjs/component-props.loader.d.ts +7 -0
  44. package/types/templating/nextjs/generate-component-builder.d.ts +45 -0
  45. package/types/templating/nextjs/index.d.ts +2 -0
  46. package/types/templating/nextjs/templates/component-builder.d.ts +7 -0
  47. package/types/templating/plugins.d.ts +67 -0
  48. package/types/templating/react/generate-component-builder.d.ts +39 -0
  49. package/types/templating/react/index.d.ts +2 -0
  50. package/types/templating/react/templates/component-builder.d.ts +8 -0
  51. package/types/templating/scaffold.d.ts +15 -0
  52. package/types/templating/utils.d.ts +38 -0
@@ -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';
@@ -21,7 +21,7 @@ pipeline.addProcessor({
21
21
  },
22
22
  });
23
23
  pipeline
24
- .runWithCompilers(['babel-core/register'])
24
+ .runWithCompilers(['@babel/register'])
25
25
  .then((result) => {
26
26
  console.log(JSON.stringify(result, null, 2));
27
27
  })
@@ -29,7 +29,7 @@ pipeline
29
29
  console.error(err);
30
30
  });
31
31
  const runner = () => __awaiter(void 0, void 0, void 0, function* () {
32
- const compilers = ['babel-core/register'];
32
+ const compilers = ['@babel/register'];
33
33
  return initCompilers(compilers)
34
34
  .then(() => configLoader({ fileGlobs: ['../test/pipelines/**/*.config.js'], workingDirectory: __dirname }))
35
35
  .then((config) => configLoader({
@@ -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,5 @@
1
+ export { getComponentList } from './components';
2
+ export { generatePlugins, ModuleType } from './plugins';
3
+ export { scaffoldFile } from './scaffold';
4
+ export { strip } from './strip';
5
+ export { getMetadata } from './metadata';
@@ -0,0 +1,25 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ /**
4
+ * Get application metadata
5
+ */
6
+ export function getMetadata() {
7
+ const metadata = { packages: {} };
8
+ const trackedScopes = ['@sitecore', '@sitecore-cloudsdk', '@sitecore-feaas', '@sitecore-jss'];
9
+ const dirs = fs.readdirSync('node_modules');
10
+ dirs.forEach((dir) => {
11
+ if (trackedScopes.includes(dir)) {
12
+ const packageNames = fs.readdirSync(path.join('node_modules', dir));
13
+ packageNames.forEach((pkg) => {
14
+ try {
15
+ const json = JSON.parse(fs.readFileSync(path.join('node_modules', dir, pkg, 'package.json'), 'utf8'));
16
+ metadata.packages[json.name] = json.version;
17
+ }
18
+ catch (e) {
19
+ console.error(`Failed to read/parse package.json for ${pkg}`, e);
20
+ }
21
+ });
22
+ }
23
+ });
24
+ return metadata;
25
+ }
@@ -0,0 +1,65 @@
1
+ import * as recast from 'recast';
2
+ /**
3
+ * Webpack loader to strip functions from the source code
4
+ * Strips the `getServerSideProps` and `getStaticProps` functions from the source code
5
+ * @param {string} source file source code
6
+ * @returns {string} output file source code with stripped functions
7
+ */
8
+ export default function componentPropsLoader(source) {
9
+ // Parse the source code into an AST (Abstract Syntax Tree)
10
+ const ast = recast.parse(source, {
11
+ parser: require('recast/parsers/babel-ts'),
12
+ });
13
+ // List of functions to strip from the AST
14
+ const functionsToStrip = ['getServerSideProps', 'getStaticProps'];
15
+ // Remove the function from the list of functions to strip
16
+ const updateList = (functionName) => {
17
+ // Remove the function from the list of functions to strip
18
+ functionsToStrip.splice(functionsToStrip.indexOf(functionName), 1);
19
+ };
20
+ // Traverse the AST and strip the functions
21
+ recast.visit(ast, {
22
+ // Visit the named export function expression
23
+ visitExportNamedDeclaration: function (path) {
24
+ var _a, _b;
25
+ // Get the variable declaration from the AST
26
+ (_b = (_a = path.node.declaration) === null || _a === void 0 ? void 0 : _a.declarations) === null || _b === void 0 ? void 0 : _b.forEach((declaration) => {
27
+ // Check if the function is in the list of functions to strip
28
+ if ('id' in declaration &&
29
+ 'name' in declaration.id &&
30
+ typeof declaration.id.name === 'string' &&
31
+ functionsToStrip.includes(declaration.id.name)) {
32
+ updateList(declaration.id.name);
33
+ // Strip the function from the AST
34
+ path.prune();
35
+ }
36
+ });
37
+ if (functionsToStrip.length === 0) {
38
+ // We have pruned all the functions we need to, so we can stop traversing the AST
39
+ return false;
40
+ }
41
+ // Continue traversing the AST
42
+ this.traverse(path);
43
+ },
44
+ // Visit the named export function declaration
45
+ visitFunctionDeclaration: function (path) {
46
+ // Check if the function is in the list of functions to strip
47
+ if (path.node.id &&
48
+ 'name' in path.node.id &&
49
+ typeof path.node.id.name === 'string' &&
50
+ functionsToStrip.includes(path.node.id.name)) {
51
+ updateList(path.node.id.name);
52
+ // Strip the function from the AST
53
+ path.prune();
54
+ }
55
+ if (functionsToStrip.length === 0) {
56
+ // We have pruned all the functions we need to, so we can stop traversing the AST
57
+ return false;
58
+ }
59
+ // Continue traversing the AST
60
+ this.traverse(path);
61
+ },
62
+ });
63
+ // Generate the output code
64
+ return recast.print(ast).code;
65
+ }
@@ -0,0 +1,63 @@
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 {ComponentFile[]} [settings.components] list of components to include in component builder
16
+ * @param {boolean} [settings.watch] whether to watch for changes to component builder sources
17
+ */
18
+ export function generateComponentBuilder({ componentRootPath = defaultComponentRootPath, componentBuilderOutputPath = defaultComponentBuilderOutputPath, packages = [], components = [], watch, } = {}) {
19
+ if (watch) {
20
+ watchComponentBuilder({ componentRootPath, componentBuilderOutputPath, packages, components });
21
+ }
22
+ else {
23
+ writeComponentBuilder({ componentRootPath, componentBuilderOutputPath, packages, components });
24
+ }
25
+ }
26
+ /**
27
+ * Watch for changes to component builder sources
28
+ * @param {Object} settings settings for component builder generation
29
+ * @param {string} settings.componentRootPath path to components root
30
+ * @param {string} settings.componentBuilderOutputPath path to component builder output
31
+ * @param {PackageDefinition[]} settings.packages list of packages to include in component builder
32
+ * @param {ComponentFile[]} settings.components list of components to include in component builder
33
+ */
34
+ export function watchComponentBuilder({ componentRootPath, componentBuilderOutputPath, packages, components, }) {
35
+ console.log(`Watching for changes to component builder sources in ${componentRootPath}...`);
36
+ watchItems([componentRootPath], writeComponentBuilder.bind(null, {
37
+ componentRootPath,
38
+ componentBuilderOutputPath,
39
+ packages,
40
+ components,
41
+ }));
42
+ }
43
+ /**
44
+ * Write component builder to file
45
+ * @param {Object} settings settings for component builder generation
46
+ * @param {string} settings.componentRootPath path to components root
47
+ * @param {string} settings.componentBuilderOutputPath path to component builder output
48
+ * @param {PackageDefinition[]} settings.packages list of packages to include in component builder
49
+ * @param {ComponentFile[]} settings.components list of components to include in component builder
50
+ */
51
+ export function writeComponentBuilder({ componentRootPath, componentBuilderOutputPath, packages, components, }) {
52
+ const items = [
53
+ ...packages,
54
+ ...components,
55
+ ...getComponentList(componentRootPath),
56
+ ];
57
+ const componentBuilderPath = path.resolve(componentBuilderOutputPath);
58
+ const fileContent = getComponentBuilderTemplate(items);
59
+ console.log(`Writing component builder to ${componentBuilderPath}`);
60
+ fs.writeFileSync(componentBuilderPath, fileContent, {
61
+ encoding: 'utf8',
62
+ });
63
+ }
@@ -0,0 +1,2 @@
1
+ export { generateComponentBuilder } from './generate-component-builder';
2
+ export { getComponentBuilderTemplate } from './templates/component-builder';
@@ -0,0 +1,55 @@
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
20
+ .map((pkg) => {
21
+ const list = pkg.components.map((c) => c.moduleName).join(', ');
22
+ return `import { ${list} } from '${pkg.name}';\n`;
23
+ })
24
+ .join('')}
25
+ ${componentFiles
26
+ .map((component) => {
27
+ if (isLazyLoadingModule(component.path)) {
28
+ const moduleName = removeDynamicModuleNameEnding(component.moduleName);
29
+ return `const ${moduleName} = {
30
+ module: () => import('${component.path}'),
31
+ element: (isEditing?: boolean) => isEditing ? require('${component.path}')?.default : dynamic(${moduleName}.module)
32
+ }`;
33
+ }
34
+ return `import * as ${component.moduleName} from '${component.path}';`;
35
+ })
36
+ .join('\n')}
37
+
38
+ export const components = new Map();
39
+ ${packages
40
+ .map((p) => p.components.map((component) => `components.set('${component.componentName}', ${component.moduleName});\n`))
41
+ .flat()
42
+ .join('')}
43
+ ${componentFiles
44
+ .map((component) => `components.set('${isLazyLoadingModule(component.path)
45
+ ? removeDynamicModuleNameEnding(component.componentName)
46
+ : component.componentName}', ${isLazyLoadingModule(component.path)
47
+ ? removeDynamicModuleNameEnding(component.moduleName)
48
+ : component.moduleName});`)
49
+ .join('\n')}
50
+
51
+ export const componentBuilder = new ComponentBuilder({ components });
52
+
53
+ export const moduleFactory = componentBuilder.getModuleFactory();
54
+ `;
55
+ };
@@ -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,55 @@
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 {ComponentFile[]} [settings.components] list of components 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, packages = [], components = [], watch, }) {
18
+ if (watch) {
19
+ watchComponentBuilder({ componentRootPath, packages, components });
20
+ }
21
+ else {
22
+ writeComponentBuilder({ componentRootPath, packages, components });
23
+ }
24
+ }
25
+ /**
26
+ * Watch for changes to component builder sources
27
+ * @param {object} config configuration for component builder watcher
28
+ * @param {string} config.componentRootPath root path to components
29
+ * @param {PackageDefinition[]} config.packages packages to include in component builder
30
+ * @param {ComponentFile[]} config.components components to include in component builder
31
+ */
32
+ export function watchComponentBuilder({ componentRootPath, packages, components, }) {
33
+ console.log(`Watching for changes to component builder sources in ${componentRootPath}...`);
34
+ watchItems([componentRootPath], writeComponentBuilder.bind(null, { componentRootPath, packages, components }));
35
+ }
36
+ /**
37
+ * Write component builder to file
38
+ * @param {Object} settings settings for component builder generation
39
+ * @param {string} settings.componentRootPath root path to components
40
+ * @param {PackageDefinition[]} settings.packages packages to include in component builder
41
+ * @param {ComponentFile[]} settings.components list of components to include in component builder
42
+ */
43
+ export function writeComponentBuilder({ componentRootPath, packages, components, }) {
44
+ const items = [
45
+ ...packages,
46
+ ...components,
47
+ ...getComponentList(componentRootPath),
48
+ ];
49
+ const componentBuilderPath = path.resolve(componentBuilderOutputPath);
50
+ const fileContent = getComponentBuilderTemplate(items, componentBuilderPath);
51
+ console.log(`Writing component builder to ${componentBuilderPath}`);
52
+ fs.writeFileSync(componentBuilderPath, fileContent, {
53
+ encoding: 'utf8',
54
+ });
55
+ }
@@ -0,0 +1,2 @@
1
+ export { getComponentBuilderTemplate } from './templates/component-builder';
2
+ export { generateComponentBuilder } from './generate-component-builder';
@@ -0,0 +1,42 @@
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}';\n`;
20
+ })
21
+ .join('')}
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});\n`))
32
+ .flat()
33
+ .join('')}
34
+ ${componentFiles
35
+ .map((component) => `components.set('${component.componentName}', ${component.moduleName});`)
36
+ .join('\n')}
37
+
38
+ const componentBuilder = new ComponentBuilder({ components });
39
+
40
+ export const componentFactory = componentBuilder.getComponentFactory();
41
+ `;
42
+ };
@@ -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
+ }
@@ -0,0 +1,48 @@
1
+ import fs from 'fs';
2
+ import chokidar from 'chokidar';
3
+ /**
4
+ * Using @var path find all files and generate output using @var resolveItem function for each file
5
+ * Can be used to generate list of components, templates, etc.
6
+ * @param {GetItemsSettings} settings
7
+ * @returns {Item[]} list of items
8
+ */
9
+ export function getItems(settings) {
10
+ const { recursive = true, path, resolveItem, cb, fileFormat = new RegExp(/(.+)(?<!\.d)\.[jt]sx?$/), } = settings;
11
+ const items = [];
12
+ const folders = [];
13
+ if (!fs.existsSync(path))
14
+ return [];
15
+ fs.readdirSync(path, { withFileTypes: true }).forEach((item) => {
16
+ if (item.isDirectory()) {
17
+ folders.push(item);
18
+ }
19
+ if (fileFormat.test(item.name)) {
20
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
21
+ const name = item.name.match(fileFormat)[1];
22
+ items.push(resolveItem(path, name));
23
+ cb && cb(name);
24
+ }
25
+ });
26
+ for (const folder of folders) {
27
+ recursive
28
+ ? items.push(...getItems({
29
+ path: `${path}/${folder.name}`,
30
+ resolveItem,
31
+ cb,
32
+ fileFormat,
33
+ }))
34
+ : items.push(resolveItem(`${path}/${folder.name}`, folder.name));
35
+ }
36
+ return items;
37
+ }
38
+ /**
39
+ * Run watch mode, watching on @var paths
40
+ * @param {string[]} paths paths to watch by chokidar
41
+ * @param {Function<void>} cb callback to run on file change
42
+ */
43
+ export function watchItems(paths, cb) {
44
+ chokidar
45
+ .watch(paths, { ignoreInitial: true, awaitWriteFinish: true })
46
+ .on('add', cb)
47
+ .on('unlink', cb);
48
+ }
@@ -0,0 +1 @@
1
+ export * from './types/templating/nextjs/component-props.loader';
@@ -0,0 +1,3 @@
1
+ const loader = require('./dist/cjs/templating/nextjs/component-props.loader');
2
+
3
+ module.exports = loader;
package/nextjs.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './types/templating/nextjs/index';
package/nextjs.js ADDED
@@ -0,0 +1,3 @@
1
+ const templating = require('./dist/cjs/templating/nextjs/index');
2
+
3
+ module.exports = { ...templating };