@jungvonmatt/cssg-plugin-hugo 1.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/README.md +156 -0
- package/index.js +243 -0
- package/package.json +33 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
# [1.0.0-alpha.0](https://github.com/jungvonmatt/contentful-ssg/compare/v0.17.3...v1.0.0-alpha.0) (2021-11-25)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @jungvonmatt/cssg-plugin-hugo
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Jung von Matt TECH (https://www.jvm.com/)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# cssg-plugin-hugo
|
|
2
|
+
|
|
3
|
+
Provides support for the [hugo](https://gohugo.io/) static site generator.
|
|
4
|
+
|
|
5
|
+
This plugin provides some usefull but opinionated settings/features for the use with the hugo static site generator.
|
|
6
|
+
|
|
7
|
+
**Multilingual Mode**
|
|
8
|
+
|
|
9
|
+
This plugin automatically generates a `/config/_default/languages.toml` file for you based on your locale configuration in contentful.
|
|
10
|
+
Your content is organized using different content directories for each of the languages. See https://gohugo.io/content-management/multilingual/#translation-by-content-directory
|
|
11
|
+
|
|
12
|
+
**Translation of Strings**
|
|
13
|
+
|
|
14
|
+
When you provide a content type for string translations, the content is automatically collected and stored as translations present in i18n/ at the root of your project.
|
|
15
|
+
See https://gohugo.io/content-management/multilingual/#translation-of-strings.
|
|
16
|
+
|
|
17
|
+
The configured translations can then be used using the [`i18n`](https://gohugo.io/functions/i18n/) function.
|
|
18
|
+
|
|
19
|
+
```go
|
|
20
|
+
{{ i18n "translation_id" }}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
<details>
|
|
24
|
+
<summary>Contentful migration for `d-i18n`</summary>
|
|
25
|
+
<p>
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
|
|
29
|
+
module.exports = function (migration) {
|
|
30
|
+
const dI18n = migration
|
|
31
|
+
.createContentType('d-i18n')
|
|
32
|
+
.name('Data: i18n')
|
|
33
|
+
.description('Key value store for i18n')
|
|
34
|
+
.displayField('key');
|
|
35
|
+
|
|
36
|
+
dI18n
|
|
37
|
+
.createField('key')
|
|
38
|
+
.name('Key')
|
|
39
|
+
.type('Symbol')
|
|
40
|
+
.localized(false)
|
|
41
|
+
.required(true)
|
|
42
|
+
.validations([
|
|
43
|
+
{
|
|
44
|
+
unique: true,
|
|
45
|
+
},
|
|
46
|
+
])
|
|
47
|
+
.disabled(false)
|
|
48
|
+
.omitted(false);
|
|
49
|
+
|
|
50
|
+
dI18n
|
|
51
|
+
.createField('other')
|
|
52
|
+
.name('Value')
|
|
53
|
+
.type('Symbol')
|
|
54
|
+
.localized(true)
|
|
55
|
+
.required(true)
|
|
56
|
+
.validations([])
|
|
57
|
+
.disabled(false)
|
|
58
|
+
.omitted(false);
|
|
59
|
+
|
|
60
|
+
dI18n
|
|
61
|
+
.createField('one')
|
|
62
|
+
.name('Singular value')
|
|
63
|
+
.type('Symbol')
|
|
64
|
+
.localized(true)
|
|
65
|
+
.required(false)
|
|
66
|
+
.validations([])
|
|
67
|
+
.disabled(false)
|
|
68
|
+
.omitted(false);
|
|
69
|
+
|
|
70
|
+
dI18n.changeFieldControl('key', 'builtin', 'singleLine', {});
|
|
71
|
+
dI18n.changeFieldControl('other', 'builtin', 'singleLine', {});
|
|
72
|
+
dI18n.changeFieldControl('one', 'builtin', 'singleLine', {
|
|
73
|
+
helpText: 'Optionally pass a dedicated singular value',
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
```
|
|
77
|
+
</p>
|
|
78
|
+
</details>
|
|
79
|
+
|
|
80
|
+
**Content Organization**
|
|
81
|
+
|
|
82
|
+
Your content will be organised according to hugo's best practices inside the `content` directory at the root of your project. See https://gohugo.io/content-management/organization/
|
|
83
|
+
In order for this to work properly it is required to provide a `slug` field in your content tyopes describing pages as well as a reference to the parent entry.
|
|
84
|
+
It's also required to have a settings content type in contentful which holds a reference to the home page.
|
|
85
|
+
This way we can compute the folder structure inside `/content` to utilize the full potential of hugos [content sections](https://gohugo.io/content-management/sections/).
|
|
86
|
+
|
|
87
|
+
**Naming Convention**
|
|
88
|
+
All keys in frontmatter besides internal ones like `translationKey` are automatically converted to `snake_case` to prevent issues with hugo storing all `.Params` as lowercase.
|
|
89
|
+
|
|
90
|
+
> Page-level .Params are only accessible in lowercase.
|
|
91
|
+
|
|
92
|
+
See https://gohugo.io/variables/page/#page-level-params and https://discourse.gohugo.io/t/config-params-should-be-all-lowercase-or-not/5051
|
|
93
|
+
|
|
94
|
+
**Contentful References**
|
|
95
|
+
|
|
96
|
+
All reference fields are extended by the path to the associated markdown file so you can easily load the content:
|
|
97
|
+
|
|
98
|
+
```go
|
|
99
|
+
{{ with .Params.reference_field }}
|
|
100
|
+
{{ $page := .Site.GetPage(.path) }}
|
|
101
|
+
{{ end }}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
## Install
|
|
106
|
+
|
|
107
|
+
`npm install @jungvonmatt/cssg-plugin-hugo`
|
|
108
|
+
|
|
109
|
+
## How to use
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
// In your contentful-ssg.config.js
|
|
113
|
+
plugins: [
|
|
114
|
+
{
|
|
115
|
+
resolve: `@jungvonmatt/cssg-plugin-hugo`,
|
|
116
|
+
options: {
|
|
117
|
+
// Add any options here
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
];
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Options
|
|
124
|
+
|
|
125
|
+
| Name | Type | Default | Description |
|
|
126
|
+
| -------------- | --------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
127
|
+
| typeIdSettings | `string` | `'d-settings'` | The id of the settings content type. |
|
|
128
|
+
| typeIdI18n | `string` | `'d-i18n'` | The id of the i18n content type for the translation of strings. |
|
|
129
|
+
| fieldIdHome | `string` | `'home'` | The id of reference field to the home page in the settings content type. |
|
|
130
|
+
| fieldIdSlug | `string` | `'slug'` | The id of the slug field in page content types. |
|
|
131
|
+
| fieldIdParent | `string` | `'parent_page'` | The id of the parent page reference field in page content types. |
|
|
132
|
+
| languageConfig | `boolean` | `true` | Auto-generate the hugo language config based on your locale configuration in contentful. |
|
|
133
|
+
| typeConfig | `object` | `{ page: ['page'], data: ['d-*']}` | Pass a map with entry types (`data`, `map`) pointing to one or more glob patterns matching the content type ids.\ Data types will be stored inside the `/data/` directory. \ pages types will be stored inside `/content/<locale>/`.\ All content types that do not match are considered headless and will be stored inside `/content/headless` |
|
|
134
|
+
|
|
135
|
+
Example:
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
// In your contentful-ssg.config.js
|
|
139
|
+
plugins: [
|
|
140
|
+
{
|
|
141
|
+
resolve: `@jungvonmatt/cssg-plugin-hugo`,
|
|
142
|
+
options: {
|
|
143
|
+
typeIdSettings: 'd-settings',
|
|
144
|
+
typeIdI18n: 'd-i18n',
|
|
145
|
+
languageConfig: true,
|
|
146
|
+
fieldIdHome: 'home',
|
|
147
|
+
fieldIdSlug: 'slug',
|
|
148
|
+
fieldIdParent: 'parent_page',
|
|
149
|
+
typeConfig: {
|
|
150
|
+
page: ['page'],
|
|
151
|
+
data: ['d-*'],
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
];
|
|
156
|
+
```
|
package/index.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
|
|
2
|
+
import mergeOptionsModule from 'merge-options';
|
|
3
|
+
|
|
4
|
+
import {snakeCaseKeys} from '@jungvonmatt/contentful-ssg/lib/object';
|
|
5
|
+
import mm from 'micromatch';
|
|
6
|
+
import {existsSync} from 'fs';
|
|
7
|
+
import {writeFile, readFile} from 'fs/promises';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
|
|
10
|
+
const mergeOptions = mergeOptionsModule.bind({ ignoreUndefined: true });
|
|
11
|
+
|
|
12
|
+
export const TYPE_PAGE = 'page';
|
|
13
|
+
export const TYPE_DATA = 'data';
|
|
14
|
+
export const TYPE_HEADLESS = 'headless';
|
|
15
|
+
|
|
16
|
+
const defaultOptions = {
|
|
17
|
+
typeIdSettings: 'd-settings',
|
|
18
|
+
typeIdI18n: 'd-i18n',
|
|
19
|
+
languageConfig: true,
|
|
20
|
+
fieldIdHome: 'home',
|
|
21
|
+
fieldIdSlug: 'slug',
|
|
22
|
+
fieldIdParent: 'parent_page',
|
|
23
|
+
typeConfig: {
|
|
24
|
+
[TYPE_PAGE]: ['page'],
|
|
25
|
+
[TYPE_DATA]: ['d-*'],
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default (args) => {
|
|
30
|
+
const options = {...defaultOptions, ...(args || {})}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
const getSettingsHelper = (runtimeContext) => {
|
|
35
|
+
let settings = {};
|
|
36
|
+
if (options.typeIdSettings) {
|
|
37
|
+
settings = Object.fromEntries(Array.from((runtimeContext?.localized ?? new Map()).entries()).map(([locale, contentfulData]) => {
|
|
38
|
+
const entryMap = contentfulData?.entryMap ?? new Map();
|
|
39
|
+
const settingsEntries = (Array.from(entryMap.values())).filter(entry => (entry?.sys?.contentType?.sys?.id ?? 'unknown') === options.typeIdSettings);
|
|
40
|
+
const settingsFields = settingsEntries.map(entry => entry?.fields ?? {});
|
|
41
|
+
return [locale, mergeOptions(...settingsFields)];
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return (key, locale, defaultValue) => settings?.[locale]?.[key] ?? defaultValue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const getEntryType = (transformContext) => {
|
|
49
|
+
const {contentTypeId} = transformContext;
|
|
50
|
+
const [type = TYPE_HEADLESS] = Object.entries(options?.typeConfig ?? {}).find(([,pattern]) => mm.isMatch(contentTypeId, pattern)) || [];
|
|
51
|
+
|
|
52
|
+
return type;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
// Before hook
|
|
59
|
+
async before(runtimeContext) {
|
|
60
|
+
const {helper,converter, data, localized} = runtimeContext;
|
|
61
|
+
const locales = data?.locales ?? [];
|
|
62
|
+
|
|
63
|
+
// initialize getSettings
|
|
64
|
+
const getSettings = getSettingsHelper(runtimeContext);
|
|
65
|
+
helper.getSettings = getSettings;
|
|
66
|
+
// Write config toml according to locale settings in contentful
|
|
67
|
+
if (options.languageConfig) {
|
|
68
|
+
const rootDir = runtimeContext?.config?.rootDir ?? process.cwd();
|
|
69
|
+
const dst = path.join(rootDir, 'config/_default/languages.toml');
|
|
70
|
+
const languageConfig = Object.fromEntries(
|
|
71
|
+
locales.map((locale) => {
|
|
72
|
+
const { code, name: languageName } = locale;
|
|
73
|
+
// Currently Hugo language internals lowercase language codes,
|
|
74
|
+
// which can cause conflicts with settings like defaultContentLanguage
|
|
75
|
+
// which are not lowercased
|
|
76
|
+
// https://github.com/gohugoio/hugo/issues/7344
|
|
77
|
+
const languageCode = code.toLowerCase();
|
|
78
|
+
const [languageNameShort] = languageCode.split('-');
|
|
79
|
+
return [
|
|
80
|
+
code,
|
|
81
|
+
{
|
|
82
|
+
contentDir: `content/${languageCode}`,
|
|
83
|
+
languageCode,
|
|
84
|
+
languageName,
|
|
85
|
+
languageNameShort,
|
|
86
|
+
weight: locale.default ? 1 : 2,
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
await writeFile(
|
|
92
|
+
dst,
|
|
93
|
+
converter.toml.stringify(languageConfig)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Find section pages and add them to the runtimeconfig
|
|
98
|
+
const enhancedLocalized = new Map(Array.from(localized.entries()).map(([localeCode, contentfulData]) => {
|
|
99
|
+
const {entries} = contentfulData;
|
|
100
|
+
const sectionIds = entries.reduce((nodes, entry) => {
|
|
101
|
+
const id = entry?.fields?.[options.fieldIdParent]?.sys?.id;
|
|
102
|
+
if (id) {
|
|
103
|
+
nodes.add(id);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return nodes;
|
|
107
|
+
}, new Set());
|
|
108
|
+
return [localeCode, {...contentfulData, sectionIds}];
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
return {...runtimeContext, helper, localized: enhancedLocalized};
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Add path markdown files for entry links
|
|
116
|
+
* @param transformContext
|
|
117
|
+
* @param runtimeContext
|
|
118
|
+
* @returns
|
|
119
|
+
*/
|
|
120
|
+
async mapEntryLink(
|
|
121
|
+
transformContext,
|
|
122
|
+
runtimeContext,
|
|
123
|
+
prev
|
|
124
|
+
) {
|
|
125
|
+
const directory = await runtimeContext.hooks.mapDirectory(transformContext);
|
|
126
|
+
const filename = await runtimeContext.hooks.mapFilename(transformContext);
|
|
127
|
+
|
|
128
|
+
return {...prev, path: path.join(directory,filename)};
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Map directories
|
|
133
|
+
* @param transformContext
|
|
134
|
+
* @returns
|
|
135
|
+
*/
|
|
136
|
+
async mapDirectory(transformContext) {
|
|
137
|
+
const {contentTypeId, locale} = transformContext;
|
|
138
|
+
const type = getEntryType(transformContext);
|
|
139
|
+
|
|
140
|
+
if (type === TYPE_DATA) {
|
|
141
|
+
return '../data';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (contentTypeId === TYPE_PAGE) {
|
|
145
|
+
return locale.code;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return path.join('headless', contentTypeId);
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Map filenames data files to data, headless bundles to headless folder and pages in a
|
|
153
|
+
* directory structure which matches the sitemap
|
|
154
|
+
* @param transformContext
|
|
155
|
+
* @param runtimeContext
|
|
156
|
+
* @returns
|
|
157
|
+
*/
|
|
158
|
+
async mapFilename(transformContext, runtimeContext) {
|
|
159
|
+
const {id, locale, entry, contentTypeId, utils} = transformContext;
|
|
160
|
+
const {helper, localized} = runtimeContext;
|
|
161
|
+
const sectionIds = localized?.get(locale.code)?.sectionIds ?? new Set();
|
|
162
|
+
|
|
163
|
+
const type = getEntryType(transformContext);
|
|
164
|
+
|
|
165
|
+
const home = helper.getSettings(options.fieldIdHome, locale.code);
|
|
166
|
+
const homeId = home?.sys?.id;
|
|
167
|
+
|
|
168
|
+
if (homeId && entry?.sys?.id === homeId) {
|
|
169
|
+
return `/_index.md`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (contentTypeId === options.typeIdSettings) {
|
|
173
|
+
return path.join(locale.code, `settings.json`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (type === TYPE_DATA) {
|
|
177
|
+
return path.join(locale.code, contentTypeId, `${id}.json`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (type === TYPE_PAGE && sectionIds.has(id)) {
|
|
181
|
+
const slugs = utils.collectValues(`fields.${options.fieldIdSlug}`, {
|
|
182
|
+
linkField: `fields.${options.fieldIdParent}`,
|
|
183
|
+
entry,
|
|
184
|
+
});
|
|
185
|
+
return path.join(...(slugs || []), `_index.md`)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (type === TYPE_PAGE) {
|
|
189
|
+
const slugs = utils.collectParentValues(`fields.${options.fieldIdSlug}`, {
|
|
190
|
+
linkField: `fields.${options.fieldIdParent}`,
|
|
191
|
+
entry
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
return path.join(...(slugs || []), `${entry?.fields?.[options.fieldIdSlug] ?? 'unknown'}.md`)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return path.join(id, `index.${locale.code}.md`);
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
async transform(transformContext, runtimeContext) {
|
|
201
|
+
const {content, id, contentTypeId, locale} = transformContext;
|
|
202
|
+
const contentDir = runtimeContext.config.directory;
|
|
203
|
+
const toml = runtimeContext.converter.toml;
|
|
204
|
+
const type = getEntryType(transformContext);
|
|
205
|
+
|
|
206
|
+
// Automatically store dictionary entries in i18n/[locale].json
|
|
207
|
+
// See https://gohugo.io/content-management/multilingual/#query-basic-translation
|
|
208
|
+
if (options.typeIdI18n && contentTypeId === options.typeIdI18n) {
|
|
209
|
+
const { key, other, one } = content;
|
|
210
|
+
const translations = one ? { one, other } : { other };
|
|
211
|
+
|
|
212
|
+
const dictionaryPath = path.join(contentDir, `../i18n/${locale.code}.toml`);
|
|
213
|
+
const oldContent = existsSync(dictionaryPath) ? toml.parse(await readFile(dictionaryPath, 'utf8')) : {};
|
|
214
|
+
await writeFile(
|
|
215
|
+
dictionaryPath,
|
|
216
|
+
toml.stringify({ ...oldContent, [key]: translations }, undefined, ' ')
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// dont't write i-18n objects to the content folder
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (type === TYPE_PAGE) {
|
|
224
|
+
return {...snakeCaseKeys({
|
|
225
|
+
...content,
|
|
226
|
+
|
|
227
|
+
}), translationKey: id};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (type === TYPE_HEADLESS) {
|
|
231
|
+
return snakeCaseKeys({
|
|
232
|
+
...content,
|
|
233
|
+
headless: true,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return snakeCaseKeys(content);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jungvonmatt/cssg-plugin-hugo",
|
|
3
|
+
"version": "1.0.0-alpha.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/jungvonmatt/contentful-ssg.git"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [],
|
|
21
|
+
"author": "Ben Zörb",
|
|
22
|
+
"license": "ISC",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/jungvonmatt/contentful-ssg/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/jungvonmatt/contentful-ssg#readme",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@jungvonmatt/contentful-ssg": "^1.0.0-alpha.0",
|
|
29
|
+
"merge-options": "^3.0.4",
|
|
30
|
+
"micromatch": "^4.0.4"
|
|
31
|
+
},
|
|
32
|
+
"gitHead": "3fdc0fb66ce8285206bd116a8d66e7a6a9990f84"
|
|
33
|
+
}
|