@w5s/mrm-preset 1.0.0-alpha.2 → 1.0.0-alpha.21

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 (51) hide show
  1. package/.turbo/turbo-build.log +11 -0
  2. package/.turbo/turbo-docs.log +43 -0
  3. package/.turbo/turbo-format.log +7 -0
  4. package/.turbo/turbo-lint.log +7 -0
  5. package/.turbo/turbo-prepare.log +2 -0
  6. package/.turbo/turbo-test.log +19 -0
  7. package/CHANGELOG.md +237 -0
  8. package/README.md +1 -1
  9. package/bootstrap/index.js +43 -42
  10. package/ci/_gitlab/AutoDevopsInclude.gitlab-ci.yml +2 -0
  11. package/ci/github.js +47 -0
  12. package/ci/gitlab.js +1 -1
  13. package/ci/index.js +7 -2
  14. package/commitlint/index.js +5 -2
  15. package/config.json +1 -0
  16. package/contributing/index.js +1 -1
  17. package/contributing/templates/CODE_OF_CONDUCT.md +3 -4
  18. package/core/block.js +2 -3
  19. package/core/commitlint.js +3 -3
  20. package/core/cspell.js +1 -10
  21. package/core/eslint.js +25 -6
  22. package/{gitignore/template.js → core/git.ignore.js} +32 -6
  23. package/core/git.js +21 -18
  24. package/core/githooks.js +8 -7
  25. package/core/githubCI.js +56 -0
  26. package/core/jest.js +50 -69
  27. package/core/jsonFile.js +8 -7
  28. package/core/lintStaged.js +3 -3
  29. package/core/npm.js +52 -15
  30. package/core/pkg.js +92 -14
  31. package/core/project.js +6 -0
  32. package/core/semanticRelease.js +4 -4
  33. package/core/turbo.js +57 -0
  34. package/core/typedoc.js +7 -20
  35. package/core/vscode.js +1 -1
  36. package/cspell/index.js +20 -10
  37. package/editorconfig/index.js +3 -1
  38. package/eslint/index.js +81 -32
  39. package/githooks/index.js +47 -56
  40. package/gitignore/index.js +5 -22
  41. package/jest/index.js +13 -17
  42. package/lang/.eslintrc.json +4 -1
  43. package/lang/index.js +22 -19
  44. package/licenses/index.js +26 -0
  45. package/package.json +17 -12
  46. package/postconfigure/index.js +3 -3
  47. package/project/index.js +217 -156
  48. package/release/index.js +5 -5
  49. package/renovate/index.js +7 -5
  50. package/tsconfig.json +2 -1
  51. package/core/workspace.js +0 -6
package/core/pkg.js CHANGED
@@ -3,14 +3,31 @@
3
3
 
4
4
  // @ts-ignore
5
5
  const { intersect } = require('semver-intersect');
6
- const { packageJson, file } = require('mrm-core');
7
- const jsonFile = require('./jsonFile');
6
+ const { packageJson, file, json } = require('mrm-core');
7
+ const glob = require('glob');
8
+ const path = require('node:path');
9
+ const jsonFile = require('./jsonFile.js');
8
10
 
9
11
  /**
10
12
  * An empty placeholder for npm script
11
13
  */
12
14
  const emptyScript = ':';
13
15
 
16
+ /**
17
+ * @param {import('mrm-core').Json} packageFile
18
+ * @returns {'application'|'library'|'workspace'} the archetype value
19
+ */
20
+ function archetype(packageFile) {
21
+ if (hasWorkspaces(packageFile)) {
22
+ return 'workspace';
23
+ }
24
+ if (packageFile.get('private') === true || (packageFile.get('main') == null && packageFile.get('exports'))) {
25
+ return 'application';
26
+ }
27
+
28
+ return 'library';
29
+ }
30
+
14
31
  /**
15
32
  * @param {(pkg: import('mrm-core').PackageJson) => void} block
16
33
  */
@@ -21,7 +38,38 @@ function withPackageJson(block) {
21
38
  }
22
39
 
