@jungvonmatt/contentful-ssg 0.17.2 → 1.0.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.
- package/LICENSE +1 -1
- package/README.md +158 -118
- package/dist/__test__/mock.d.ts +28 -0
- package/dist/__test__/mock.js +83 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +85 -0
- package/dist/converter/index.d.ts +7 -0
- package/dist/converter/index.js +42 -0
- package/dist/converter/json.d.ts +3 -0
- package/dist/converter/json.js +2 -0
- package/dist/converter/markdown.d.ts +3 -0
- package/dist/converter/markdown.js +17 -0
- package/dist/converter/toml.d.ts +3 -0
- package/dist/converter/toml.js +3 -0
- package/dist/converter/yaml.d.ts +3 -0
- package/dist/converter/yaml.js +27 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +125 -0
- package/dist/lib/array.d.ts +4 -0
- package/dist/lib/array.js +25 -0
- package/dist/lib/config.d.ts +3 -0
- package/dist/lib/config.js +144 -0
- package/dist/lib/contentful.d.ts +40 -0
- package/dist/lib/contentful.js +145 -0
- package/dist/lib/create-require.d.ts +2 -0
- package/dist/lib/create-require.js +4 -0
- package/dist/lib/error.d.ts +9 -0
- package/dist/lib/error.js +17 -0
- package/dist/lib/file-manager.d.ts +17 -0
- package/dist/lib/file-manager.js +64 -0
- package/dist/lib/hook-manager.d.ts +15 -0
- package/dist/lib/hook-manager.js +94 -0
- package/dist/lib/object.d.ts +11 -0
- package/dist/lib/object.js +40 -0
- package/dist/lib/stats.d.ts +18 -0
- package/dist/lib/stats.js +74 -0
- package/dist/lib/ui.d.ts +6 -0
- package/dist/lib/ui.js +88 -0
- package/dist/lib/utils.d.ts +4 -0
- package/dist/lib/utils.js +31 -0
- package/dist/mapper/map-date-field.d.ts +1 -0
- package/dist/mapper/map-date-field.js +6 -0
- package/dist/mapper/map-entry.d.ts +4 -0
- package/dist/mapper/map-entry.js +42 -0
- package/dist/mapper/map-field.d.ts +2 -0
- package/dist/mapper/map-field.js +24 -0
- package/dist/mapper/map-meta-fields.d.ts +9 -0
- package/dist/mapper/map-meta-fields.js +8 -0
- package/dist/mapper/map-reference-field.d.ts +11 -0
- package/dist/mapper/map-reference-field.js +71 -0
- package/dist/mapper/map-rich-text-field.d.ts +7 -0
- package/dist/mapper/map-rich-text-field.js +47 -0
- package/dist/tasks/fetch.d.ts +2 -0
- package/dist/tasks/fetch.js +12 -0
- package/dist/tasks/localize.d.ts +6 -0
- package/dist/tasks/localize.js +48 -0
- package/dist/tasks/setup.d.ts +2 -0
- package/dist/tasks/setup.js +26 -0
- package/dist/tasks/transform.d.ts +2 -0
- package/dist/tasks/transform.js +5 -0
- package/dist/tasks/write.d.ts +2 -0
- package/dist/tasks/write.js +33 -0
- package/dist/types.d.ts +194 -0
- package/dist/types.js +1 -0
- package/package.json +118 -91
- package/src/__test__/fixtures/assets.json +47 -0
- package/src/__test__/fixtures/content_types.json +181 -0
- package/src/__test__/fixtures/entries.json +783 -0
- package/src/__test__/fixtures/locales.json +35 -0
- package/src/__test__/fixtures/richtext.json +135 -0
- package/src/__test__/mock.ts +106 -0
- package/src/cli.ts +134 -0
- package/src/converter/index.test.ts +38 -0
- package/src/converter/index.ts +60 -0
- package/src/converter/json.test.ts +25 -0
- package/src/converter/json.ts +16 -0
- package/src/converter/markdown.test.ts +58 -0
- package/{lib/converter/markdown.js → src/converter/markdown.ts} +8 -10
- package/src/converter/toml.test.ts +74 -0
- package/src/converter/toml.ts +17 -0
- package/src/converter/yaml.test.ts +51 -0
- package/src/converter/yaml.ts +51 -0
- package/src/index.test.ts +89 -0
- package/src/index.ts +155 -0
- package/src/lib/array.test.ts +105 -0
- package/src/lib/array.ts +84 -0
- package/src/lib/config.ts +195 -0
- package/src/lib/contentful.test.ts +251 -0
- package/{lib/contentful.js → src/lib/contentful.ts} +99 -122
- package/src/lib/create-require.ts +6 -0
- package/src/lib/error.ts +19 -0
- package/src/lib/file-manager.test.ts +73 -0
- package/src/lib/file-manager.ts +106 -0
- package/src/lib/hook-manager.test.ts +169 -0
- package/src/lib/hook-manager.ts +161 -0
- package/src/lib/object.test.ts +56 -0
- package/src/lib/object.ts +102 -0
- package/src/lib/stats.test.ts +78 -0
- package/src/lib/stats.ts +112 -0
- package/src/lib/ui.test.ts +58 -0
- package/src/lib/ui.ts +128 -0
- package/src/lib/utils.test.ts +85 -0
- package/src/lib/utils.ts +57 -0
- package/src/mapper/map-date-field.ts +12 -0
- package/src/mapper/map-entry.test.ts +191 -0
- package/src/mapper/map-entry.ts +77 -0
- package/src/mapper/map-field.test.ts +577 -0
- package/src/mapper/map-field.ts +57 -0
- package/src/mapper/map-meta-fields.ts +17 -0
- package/src/mapper/map-reference-field.ts +122 -0
- package/src/mapper/map-rich-text-field.ts +107 -0
- package/src/tasks/fetch.test.ts +32 -0
- package/src/tasks/fetch.ts +17 -0
- package/src/tasks/localize.test.ts +83 -0
- package/src/tasks/localize.ts +95 -0
- package/src/tasks/setup.test.ts +33 -0
- package/src/tasks/setup.ts +31 -0
- package/src/tasks/transform.test.ts +26 -0
- package/src/tasks/transform.ts +11 -0
- package/src/tasks/write.test.ts +94 -0
- package/src/tasks/write.ts +49 -0
- package/src/types.ts +271 -0
- package/index.js +0 -90
- package/lib/array.js +0 -48
- package/lib/config.js +0 -142
- package/lib/converter/index.js +0 -63
- package/lib/converter/json.js +0 -20
- package/lib/converter/toml.js +0 -22
- package/lib/converter/yaml.js +0 -40
- package/lib/dump.js +0 -337
- package/lib/presets/grow.js +0 -88
- package/lib/transform/localize.js +0 -59
- package/lib/transform/mapper.js +0 -293
- 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] [![
|
|
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
|
|
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
|
|
38
|
-
| ------------------ |
|
|
39
|
-
| accessToken | `
|
|
40
|
-
| previewAccessToken | `
|
|
41
|
-
| spaceId | `
|
|
42
|
-
| environmentId | `
|
|
43
|
-
| format | `
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
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: (
|
|
67
|
-
const {
|
|
68
|
-
const slugs =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-

|
|
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
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,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
|
+
};
|