@jungvonmatt/contentful-ssg 0.17.3 → 1.0.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.
Files changed (134) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +158 -118
  3. package/dist/__test__/mock.d.ts +28 -0
  4. package/dist/__test__/mock.js +83 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +85 -0
  7. package/dist/converter/index.d.ts +7 -0
  8. package/dist/converter/index.js +42 -0
  9. package/dist/converter/json.d.ts +3 -0
  10. package/dist/converter/json.js +2 -0
  11. package/dist/converter/markdown.d.ts +3 -0
  12. package/dist/converter/markdown.js +17 -0
  13. package/dist/converter/toml.d.ts +3 -0
  14. package/dist/converter/toml.js +3 -0
  15. package/dist/converter/yaml.d.ts +3 -0
  16. package/dist/converter/yaml.js +27 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.js +125 -0
  19. package/dist/lib/array.d.ts +4 -0
  20. package/dist/lib/array.js +25 -0
  21. package/dist/lib/config.d.ts +3 -0
  22. package/dist/lib/config.js +144 -0
  23. package/dist/lib/contentful.d.ts +40 -0
  24. package/dist/lib/contentful.js +145 -0
  25. package/dist/lib/create-require.d.ts +2 -0
  26. package/dist/lib/create-require.js +4 -0
  27. package/dist/lib/error.d.ts +9 -0
  28. package/dist/lib/error.js +17 -0
  29. package/dist/lib/file-manager.d.ts +17 -0
  30. package/dist/lib/file-manager.js +64 -0
  31. package/dist/lib/hook-manager.d.ts +15 -0
  32. package/dist/lib/hook-manager.js +94 -0
  33. package/dist/lib/object.d.ts +11 -0
  34. package/dist/lib/object.js +40 -0
  35. package/dist/lib/stats.d.ts +18 -0
  36. package/dist/lib/stats.js +74 -0
  37. package/dist/lib/ui.d.ts +6 -0
  38. package/dist/lib/ui.js +88 -0
  39. package/dist/lib/utils.d.ts +4 -0
  40. package/dist/lib/utils.js +31 -0
  41. package/dist/mapper/map-date-field.d.ts +1 -0
  42. package/dist/mapper/map-date-field.js +6 -0
  43. package/dist/mapper/map-entry.d.ts +4 -0
  44. package/dist/mapper/map-entry.js +42 -0
  45. package/dist/mapper/map-field.d.ts +2 -0
  46. package/dist/mapper/map-field.js +24 -0
  47. package/dist/mapper/map-meta-fields.d.ts +9 -0
  48. package/dist/mapper/map-meta-fields.js +8 -0
  49. package/dist/mapper/map-reference-field.d.ts +11 -0
  50. package/dist/mapper/map-reference-field.js +71 -0
  51. package/dist/mapper/map-rich-text-field.d.ts +7 -0
  52. package/dist/mapper/map-rich-text-field.js +47 -0
  53. package/dist/tasks/fetch.d.ts +2 -0
  54. package/dist/tasks/fetch.js +12 -0
  55. package/dist/tasks/localize.d.ts +6 -0
  56. package/dist/tasks/localize.js +48 -0
  57. package/dist/tasks/setup.d.ts +2 -0
  58. package/dist/tasks/setup.js +26 -0
  59. package/dist/tasks/transform.d.ts +2 -0
  60. package/dist/tasks/transform.js +5 -0
  61. package/dist/tasks/write.d.ts +2 -0
  62. package/dist/tasks/write.js +33 -0
  63. package/dist/types.d.ts +194 -0
  64. package/dist/types.js +1 -0
  65. package/package.json +119 -91
  66. package/src/__test__/fixtures/assets.json +47 -0
  67. package/src/__test__/fixtures/content_types.json +181 -0
  68. package/src/__test__/fixtures/entries.json +783 -0
  69. package/src/__test__/fixtures/locales.json +35 -0
  70. package/src/__test__/fixtures/richtext.json +135 -0
  71. package/src/__test__/mock.ts +106 -0
  72. package/src/cli.ts +134 -0
  73. package/src/converter/index.test.ts +38 -0
  74. package/src/converter/index.ts +60 -0
  75. package/src/converter/json.test.ts +25 -0
  76. package/src/converter/json.ts +16 -0
  77. package/src/converter/markdown.test.ts +58 -0
  78. package/{lib/converter/markdown.js → src/converter/markdown.ts} +8 -10
  79. package/src/converter/toml.test.ts +74 -0
  80. package/src/converter/toml.ts +17 -0
  81. package/src/converter/yaml.test.ts +51 -0
  82. package/src/converter/yaml.ts +51 -0
  83. package/src/index.test.ts +89 -0
  84. package/src/index.ts +155 -0
  85. package/src/lib/array.test.ts +105 -0
  86. package/src/lib/array.ts +84 -0
  87. package/src/lib/config.ts +195 -0
  88. package/src/lib/contentful.test.ts +251 -0
  89. package/{lib/contentful.js → src/lib/contentful.ts} +99 -122
  90. package/src/lib/create-require.ts +6 -0
  91. package/src/lib/error.ts +19 -0
  92. package/src/lib/file-manager.test.ts +73 -0
  93. package/src/lib/file-manager.ts +106 -0
  94. package/src/lib/hook-manager.test.ts +169 -0
  95. package/src/lib/hook-manager.ts +161 -0
  96. package/src/lib/object.test.ts +56 -0
  97. package/src/lib/object.ts +102 -0
  98. package/src/lib/stats.test.ts +78 -0
  99. package/src/lib/stats.ts +112 -0
  100. package/src/lib/ui.test.ts +58 -0
  101. package/src/lib/ui.ts +128 -0
  102. package/src/lib/utils.test.ts +85 -0
  103. package/src/lib/utils.ts +57 -0
  104. package/src/mapper/map-date-field.ts +12 -0
  105. package/src/mapper/map-entry.test.ts +191 -0
  106. package/src/mapper/map-entry.ts +77 -0
  107. package/src/mapper/map-field.test.ts +577 -0
  108. package/src/mapper/map-field.ts +57 -0
  109. package/src/mapper/map-meta-fields.ts +17 -0
  110. package/src/mapper/map-reference-field.ts +122 -0
  111. package/src/mapper/map-rich-text-field.ts +107 -0
  112. package/src/tasks/fetch.test.ts +32 -0
  113. package/src/tasks/fetch.ts +17 -0
  114. package/src/tasks/localize.test.ts +83 -0
  115. package/src/tasks/localize.ts +95 -0
  116. package/src/tasks/setup.test.ts +33 -0
  117. package/src/tasks/setup.ts +31 -0
  118. package/src/tasks/transform.test.ts +26 -0
  119. package/src/tasks/transform.ts +11 -0
  120. package/src/tasks/write.test.ts +94 -0
  121. package/src/tasks/write.ts +49 -0
  122. package/src/types.ts +271 -0
  123. package/index.js +0 -90
  124. package/lib/array.js +0 -48
  125. package/lib/config.js +0 -142
  126. package/lib/converter/index.js +0 -63
  127. package/lib/converter/json.js +0 -20
  128. package/lib/converter/toml.js +0 -22
  129. package/lib/converter/yaml.js +0 -40
  130. package/lib/dump.js +0 -337
  131. package/lib/presets/grow.js +0 -88
  132. package/lib/transform/localize.js +0 -59
  133. package/lib/transform/mapper.js +0 -293
  134. package/lib/utils.js +0 -150
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 Jung von Matt
3
+ Copyright (c) 2021 Jung von Matt TECH (https://www.jvm.com/)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![NPM version][npm-image]][npm-url] [![Build Status][ci-image]][ci-url] [![dependencies Status][depstat-image]][depstat-url] [![devDependencies Status][devdepstat-image]][devdepstat-url] [![Coverage][coveralls-image]][coveralls-url]
1
+ [![NPM version][npm-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Coverage][coveralls-image]][coveralls-url]
2
2
 
3
3
  # JvM Contentful export for static site generators
4
4
 
@@ -12,7 +12,7 @@ When a `.gitignore` file is found only ignored files are removed.
12
12
  ### Install
13
13
 
14
14
  ```bash
15
- npm i @jungvonmatt/contentful-ssg
15
+ npm install --save-dev @jungvonmatt/contentful-ssg
16
16
  ```
17
17
 
18
18
  ## Commands
@@ -31,29 +31,160 @@ npx cssg init
31
31
 
32
32
  Initializes contentful-ssg and stores the config values in the `contentful-ssg.config.js` file.
33
33
 
34
+ Contentful SSG ships with built in typescript support. Add `--typescript` to generate a typescript configuration file.
35
+
36
+ ```bash
37
+ npx cssg init --typescript
38
+ ```
39
+
34
40
  <!-- prettier-ignore -->
35
41
  #### Configuration values
36
42
 
37
- | Name | Type | Default | Description |
38
- | ------------------ | ------------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
39
- | accessToken | `String` | `undefined` | Content Delivery API - access token |
40
- | previewAccessToken | `String` | `undefined` | Content Preview API - access token |
41
- | spaceId | `String` | `undefined` | Contentful Space id |
42
- | environmentId | `String` | `'master'` | Contentful Environment id |
43
- | format | `String`\|`Function`\|`Object` | `'yaml'` | File format ( `yaml`, `toml`, `md`, `json`) You can add a function returning the format or you can add a mapping object like `{yaml: [glob pattern]}` ([pattern](https://github.com/micromatch/micromatch) should match the directory) |
44
- | directory | `String` | `'./content'` | Base directory for content files. |
45
- | typeConfig | `Object` | `undefined` | Pass a map with e.g. grow's blueprint config ({<contenttypeid>: {$path: '...', $view: '...'}}) |
46
- | preset | `String` | `undefined` | Pass `grow` to enable generator specific addons |
47
- | validate | `Function` | `undefined` | Pass `function(content, { requiredFields, requiredFieldMissing, entry, contentType, locale, ... }){...}` to validate an entry. Return a 'falsy' value to skip the entry completely. Without a validate function entries where a required field is missing are skipped. |
48
- | transform | `Function` | `undefined` | Pass `function(content, { entry, contentType, locale, helper, ... }){...}` to modify the stored object. Return `undefined` to skip the entry completely. (no file will be written) |
49
- | mapDirectory | `Function` | `undefined` | Pass `function(contentType, { locale, helper })` to customize the directory per content-type relative to the base directory. |
50
- | mapFilename | `Function` | `undefined` | Pass `function(data, { locale, contentType, entry, format, helper })` to customize the filename per entry |
51
- | mapAssetLink | `Function` | `undefined` | Pass `function(asset){...}` to customize how asset links are stored |
52
- | mapEntryLink | `Function` | `undefined` | Pass `function(entry){...}` to customize how entry links are stored |
53
- | mapMetaFields | `Function` | `undefined` | Pass `function(entry, {contentType, spaceId, locale, helper, ... }){...}` to customize the meta fields per entry |
54
- | richTextRenderer | `Object`\|`Function` | `Boolean` | `{}` We use the contentful [`rich-text-html-renderer`](https://github.com/contentful/rich-text/tree/master/packages/rich-text-html-renderer) to render the html.<br/> You can pass a [configuration object](https://github.com/contentful/rich-text/tree/master/packages/rich-text-html-renderer#usage)<br/> or you can pass `function(document){...}` to use your own richtext renderer or you can turn it off to get a mirrored version of the JSON output |
55
- | before | `Function` | `undefined` | Runs `function(context){...}` before processing the content right after pulling data from contentful |
56
- | after | `Function` | `undefined` | Runs `function(context){...}` after processing the content right before the cleanup |
43
+ | Name | Type | Default | Description |
44
+ | ------------------ | --------------------------------------------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
+ | accessToken | `string` | `undefined` | Content Delivery API - access token |
46
+ | previewAccessToken | `string` | `undefined` | Content Preview API - access token |
47
+ | spaceId | `string` | `undefined` | Contentful Space id |
48
+ | environmentId | `string` | `'master'` | Contentful Environment id |
49
+ | format | `string`\|`function`\|`object` | `'yaml'` | File format ( `yaml`, `toml`, `md`, `json`) You can add a function returning the format or you can add a mapping object like `{yaml: [glob pattern]}` ([pattern](https://github.com/micromatch/micromatch) should match the directory) |
50
+ | plugins | `[string]`\|`[[string, options]]`\|`[{resolve:'string', options:{}}]` | `[]` | Add plugins to contentful-ssg. See [Plugins](#plugins) |
51
+ | directory | `string` | `'./content'` | Base directory for content files. |
52
+ | validate | `function` | `undefined` | Pass `function(transformContext, runtimeContext){...}` to validate an entry. Return `false` to skip the entry completely. Without a validate function entries with a missing required field are skipped. |
53
+ | transform | `function` | `undefined` | Pass `function(transformContext, runtimeContext){...}` to modify the stored object. Return `undefined` to skip the entry completely. (no file will be written) |
54
+ | mapDirectory | `function` | `undefined` | Pass `function(transformContext, runtimeContext, defaultValue){...}` to customize the directory per content-type relative to the base directory. |
55
+ | mapFilename | `function` | `undefined` | Pass `function(transformContext, runtimeContext, defaultValue){...}` to customize the filename per entry |
56
+ | mapAssetLink | `function` | `undefined` | Pass `function(transformContext, runtimeContext, defaultValue){...}` to customize how asset links are stored |
57
+ | mapEntryLink | `function` | `undefined` | Pass `function(transformContext, runtimeContext, defaultValue){...}` to customize how entry links are stored |
58
+ | mapMetaFields | `function` | `undefined` | Pass `function(transformContext, runtimeContext, defaultValue){...}` to customize the meta fields per entry |
59
+ | richTextRenderer | `boolean`\|`object`\|`function` | `{}` | We use the contentful [`rich-text-html-renderer`](https://github.com/contentful/rich-text/tree/master/packages/rich-text-html-renderer) to render the html.<br/> You can pass a [configuration object](https://github.com/contentful/rich-text/tree/master/packages/rich-text-html-renderer#usage)<br/> or you can pass `function(document){...}` to use your own richtext renderer or you can turn it off by passing `false` to get a mirrored version of the JSON output |
60
+ | before | `function` | `undefined` | Runs `function(runtimeContext){...}` before processing the content right after pulling data from contentful |
61
+ | after | `function` | `undefined` | Runs `function(runtimeContext){...}` after processing the content right before the cleanup |
62
+
63
+ ### Plugins
64
+
65
+ You can add plugins to contentful-ssg by adding the package name or a local path to the plugins array of your configuration.
66
+
67
+ ```js
68
+ plugins: ['my-plugin-package', './plugins/my-local-plugin]
69
+ ```
70
+
71
+ All plugins can have options specified by wrapping the name and an options object in an array inside your config or by using a more verbose object notation.
72
+
73
+ For specifying no options, these are all equivalent:
74
+ ```js
75
+ {
76
+ "plugins": ["my-plugin", ["my-plugin"], ["my-plugin", {}], {resolve: "my-plugin", options: {}}]
77
+ }
78
+ ```
79
+
80
+ To specify an option, pass an object with the keys as the option names.
81
+ ```js
82
+ {
83
+ "plugins": [
84
+ [
85
+ "my-plugin-a",
86
+ {
87
+ "option": "value"
88
+ }
89
+ ],
90
+ {
91
+ resolve: "my-plugin-b",
92
+ options: {
93
+ "option": "value"
94
+ }
95
+ }
96
+ ]
97
+ }
98
+ ```
99
+
100
+ ### Runtime Hooks
101
+
102
+ **before**
103
+
104
+ ```js
105
+ import
106
+ (runtimeContext) => {
107
+ // Do things before processing the localized contentful entries
108
+ // The return value should be an object which is merged with the runtime context.
109
+ return { key: 'test' };
110
+ }
111
+ ```
112
+
113
+ **after**
114
+
115
+ ```js
116
+ (runtimeContext) => {
117
+ // Do things after processing the localized contentful entries before cleanup
118
+ // We have access to values added to the context in the before hook
119
+ console.log(runtimeContext.key); // -> 'test'
120
+ };
121
+ ```
122
+
123
+ ### Transform Hooks
124
+
125
+ **transform**
126
+
127
+ ```js
128
+ (transformContext, runtimeContext) => {
129
+ const { content } = transformContext;
130
+ // modify content and
131
+ // return object
132
+ return content;
133
+ };
134
+ ```
135
+
136
+ **mapFilename**
137
+
138
+ ```js
139
+ (transformContext, runtimeContext, defaultValue) => {
140
+ // customize the filename on entry level
141
+ // return string
142
+ return defaultValue;
143
+ };
144
+ ```
145
+
146
+ **mapDirectory**
147
+
148
+ ```js
149
+ (transformContext, runtimeContext, defaultValue) => {
150
+ // customize the directory on entry level
151
+ // return string
152
+ return defaultValue;
153
+ };
154
+ ```
155
+
156
+ **mapAssetLink**
157
+
158
+ ```js
159
+ (transformContext, runtimeContext, defaultValue) => {
160
+ const {asset} = transformContext;
161
+ // customize the asset representation in front matter
162
+ // return object
163
+ return { ...defaultValue, ... };
164
+ }
165
+ ```
166
+
167
+ **mapEntryLink**
168
+
169
+ ```js
170
+ (transformContext, runtimeContext, defaultValue) => {
171
+ const {entry} = transformContext;
172
+ // customize how the entry is added to your front matter
173
+ // return object
174
+ return { ...defaultValue, ... };
175
+ }
176
+ ```
177
+
178
+ **mapMetaFields**
179
+
180
+ ```js
181
+ (transformContext, runtimeContext, defaultValue) => {
182
+ const {entry} = transformContext;
183
+ // customize how the sys meta data is added to your front matter
184
+ // return object
185
+ return { ...defaultValue, ... };
186
+ }
187
+ ```
57
188
 
58
189
  #### Helper functions
59
190
 
@@ -63,9 +194,9 @@ Get values from linked pages to e.g. build an url out of parent slugs.
63
194
 
64
195
  ```js
65
196
  {
66
- transform: (content, options) => {
67
- const { helper } = options;
68
- const slugs = helper.collectValues('fields.slug', {
197
+ transform: (context) => {
198
+ const { utils } = context;
199
+ const slugs = utils.collectValues('fields.slug', {
69
200
  linkField: 'fields.parentPage',
70
201
  });
71
202
 
@@ -74,8 +205,6 @@ Get values from linked pages to e.g. build an url out of parent slugs.
74
205
  }
75
206
  ```
76
207
 
77
- _contentful-ssg.config.js_
78
-
79
208
  ###### collectParentValues
80
209
 
81
210
  The same as collectValues just without the value from the current entry
@@ -92,104 +221,15 @@ npx cssg fetch
92
221
 
93
222
  ### Grow
94
223
 
95
- ```js
96
- const path = require('path');
97
-
98
- module.exports = {
99
- spaceId: '...',
100
- environmentId: '...',
101
- accessToken: '...',
102
- previewAccessToken: '...',
103
- directory: 'content',
104
- preset: 'grow',
105
- mapDirectory: (contentType) => {
106
- switch (contentType.substr(0, 2)) {
107
- case 't-':
108
- return contentType;
109
- case 'o-':
110
- return path.join('partials/organisms', contentType);
111
- case 'm-':
112
- return path.join('partials/molecules', contentType);
113
- case 'a-':
114
- return path.join('partials/atoms', contentType);
115
- default:
116
- return path.join('partials', contentType);
117
- }
118
- },
119
- typeConfig: {
120
- 't-home': {
121
- view: '/views/t-home.html',
122
- path: '/{locale}/',
123
- },
124
- 't-article': {
125
- view: '/views/t-article.html',
126
- path: '/{locale}/{category}/{slug}/',
127
- },
128
- },
129
- };
130
- ```
224
+ See [`cssg-plugin-grow`](../cssg-plugin-grow)
131
225
 
132
226
  ### Hugo
133
227
 
134
- ```js
135
- const path = require('path');
136
-
137
- module.exports = {
138
- spaceId: '...',
139
- environmentId: '...',
140
- accessToken: '...',
141
- previewAccessToken: '...',
142
- directory: 'content',
143
- format: 'md',
144
- mapDirectory: function (contentType, { locale, helper }) {
145
- if (contentType === 't-home') {
146
- return '/';
147
- } else if (contentType.substr(0, 2) === 't-') {
148
- return 'pages';
149
- } else {
150
- return path.join('headlessBundles', contentType);
151
- }
152
- },
153
- mapFilename: function (data, { locale, contentType, entry, format, helper }) {
154
- if (contentType === 't-home') {
155
- return path.join('_index.' + locale.code + '.' + format);
156
- } else {
157
- return path.join(entry.sys.id + '/index.' + locale.code + '.' + format);
158
- }
159
- },
160
- transform: (content, options) => {
161
- const { helper } = options;
162
- const slugs = helper.collectValues('fields.slug', {
163
- linkField: 'fields.parentPage',
164
- });
165
- if (content.contentType === 't-home') {
166
- return { ...content };
167
- } else if (content.contentType.substr(0, 2) === 't-') {
168
- return { ...content, url: slugs.join('/') };
169
- } else {
170
- return { ...content, headless: true };
171
- }
172
- },
173
- };
174
- ```
175
-
176
- ## Demo
177
-
178
- ![Demo](https://github.com/jungvonmatt/contentful-ssg/blob/main/demo.gif?raw=true)
179
-
180
- ## Can I contribute?
181
-
182
- Of course. We appreciate all of our [contributors](https://github.com/jungvonmatt/contentful-ssg/graphs/contributors) and
183
- welcome contributions to improve the project further. If you're uncertain whether an addition should be made, feel
184
- free to open up an issue and we can discuss it.
228
+ See [`cssg-plugin-hugo`](../cssg-plugin-hugo)
185
229
 
186
230
  [npm-url]: https://www.npmjs.com/package/@jungvonmatt/contentful-ssg
187
231
  [npm-image]: https://img.shields.io/npm/v/@jungvonmatt/contentful-ssg.svg
188
232
  [ci-url]: https://github.com/jungvonmatt/contentful-ssg/actions?workflow=Tests
189
233
  [ci-image]: https://github.com/jungvonmatt/contentful-ssg/workflows/Tests/badge.svg
190
- [depstat-url]: https://david-dm.org/jungvonmatt/contentful-ssg
191
- [depstat-image]: https://img.shields.io/david/jungvonmatt/contentful-ssg.svg
192
- [devdepstat-url]: https://david-dm.org/jungvonmatt/contentful-ssg?type=dev
193
- [devdepstat-image]: https://img.shields.io/david/dev/jungvonmatt/contentful-ssg.svg
194
234
  [coveralls-url]: https://coveralls.io/github/jungvonmatt/contentful-ssg?branch=main
195
235
  [coveralls-image]: https://coveralls.io/repos/github/jungvonmatt/contentful-ssg/badge.svg?branch=main
@@ -0,0 +1,28 @@
1
+ import type { Config, RuntimeContext, TransformContext } from '../types.js';
2
+ export declare const readFixture: (file: any) => Promise<any>;
3
+ export declare const readFixtureSync: (file: any) => any;
4
+ export declare const getContent: () => Promise<{
5
+ entries: any;
6
+ assets: any;
7
+ contentTypes: any;
8
+ locales: any;
9
+ assetLink: {
10
+ sys: {
11
+ id: string;
12
+ type: string;
13
+ linkType: string;
14
+ };
15
+ };
16
+ entryLink: {
17
+ sys: {
18
+ id: string;
19
+ type: string;
20
+ linkType: string;
21
+ };
22
+ };
23
+ entry: any;
24
+ asset: any;
25
+ }>;
26
+ export declare const getConfig: (fixture?: Partial<Config>) => Config;
27
+ export declare const getRuntimeContext: (fixture?: Partial<RuntimeContext>) => RuntimeContext;
28
+ export declare const getTransformContext: (fixture?: Partial<TransformContext>) => TransformContext;
@@ -0,0 +1,83 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import { FIELD_TYPE_LINK, getFieldSettings, LINK_TYPE_ASSET, LINK_TYPE_ENTRY, } from '../lib/contentful.js';
4
+ import { FileManager } from '../lib/file-manager.js';
5
+ import { HookManager } from '../lib/hook-manager.js';
6
+ const cache = new Map();
7
+ export const readFixture = async (file) => {
8
+ if (!cache.has(file)) {
9
+ const content = await fs.readJSON(path.join(__dirname, 'fixtures', file));
10
+ cache.set(file, content);
11
+ }
12
+ return cache.get(file);
13
+ };
14
+ export const readFixtureSync = (file) => {
15
+ if (!cache.has(file)) {
16
+ const content = fs.readJSONSync(path.join(__dirname, 'fixtures', file));
17
+ cache.set(file, content);
18
+ }
19
+ return cache.get(file);
20
+ };
21
+ export const getContent = async () => {
22
+ const assets = await readFixture('assets.json');
23
+ const entries = await readFixture('entries.json');
24
+ const locales = await readFixture('locales.json');
25
+ const contentTypes = await readFixture('content_types.json');
26
+ const [entry] = entries;
27
+ const [asset] = assets;
28
+ const assetLink = {
29
+ sys: {
30
+ id: 'asset-id',
31
+ type: FIELD_TYPE_LINK,
32
+ linkType: LINK_TYPE_ASSET,
33
+ },
34
+ };
35
+ const entryLink = {
36
+ sys: {
37
+ id: 'entry-id',
38
+ type: FIELD_TYPE_LINK,
39
+ linkType: LINK_TYPE_ENTRY,
40
+ },
41
+ };
42
+ return { entries, assets, contentTypes, locales, assetLink, entryLink, entry, asset };
43
+ };
44
+ export const getConfig = (fixture = {}) => ({
45
+ directory: 'test',
46
+ plugins: [],
47
+ ...fixture,
48
+ });
49
+ export const getRuntimeContext = (fixture = {}) => {
50
+ const assets = readFixtureSync('assets.json');
51
+ const entries = readFixtureSync('entries.json');
52
+ const locales = readFixtureSync('locales.json');
53
+ const contentTypes = readFixtureSync('content_types.json');
54
+ const fieldSettings = getFieldSettings(contentTypes);
55
+ const { code: defaultLocale } = locales.find((locale) => locale.default) || locales[0];
56
+ const result = {
57
+ config: getConfig(),
58
+ localized: new Map(),
59
+ data: {
60
+ assets,
61
+ entries,
62
+ contentTypes,
63
+ locales,
64
+ fieldSettings,
65
+ },
66
+ defaultLocale,
67
+ ...fixture,
68
+ };
69
+ const hooks = new HookManager(result, result.config);
70
+ const fileManager = new FileManager({ directory: '/testbase' });
71
+ fileManager.cleanup = jest.fn();
72
+ fileManager.initialize = jest.fn();
73
+ fileManager.deleteFile = jest.fn();
74
+ fileManager.writeFile = jest.fn();
75
+ return { ...result, hooks, fileManager };
76
+ };
77
+ export const getTransformContext = (fixture = {}) => ({
78
+ assets: [],
79
+ entries: [],
80
+ assetMap: new Map(),
81
+ entryMap: new Map(),
82
+ ...fixture,
83
+ });
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import { existsSync } from 'fs';
5
+ import { outputFile } from 'fs-extra';
6
+ import prettier from 'prettier';
7
+ import { Command } from 'commander';
8
+ import dotenv from 'dotenv';
9
+ import dotenvExpand from 'dotenv-expand';
10
+ import { logError, confirm, askAll, askMissing } from './lib/ui.js';
11
+ import { omitKeys } from './lib/object.js';
12
+ import { getConfig, getEnvironmentConfig } from './lib/config.js';
13
+ import { run } from './index.js';
14
+ const env = dotenv.config();
15
+ dotenvExpand(env);
16
+ const parseArgs = (cmd) => ({
17
+ environment: cmd.env,
18
+ preview: Boolean(cmd.preview),
19
+ verbose: Boolean(cmd.verbose),
20
+ });
21
+ const errorHandler = (error, silence) => {
22
+ if (!silence) {
23
+ const { errors } = error;
24
+ logError(error);
25
+ (errors || []).forEach((error) => {
26
+ logError(error);
27
+ });
28
+ }
29
+ process.exit(1);
30
+ };
31
+ const actionRunner = (fn, log = true) => (...args) => fn(...args).catch((error) => errorHandler(error, !log));
32
+ const program = new Command();
33
+ program
34
+ .command('init')
35
+ .description('Initialize contentful-ssg')
36
+ .option('--typescript', 'Initialize typescript config')
37
+ .action(actionRunner(async (cmd) => {
38
+ const useTypescript = Boolean(cmd?.typescript ?? false);
39
+ const config = await getConfig(parseArgs(cmd || {}));
40
+ const verified = await askAll(config);
41
+ const environmentConfig = getEnvironmentConfig();
42
+ const filePath = path.join(process.cwd(), `contentful-ssg.config.${useTypescript ? 'ts' : 'js'}`);
43
+ const prettierOptions = await prettier.resolveConfig(filePath);
44
+ if (verified.directory?.startsWith('/')) {
45
+ verified.directory = path.relative(process.cwd(), verified.directory);
46
+ }
47
+ const environmentKeys = Object.keys(environmentConfig).filter((key) => environmentConfig[key] === verified[key]);
48
+ const cleanedConfig = omitKeys(verified, 'preview', 'verbose', 'rootDir', 'resolvedPlugins', 'host', 'managementToken', ...environmentKeys);
49
+ let content = '';
50
+ if (useTypescript) {
51
+ content = prettier.format(`import {Config} from '@jungvonmatt/contentful-ssg';
52
+ export default <Config>${JSON.stringify(cleanedConfig)}`, {
53
+ parser: 'typescript',
54
+ ...prettierOptions,
55
+ });
56
+ }
57
+ else {
58
+ content = prettier.format(`module.exports = ${JSON.stringify(cleanedConfig)}`, {
59
+ parser: 'babel',
60
+ ...prettierOptions,
61
+ });
62
+ }
63
+ let writeFile = true;
64
+ if (existsSync(filePath)) {
65
+ writeFile = await confirm(`Config file already exists. Overwrite?\n\n${chalk.reset(content)}`);
66
+ }
67
+ else {
68
+ writeFile = await confirm(`Please verify your settings:\n\n${chalk.reset(content)}`, true);
69
+ }
70
+ if (writeFile) {
71
+ await outputFile(filePath, content);
72
+ console.log(`\nConfiguration saved to ${chalk.cyan(path.relative(process.cwd(), filePath))}`);
73
+ }
74
+ }));
75
+ program
76
+ .command('fetch')
77
+ .description('Fetch content objects')
78
+ .option('-p, --preview', 'Fetch with preview mode')
79
+ .option('-v, --verbose', 'Verbose output')
80
+ .action(actionRunner(async (cmd) => {
81
+ const config = await getConfig(parseArgs(cmd || {}));
82
+ const verified = await askMissing(config);
83
+ return run(verified);
84
+ }));
85
+ program.parse(process.argv);
@@ -0,0 +1,7 @@
1
+ import { KeyValueMap } from '../types.js';
2
+ export declare const TYPE_JSON = "json";
3
+ export declare const TYPE_YAML = "yaml";
4
+ export declare const TYPE_MARKDOWN = "markdown";
5
+ export declare const TYPE_TOML = "toml";
6
+ export declare const stringify: <T = KeyValueMap<any>>(obj: T, format?: string) => string;
7
+ export declare const parse: (str: string, format?: string) => KeyValueMap<any>;
@@ -0,0 +1,42 @@
1
+ import { stringify as stringifyJson, parse as parseJson } from './json.js';
2
+ import { stringify as stringifyMarkdown, parse as parseMarkdown } from './markdown.js';
3
+ import { stringify as stringifyToml, parse as parseToml } from './toml.js';
4
+ import { stringify as stringifyYaml, parse as parseYaml } from './yaml.js';
5
+ export const TYPE_JSON = 'json';
6
+ export const TYPE_YAML = 'yaml';
7
+ export const TYPE_MARKDOWN = 'markdown';
8
+ export const TYPE_TOML = 'toml';
9
+ export const stringify = (obj, format = 'yaml') => {
10
+ switch (format) {
11
+ case 'yml':
12
+ case TYPE_YAML:
13
+ return stringifyYaml(obj);
14
+ case 'md':
15
+ case TYPE_MARKDOWN:
16
+ return stringifyMarkdown(obj);
17
+ case TYPE_JSON:
18
+ return stringifyJson(obj);
19
+ case TYPE_TOML:
20
+ return stringifyToml(obj);
21
+ default:
22
+ throw new Error(`Format ${JSON.stringify(format)} is not supported`);
23
+ }
24
+ };
25
+ export const parse = (str, format = 'yaml') => {
26
+ switch (format) {
27
+ case 'yml':
28
+ case TYPE_YAML:
29
+ return parseYaml(str);
30
+ case 'md':
31
+ case TYPE_MARKDOWN: {
32
+ const { data } = parseMarkdown(str);
33
+ return data;
34
+ }
35
+ case TYPE_JSON:
36
+ return parseJson(str);
37
+ case TYPE_TOML:
38
+ return parseToml(str);
39
+ default:
40
+ throw new Error(`Format "${format}" is not supported`);
41
+ }
42
+ };
@@ -0,0 +1,3 @@
1
+ import { KeyValueMap } from '../types';
2
+ export declare const stringify: <T = KeyValueMap<any>>(obj: T) => string;
3
+ export declare const parse: <T = KeyValueMap<any>>(string: string) => T;
@@ -0,0 +1,2 @@
1
+ export const stringify = (obj) => JSON.stringify(obj, null, ' ');
2
+ export const parse = (string) => JSON.parse(string);
@@ -0,0 +1,3 @@
1
+ import { KeyValueMap } from '../types.js';
2
+ export declare const stringify: <T = KeyValueMap<any>>(obj: T, content?: string) => string;
3
+ export declare const parse: <T = KeyValueMap<any>>(string: string) => T;
@@ -0,0 +1,17 @@
1
+ import matter from 'gray-matter';
2
+ import { stringify as stringifyYaml, parse as parseYaml } from './yaml.js';
3
+ export const stringify = (obj, content = '') => {
4
+ let frontMatter = '';
5
+ frontMatter += '---\n';
6
+ frontMatter += stringifyYaml(obj);
7
+ frontMatter += `---\n${content}`;
8
+ return frontMatter;
9
+ };
10
+ export const parse = (string) => {
11
+ const data = matter(string, {
12
+ engines: {
13
+ yaml: (string) => parseYaml(string),
14
+ },
15
+ });
16
+ return data;
17
+ };
@@ -0,0 +1,3 @@
1
+ import { KeyValueMap } from '../types';
2
+ export declare const stringify: <T = KeyValueMap<any>>(obj: T) => string;
3
+ export declare const parse: <T = KeyValueMap<any>>(string: string) => T;
@@ -0,0 +1,3 @@
1
+ import TOML from '@iarna/toml';
2
+ export const stringify = (obj) => TOML.stringify(obj);
3
+ export const parse = (string) => TOML.parse(string);