23
40
  /**
24
- * @param {import('mrm-core').PackageJson} packageFile
41
+ * @param {import("mrm-core").Json} packageFile
42
+ * @returns {string[]} - The list of workspace matchers
43
+ */
44
+ function listWorkspaceMatchers(packageFile) {
45
+ return packageFile.get('workspaces.packages', packageFile.get('workspaces', []));
46
+ }
47
+
48
+ /**
49
+ * @param {(workspace: {
50
+ * projectDir: string;
51
+ * packageFile: import("mrm-core").Json;
52
+ * }) => void} fn
53
+ */
54
+ function forEachWorkspace(fn) {
55
+ const packageRoot = packageJson();
56
+ const workspacesMatchers = listWorkspaceMatchers(packageRoot);
57
+
58
+ for (const workspaceMatcher of workspacesMatchers) {
59
+ const directories = glob.sync(workspaceMatcher);
60
+ directories.forEach((directory) => {
61
+ const packageFile = json(path.join(directory, 'package.json'));
62
+ fn({
63
+ projectDir: directory,
64
+ packageFile,
65
+ });
66
+ packageFile.save();
67
+ });
68
+ }
69
+ }
70
+
71
+ /**
72
+ * @param {import('mrm-core').Json} packageFile
25
73
  * @param {{
26
74
  * name: string,
27
75
  * state: 'present'|'absent'|'default',
@@ -30,9 +78,9 @@ function withPackageJson(block) {
30
78
  */
31
79
  function script(packageFile, { name, state, script: scriptName }) {
32
80
  if (state === 'absent') {
33
- packageFile.removeScript(name);
34
- } else if (state === 'present' || (state === 'default' && !packageFile.getScript(name))) {
35
- packageFile.setScript(name, scriptName);
81
+ packageFile.unset(['scripts', name]);
82
+ } else if (state === 'present' || (state === 'default' && !packageFile.get(['scripts', name]))) {
83
+ packageFile.set(['scripts', name], scriptName);
36
84
  }
37
85
  }
38
86
 
@@ -40,7 +88,7 @@ const defaultManager = 'npm';
40
88
 
41
89
  /**
42
90
  * @param {import('mrm-core').PackageJson} packageFile
43
- * @returns {'yarn'|'npm'}
91
+ * @returns {'yarn'|'npm'} - The manager used by the package
44
92
  */
