@exdst-sitecore-content-sdk/astro 0.0.1

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 (87) hide show
  1. package/LICENSE.txt +202 -0
  2. package/README.md +3 -0
  3. package/package.json +101 -0
  4. package/src/client/index.ts +12 -0
  5. package/src/client/sitecore-astro-client.test.ts +271 -0
  6. package/src/client/sitecore-astro-client.ts +137 -0
  7. package/src/components/AstroImage.astro +114 -0
  8. package/src/components/Date.astro +76 -0
  9. package/src/components/DefaultEmptyFieldEditingComponentImage.astro +24 -0
  10. package/src/components/DefaultEmptyFieldEditingComponentText.astro +12 -0
  11. package/src/components/EditingScripts.astro +49 -0
  12. package/src/components/EmptyRendering.astro +3 -0
  13. package/src/components/ErrorBoundary.astro +77 -0
  14. package/src/components/FieldMetadata.astro +30 -0
  15. package/src/components/File.astro +46 -0
  16. package/src/components/HiddenRendering.astro +22 -0
  17. package/src/components/Image.astro +155 -0
  18. package/src/components/Link.astro +105 -0
  19. package/src/components/MissingComponent.astro +39 -0
  20. package/src/components/Placeholder/EmptyPlaceholder.astro +9 -0
  21. package/src/components/Placeholder/Placeholder.astro +100 -0
  22. package/src/components/Placeholder/PlaceholderMetadata.astro +102 -0
  23. package/src/components/Placeholder/PlaceholderUtils.astro +153 -0
  24. package/src/components/Placeholder/index.ts +5 -0
  25. package/src/components/Placeholder/models.ts +82 -0
  26. package/src/components/Placeholder/placeholder-utils.test.ts +162 -0
  27. package/src/components/Placeholder/placeholder-utils.ts +80 -0
  28. package/src/components/RenderWrapper.astro +31 -0
  29. package/src/components/RichText.astro +59 -0
  30. package/src/components/Text.astro +97 -0
  31. package/src/components/sharedTypes/index.ts +1 -0
  32. package/src/components/sharedTypes/props.ts +17 -0
  33. package/src/config/define-config.test.ts +526 -0
  34. package/src/config/define-config.ts +99 -0
  35. package/src/config/index.ts +1 -0
  36. package/src/config-cli/define-cli-config.test.ts +95 -0
  37. package/src/config-cli/define-cli-config.ts +50 -0
  38. package/src/config-cli/index.ts +1 -0
  39. package/src/context.ts +68 -0
  40. package/src/editing/constants.ts +8 -0
  41. package/src/editing/editing-config-middleware.test.ts +166 -0
  42. package/src/editing/editing-config-middleware.ts +111 -0
  43. package/src/editing/editing-render-middleware.test.ts +801 -0
  44. package/src/editing/editing-render-middleware.ts +288 -0
  45. package/src/editing/index.ts +16 -0
  46. package/src/editing/render-middleware.test.ts +57 -0
  47. package/src/editing/render-middleware.ts +51 -0
  48. package/src/editing/utils.test.ts +852 -0
  49. package/src/editing/utils.ts +308 -0
  50. package/src/enhancers/WithEmptyFieldEditingComponent.astro +56 -0
  51. package/src/enhancers/WithFieldMetadata.astro +31 -0
  52. package/src/env.d.ts +12 -0
  53. package/src/index.ts +16 -0
  54. package/src/middleware/index.ts +24 -0
  55. package/src/middleware/middleware.test.ts +507 -0
  56. package/src/middleware/middleware.ts +167 -0
  57. package/src/middleware/multisite-middleware.test.ts +672 -0
  58. package/src/middleware/multisite-middleware.ts +147 -0
  59. package/src/middleware/robots-middleware.test.ts +113 -0
  60. package/src/middleware/robots-middleware.ts +47 -0
  61. package/src/middleware/sitemap-middleware.test.ts +152 -0
  62. package/src/middleware/sitemap-middleware.ts +65 -0
  63. package/src/services/component-props-service.ts +182 -0
  64. package/src/sharedTypes/component-props.ts +17 -0
  65. package/src/site/index.ts +1 -0
  66. package/src/test-data/components/Bar.astro +0 -0
  67. package/src/test-data/components/Baz.astro +0 -0
  68. package/src/test-data/components/Foo.astro +0 -0
  69. package/src/test-data/components/Hero.variant.astro +0 -0
  70. package/src/test-data/components/NotComponent.bsx +0 -0
  71. package/src/test-data/components/Qux.astro +0 -0
  72. package/src/test-data/components/folded/Folded.astro +0 -0
  73. package/src/test-data/components/folded/random-file-2.docx +0 -0
  74. package/src/test-data/components/random-file.txt +0 -0
  75. package/src/test-data/helpers.ts +46 -0
  76. package/src/test-data/personalizeData.ts +63 -0
  77. package/src/tools/generate-map.ts +83 -0
  78. package/src/tools/index.ts +8 -0
  79. package/src/tools/templating/components.test.ts +305 -0
  80. package/src/tools/templating/components.ts +49 -0
  81. package/src/tools/templating/constants.ts +4 -0
  82. package/src/tools/templating/default-component.test.ts +31 -0
  83. package/src/tools/templating/default-component.ts +63 -0
  84. package/src/tools/templating/index.ts +2 -0
  85. package/src/utils/index.ts +1 -0
  86. package/src/utils/utils.test.ts +48 -0
  87. package/src/utils/utils.ts +52 -0
