@w5s/mrm-preset 1.0.0-alpha.1

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/.eslintignore +1 -0
  2. package/CHANGELOG.md +17 -0
  3. package/README.md +56 -0
  4. package/bootstrap/README.md +5 -0
  5. package/bootstrap/index.js +97 -0
  6. package/ci/_gitlab/AutoDevops.gitlab-ci.yml +77 -0
  7. package/ci/_gitlab/AutoDevopsInclude.gitlab-ci.yml +251 -0
  8. package/ci/_gitlab/README.md +20 -0
  9. package/ci/_gitlab/Renovate.gitlab-ci.yml +30 -0
  10. package/ci/gitlab.js +38 -0
  11. package/ci/index.js +14 -0
  12. package/commitlint/index.js +40 -0
  13. package/config.json +20 -0
  14. package/contributing/index.js +26 -0
  15. package/contributing/templates/CODE_OF_CONDUCT.md +134 -0
  16. package/core/block.js +77 -0
  17. package/core/commitlint.js +39 -0
  18. package/core/cspell.js +66 -0
  19. package/core/eslint.js +22 -0
  20. package/core/file.js +29 -0
  21. package/core/git.js +73 -0
  22. package/core/githooks.js +71 -0
  23. package/core/gitlabCI.js +8 -0
  24. package/core/jest.js +105 -0
  25. package/core/jsonFile.js +65 -0
  26. package/core/lintStaged.js +36 -0
  27. package/core/npm.js +271 -0
  28. package/core/pkg.js +97 -0
  29. package/core/project.js +58 -0
  30. package/core/semanticRelease.js +43 -0
  31. package/core/typedoc.js +82 -0
  32. package/core/vscode.js +92 -0
  33. package/core/workspace.js +6 -0
  34. package/cspell/index.js +38 -0
  35. package/editorconfig/index.js +107 -0
  36. package/eslint/index.js +127 -0
  37. package/githooks/index.js +62 -0
  38. package/githooks/templates/CODEOWNERS +4 -0
  39. package/gitignore/index.js +25 -0
  40. package/gitignore/template.js +145 -0
  41. package/jest/index.js +19 -0
  42. package/lang/.eslintrc.json +8 -0
  43. package/lang/index.js +143 -0
  44. package/lang/templates/index.spec.ts +7 -0
  45. package/lang/templates/index.ts +6 -0
  46. package/package.json +48 -0
  47. package/postconfigure/index.js +17 -0
  48. package/project/index.js +232 -0
  49. package/release/index.js +29 -0
  50. package/renovate/index.js +61 -0
  51. package/tsconfig.json +13 -0