45
93
  function manager(packageFile) {
46
94
  if (packageFile.get('packagerManager')) {
@@ -58,9 +106,37 @@ function manager(packageFile) {
58
106
  return defaultManager;
59
107
  }
60
108
 
109
+ /**
110
+ *
111
+ * @param {import('mrm-core').Json} packageFile
112
+ */
113
+ function hasWorkspaces(packageFile) {
114
+ return Boolean(packageFile.get('workspaces'));
115
+ }
116
+
61
117
  /**
62
118
  *
63
119
  * @param {import('mrm-core').PackageJson} packageFile
120
+ * @param {string} packageName
121
+ * @param {'normal'|'dev'|'peer'=} dependencyType
122
+ */
123
+ function hasDependency(packageFile, packageName, dependencyType) {
124
+ return Boolean(
125
+ packageFile.get(
126
+ `${
127
+ dependencyType == null || dependencyType === 'normal'
128
+ ? 'dependencies'
129
+ : dependencyType === 'dev'
130
+ ? 'devDependencies'
131
+ : 'peerDependencies'
132
+ }.${packageName}`
133
+ )
134
+ );
135
+ }
136
+
137
+ /**
138
+ *
139
+ * @param {import('mrm-core').Json} packageFile
64
140
  * @param {Record<string, string>} engineVersionMap
65
141
  */
66
142
  function engineMinVersion(packageFile, engineVersionMap) {
@@ -72,27 +148,29 @@ function engineMinVersion(packageFile, engineVersionMap) {
72
148
  const currentVersion = packageFile.get(`engines.${engineName}`, defaultVersion);
73
149
  try {
74
150
  return intersect(currentVersion, defaultVersion);
75
- } catch (_) {
151
+ } catch {
76
152
  return currentVersion; // leave unchanged
77
153
  }
78
154
  };
79
155
 
80
156
  packageFile.merge({
81
- engines: Object.keys(engineVersionMap).reduce(
82
- (acc, engineName) => ({
83
- ...acc,
84
- [engineName]: engineConstraint(engineName),
85
- }),
86
- {}
157
+ engines: Object.fromEntries(
158
+ Object.keys(engineVersionMap).map((engineName) => [engineName, engineConstraint(engineName)])
87
159
  ),
88
160
  });
161
+ return packageFile.get('engines');
89
162
  }
90
163
 
91
164
  module.exports = {
92
165
  ...jsonFile,
93
166
  emptyScript,
167
+ archetype,
94
168
  script,
95
169
  manager,
96
170
  engineMinVersion,
171
+ hasDependency,
172
+ hasWorkspaces,
97
173
  withPackageJson,
174
+ forEachWorkspace,
175
+ listWorkspaceMatchers,
98
176
  };
package/core/project.js CHANGED
@@ -1,3 +1,5 @@
1
+ /** @type {'docs'} */
2
+ const docs = 'docs';
1
3
  /** @type {'install'} */
2
4
  const install = 'install';
3
5
  /** @type {'prepare'} */
@@ -24,6 +26,8 @@ const validate = 'validate';
24
26
  const release = 'release';
25
27
  /** @type {'rescue'} */
26
28
  const rescue = 'rescue';
29
+ /** @type {'spellcheck'} */
30
+ const spellcheck = 'spellcheck';
27
31
 
28
32
  /**
29
33
  * @param {string} taskName
@@ -41,6 +45,7 @@ function post(taskName) {
41
45
 
42
46
  module.exports = {
43
47
  build,
48
+ docs,
44
49
  prepare,
45
50
  develop,
46
51
  clean,
@@ -55,4 +60,5 @@ module.exports = {
55
60
  rescue,
56
61
  test,
57
62
  validate,
63
+ spellcheck,
58
64
  };
@@ -1,6 +1,6 @@
1
- const npm = require('./npm');
2
- const pkg = require('./pkg');
3
- const jsonFile = require('./jsonFile');
1
+ const npm = require('./npm.js');
2
+ const pkg = require('./pkg.js');
3
+ const jsonFile = require('./jsonFile.js');
4
4
 
5
5
  /**
6
6
  * @typedef {{
@@ -34,7 +34,7 @@ function semanticRelease({ state, update, preset }) {
34
34
  });
35
35
  });
36
36
  }
37
- semanticRelease.command = function () {
37
+ semanticRelease.command = function command() {
38
38
  return 'semantic-release';
39
39
  };
40
40
 
package/core/turbo.js ADDED
@@ -0,0 +1,57 @@
1
+ const { packageJson, json } = require('mrm-core');
2
+ const pkg = require('./pkg.js');
3
+ const npm = require('./npm.js');
4
+ const jsonFile = require('./jsonFile.js');
5
+
6
+ /**
7
+ * @typedef {{
8
+ * $schema: string,
9
+ * baseBranch?: string,
10
+ * pipeline?: Record<string, unknown>,
11
+ * globalDependencies?: Array<string>,
12
+ * }} TurboConfig
13
+ */
14
+
15
+ /**
16
+ * @param {{
17
+ * state: 'present'|'absent',
18
+ * update: (config: TurboConfig) => TurboConfig
19
+ * }} options
20
+ */
21
+ function turbo({ state, update }) {
22
+ const packageFileDefault = packageJson();
23
+ const hasWorkspaces = pkg.hasWorkspaces(packageFileDefault);
24
+ const hasTurbo = state === 'present' && hasWorkspaces;
25
+
26
+ const turboFile = json('turbo.json');
27
+
28
+ if (hasTurbo) {
29
+ jsonFile.value(turboFile, {
30
+ path: undefined,
31
+ state,
32
+ update,
33
+ /** @type {TurboConfig} */
34
+ default: {
35
+ $schema: 'https://turborepo.org/schema.json',
36
+ },
37
+ });
38
+
39
+ /**
40
+ * Otherwise save the file with content
41
+ */
42
+ turboFile.save();
43
+ } else {
44
+ turboFile.delete();
45
+ }
46
+
47
+ // Dependencies
48
+ npm.dependency({
49
+ dev: true,
50
+ name: ['turbo'],
51
+ state: hasTurbo ? 'present' : 'absent',
52
+ });
53
+ }
54
+
55
+ module.exports = {
56
+ turbo,
57
+ };
package/core/typedoc.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const { packageJson, json } = require('mrm-core');
2
- const pkg = require('./pkg');
3
- const npm = require('./npm');
4
- const jsonFile = require('./jsonFile');
2
+ const pkg = require('./pkg.js');
3
+ const npm = require('./npm.js');
4
+ const jsonFile = require('./jsonFile.js');
5
5
 
6
6
  /**
7
7
  * @typedef {{
@@ -23,17 +23,9 @@ const jsonFile = require('./jsonFile');
23
23
  */
24
24
  function typedoc({ state, update }) {
25
25
  const packageFileDefault = packageJson();
26
- const hasWorkspaces = Boolean(packageFileDefault.get('workspaces'));
26
+ const hasWorkspaces = pkg.hasWorkspaces(packageFileDefault);
27
27
  const hasTypedoc = state === 'present';
28
28
 
29
- pkg.withPackageJson((packageFile) => {
30
- pkg.script(packageFile, {
31
- name: 'typedoc',
32
- script: 'typedoc',
33
- state: !hasTypedoc || hasWorkspaces ? 'absent' : 'present',
34
- });
35
- });
36
-
37
29
  const typedocFile = json('typedoc.json');
38
30
 
39
31
  if (hasTypedoc) {
@@ -44,11 +36,11 @@ function typedoc({ state, update }) {
44
36
  ...update(config),
45
37
  ...(hasWorkspaces
46
38
  ? {
47
- 'external-modulemap': '.*packages/([^/]+)/.*',
48
- entryPoints: ['packages/'],
39
+ entryPointStrategy: 'packages',
40
+ entryPoints: undefined,
49
41
  }
50
42
  : {
51
- 'external-modulemap': undefined,
43
+ entryPointStrategy: undefined,
52
44
  entryPoints: ['src/index.ts'],
53
45
  }),
54
46
  }),
@@ -70,11 +62,6 @@ function typedoc({ state, update }) {
70
62
  name: ['typedoc'],
71
63
  state: hasTypedoc ? 'present' : 'absent',
72
64
  });
73
- npm.dependency({
74
- dev: true,
75
- name: ['@strictsoftware/typedoc-plugin-monorepo'],
76
- state: hasTypedoc && hasWorkspaces ? 'present' : 'absent',
77
- });
78
65
  }
79
66
 
80
67
  module.exports = {
package/core/vscode.js CHANGED
@@ -31,7 +31,7 @@ function vscodeTask(newTask) {
31
31
  * @type {Array<any>}
32
32
  */
33
33
  const tasks = vscodeTaskFile.get('tasks', []);
34
- if (tasks.find((task) => task.script === newTask.script)) {
34
+ if (tasks.some((task) => task.script === newTask.script)) {
35
35
  vscodeTaskFile.set(
36
36
  'tasks',
37
37
  tasks.map((task) => (task.script === newTask.script ? newTask : task))
package/cspell/index.js CHANGED
@@ -1,9 +1,8 @@
1
- const { cspell } = require('../core/cspell');
2
- const { lintStaged } = require('../core/lintStaged');
3
- const { hasGit } = require('../core/git');
1
+ const { cspell } = require('../core/cspell.js');
2
+ const project = require('../core/project.js');
3
+ const pkg = require('../core/pkg.js');
4
4
 
5
5
  function task() {
6
- const gitSupported = hasGit();
7
6
  cspell({
8
7
  state: 'present',
9
8
  update: (_) => ({
@@ -24,12 +23,23 @@ function task() {
24
23
  }),
25
24
  });
26
25
 
27
- lintStaged({
28
- state: gitSupported ? 'present' : 'absent',
29
- update: (config) => ({
30
- ...config,
31
- '*.*': ['cspell --no-must-find-files'],
32
- }),
26
+ pkg.withPackageJson((packageFile) => {
27
+ const hasWorkspaces = pkg.hasWorkspaces(packageFile);
28
+ const workspaceMatchers = pkg.listWorkspaceMatchers(packageFile);
29
+ pkg.script(packageFile, {
30
+ name: project.spellcheck,
31
+ script: `cspell --no-progress '**' ${
32
+ hasWorkspaces ? `${workspaceMatchers.map((_) => `--exclude='${_}/**'`).join(' ')} && turbo run spellcheck` : ''
33
+ }`,
34
+ state: 'present',
35
+ });
36
+ });
37
+ pkg.forEachWorkspace(({ packageFile }) => {
38
+ pkg.script(packageFile, {
39
+ name: project.spellcheck,
40
+ script: `cspell --no-progress '**'`,
41
+ state: 'present',
42
+ });
33
43
  });
34
44
  }
35
45
 
@@ -1,6 +1,6 @@
1
1
  const { ini } = require('mrm-core');
2
2
  const createDebug = require('debug');
3
- const { vscodeRecommendedExtension } = require('../core/vscode');
3
+ const { vscodeRecommendedExtension } = require('../core/vscode.js');
4
4
 
5
5
  /**
6
6
  *
@@ -26,6 +26,7 @@ function createEditorConfig(defaults) {
26
26
 
27
27
  /**
28
28
  * @param {string} section
29
+ * @param {defaults} existing
29
30
  */
30
31
  function mergeSection(section, existing = {}) {
31
32
  return Object.assign(existing, defaults[section] || {});
@@ -52,6 +53,7 @@ function createEditorConfig(defaults) {
52
53
 
53
54
  module.exports = createEditorConfig({
54
55
  '*': {
56
+ // eslint-disable-next-line unicorn/text-encoding-identifier-case
55
57
  charset: 'utf-8',
56
58
  continuation_indent_size: 4,
57
59
  curly_bracket_next_line: false,
package/eslint/index.js CHANGED
@@ -1,21 +1,22 @@
1
1
  const { packageJson } = require('mrm-core');
2
- const pkg = require('../core/pkg');
3
- const npm = require('../core/npm');
4
- const { gitIgnore } = require('../core/git');
5
- const { eslintIgnore, eslintConfig } = require('../core/eslint');
6
- const project = require('../core/project');
7
- const { vscodeSettings } = require('../core/vscode');
2
+ const pkg = require('../core/pkg.js');
3
+ const npm = require('../core/npm.js');
4
+ const { gitIgnore } = require('../core/git.js');
5
+ const { eslintIgnore, eslintConfig } = require('../core/eslint.js');
6
+ const project = require('../core/project.js');
7
+ const { vscodeSettings } = require('../core/vscode.js');
8
8
 
9
9
  function createESLint({ eslintPreset: eslintPresetDefault = 'eslint:recommended' }) {
10
10
  /**
11
11
  *
12
12
  * @param {{
13
13
  * eslintPreset: string,
14
- * eslintRules: Record<string, any>
15
14
  * }} config
16
15
  */
17
- function task({ eslintPreset, eslintRules }) {
18
- const hasTypescript = packageJson().get('devDependencies.typescript');
16
+ function task({ eslintPreset }) {
17
+ const packageFileDefault = packageJson();
18
+ const hasWorkspaces = pkg.hasWorkspaces(packageFileDefault);
19
+ const hasTypescript = pkg.hasDependency(packageFileDefault, 'typescript', 'dev');
19
20
  const hasJSX = true;
20
21
  const hasJSON = true;
21
22
 
@@ -53,15 +54,21 @@ function createESLint({ eslintPreset: eslintPresetDefault = 'eslint:recommended'
53
54
  state: !eslintPreset.startsWith('eslint:') ? 'present' : 'absent',
54
55
  });
55
56
  eslintConfig({
56
- extends: [eslintPreset],
57
- rules: eslintRules,
58
- parserOptions: {
59
- project: hasTypescript ? './tsconfig.json' : undefined,
60
- },
57
+ state: 'present',
58
+ update: (config) => ({
59
+ ...config,
60
+ extends: [eslintPreset],
61
+ parserOptions: {
62
+ project: hasTypescript ? './tsconfig.json' : undefined,
63
+ ...config.parserOptions,
64
+ },
65
+ }),
61
66
  });
62
67
 
63
68
  /** @type {Record<string, boolean>} */
64
69
  const extsMap = {
70
+ mjs: true,
71
+ cjs: true,
65
72
  js: true,
66
73
  jsx: hasJSX,
67
74
  ts: hasTypescript,
@@ -69,18 +76,57 @@ function createESLint({ eslintPreset: eslintPresetDefault = 'eslint:recommended'
69
76
  json: hasJSON,
70
77
  };
71
78
  const extList = Object.keys(extsMap).filter((ext) => extsMap[ext]);
72
- const extOption = ` --ext ${extList.map((ext) => `.${ext}`).join(',')}`;
79
+ const extOption = ` --ext=${extList.join(',')}`;
73
80
 
74
81
  pkg.withPackageJson((packageFile) => {
82
+ const ignorePatterns = pkg
83
+ .listWorkspaceMatchers(packageFile)
84
+ .map((_) => ` --ignore-pattern='${_}/**'`)
85
+ .join('');
86
+
87
+ // workspaces
88
+ pkg.script(packageFile, {
89
+ name: `${project.lint}:root`,
90
+ script: `eslint .${extOption}${ignorePatterns}`,
91
+ state: hasWorkspaces ? 'present' : 'absent',
92
+ });
93
+ pkg.script(packageFile, {
94
+ name: `${project.format}:root`,
95
+ script: `eslint .${extOption}${ignorePatterns} --fix`,
96
+ state: hasWorkspaces ? 'present' : 'absent',
97
+ });
98
+ pkg.script(packageFile, {
99
+ name: `${project.lint}:packages`,
100
+ script: `turbo run ${project.lint}`,
101
+ state: hasWorkspaces ? 'present' : 'absent',
102
+ });
103
+ pkg.script(packageFile, {
104
+ name: `${project.format}:packages`,
105
+ script: `turbo run ${project.format}`,
106
+ state: hasWorkspaces ? 'present' : 'absent',
107
+ });
108
+ // regular package
75
109
  pkg.script(packageFile, {
76
- name: project.lint,
77
- script: `eslint . --cache${extOption}`,
78
- state: 'present',
110
+ name: `${project.lint}:src`,
111
+ script: `eslint .${extOption}`,
112
+ state: !hasWorkspaces ? 'present' : 'absent',
79
113
  });
80
114
  pkg.script(packageFile, {
81
- name: project.format,
82
- script: `eslint . --quiet --cache --fix${extOption}`,
83
- state: 'present',
115
+ name: `${project.format}:src`,
116
+ script: `eslint . --fix${extOption}`,
117
+ state: !hasWorkspaces ? 'present' : 'absent',
118
+ });
119
+ });
120
+ pkg.forEachWorkspace(({ packageFile }) => {
121
+ pkg.script(packageFile, {
122
+ name: `${project.lint}:src`,
123
+ script: `eslint .${extOption}`,
124
+ state: 'default',
125
+ });
126
+ pkg.script(packageFile, {
127
+ name: `${project.format}:src`,
128
+ script: `eslint . --fix${extOption}`,
129
+ state: 'default',
84
130
  });
85
131
  });
86
132
 
@@ -92,14 +138,20 @@ function createESLint({ eslintPreset: eslintPresetDefault = 'eslint:recommended'
92
138
  'editor.codeActionsOnSave': settings['editor.codeActionsOnSave'] || {
93
139
  'source.fixAll': true,
94
140
  },
95
- 'eslint.validate': extList.map(
96
- (ext) =>
97
- ({
98
- jsx: 'javascriptreact',
99
- js: 'javascript',
100
- tsx: 'typescriptreact',
101
- ts: 'typescript',
102
- }[ext] || ext)
141
+ 'eslint.validate': Array.from(
142
+ new Set(
143
+ extList.map(
144
+ (ext) =>
145
+ ({
146
+ cjs: 'javascript',
147
+ mjs: 'javascript',
148
+ jsx: 'javascriptreact',
149
+ js: 'javascript',
150
+ tsx: 'typescriptreact',
151
+ ts: 'typescript',
152
+ }[ext] || ext)
153
+ )
154
+ )
103
155
  ),
104
156
  }),
105
157
  });
@@ -112,9 +164,6 @@ function createESLint({ eslintPreset: eslintPresetDefault = 'eslint:recommended'
112
164
  message: 'Enter ESLint preset name',
113
165
  type: 'input',
114
166
  },
115
- eslintRules: {
116
- type: 'config',
117
- },
118
167
  };
119
168
 
120
169
  return task;
package/githooks/index.js CHANGED
@@ -1,62 +1,53 @@
1
- const path = require('path');
1
+ const path = require('node:path');
2
2
  const { packageJson, template } = require('mrm-core');
3
- const project = require('../core/project');
4
- const { hasGit } = require('../core/git');
5
- const { gitHook, husky } = require('../core/githooks');
6
- const { lintStaged } = require('../core/lintStaged');
7
- const { file } = require('../core/file');
3
+ const project = require('../core/project.js');
4
+ const pkg = require('../core/pkg.js');
5
+ const { hasGit } = require('../core/git.js');
6
+ const { gitHook, husky } = require('../core/githooks.js');
7
+ const { lintStaged } = require('../core/lintStaged.js');
8
+ const { file } = require('../core/file.js');
8
9
 
9
- function createGitHooks() {
10
- function task() {
11
- const gitSupported = hasGit();
12
- const packageFile = packageJson();
13
- const hasESLint = Boolean(packageFile.get('devDependencies.eslint'));
14
- const hasJest = Boolean(packageFile.get('devDependencies.jest'));
15
- const hasTsc = Boolean(packageFile.get('devDependencies.typescript'));
10
+ function task() {
11
+ const gitSupported = hasGit();
12
+ const packageFile = packageJson();
13
+ const hasESLint = pkg.hasDependency(packageFile, 'eslint', 'dev');
16
14
 
17
- husky({
18
- state: gitSupported ? 'present' : 'absent',
19
- });
20
- lintStaged({
21
- state: gitSupported ? 'present' : 'absent',
22
- update: (config) => ({
23
- ...config,
24
- '*.json': [...(hasESLint ? ['eslint'] : [])],
25
- '*.js?(x)': [
26
- ...(hasTsc ? ["bash -c 'tsc --noEmit'"] : []),
27
- ...(hasESLint ? ['eslint'] : []),
28
- ...(hasJest ? ['jest --ci --bail --findRelatedTests'] : []),
29
- ],
30
- '*.ts?(x)': [
31
- ...(hasTsc ? ["bash -c 'tsc --noEmit'"] : []),
32
- ...(hasESLint ? ['eslint'] : []),
33
- ...(hasJest ? ['jest --ci --bail --findRelatedTests'] : []),
34
- ],
35
- }),
36
- });
37
- gitHook({
38
- name: 'pre-commit',
39
- content: `npm exec --no -- lint-staged`,
40
- state: gitSupported ? 'present' : 'absent',
41
- });
42
- gitHook({
43
- name: 'pre-push',
44
- content: `npm run ${project.validate}`,
45
- state: gitSupported ? 'present' : 'absent',
46
- });
15
+ husky({
16
+ state: gitSupported ? 'present' : 'absent',
17
+ });
18
+ lintStaged({
19
+ state: gitSupported ? 'present' : 'absent',
20
+ update: (config) => ({
21
+ ...config,
22
+ '*.json': [...(hasESLint ? ['eslint'] : [])],
23
+ '*.js?(x)': [...(hasESLint ? ['eslint'] : [])],
24
+ '*.ts?(x)': [
25
+ // TODO: https://github.com/okonet/lint-staged/issues/825
26
+ // ...(hasTsc ? ["tsc --noEmit --skipLibCheck"] : []),
27
+ ...(hasESLint ? ['eslint'] : []),
28
+ ],
29
+ }),
30
+ });
31
+ gitHook({
32
+ name: 'pre-commit',
33
+ content: `npm exec --no -- lint-staged`,
34
+ state: gitSupported ? 'present' : 'absent',
35
+ });
36
+ gitHook({
37
+ name: 'pre-push',
38
+ content: `npm run ${project.validate}`,
39
+ state: gitSupported ? 'present' : 'absent',
40
+ });
47
41
 
48
- file({
49
- path: 'CODEOWNERS',
50
- state: gitSupported ? 'file' : 'absent',
51
- update: (content) =>
52
- content.length === 0 ? template('', path.join(__dirname, 'templates', 'CODEOWNERS')).apply().get() : undefined,
53
- });
54
- }
55
-
56
- task.description = 'Setup Git hooks';
57
- task.parameters = {};
58
-
59
- return task;
42
+ file({
43
+ path: 'CODEOWNERS',
44
+ state: gitSupported ? 'file' : 'absent',
45
+ update: (content) =>
46
+ content.length === 0 ? template('', path.join(__dirname, 'templates', 'CODEOWNERS')).apply().get() : undefined,
47
+ });
60
48
  }
61
49
 
62
- module.exports = createGitHooks();
50
+ task.description = 'Setup Git hooks';
51
+ task.parameters = {};
52
+
53
+ module.exports = task;