gatsby-theme-q3 3.1.5 → 3.2.3
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 +75 -36
- package/gatsby-browser.js +29 -0
- package/gatsby-config.js +7 -47
- package/gatsby-node.js +0 -1
- package/lib/components/FormBoxContent.js +2 -1
- package/lib/components/PageWrapper.js +2 -11
- package/lib/components/PublicTemplate.js +130 -6
- package/lib/components/SearchEngine.js +67 -20
- package/lib/components/Wrapper.js +3 -25
- package/lib/components/__tests__/SearchEngine.test.js +41 -0
- package/lib/components/useSiteMetaData.js +13 -12
- package/lib/components/withPublicTemplate.js +17 -0
- package/lib/components/withSuccessOp.js +1 -1
- package/lib/pages/login.js +7 -4
- package/lib/pages/password-change.js +4 -3
- package/lib/pages/password-reset.js +4 -3
- package/lib/pages/reverify.js +5 -2
- package/lib/pages/verify.js +5 -3
- package/package.json +6 -6
- package/src/components/FormBoxContent.jsx +1 -1
- package/src/components/PageWrapper.jsx +1 -13
- package/src/components/PublicTemplate.jsx +134 -5
- package/src/components/SearchEngine.jsx +82 -23
- package/src/components/Wrapper.jsx +3 -27
- package/src/components/__tests__/SearchEngine.test.jsx +58 -0
- package/src/components/useSiteMetaData.js +17 -16
- package/src/components/withPublicTemplate.jsx +11 -0
- package/src/components/withSuccessOp.jsx +1 -1
- package/src/pages/login.jsx +55 -43
- package/src/pages/password-change.jsx +5 -3
- package/src/pages/password-reset.jsx +5 -3
- package/src/pages/reverify.jsx +4 -2
- package/src/pages/verify.jsx +9 -12
- package/__tests__/config.int.test.js +0 -73
- package/helpers/__tests__/loadContent.unit.test.js +0 -13
- package/helpers/__tests__/pagination.unit.test.js +0 -139
- package/helpers/__tests__/slug.unit.test.js +0 -21
- package/helpers/archive.js +0 -42
- package/helpers/index.js +0 -19
- package/helpers/loadContent.js +0 -45
- package/helpers/loadTheme.js +0 -10
- package/helpers/pagination.js +0 -109
- package/helpers/setup.js +0 -60
- package/helpers/slug.js +0 -31
- package/helpers/slugType.js +0 -24
- package/lib/components/LocaleBundles.js +0 -42
- package/lib/components/useLocale.js +0 -31
- package/src/components/LocaleBundles.jsx +0 -37
- package/src/components/useLocale.js +0 -20
@@ -0,0 +1,11 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PublicTemplate from './PublicTemplate';
|
3
|
+
|
4
|
+
const withPublicTemplate = (Component) => (props) =>
|
5
|
+
(
|
6
|
+
<PublicTemplate {...props}>
|
7
|
+
<Component {...props} />
|
8
|
+
</PublicTemplate>
|
9
|
+
);
|
10
|
+
|
11
|
+
export default withPublicTemplate;
|
package/src/pages/login.jsx
CHANGED
@@ -9,48 +9,60 @@ import Box from '@material-ui/core/Box';
|
|
9
9
|
import { Form, Field } from 'q3-ui-forms/lib/builders';
|
10
10
|
import FormBox from '../components/FormBox';
|
11
11
|
import withAuthenticate from '../components/withAuthenticate';
|
12
|
+
import withPublicTemplate from '../components/withPublicTemplate';
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
const Login = withPublicTemplate(
|
15
|
+
withAuthenticate(({ authenticate }) => {
|
16
|
+
const { t } = useTranslation();
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
18
|
+
return (
|
19
|
+
<FormBox
|
20
|
+
renderBottom={
|
21
|
+
<>
|
22
|
+
<Form onSubmit={authenticate}>
|
23
|
+
<Field
|
24
|
+
name="email"
|
25
|
+
type="email"
|
26
|
+
required
|
27
|
+
xl={12}
|
28
|
+
lg={12}
|
29
|
+
/>
|
30
|
+
<Field
|
31
|
+
required
|
32
|
+
name="password"
|
33
|
+
type="password"
|
34
|
+
xl={12}
|
35
|
+
lg={12}
|
36
|
+
/>
|
37
|
+
</Form>
|
38
|
+
<Box mt={2} mb={1}>
|
39
|
+
<Divider />
|
40
|
+
</Box>
|
41
|
+
<Grid container spacing={1}>
|
42
|
+
<MuiLink
|
43
|
+
component={Link}
|
44
|
+
to="/password-reset"
|
45
|
+
>
|
46
|
+
{t('labels:requestNewPassword')}
|
47
|
+
</MuiLink>
|
48
|
+
<MuiLink component={Link} to="/reverify">
|
49
|
+
{t('labels:reverifyLink')}
|
50
|
+
</MuiLink>
|
51
|
+
</Grid>
|
52
|
+
</>
|
53
|
+
}
|
54
|
+
renderTop={
|
55
|
+
<Typography
|
56
|
+
component="h1"
|
57
|
+
variant="h2"
|
58
|
+
gutterBottom
|
59
|
+
>
|
60
|
+
{t('titles:login')}
|
61
|
+
</Typography>
|
62
|
+
}
|
63
|
+
/>
|
64
|
+
);
|
65
|
+
}),
|
66
|
+
);
|
67
|
+
|
68
|
+
export default Login;
|
@@ -8,6 +8,7 @@ import { Form, Field } from 'q3-ui-forms/lib/builders';
|
|
8
8
|
import FormBoxContent from '../components/FormBoxContent';
|
9
9
|
import FormBox from '../components/FormBox';
|
10
10
|
import withSuccessOp from '../components/withSuccessOp';
|
11
|
+
import withPublicTemplate from '../components/withPublicTemplate';
|
11
12
|
|
12
13
|
const PasswordChange = ({ onSuccess, location }) => {
|
13
14
|
const { passwordResetToken, email } = queryString.parse(
|
@@ -64,7 +65,8 @@ PasswordChange.propTypes = {
|
|
64
65
|
}).isRequired,
|
65
66
|
};
|
66
67
|
|
67
|
-
|
68
|
-
PasswordChange,
|
69
|
-
'passwordChangeNotice',
|
68
|
+
const PasswordChangeWithTemplate = withPublicTemplate(
|
69
|
+
withSuccessOp(PasswordChange, 'passwordChangeNotice'),
|
70
70
|
);
|
71
|
+
|
72
|
+
export default PasswordChangeWithTemplate;
|
@@ -5,6 +5,7 @@ import { Form, Field } from 'q3-ui-forms/lib/builders';
|
|
5
5
|
import FormBox from '../components/FormBox';
|
6
6
|
import FormBoxContent from '../components/FormBoxContent';
|
7
7
|
import withSuccessOp from '../components/withSuccessOp';
|
8
|
+
import withPublicTemplate from '../components/withPublicTemplate';
|
8
9
|
|
9
10
|
const PasswordReset = ({ onSuccess }) => (
|
10
11
|
<FormBox
|
@@ -39,7 +40,8 @@ PasswordReset.propTypes = {
|
|
39
40
|
onSuccess: PropTypes.func.isRequired,
|
40
41
|
};
|
41
42
|
|
42
|
-
|
43
|
-
PasswordReset,
|
44
|
-
'passwordResetNotice',
|
43
|
+
const PasswordResetWithTemplate = withPublicTemplate(
|
44
|
+
withSuccessOp(PasswordReset, 'passwordResetNotice'),
|
45
45
|
);
|
46
|
+
|
47
|
+
export default PasswordResetWithTemplate;
|
package/src/pages/reverify.jsx
CHANGED
@@ -9,6 +9,7 @@ import FormBox from '../components/FormBox';
|
|
9
9
|
import FormBoxContent from '../components/FormBoxContent';
|
10
10
|
import FormBoxNotice from '../components/FormBoxNotice';
|
11
11
|
import { hasOp, toOp } from '../components/utils';
|
12
|
+
import withPublicTemplate from '../components/withPublicTemplate';
|
12
13
|
|
13
14
|
const Reverify = ({ location: { search, pathname } }) => {
|
14
15
|
const { t } = useTranslation();
|
@@ -23,7 +24,7 @@ const Reverify = ({ location: { search, pathname } }) => {
|
|
23
24
|
component={Link}
|
24
25
|
to="/reverify"
|
25
26
|
variant="contained"
|
26
|
-
color="
|
27
|
+
color="secondary"
|
27
28
|
>
|
28
29
|
{t('labels:tryAgain')}
|
29
30
|
</Button>
|
@@ -67,4 +68,5 @@ Reverify.propTypes = {
|
|
67
68
|
}).isRequired,
|
68
69
|
};
|
69
70
|
|
70
|
-
|
71
|
+
const ReverifyWithTemplate = withPublicTemplate(Reverify);
|
72
|
+
export default ReverifyWithTemplate;
|
package/src/pages/verify.jsx
CHANGED
@@ -8,19 +8,14 @@ import { Form, Field } from 'q3-ui-forms/lib/builders';
|
|
8
8
|
import FormBoxContent from '../components/FormBoxContent';
|
9
9
|
import FormBox from '../components/FormBox';
|
10
10
|
import withAuthenticate from '../components/withAuthenticate';
|
11
|
+
import withPublicTemplate from '../components/withPublicTemplate';
|
11
12
|
|
12
|
-
|
13
|
-
({ authenticate, ...props }) => {
|
14
|
-
const {
|
15
|
-
|
16
|
-
id,
|
17
|
-
email,
|
18
|
-
} = queryString.parse(
|
19
|
-
get(props, 'location.search', ''),
|
20
|
-
{
|
13
|
+
const Verify = withPublicTemplate(
|
14
|
+
withAuthenticate(({ authenticate, ...props }) => {
|
15
|
+
const { verificationCode, id, email } =
|
16
|
+
queryString.parse(get(props, 'location.search', ''), {
|
21
17
|
decode: false,
|
22
|
-
}
|
23
|
-
);
|
18
|
+
});
|
24
19
|
|
25
20
|
return (
|
26
21
|
<FormBox
|
@@ -69,5 +64,7 @@ export default withAuthenticate(
|
|
69
64
|
}
|
70
65
|
/>
|
71
66
|
);
|
72
|
-
},
|
67
|
+
}),
|
73
68
|
);
|
69
|
+
|
70
|
+
export default Verify;
|
@@ -1,73 +0,0 @@
|
|
1
|
-
import { get } from 'lodash';
|
2
|
-
import config from '../gatsby-config';
|
3
|
-
|
4
|
-
const CANONICAL = 'gatsby-plugin-canonical-urls';
|
5
|
-
const MANIFEST = 'gatsby-plugin-manifest';
|
6
|
-
const ROBOTS = 'gatsby-plugin-robots-txt';
|
7
|
-
|
8
|
-
const ENV = {
|
9
|
-
contentfulSpaceID: 1,
|
10
|
-
contentfulAccessToken: 1,
|
11
|
-
};
|
12
|
-
|
13
|
-
const containsResolver = (plugins = [], name) =>
|
14
|
-
plugins.find(
|
15
|
-
(p) => typeof p === 'object' && p.resolve === name,
|
16
|
-
);
|
17
|
-
|
18
|
-
const checkPlugins = (args = {}, plugin) => {
|
19
|
-
const { plugins } = config({ ...ENV, ...args });
|
20
|
-
const statement = expect(
|
21
|
-
containsResolver(plugins, plugin),
|
22
|
-
);
|
23
|
-
|
24
|
-
return {
|
25
|
-
has: () => statement.not.toBeUndefined(),
|
26
|
-
hasNot: () => statement.toBeUndefined(),
|
27
|
-
};
|
28
|
-
};
|
29
|
-
|
30
|
-
describe('gatsby-config', () => {
|
31
|
-
describe('plugins', () => {
|
32
|
-
it('should error without contentful access token', () => {
|
33
|
-
process.env.URL =
|
34
|
-
'https://development.netlify.3merge.com';
|
35
|
-
expect(() =>
|
36
|
-
config({
|
37
|
-
contentfulSpaceID: '1',
|
38
|
-
}),
|
39
|
-
).toThrowError();
|
40
|
-
});
|
41
|
-
|
42
|
-
it('should include conditional plugins', () =>
|
43
|
-
[CANONICAL, MANIFEST].forEach((name) =>
|
44
|
-
checkPlugins(
|
45
|
-
{
|
46
|
-
brandingColor: '#FFF',
|
47
|
-
title: 'Foo',
|
48
|
-
siteUrl: 'https://google.ca',
|
49
|
-
},
|
50
|
-
name,
|
51
|
-
).has(),
|
52
|
-
));
|
53
|
-
|
54
|
-
it('should exclude conditional plugins', () =>
|
55
|
-
[CANONICAL, MANIFEST].forEach((name) =>
|
56
|
-
checkPlugins({}, name).hasNot(),
|
57
|
-
));
|
58
|
-
|
59
|
-
it.each([
|
60
|
-
['https://dev.netlify.3merge.com', 'disallow'],
|
61
|
-
['https://3merge.com', 'allow'],
|
62
|
-
])('should disable indexing', (url, key) => {
|
63
|
-
process.env.URL = url;
|
64
|
-
const { plugins } = config({ ...ENV });
|
65
|
-
const res = containsResolver(plugins, ROBOTS);
|
66
|
-
const prod = get(
|
67
|
-
res,
|
68
|
-
'options.env.production.policy',
|
69
|
-
)[0];
|
70
|
-
expect(prod).toHaveProperty(key, '/');
|
71
|
-
});
|
72
|
-
});
|
73
|
-
});
|
@@ -1,13 +0,0 @@
|
|
1
|
-
const path = require('path');
|
2
|
-
const loadContent = require('../loadContent');
|
3
|
-
|
4
|
-
describe('loadContent', () => {
|
5
|
-
it('should fetch all content from directory', () => {
|
6
|
-
const out = loadContent(
|
7
|
-
path.resolve(__dirname, '../../__fixtures__'),
|
8
|
-
);
|
9
|
-
|
10
|
-
expect(out).toHaveProperty('en');
|
11
|
-
expect(out).toHaveProperty('fr');
|
12
|
-
});
|
13
|
-
});
|
@@ -1,139 +0,0 @@
|
|
1
|
-
const {
|
2
|
-
genCursor,
|
3
|
-
appendSiblingsToContext,
|
4
|
-
getPreviousArchiveUrl,
|
5
|
-
getNextArchiveUrl,
|
6
|
-
getNumberOfPages,
|
7
|
-
paginateArchiveContext,
|
8
|
-
} = require('../pagination');
|
9
|
-
|
10
|
-
const genEntries = () => {
|
11
|
-
const entries = [];
|
12
|
-
for (let i = 0; i < 30; i += 1) entries.push(i);
|
13
|
-
return entries;
|
14
|
-
};
|
15
|
-
|
16
|
-
describe('pagination', () => {
|
17
|
-
describe('"genCursor"', () => {
|
18
|
-
const stub = ['foo', 'bar', 'quuz', 'garply'];
|
19
|
-
const cursor = genCursor(stub, 2);
|
20
|
-
// current index targets "quuz"
|
21
|
-
|
22
|
-
it('should identify first item', () => {
|
23
|
-
expect(cursor.first).toMatch('foo');
|
24
|
-
});
|
25
|
-
|
26
|
-
it('should identify last item', () => {
|
27
|
-
expect(cursor.last).toMatch('garply');
|
28
|
-
});
|
29
|
-
|
30
|
-
it('should identify next item', () => {
|
31
|
-
expect(cursor.next).toMatch('garply');
|
32
|
-
});
|
33
|
-
|
34
|
-
it('should identify previous item', () => {
|
35
|
-
expect(cursor.prev).toMatch('bar');
|
36
|
-
});
|
37
|
-
|
38
|
-
it('should identify first position', () => {
|
39
|
-
expect(cursor.isFirst).toBeFalsy();
|
40
|
-
expect(genCursor(stub, 0).isFirst).toBeTruthy();
|
41
|
-
});
|
42
|
-
|
43
|
-
it('should identify last position', () => {
|
44
|
-
expect(cursor.isLast).toBeFalsy();
|
45
|
-
expect(genCursor(stub, 3).isLast).toBeTruthy();
|
46
|
-
});
|
47
|
-
});
|
48
|
-
|
49
|
-
describe('"appendSiblingsToContext"', () => {
|
50
|
-
const mockContentfulEntry = (id) => ({
|
51
|
-
contentful_id: id,
|
52
|
-
});
|
53
|
-
|
54
|
-
const stubWithContentful = [
|
55
|
-
mockContentfulEntry(1),
|
56
|
-
mockContentfulEntry(2),
|
57
|
-
mockContentfulEntry(3),
|
58
|
-
];
|
59
|
-
|
60
|
-
it('should map contentful entries using cursor', () => {
|
61
|
-
const entries = appendSiblingsToContext(
|
62
|
-
stubWithContentful,
|
63
|
-
);
|
64
|
-
expect(entries[0]).toMatchObject({
|
65
|
-
prev: 3,
|
66
|
-
next: 2,
|
67
|
-
});
|
68
|
-
expect(entries[2]).toMatchObject({
|
69
|
-
prev: 2,
|
70
|
-
next: 1,
|
71
|
-
});
|
72
|
-
});
|
73
|
-
});
|
74
|
-
|
75
|
-
describe('"getPreviousArchiveUrl"', () => {
|
76
|
-
it('should return null', () => {
|
77
|
-
expect(getPreviousArchiveUrl('/foo', 1)).toBeNull();
|
78
|
-
});
|
79
|
-
|
80
|
-
it('should return archive', () => {
|
81
|
-
expect(getPreviousArchiveUrl('/foo', 2)).toEqual(
|
82
|
-
'/foo',
|
83
|
-
);
|
84
|
-
});
|
85
|
-
|
86
|
-
it('should return archive sub-directory', () => {
|
87
|
-
expect(getPreviousArchiveUrl('/foo', 3)).toEqual(
|
88
|
-
'/foo/2',
|
89
|
-
);
|
90
|
-
});
|
91
|
-
});
|
92
|
-
|
93
|
-
describe('"getNextArchiveUrl"', () => {
|
94
|
-
it('should return sub-directory', () => {
|
95
|
-
expect(getNextArchiveUrl('/foo', 8, 9)).toEqual(
|
96
|
-
'/foo/9',
|
97
|
-
);
|
98
|
-
});
|
99
|
-
|
100
|
-
it('should return null', () => {
|
101
|
-
expect(getNextArchiveUrl('/foo', 9, 9)).toBeNull();
|
102
|
-
});
|
103
|
-
});
|
104
|
-
|
105
|
-
describe('"getNumberOfPages"', () => {
|
106
|
-
it('should return number divisible by', () => {
|
107
|
-
expect(getNumberOfPages(genEntries(), 5)).toBe(6);
|
108
|
-
});
|
109
|
-
});
|
110
|
-
|
111
|
-
describe('"paginateArchiveContext"', () => {
|
112
|
-
it('should return pagination meta', () => {
|
113
|
-
// default 15 per page
|
114
|
-
const res = paginateArchiveContext(
|
115
|
-
genEntries(),
|
116
|
-
'/foo',
|
117
|
-
);
|
118
|
-
|
119
|
-
expect(res).toHaveLength(2);
|
120
|
-
expect(res[0]).toMatchObject({
|
121
|
-
path: '/foo',
|
122
|
-
limit: 15,
|
123
|
-
skip: 0,
|
124
|
-
pageNum: 0,
|
125
|
-
prev: null,
|
126
|
-
next: '/foo/2',
|
127
|
-
});
|
128
|
-
|
129
|
-
expect(res[1]).toMatchObject({
|
130
|
-
path: '/foo/2',
|
131
|
-
limit: 15,
|
132
|
-
skip: 15,
|
133
|
-
pageNum: 1,
|
134
|
-
prev: '/foo',
|
135
|
-
next: null,
|
136
|
-
});
|
137
|
-
});
|
138
|
-
});
|
139
|
-
});
|
@@ -1,21 +0,0 @@
|
|
1
|
-
const slug = require('../slug');
|
2
|
-
|
3
|
-
describe('slug', () => {
|
4
|
-
it('should combine use slug attribute', () => {
|
5
|
-
expect(
|
6
|
-
slug({ slug: 'already-formatted-as-slug' }),
|
7
|
-
).toMatch('/already-formatted-as-slug');
|
8
|
-
});
|
9
|
-
|
10
|
-
it('should combine use title attribute', () => {
|
11
|
-
expect(
|
12
|
-
slug({ title: 'This is a post' }, 'foos'),
|
13
|
-
).toMatch('/foos/this-is-a-post');
|
14
|
-
});
|
15
|
-
|
16
|
-
it('should combine use name attribute', () => {
|
17
|
-
expect(slug({ name: "Post's name" }, '/foos')).toMatch(
|
18
|
-
'/foos/posts-name',
|
19
|
-
);
|
20
|
-
});
|
21
|
-
});
|
package/helpers/archive.js
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
const { get } = require('lodash');
|
2
|
-
const { resolve } = require('path');
|
3
|
-
const {
|
4
|
-
appendSiblingsToContext,
|
5
|
-
paginateArchiveContext,
|
6
|
-
} = require('./pagination');
|
7
|
-
|
8
|
-
module.exports = ({
|
9
|
-
archiveComponentRelativePath,
|
10
|
-
createPage,
|
11
|
-
detailComponentRelativePath,
|
12
|
-
nodesKeyName,
|
13
|
-
slug,
|
14
|
-
}) => async ({ data, errors }) => {
|
15
|
-
if (errors) throw errors;
|
16
|
-
const { nodes = [] } = get(data, nodesKeyName, {
|
17
|
-
nodes: [],
|
18
|
-
});
|
19
|
-
|
20
|
-
const archives = appendSiblingsToContext(nodes).map(
|
21
|
-
(context) =>
|
22
|
-
createPage({
|
23
|
-
path:
|
24
|
-
// see slugType for more details on this field
|
25
|
-
context.to || `/${slug}/${context.contentful_id}`,
|
26
|
-
component: resolve(detailComponentRelativePath),
|
27
|
-
context,
|
28
|
-
}),
|
29
|
-
);
|
30
|
-
|
31
|
-
const entries = paginateArchiveContext(nodes, slug).map(
|
32
|
-
({ path, ...context }) =>
|
33
|
-
createPage({
|
34
|
-
component: resolve(archiveComponentRelativePath),
|
35
|
-
path,
|
36
|
-
context,
|
37
|
-
}),
|
38
|
-
);
|
39
|
-
|
40
|
-
await Promise.all(archives);
|
41
|
-
await Promise.all(entries);
|
42
|
-
};
|
package/helpers/index.js
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
const ArchiveBuilder = require('./archive');
|
2
|
-
const loadContent = require('./loadContent');
|
3
|
-
const {
|
4
|
-
appendSiblingsToContext,
|
5
|
-
paginateArchiveContext,
|
6
|
-
} = require('./pagination');
|
7
|
-
const slug = require('./slug');
|
8
|
-
const slugType = require('./slugType');
|
9
|
-
const setup = require('./setup');
|
10
|
-
|
11
|
-
module.exports = {
|
12
|
-
ArchiveBuilder,
|
13
|
-
loadContent,
|
14
|
-
appendSiblingsToContext,
|
15
|
-
paginateArchiveContext,
|
16
|
-
setup,
|
17
|
-
slug,
|
18
|
-
slugType,
|
19
|
-
};
|
package/helpers/loadContent.js
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
const fs = require('fs');
|
2
|
-
const path = require('path');
|
3
|
-
|
4
|
-
const readJsonFile = (dir, filename) => {
|
5
|
-
try {
|
6
|
-
const file = path.resolve(dir, filename);
|
7
|
-
const buffer = fs.readFileSync(file);
|
8
|
-
return JSON.parse(buffer);
|
9
|
-
} catch (e) {
|
10
|
-
return {};
|
11
|
-
}
|
12
|
-
};
|
13
|
-
|
14
|
-
const reduceFileSystem = (name, next) =>
|
15
|
-
fs
|
16
|
-
.readdirSync(name, { withFileTypes: true })
|
17
|
-
.reduce(next, {});
|
18
|
-
|
19
|
-
const getJsonFileNameFromDirent = ({ name }) =>
|
20
|
-
path.basename(name, '.json');
|
21
|
-
|
22
|
-
const readFilePathFromDirent = ({ name }, root, next) =>
|
23
|
-
next(path.join(root, name));
|
24
|
-
|
25
|
-
const recurseFileSystem = (pathName) =>
|
26
|
-
reduceFileSystem(pathName, (curr, dirent) =>
|
27
|
-
Object.assign(curr, {
|
28
|
-
[getJsonFileNameFromDirent(
|
29
|
-
dirent,
|
30
|
-
)]: dirent.isDirectory()
|
31
|
-
? readFilePathFromDirent(
|
32
|
-
dirent,
|
33
|
-
pathName,
|
34
|
-
recurseFileSystem,
|
35
|
-
)
|
36
|
-
: readJsonFile(pathName, dirent.name),
|
37
|
-
}),
|
38
|
-
);
|
39
|
-
|
40
|
-
recurseFileSystem.readJsonFile = readJsonFile;
|
41
|
-
recurseFileSystem.reduceFileSystem = reduceFileSystem;
|
42
|
-
recurseFileSystem.getJsonFileNameFromDirent = getJsonFileNameFromDirent;
|
43
|
-
recurseFileSystem.readFilePathFromDirent = readFilePathFromDirent;
|
44
|
-
|
45
|
-
module.exports = recurseFileSystem;
|