package/core/vscode.js ADDED
@@ -0,0 +1,92 @@
1
+ const { json } = require('mrm-core');
2
+
3
+ /**
4
+ * @param {Array<string>} recommendations
5
+ */
6
+ function vscodeRecommendedExtension(recommendations) {
7
+ const packageFile = json('.vscode/extensions.json');
8
+ packageFile.merge({
9
+ recommendations,
10
+ });
11
+ packageFile.save();
12
+ }
13
+ exports.vscodeRecommendedExtension = vscodeRecommendedExtension;
14
+
15
+ /**
16
+ * @param {{
17
+ * type: string,
18
+ * script: string;
19
+ * group: {
20
+ * kind: string,
21
+ * isDefault: boolean
22
+ * }
23
+ * }} newTask
24
+ */
25
+ function vscodeTask(newTask) {
26
+ const vscodeTaskFile = json('.vscode/tasks.json', {
27
+ tasks: [],
28
+ version: '2.0.0',
29
+ });
30
+ /**
31
+ * @type {Array<any>}
32
+ */
33
+ const tasks = vscodeTaskFile.get('tasks', []);
34
+ if (
35
+ tasks.find((task) => {
36
+ return task.script === newTask.script;
37
+ })
38
+ ) {
39
+ vscodeTaskFile.set(
40
+ 'tasks',
41
+ tasks.map((task) => {
42
+ return task.script === newTask.script ? newTask : task;
43
+ })
44
+ );
45
+ } else {
46
+ vscodeTaskFile.set('tasks', [newTask].concat(tasks));
47
+ }
48
+ vscodeTaskFile.save();
49
+ }
50
+ exports.vscodeTask = vscodeTask;
51
+
52
+ /**
53
+ * @param {{
54
+ * name: string,
55
+ * state: 'present'|'absent',
56
+ * snippets: {
57
+ * [key: string]: {
58
+ * scope: string,
59
+ * prefix: string,
60
+ * body: string|string[],
61
+ * description?: string,
62
+ * }
63
+ * }
64
+ * }} snippets
65
+ */
66
+ function vscodeSnippets({ name = 'mrm', state = 'present', snippets }) {
67
+ const snippetFile = json(`.vscode/${name}.code-snippets`);
68
+ if (state === 'present') {
69
+ snippetFile.merge(snippets);
70
+ snippetFile.save();
71
+ } else {
72
+ snippetFile.delete();
73
+ }
74
+ }
75
+ exports.vscodeSnippets = vscodeSnippets;
76
+
77
+ /**
78
+ * @param {{
79
+ * state: 'present'|'absent',
80
+ * update: (settings: Record<string, any>) => Record<string, any>
81
+ * }} parameters
82
+ */
83
+ function vscodeSettings({ state = 'present', update }) {
84
+ const settingFile = json('.vscode/settings.json');
85
+ if (state === 'present') {
86
+ settingFile.set(update(settingFile.get() || {}));
87
+ settingFile.save();
88
+ } else {
89
+ settingFile.delete();
90
+ }
91
+ }
92
+ exports.vscodeSettings = vscodeSettings;
@@ -0,0 +1,6 @@
1
+ const { packageJson } = require('mrm-core');
2
+
3
+ function useWorkspaces() {
4
+ return packageJson().get('mrmConfig.packageArchetype') === 'workspace';
5
+ }
6
+ exports.useWorkspaces = useWorkspaces;
@@ -0,0 +1,38 @@
1
+ const { cspell } = require('../core/cspell');
2
+ const { lintStaged } = require('../core/lintStaged');
3
+ const { hasGit } = require('../core/git');
4
+
5
+ function task() {
6
+ const gitSupported = hasGit();
7
+ cspell({
8
+ state: 'present',
9
+ update: (_) => ({
10
+ ..._,
11
+ ignorePaths: Array.from(
12
+ new Set([
13
+ '**/build/**',
14
+ '**/lib/**',
15
+ '**/node_modules/**',
16
+ '**/package.json',
17
+ '**/package-lock.json',
18
+ '**/yarn.lock',
19
+ '**/*.log',
20
+ '**/CHANGELOG.md',
21
+ ...(_.ignorePaths || []),
22
+ ])
23
+ ),
24
+ }),
25
+ });
26
+
27
+ lintStaged({
28
+ state: gitSupported ? 'present' : 'absent',
29
+ update: (config) => ({
30
+ ...config,
31
+ '*.*': ['cspell --no-must-find-files'],
32
+ }),
33
+ });
34
+ }
35
+
36
+ task.description = 'Adds CSpell support';
37
+
38
+ module.exports = task;
@@ -0,0 +1,107 @@
1
+ const { ini } = require('mrm-core');
2
+ const createDebug = require('debug');
3
+ const { vscodeRecommendedExtension } = require('../core/vscode');
4
+
5
+ /**
6
+ *
7
+ * @param {Record<string, Partial<{
8
+ * charset: string,
9
+ * continuation_indent_size: number,
10
+ * curly_bracket_next_line: boolean,
11
+ * end_of_line: 'lf'|'crlf',
12
+ * indent_brace_style: 'Stroustrup',
13
+ * indent_size: number,
14
+ * indent_style: 'tab'|'space',
15
+ * insert_final_newline: boolean|'ignore',
16
+ * max_line_length: number,
17
+ * quote_type: 'single'|'double',
18
+ * root: boolean,
19
+ * spaces_around_brackets: 'outside',
20
+ * spaces_around_operators: boolean,
21
+ * trim_trailing_whitespace: boolean,
22
+ * }>>} defaults
23
+ */
24
+ function createEditorConfig(defaults) {
25
+ const debug = createDebug('mrm-editorconfig');
26
+
27
+ /**
28
+ * @param {string} section
29
+ */
30
+ function mergeSection(section, existing = {}) {
31
+ return Object.assign(existing, defaults[section] || {});
32
+ }
33
+
34
+ function task() {
35
+ const editorConfigFile = ini('.editorconfig', 'http://editorconfig.org');
36
+
37
+ Object.keys(defaults).forEach((name) => {
38
+ const values = mergeSection(name, editorConfigFile.get(name));
39
+ debug('section %s: %o', name, values);
40
+ editorConfigFile.set(name, values);
41
+ });
42
+
43
+ editorConfigFile.save();
44
+
45
+ vscodeRecommendedExtension(['editorconfig.editorconfig']);
46
+ }
47
+
48
+ task.description = 'Adds EditorConfig file';
49
+
50
+ return task;
51
+ }
52
+
53
+ module.exports = createEditorConfig({
54
+ '*': {
55
+ charset: 'utf-8',
56
+ continuation_indent_size: 4,
57
+ curly_bracket_next_line: false,
58
+ end_of_line: 'lf',
59
+ indent_brace_style: 'Stroustrup',
60
+ indent_size: 2,
61
+ indent_style: 'space',
62
+ insert_final_newline: true,
63
+ spaces_around_brackets: 'outside',
64
+ spaces_around_operators: true,
65
+ trim_trailing_whitespace: true,
66
+ },
67
+ '*.json': {
68
+ indent_size: 2,
69
+ indent_style: 'space',
70
+ insert_final_newline: 'ignore',
71
+ },
72
+ '*.yml': {
73
+ indent_size: 2,
74
+ indent_style: 'space',
75
+ },
76
+ '*.{bat,reg,ps1,vbs,cs,,fs,ahk}': {
77
+ end_of_line: 'crlf',
78
+ },
79
+ '*.{css,scss,less}': {
80
+ indent_size: 2,
81
+ indent_style: 'space',
82
+ max_line_length: 120,
83
+ quote_type: 'single',
84
+ },
85
+ '*.{js,jsx,ts,tsx,js.hbs}': {
86
+ indent_size: 2,
87
+ indent_style: 'space',
88
+ max_line_length: 120,
89
+ quote_type: 'single',
90
+ },
91
+ '*.{md,mdwn,mdown,markdown,apib}': {
92
+ indent_size: 4,
93
+ indent_style: 'space',
94
+ insert_final_newline: true,
95
+ trim_trailing_whitespace: false,
96
+ },
97
+ '*.{py,robot}': {
98
+ indent_size: 4,
99
+ indent_style: 'space',
100
+ },
101
+ Makefile: {
102
+ indent_style: 'tab',
103
+ },
104
+ _global: {
105
+ root: true,
106
+ },
107
+ });
@@ -0,0 +1,127 @@
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');
8
+
9
+ function createESLint({ eslintPreset: eslintPresetDefault = 'eslint:recommended' }) {
10
+ /**
11
+ *
12
+ * @param {{
13
+ * eslintPreset: string,
14
+ * eslintRules: Record<string, any>
15
+ * }} config
16
+ */
17
+ function task({ eslintPreset, eslintRules }) {
18
+ const hasTypescript = packageJson().get('devDependencies.typescript');
19
+ const hasJSX = true;
20
+ const hasJSON = true;
21
+
22
+ // Should be added first
23
+ gitIgnore('ESLint', ['.eslintcache']);
24
+ eslintIgnore([
25
+ // List of paths to ignore
26
+ 'node_modules/',
27
+ 'coverage/',
28
+ 'build/',
29
+ '.cache/',
30
+ '**/tsconfig.json',
31
+ '.vscode/**',
32
+ 'public/',
33
+ ]);
34
+
35
+ // Dependencies
36
+ npm.dependency({
37
+ dev: true,
38
+ name: ['eslint', '@babel/core', '@babel/eslint-parser', 'prettier'],
39
+ state: 'present',
40
+ });
41
+
42
+ // Clean legacy
43
+ npm.dependency({
44
+ dev: true,
45
+ name: ['@typescript-eslint/parser', '@typescript-eslint/eslint-plugin', 'babel-eslint'],
46
+ state: 'absent',
47
+ });
48
+
49
+ // Preset
50
+ npm.dependency({
51
+ dev: true,
52
+ name: eslintPreset,
53
+ state: !eslintPreset.startsWith('eslint:') ? 'present' : 'absent',
54
+ });
55
+ eslintConfig({
56
+ extends: [eslintPreset],
57
+ rules: eslintRules,
58
+ parserOptions: {
59
+ project: hasTypescript ? './tsconfig.json' : undefined,
60
+ },
61
+ });
62
+
63
+ /** @type {Record<string, boolean>} */
64
+ const extsMap = {
65
+ js: true,
66
+ jsx: hasJSX,
67
+ ts: hasTypescript,
68
+ tsx: hasTypescript && hasJSX,
69
+ json: hasJSON,
70
+ };
71
+ const extList = Object.keys(extsMap).filter((ext) => extsMap[ext]);
72
+ const extOption = ` --ext ${extList.map((ext) => `.${ext}`).join(',')}`;
73
+
74
+ pkg.withPackageJson((packageFile) => {
75
+ pkg.script(packageFile, {
76
+ name: project.lint,
77
+ script: `eslint . --cache${extOption}`,
78
+ state: 'present',
79
+ });
80
+ pkg.script(packageFile, {
81
+ name: project.format,
82
+ script: `eslint . --quiet --cache --fix${extOption}`,
83
+ state: 'present',
84
+ });
85
+ });
86
+
87
+ // VSCode support
88
+ vscodeSettings({
89
+ state: 'present',
90
+ update: (settings) => {
91
+ return {
92
+ ...settings,
93
+ 'editor.codeActionsOnSave': settings['editor.codeActionsOnSave'] || {
94
+ 'source.fixAll.eslint': true,
95
+ },
96
+ 'eslint.validate': extList.map(
97
+ (ext) =>
98
+ ({
99
+ jsx: 'javascriptreact',
100
+ js: 'javascript',
101
+ tsx: 'typescriptreact',
102
+ ts: 'typescript',
103
+ }[ext] || ext)
104
+ ),
105
+ };
106
+ },
107
+ });
108
+ }
109
+
110
+ task.description = 'Setup ESLint';
111
+ task.parameters = {
112
+ eslintPreset: {
113
+ default: eslintPresetDefault,
114
+ message: 'Enter ESLint preset name',
115
+ type: 'input',
116
+ },
117
+ eslintRules: {
118
+ type: 'config',
119
+ },
120
+ };
121
+
122
+ return task;
123
+ }
124
+
125
+ module.exports = createESLint({
126
+ eslintPreset: '@w5s/eslint-config',
127
+ });
@@ -0,0 +1,62 @@
1
+ const path = require('path');
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');
8
+
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'));
16
+
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
+ });
47
+
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;
60
+ }
61
+
62
+ module.exports = createGitHooks();
@@ -0,0 +1,4 @@
1
+ # https://docs.gitlab.com/ee/user/project/code_owners.html
2
+
3
+ # Default owners
4
+ # * @someone
@@ -0,0 +1,25 @@
1
+ const { gitIgnore } = require('../core/git');
2
+
3
+ /**
4
+ *
5
+ * @param {string} templatePath
6
+ * @param {Array<string>} flags
7
+ */
8
+ function createGitIgnore(templatePath, flags) {
9
+ function task() {
10
+ // eslint-disable-next-line global-require, import/no-dynamic-require
11
+ const templateMap = require(templatePath);
12
+
13
+ flags.forEach((flag) => {
14
+ if (templateMap[flag]) {
15
+ gitIgnore(flag, templateMap[flag]);
16
+ }
17
+ });
18
+ }
19
+
20
+ task.description = 'Adds Gitignore file';
21
+
22
+ return task;
23
+ }
24
+
25
+ module.exports = createGitIgnore(require.resolve('./template'), ['macOS', 'NodeJS', 'VisualStudioCode']);
@@ -0,0 +1,145 @@
1
+ /* cSpell: disable */
2
+
3
+ // A dictionary of { tool: git_ignore_section}
4
+
5
+ module.exports = {
6
+ NodeJS: `
7
+ # Logs
8
+ logs
9
+ *.log
10
+ npm-debug.log*
11
+ yarn-debug.log*
12
+ yarn-error.log*
13
+ lerna-debug.log*
14
+
15
+ # Diagnostic reports (https://nodejs.org/api/report.html)
16
+ report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
17
+
18
+ # Runtime data
19
+ pids
20
+ *.pid
21
+ *.seed
22
+ *.pid.lock
23
+
24
+ # Directory for instrumented libs generated by jscoverage/JSCover
25
+ lib-cov
26
+
27
+ # Coverage directory used by tools like istanbul
28
+ coverage
29
+ *.lcov
30
+
31
+ # nyc test coverage
32
+ .nyc_output
33
+
34
+ # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
35
+ .grunt
36
+
37
+ # Bower dependency directory (https://bower.io/)
38
+ bower_components
39
+
40
+ # node-waf configuration
41
+ .lock-wscript
42
+
43
+ # Compiled binary addons (https://nodejs.org/api/addons.html)
44
+ build/Release
45
+
46
+ # Dependency directories
47
+ node_modules/
48
+ jspm_packages/
49
+
50
+ # TypeScript v1 declaration files
51
+ typings/
52
+
53
+ # TypeScript cache
54
+ *.tsbuildinfo
55
+
56
+ # Optional npm cache directory
57
+ .npm
58
+
59
+ # Optional eslint cache
60
+ .eslintcache
61
+
62
+ # Microbundle cache
63
+ .rpt2_cache/
64
+ .rts2_cache_cjs/
65
+ .rts2_cache_es/
66
+ .rts2_cache_umd/
67
+
68
+ # Optional REPL history
69
+ .node_repl_history
70
+
71
+ # Output of 'npm pack'
72
+ *.tgz
73
+
74
+ # Yarn Integrity file
75
+ .yarn-integrity
76
+
77
+ # dotenv environment variables file
78
+ .env
79
+ .env.test
80
+
81
+ # parcel-bundler cache (https://parceljs.org/)
82
+ .cache
83
+
84
+ # Next.js build output
85
+ .next
86
+
87
+ # Nuxt.js build / generate output
88
+ .nuxt
89
+ dist
90
+
91
+ # Gatsby files
92
+ .cache/
93
+ # Comment in the public line in if your project uses Gatsby and not Next.js
94
+ # https://nextjs.org/blog/next-9-1#public-directory-support
95
+ public/
96
+
97
+ # vuepress build output
98
+ .vuepress/dist
99
+
100
+ # Serverless directories
101
+ .serverless/
102
+
103
+ # FuseBox cache
104
+ .fusebox/
105
+
106
+ # DynamoDB Local files
107
+ .dynamodb/
108
+
109
+ # TernJS port file
110
+ .tern-port`,
111
+ VisualStudioCode: `
112
+ .vscode/*
113
+ !.vscode/settings.json
114
+ !.vscode/tasks.json
115
+ !.vscode/launch.json
116
+ !.vscode/extensions.json
117
+ !.vscode/*.code-snippets`,
118
+ macOS: `
119
+ # General
120
+ .DS_Store
121
+ .AppleDouble
122
+ .LSOverride
123
+
124
+ # Icon must end with two \\r
125
+ Icon
126
+
127
+ # Thumbnails
128
+ ._*
129
+
130
+ # Files that might appear in the root of a volume
131
+ .DocumentRevisions-V100
132
+ .fseventsd
133
+ .Spotlight-V100
134
+ .TemporaryItems
135
+ .Trashes
136
+ .VolumeIcon.icns
137
+ .com.apple.timemachine.donotpresent
138
+
139
+ # Directories potentially created on remote AFP share
140
+ .AppleDB
141
+ .AppleDesktop
142
+ Network Trash Folder
143
+ Temporary Items
144
+ .apdisk`,
145
+ };
package/jest/index.js ADDED
@@ -0,0 +1,19 @@
1
+ const { jest } = require('../core/jest');
2
+
3
+ function createJest() {
4
+ /**
5
+ *
6
+ */
7
+ function task() {
8
+ jest({
9
+ state: 'present',
10
+ });
11
+ }
12
+
13
+ task.description = 'Setup Jest';
14
+ task.parameters = {};
15
+
16
+ return task;
17
+ }
18
+
19
+ module.exports = createJest();
@@ -0,0 +1,8 @@
1
+ {
2
+ "rules": {
3
+ "import/no-extraneous-dependencies": "off",
4
+ "@typescript-eslint/no-unsafe-call": "off",
5
+ "@typescript-eslint/no-unsafe-assignment": "off",
6
+ "@typescript-eslint/no-unsafe-member-access": "off"
7
+ }
8
+ }