@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.
- package/.turbo/turbo-build.log +11 -0
- package/.turbo/turbo-docs.log +43 -0
- package/.turbo/turbo-format.log +7 -0
- package/.turbo/turbo-lint.log +7 -0
- package/.turbo/turbo-prepare.log +2 -0
- package/.turbo/turbo-test.log +19 -0
- package/CHANGELOG.md +237 -0
- package/README.md +1 -1
- package/bootstrap/index.js +43 -42
- package/ci/_gitlab/AutoDevopsInclude.gitlab-ci.yml +2 -0
- package/ci/github.js +47 -0
- package/ci/gitlab.js +1 -1
- package/ci/index.js +7 -2
- package/commitlint/index.js +5 -2
- package/config.json +1 -0
- package/contributing/index.js +1 -1
- package/contributing/templates/CODE_OF_CONDUCT.md +3 -4
- package/core/block.js +2 -3
- package/core/commitlint.js +3 -3
- package/core/cspell.js +1 -10
- package/core/eslint.js +25 -6
- package/{gitignore/template.js → core/git.ignore.js} +32 -6
- package/core/git.js +21 -18
- package/core/githooks.js +8 -7
- package/core/githubCI.js +56 -0
- package/core/jest.js +50 -69
- package/core/jsonFile.js +8 -7
- package/core/lintStaged.js +3 -3
- package/core/npm.js +52 -15
- package/core/pkg.js +92 -14
- package/core/project.js +6 -0
- package/core/semanticRelease.js +4 -4
- package/core/turbo.js +57 -0
- package/core/typedoc.js +7 -20
- package/core/vscode.js +1 -1
- package/cspell/index.js +20 -10
- package/editorconfig/index.js +3 -1
- package/eslint/index.js +81 -32
- package/githooks/index.js +47 -56
- package/gitignore/index.js +5 -22
- package/jest/index.js +13 -17
- package/lang/.eslintrc.json +4 -1
- package/lang/index.js +22 -19
- package/licenses/index.js +26 -0
- package/package.json +17 -12
- package/postconfigure/index.js +3 -3
- package/project/index.js +217 -156
- package/release/index.js +5 -5
- package/renovate/index.js +7 -5
- package/tsconfig.json +2 -1
- 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
|
|
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(
|
|
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.
|
|
34
|
-
} else if (state === 'present' || (state === 'default' && !packageFile.
|
|
35
|
-
packageFile.
|
|
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.
|
|
82
|
-
(
|
|
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
|
};
|
package/core/semanticRelease.js
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
48
|
-
entryPoints:
|
|
39
|
+
entryPointStrategy: 'packages',
|
|
40
|
+
entryPoints: undefined,
|
|
49
41
|
}
|
|
50
42
|
: {
|
|
51
|
-
|
|
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.
|
|
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
|
|
3
|
-
const
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
|
package/editorconfig/index.js
CHANGED
|
@@ -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
|
|
18
|
-
const
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
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
|
|
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 . --
|
|
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':
|
|
96
|
-
(
|
|
97
|
-
(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
7
|
-
const {
|
|
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
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
50
|
+
task.description = 'Setup Git hooks';
|
|
51
|
+
task.parameters = {};
|
|
52
|
+
|
|
53
|
+
module.exports = task;
|