@@ -0,0 +1,17 @@
1
+ export type ComponentPropsError = { error: string; componentName: string };
2
+
3
+ /**
4
+ * Shape of component props storage
5
+ */
6
+ export type ComponentPropsCollection = {
7
+ [componentUid: string]: unknown | ComponentPropsError;
8
+ };
9
+
10
+ export type AstroContentSdkComponent = (_props: Record<string, any>) => any;
11
+
12
+ export type PreviewData = string | false | object | undefined;
13
+
14
+ export type ComponentMap<
15
+ TComponent extends AstroContentSdkComponent = AstroContentSdkComponent
16
+ > = Map<string, TComponent>;
17
+
@@ -0,0 +1 @@
1
+ export { SiteResolver, SiteInfo } from '@sitecore-content-sdk/core/site';
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,46 @@
1
+ export type Query = {
2
+ [key: string]: string | string[];
3
+ };
4
+
5
+ const baseUrl = 'https://test.com';
6
+
7
+ export const mockRequest = ({
8
+ url,
9
+ method,
10
+ query,
11
+ headers,
12
+ }: {
13
+ url?: string;
14
+ method?: string;
15
+ query?: Query;
16
+ headers?: { [key: string]: string };
17
+ }) => {
18
+ const requestUrl = addQueryToUrl(url || baseUrl, query);
19
+ return new Request(requestUrl, {
20
+ method,
21
+ headers: headers,
22
+ });
23
+ };
24
+
25
+ export const addQueryToUrl = (baseUrl: string, query?: Query): string => {
26
+ const url = new URL(baseUrl);
27
+ const params = new URLSearchParams();
28
+
29
+ if (query) {
30
+ Object.entries(query).forEach(([key, value]) => {
31
+ if (Array.isArray(value)) {
32
+ value.forEach((item) => {
33
+ params.append(key, item);
34
+ });
35
+ } else {
36
+ params.append(key, value);
37
+ }
38
+ });
39
+
40
+ params.forEach((value, key) => {
41
+ url.searchParams.append(key, value);
42
+ });
43
+ }
44
+
45
+ return url.toString();
46
+ };
@@ -0,0 +1,63 @@
1
+ export const mountain_bike_audience = {
2
+ uid: '0b6d23d8-c50e-4e79-9eca-317ec43e82b0',
3
+ componentName: 'ContentBlock',
4
+ dataSource: '20679cd4-356b-4452-b507-453beeb0be39',
5
+ fields: {
6
+ content: {
7
+ value:
8
+ '<p><img src="https://edge-beta.sitecorecloud.io/ser-edge-personalization/media/CsdkNextWeb/Mountain-Bike.jpg?h=675&amp;w=1200" style="width:1200px;height:675px;" /></p>',
9
+ },
10
+ heading: { value: 'Mountain Bike' },
11
+ },
12
+ };
13
+
14
+ export const city_bike_audience = {
15
+ uid: '0b6d23d8-c50e-4e79-9eca-317ec43e82b0',
16
+ componentName: 'ContentBlock',
17
+ dataSource: '36e02581-2056-4c55-a4d5-f4b700ba1ae2',
18
+ fields: {
19
+ content: {
20
+ value:
21
+ '<p><img src="https://edge-beta.sitecorecloud.io/ser-edge-personalization/media/CsdkNextWeb/Mountain-Bike.jpg?h=675&amp;w=1200" style="width:1200px;height:675px;" /></p>',
22
+ },
23
+ heading: { value: 'Mountain Bike' },
24
+ },
25
+ };
26
+
27
+ export const layoutData = {
28
+ sitecore: {
29
+ context: {
30
+ pageEditing: false,
31
+ site: { name: 'CsdkNextWeb' },
32
+ visitorIdentificationTimestamp: 1038543,
33
+ language: 'en',
34
+ variantId: undefined,
35
+ },
36
+ route: {
37
+ name: 'landingpage',
38
+ placeholders: {
39
+ 'content-sdk-main': [
40
+ {
41
+ uid: '0b6d23d8-c50e-4e79-9eca-317ec43e82b0',
42
+ componentName: 'ContentBlock',
43
+ dataSource: 'e020fb58-1be8-4537-aab8-67916452ecf2',
44
+ fields: { content: { value: '' }, heading: { value: 'Default Content' } },
45
+ experiences: {
46
+ mountain_bike_audience: mountain_bike_audience,
47
+ city_bike_audience: city_bike_audience,
48
+ },
49
+ },
50
+ ],
51
+ },
52
+ },
53
+ },
54
+ };
55
+
56
+ export const componentWithExperiences = {
57
+ uid: '0b6d23d8-c50e-4e79-9eca-317ec43e82b0',
58
+ componentName: 'ContentBlock',
59
+ dataSource: '20679cd4-356b-4452-b507-453beeb0be39',
60
+ fields: mountain_bike_audience.fields,
61
+ };
62
+
63
+ export const componentsWithExperiencesArray = [componentWithExperiences];
@@ -0,0 +1,83 @@
1
+ import {
2
+ GenerateMapArgs,
3
+ GenerateMapFunction,
4
+ ComponentMapTemplate,
5
+ } from '@sitecore-content-sdk/core/tools';
6
+ import path from 'path';
7
+ import fs from 'fs';
8
+ import { getComponentList } from './templating/components';
9
+
10
+ /**
11
+ * Generate and write componentMap.ts file based on provided params.
12
+ * @param {GenerateMapArgs} param0 params for generateMap
13
+ */
14
+ export const generateMap: GenerateMapFunction = ({
15
+ paths,
16
+ destination = '.sitecore',
17
+ exclude,
18
+ componentImports,
19
+ mapTemplate = buildAstroMapContent,
20
+ }: GenerateMapArgs) => {
21
+ const components = getComponentList(paths, exclude);
22
+
23
+ const content = (mapTemplate as ComponentMapTemplate)(components, componentImports);
24
+
25
+ const componentMapFile = path.join(process.cwd(), destination, 'component-map.ts');
26
+
27
+ try {
28
+ fs.writeFileSync(componentMapFile, content, {
29
+ encoding: 'utf8',
30
+ });
31
+ } catch (error) {
32
+ console.error(`Component Map generation failed. Error writing to file ${destination}:`, error);
33
+ throw error;
34
+ }
35
+ };
36
+
37
+ const buildAstroMapContent: ComponentMapTemplate = (components, componentImports): string => {
38
+ const wildcardImports: string[] = [];
39
+ const namedImports: string[] = [];
40
+
41
+ const componentMapEntries: string[] = [];
42
+
43
+ components.forEach((component) => {
44
+ wildcardImports.push(`import ${component.moduleName} from '${component.importPath}.astro';`);
45
+ componentMapEntries.push(`['${component.moduleName}', ${component.moduleName}]`);
46
+ });
47
+
48
+ componentImports?.forEach((packageEntry) => {
49
+ if (packageEntry.importInfo.namedImports) {
50
+ namedImports.push(
51
+ `import { ${packageEntry.importInfo.namedImports.join(', ')} } from '${
52
+ packageEntry.importInfo.importFrom
53
+ }.astro';`
54
+ );
55
+ packageEntry.importInfo.namedImports.forEach((importName) => {
56
+ componentMapEntries.push(`['${importName}', ${importName}]`);
57
+ });
58
+ } else {
59
+ wildcardImports.push(
60
+ `import ${packageEntry.importName} from '${packageEntry.importInfo.importFrom}';`
61
+ );
62
+ componentMapEntries.push(`['${packageEntry.importName}', ${packageEntry.importName}]`);
63
+ }
64
+ });
65
+
66
+ return `//@ts-nocheck
67
+ import { AstroContentSdkComponent } from '@astro-sitecore-jss/astro-content-sdk';
68
+
69
+ // Components imported from the app itself
70
+ ${wildcardImports.join('\n')}
71
+ ${namedImports.join('\n')}
72
+
73
+ // Components must be registered within the map to match the string key with component name in Sitecore
74
+ export const componentMap = new Map<string, AstroContentSdkComponent>([
75
+ ${componentMapEntries
76
+ .map((component) => {
77
+ return ` ${component},\n`;
78
+ })
79
+ .join('')}]);
80
+
81
+ export default componentMap;
82
+ `;
83
+ };
@@ -0,0 +1,8 @@
1
+ export {
2
+ generateSites,
3
+ generateMetadata,
4
+ } from '@sitecore-content-sdk/core/tools';
5
+
6
+ export { generateMap } from './generate-map';
7
+
8
+ export * from './templating';
@@ -0,0 +1,305 @@
1
+ /* eslint-disable no-unused-expressions */
2
+ import { expect } from 'chai';
3
+ import sinon from 'sinon';
4
+ import { getComponentList } from './components';
5
+ import { ComponentFile } from '@sitecore-content-sdk/core/tools';
6
+ import path from 'path';
7
+
8
+ describe('components', () => {
9
+ const sandbox = sinon.createSandbox();
10
+ beforeEach(() => {
11
+ sandbox.restore();
12
+ });
13
+
14
+ describe('getComponentList', () => {
15
+ afterEach(() => {
16
+ sandbox.restore();
17
+ });
18
+
19
+ it('should return results when one of "paths" is a glob pattern', () => {
20
+ const items = [
21
+ {
22
+ importPath: 'src/test-data/components/Qux',
23
+ filePath: path.normalize('src/test-data/components/Qux.astro'),
24
+ componentName: 'Qux',
25
+ moduleName: 'Qux',
26
+ },
27
+ {
28
+ importPath: 'src/test-data/components/Foo',
29
+ filePath: path.normalize('src/test-data/components/Foo.astro'),
30
+ componentName: 'Foo',
31
+ moduleName: 'Foo',
32
+ },
33
+ {
34
+ importPath: 'src/test-data/components/Baz',
35
+ filePath: path.normalize('src/test-data/components/Baz.astro'),
36
+ componentName: 'Baz',
37
+ moduleName: 'Baz',
38
+ },
39
+ {
40
+ importPath: 'src/test-data/components/Bar',
41
+ filePath: path.normalize('src/test-data/components/Bar.astro'),
42
+ componentName: 'Bar',
43
+ moduleName: 'Bar',
44
+ },
45
+ ] as ComponentFile[];
46
+
47
+ const result = getComponentList(['src/test-data/components/*.astro'], ['**/*.test.*'], false);
48
+ expect(result).to.deep.equal(items);
49
+ });
50
+
51
+ it('should return results with all folded paths when path is a non-glob path', () => {
52
+ const items = [
53
+ {
54
+ importPath: 'src/test-data/components/Qux',
55
+ filePath: path.normalize('src/test-data/components/Qux.astro'),
56
+ componentName: 'Qux',
57
+ moduleName: 'Qux',
58
+ },
59
+ {
60
+ importPath: 'src/test-data/components/Foo',
61
+ filePath: path.normalize('src/test-data/components/Foo.astro'),
62
+ componentName: 'Foo',
63
+ moduleName: 'Foo',
64
+ },
65
+ {
66
+ importPath: 'src/test-data/components/Baz',
67
+ filePath: path.normalize('src/test-data/components/Baz.astro'),
68
+ componentName: 'Baz',
69
+ moduleName: 'Baz',
70
+ },
71
+ {
72
+ importPath: 'src/test-data/components/Bar',
73
+ filePath: path.normalize('src/test-data/components/Bar.astro'),
74
+ componentName: 'Bar',
75
+ moduleName: 'Bar',
76
+ },
77
+ {
78
+ importPath: 'src/test-data/components/folded/Folded',
79
+ filePath: path.normalize('src/test-data/components/folded/Folded.astro'),
80
+ componentName: 'Folded',
81
+ moduleName: 'Folded',
82
+ },
83
+ ] as ComponentFile[];
84
+
85
+ const result = getComponentList(['src/test-data/components'], ['**/*.test.*'], false);
86
+ expect(result).to.deep.equal(items);
87
+ });
88
+
89
+ it('should filter out results that are not components', () => {
90
+ const items = [
91
+ {
92
+ importPath: 'src/test-data/components/Qux',
93
+ filePath: path.normalize('src/test-data/components/Qux.astro'),
94
+ componentName: 'Qux',
95
+ moduleName: 'Qux',
96
+ },
97
+ {
98
+ importPath: 'src/test-data/components/Foo',
99
+ filePath: path.normalize('src/test-data/components/Foo.astro'),
100
+ componentName: 'Foo',
101
+ moduleName: 'Foo',
102
+ },
103
+ {
104
+ importPath: 'src/test-data/components/Baz',
105
+ filePath: path.normalize('src/test-data/components/Baz.astro'),
106
+ componentName: 'Baz',
107
+ moduleName: 'Baz',
108
+ },
109
+ {
110
+ importPath: 'src/test-data/components/Bar',
111
+ filePath: path.normalize('src/test-data/components/Bar.astro'),
112
+ componentName: 'Bar',
113
+ moduleName: 'Bar',
114
+ },
115
+ {
116
+ importPath: 'src/test-data/components/folded/Folded',
117
+ filePath: path.normalize('src/test-data/components/folded/Folded.astro'),
118
+ componentName: 'Folded',
119
+ moduleName: 'Folded',
120
+ },
121
+ ] as ComponentFile[];
122
+
123
+ const result = getComponentList(['src/test-data/components/**/*']);
124
+ expect(result).to.deep.equal(items);
125
+ });
126
+
127
+ it('should return result when "paths" contain exact paths to Astro components', () => {
128
+ const items = [
129
+ {
130
+ importPath: 'src/test-data/components/Foo',
131
+ filePath: path.normalize('src/test-data/components/Foo.astro'),
132
+ componentName: 'Foo',
133
+ moduleName: 'Foo',
134
+ },
135
+ {
136
+ importPath: 'src/test-data/components/Bar',
137
+ filePath: path.normalize('src/test-data/components/Bar.astro'),
138
+ componentName: 'Bar',
139
+ moduleName: 'Bar',
140
+ },
141
+ {
142
+ importPath: 'src/test-data/components/Baz',
143
+ filePath: path.normalize('src/test-data/components/Baz.astro'),
144
+ componentName: 'Baz',
145
+ moduleName: 'Baz',
146
+ },
147
+ {
148
+ importPath: 'src/test-data/components/Qux',
149
+ filePath: path.normalize('src/test-data/components/Qux.astro'),
150
+ componentName: 'Qux',
151
+ moduleName: 'Qux',
152
+ },
153
+ ];
154
+
155
+ const result = getComponentList([
156
+ 'src/test-data/components/Foo.astro',
157
+ 'src/test-data/components/Bar.astro',
158
+ 'src/test-data/components/Baz.astro',
159
+ 'src/test-data/components/Qux.astro',
160
+ ]);
161
+ expect(result).to.deep.equal(items);
162
+ });
163
+
164
+ it('should return filtered results when "exclude" contains a glob pattern', () => {
165
+ const exclude = ['**/components/**'];
166
+ expect(getComponentList(['src/test-data/components/*.astro'], exclude)).to.be.empty;
167
+ });
168
+
169
+ it('should return variants in results when includeVariants is true', () => {
170
+ sandbox.stub(console, 'debug');
171
+
172
+ const items = [
173
+ {
174
+ importPath: 'src/test-data/components/Qux',
175
+ filePath: path.normalize('src/test-data/components/Qux.astro'),
176
+ componentName: 'Qux',
177
+ moduleName: 'Qux',
178
+ },
179
+ // variant component
180
+ {
181
+ importPath: 'src/test-data/components/Hero.variant',
182
+ filePath: path.normalize('src/test-data/components/Hero.variant.astro'),
183
+ componentName: 'Hero.variant',
184
+ moduleName: 'Herovariant',
185
+ },
186
+ {
187
+ importPath: 'src/test-data/components/Foo',
188
+ filePath: path.normalize('src/test-data/components/Foo.astro'),
189
+ componentName: 'Foo',
190
+ moduleName: 'Foo',
191
+ },
192
+ {
193
+ importPath: 'src/test-data/components/Baz',
194
+ filePath: path.normalize('src/test-data/components/Baz.astro'),
195
+ componentName: 'Baz',
196
+ moduleName: 'Baz',
197
+ },
198
+ {
199
+ importPath: 'src/test-data/components/Bar',
200
+ filePath: path.normalize('src/test-data/components/Bar.astro'),
201
+ componentName: 'Bar',
202
+ moduleName: 'Bar',
203
+ },
204
+ {
205
+ importPath: 'src/test-data/components/folded/Folded',
206
+ filePath: path.normalize('src/test-data/components/folded/Folded.astro'),
207
+ componentName: 'Folded',
208
+ moduleName: 'Folded',
209
+ },
210
+ ] as ComponentFile[];
211
+
212
+ const result = getComponentList(['src/test-data/components'], ['**/*.test.*'], true);
213
+ expect(result).to.deep.equal(items);
214
+ });
215
+
216
+ it('should return filtered results when "exclude" contains an exact path', () => {
217
+ const exclude = ['src/test-data/components/Foo.astro'];
218
+ getComponentList(['src/test-data/components/*.astro'], exclude);
219
+ });
220
+
221
+ it('should return correct result in unix file systems', () => {
222
+ const stubbedPaths = [
223
+ 'src/test-data/components/Foo.astro',
224
+ 'src/test-data/components/Bar.astro',
225
+ 'src/test-data/components/Baz.astro',
226
+ 'src/test-data/components/Qux.astro',
227
+ ];
228
+ const expected = [
229
+ {
230
+ importPath: 'src/test-data/components/Foo',
231
+ filePath: 'src/test-data/components/Foo.astro',
232
+ componentName: 'Foo',
233
+ moduleName: 'Foo',
234
+ },
235
+ {
236
+ importPath: 'src/test-data/components/Bar',
237
+ filePath: 'src/test-data/components/Bar.astro',
238
+ componentName: 'Bar',
239
+ moduleName: 'Bar',
240
+ },
241
+ {
242
+ importPath: 'src/test-data/components/Baz',
243
+ filePath: 'src/test-data/components/Baz.astro',
244
+ componentName: 'Baz',
245
+ moduleName: 'Baz',
246
+ },
247
+ {
248
+ importPath: 'src/test-data/components/Qux',
249
+ filePath: 'src/test-data/components/Qux.astro',
250
+ componentName: 'Qux',
251
+ moduleName: 'Qux',
252
+ },
253
+ ];
254
+
255
+ const globSyncStub = sandbox.stub(require('glob'), 'sync').returns(stubbedPaths);
256
+
257
+ const result = getComponentList(['src/test-data/components/*.astro']);
258
+ expect(result).to.deep.equal(expected);
259
+
260
+ globSyncStub.restore();
261
+ });
262
+
263
+ it('should return correct result in windows file systems', () => {
264
+ const stubbedPaths = [
265
+ 'src\\test-data\\components\\Foo.astro',
266
+ 'src\\test-data\\components\\Bar.astro',
267
+ 'src\\test-data\\components\\Baz.astro',
268
+ 'src\\test-data\\components\\Qux.astro',
269
+ ];
270
+ const expected = [
271
+ {
272
+ importPath: 'src/test-data/components/Foo',
273
+ filePath: 'src\\test-data\\components\\Foo.astro',
274
+ componentName: 'Foo',
275
+ moduleName: 'Foo',
276
+ },
277
+ {
278
+ importPath: 'src/test-data/components/Bar',
279
+ filePath: 'src\\test-data\\components\\Bar.astro',
280
+ componentName: 'Bar',
281
+ moduleName: 'Bar',
282
+ },
283
+ {
284
+ importPath: 'src/test-data/components/Baz',
285
+ filePath: 'src\\test-data\\components\\Baz.astro',
286
+ componentName: 'Baz',
287
+ moduleName: 'Baz',
288
+ },
289
+ {
290
+ importPath: 'src/test-data/components/Qux',
291
+ filePath: 'src\\test-data\\components\\Qux.astro',
292
+ componentName: 'Qux',
293
+ moduleName: 'Qux',
294
+ },
295
+ ];
296
+
297
+ const globSyncStub = sandbox.stub(require('glob'), 'sync').returns(stubbedPaths);
298
+
299
+ const result = getComponentList(['src/test-data/components/*.astro']);
300
+ expect(result).to.deep.equal(expected);
301
+
302
+ globSyncStub.restore();
303
+ });
304
+ });
305
+ });
@@ -0,0 +1,49 @@
1
+ import * as glob from 'glob';
2
+ import { ComponentFile } from '@sitecore-content-sdk/core/tools';
3
+
4
+ const componentNamePattern = /^[\/]*(.+[\/\\])*(.+)\.astro?$/;
5
+
6
+ const componentPathPattern = /^([\/]*.+[\/\\].+)\..+$/;
7
+
8
+ /**
9
+ * Get list of components from @var path
10
+ * Returns a list of components in the following format:
11
+ * {
12
+ * path: 'path/to/component',
13
+ * componentName: 'ComponentName',
14
+ * moduleName: 'ComponentName'
15
+ * }
16
+ * @param {string[]} paths paths to search
17
+ * @param {string[]} [exclude] paths and glob patterns to exclude from final result
18
+ * @param {boolean} [includeVariants] whether to include variant components
19
+ */
20
+ export function getComponentList(
21
+ paths: string[],
22
+ exclude?: string[],
23
+ includeVariants?: boolean
24
+ ): ComponentFile[] {
25
+ const components = paths.reduce<ComponentFile[]>((result, path) => {
26
+ const globPath =
27
+ glob.hasMagic(path, { magicalBraces: true }) || path.match(componentNamePattern)
28
+ ? path
29
+ : path.replace(/\/$/, '').concat('/**/*.astro');
30
+ return result.concat(
31
+ ...glob
32
+ .sync(globPath, { ignore: exclude, nodir: true })
33
+ .filter((path: string) => path.match(componentNamePattern))
34
+ .map((filePath: string) => {
35
+ const name = filePath.match(componentNamePattern)![2];
36
+ return {
37
+ filePath,
38
+ importPath: filePath.match(componentPathPattern)![1].replace(/\\/g, '/'), // use forward slashes for consistency
39
+ componentName: name,
40
+ moduleName: name.replace(/[^\w]+/g, ''),
41
+ };
42
+ })
43
+ );
44
+ }, []);
45
+
46
+ return includeVariants
47
+ ? components
48
+ : components.filter((component) => !component.componentName.includes('.'));
49
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * The file extension for Astro components
3
+ */
4
+ export const COMPONENT_FILE_EXTENSION = 'astro';
@@ -0,0 +1,31 @@
1
+ /* eslint-disable no-unused-expressions, @typescript-eslint/no-unused-expressions */
2
+ import { expect } from 'chai';
3
+ import { defaultTemplate } from './default-component';
4
+ import chalk from 'chalk';
5
+
6
+ describe('default-component', () => {
7
+ describe('generateTemplate', () => {
8
+ it('should generate a template with the given component name', () => {
9
+ const componentName = 'TestComponent';
10
+ const template = defaultTemplate.generateTemplate(componentName);
11
+ expect(template).to.include(`export type ${componentName}Props`);
12
+ expect(template).to.include(`<p>${componentName} Component</p>`);
13
+ });
14
+ });
15
+
16
+ describe('getNextSteps', () => {
17
+ it('should return an empty array if no componentOutputPath is provided', () => {
18
+ const nextSteps = defaultTemplate.getNextSteps && defaultTemplate.getNextSteps('');
19
+ expect(nextSteps).to.be.an('array').that.is.empty;
20
+ });
21
+
22
+ it('should return an array with next steps if componentOutputPath is provided', () => {
23
+ const componentOutputPath = 'src/components/TestComponent.astro';
24
+ const nextSteps =
25
+ defaultTemplate.getNextSteps && defaultTemplate.getNextSteps(componentOutputPath);
26
+ expect(nextSteps)
27
+ .to.be.an('array')
28
+ .that.includes(`* Implement the Astro component in ${chalk.green(componentOutputPath)}`);
29
+ });
30
+ });
31
+ });