-1
.gitignore
-1
.gitignore
+8
.husky/pre-commit
+8
.husky/pre-commit
+7
CONTRIBUTING.md
+7
CONTRIBUTING.md
···
164
164
- Commit messages **must** start with a capital letter
165
165
- Commit messages **must not** end with a period `.`
166
166
167
+
### Pre-commit Hooks
168
+
169
+
This project uses [husky][] for pre-commit hooks.
170
+
171
+
Some JSON files are generated during Build time with empty files as placeholders. Build time happens when you run `npx turbo serve` or `npx turbo build`. We don't want to commit those unnecessary changes. Since these files exist in the repository, `.gitignore` won't work for them. As the workaround, we have a pre-commit hook to discard those changes.
172
+
167
173
# Pull Request Policy
168
174
169
175
This policy governs how contributions should land within this repository. The lines below state the checks and policies to be followed before merging and on the act of merging.
···
219
225
[`squash`]: https://help.github.com/en/articles/about-pull-request-merges#squash-and-merge-your-pull-request-commits
220
226
[Conventional Commits]: https://www.conventionalcommits.org/
221
227
[Commit Signing]: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits
228
+
[husky]: https://typicode.github.io/husky/
-60
hooks/useFetchNodeReleases.ts
-60
hooks/useFetchNodeReleases.ts
···
1
-
import { useMemo } from 'react';
2
-
import useSWR from 'swr';
3
-
import { useRouter } from './useRouter';
4
-
import { getNodeReleaseStatus } from '../util/nodeRelease';
5
-
import type { NodeRelease } from '../types';
6
-
7
-
interface NodeReleaseJSON {
8
-
major: number;
9
-
version: string;
10
-
codename?: string;
11
-
currentStart: string;
12
-
ltsStart?: string;
13
-
maintenanceStart?: string;
14
-
endOfLife: string;
15
-
npm?: string;
16
-
v8?: string;
17
-
releaseDate?: string;
18
-
modules?: string;
19
-
}
20
-
21
-
const fetcher = (...args: Parameters<typeof fetch>) =>
22
-
fetch(...args).then(res => res.json());
23
-
24
-
export const useFetchNodeReleases = (): NodeRelease[] => {
25
-
const { basePath } = useRouter();
26
-
27
-
const { data = [] } = useSWR<NodeReleaseJSON[]>(
28
-
`${basePath}/node-releases-data.json`,
29
-
fetcher
30
-
);
31
-
32
-
return useMemo(() => {
33
-
const now = new Date();
34
-
35
-
return data.map(raw => {
36
-
const support = {
37
-
currentStart: raw.currentStart,
38
-
ltsStart: raw.ltsStart,
39
-
maintenanceStart: raw.maintenanceStart,
40
-
endOfLife: raw.endOfLife,
41
-
};
42
-
43
-
const status = getNodeReleaseStatus(now, support);
44
-
45
-
return {
46
-
...support,
47
-
major: raw.major,
48
-
version: raw.version,
49
-
versionWithPrefix: `v${raw.version}`,
50
-
codename: raw.codename || '',
51
-
isLts: status === 'Active LTS' || status === 'Maintenance LTS',
52
-
status: status,
53
-
npm: raw.npm || '',
54
-
v8: raw.v8 || '',
55
-
releaseDate: raw.releaseDate || '',
56
-
modules: raw.modules || '',
57
-
};
58
-
});
59
-
}, [data]);
60
-
};
+16
package-lock.json
+16
package-lock.json
···
65
65
"feed": "^4.2.2",
66
66
"gray-matter": "^4.0.3",
67
67
"handlebars": "^4.7.7",
68
+
"husky": "^8.0.0",
68
69
"jest": "^29.5.0",
69
70
"jest-environment-jsdom": "^29.5.0",
70
71
"next-sitemap": "^4.1.3",
···
15954
15955
"dev": true,
15955
15956
"engines": {
15956
15957
"node": ">=10.17.0"
15958
+
}
15959
+
},
15960
+
"node_modules/husky": {
15961
+
"version": "8.0.3",
15962
+
"resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz",
15963
+
"integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==",
15964
+
"dev": true,
15965
+
"bin": {
15966
+
"husky": "lib/bin.js"
15967
+
},
15968
+
"engines": {
15969
+
"node": ">=14"
15970
+
},
15971
+
"funding": {
15972
+
"url": "https://github.com/sponsors/typicode"
15957
15973
}
15958
15974
},
15959
15975
"node_modules/iconv-lite": {
+4
-2
package.json
+4
-2
package.json
···
32
32
"test:storybook": "concurrently -P -k -s first -n \"storybook,test-storybook\" -c \"magenta,blue\" \"npm:storybook -- --ci\" \"wait-on http://localhost:6006 && test-storybook {@}\"",
33
33
"test:storybook:snapshot": "npm run test:storybook -- -- --updateSnapshot",
34
34
"test:storybook:watch": "npm run test:storybook -- -- --watch",
35
-
"test": "concurrently -s all -n \"test:unit,test:storybook\" -c \"yellow,green\" \"npm:test:unit\" \"npm:test:storybook\""
35
+
"test": "concurrently -s all -n \"test:unit,test:storybook\" -c \"yellow,green\" \"npm:test:unit\" \"npm:test:storybook\"",
36
+
"prepare": "husky install"
36
37
},
37
38
"dependencies": {
38
39
"@emotion/react": "^11.11.1",
···
105
106
"stylelint-selector-bem-pattern": "^2.1.1",
106
107
"typescript": "^5.0.4",
107
108
"user-agent-data-types": "^0.3.1",
108
-
"wait-on": "^7.0.1"
109
+
"wait-on": "^7.0.1",
110
+
"husky": "^8.0.0"
109
111
}
110
112
}
+32
-4
providers/nodeReleasesProvider.tsx
+32
-4
providers/nodeReleasesProvider.tsx
···
1
-
import { createContext } from 'react';
2
-
import { useFetchNodeReleases } from '../hooks/useFetchNodeReleases';
1
+
import { createContext, useMemo } from 'react';
2
+
import nodeReleasesData from '../public/node-releases-data.json';
3
+
import { getNodeReleaseStatus } from '../util/nodeRelease';
3
4
import type { FC, PropsWithChildren } from 'react';
4
-
import type { NodeRelease } from '../types';
5
+
import type { NodeReleaseSource, NodeRelease } from '../types';
5
6
6
7
export const NodeReleasesContext = createContext<NodeRelease[]>([]);
7
8
8
9
export const NodeReleasesProvider: FC<PropsWithChildren> = ({ children }) => {
9
-
const releases = useFetchNodeReleases();
10
+
const releases = useMemo(() => {
11
+
const now = new Date();
12
+
13
+
return nodeReleasesData.map((raw: NodeReleaseSource) => {
14
+
const support = {
15
+
currentStart: raw.currentStart,
16
+
ltsStart: raw.ltsStart,
17
+
maintenanceStart: raw.maintenanceStart,
18
+
endOfLife: raw.endOfLife,
19
+
};
20
+
21
+
const status = getNodeReleaseStatus(now, support);
22
+
23
+
return {
24
+
...support,
25
+
major: raw.major,
26
+
version: raw.version,
27
+
versionWithPrefix: `v${raw.version}`,
28
+
codename: raw.codename || '',
29
+
isLts: status === 'Active LTS' || status === 'Maintenance LTS',
30
+
status: status,
31
+
npm: raw.npm || '',
32
+
v8: raw.v8 || '',
33
+
releaseDate: raw.releaseDate || '',
34
+
modules: raw.modules || '',
35
+
};
36
+
});
37
+
}, []);
10
38
11
39
return (
12
40
<NodeReleasesContext.Provider value={releases}>
+1
public/node-releases-data.json
+1
public/node-releases-data.json
···
1
+
[]
+12
-9
types/releases.ts
+12
-9
types/releases.ts
···
16
16
| 'End-of-life'
17
17
| 'Pending';
18
18
19
-
export interface NodeRelease {
19
+
export interface NodeReleaseSource {
20
20
major: number;
21
21
version: string;
22
-
versionWithPrefix: string;
23
-
codename: string;
24
-
isLts: boolean;
25
-
status: NodeReleaseStatus;
22
+
codename?: string;
26
23
currentStart: string;
27
24
ltsStart?: string;
28
25
maintenanceStart?: string;
29
26
endOfLife: string;
30
-
npm: string;
31
-
v8: string;
32
-
releaseDate: string;
33
-
modules: string;
27
+
npm?: string;
28
+
v8?: string;
29
+
releaseDate?: string;
30
+
modules?: string;
31
+
}
32
+
33
+
export interface NodeRelease extends NodeReleaseSource {
34
+
versionWithPrefix: string;
35
+
isLts: boolean;
36
+
status: NodeReleaseStatus;
34
37
}
35
38
36
39
export type NodeReleaseSupport = Pick<