create-packkit 0.1.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.
- package/LICENSE +21 -0
- package/README.md +63 -0
- package/bin/cli.js +7 -0
- package/package.json +59 -0
- package/src/cli/args.js +62 -0
- package/src/cli/index.js +112 -0
- package/src/cli/wizard.js +59 -0
- package/src/cli/write.js +46 -0
- package/src/core/features/agents.js +57 -0
- package/src/core/features/bundler.js +118 -0
- package/src/core/features/cli.js +35 -0
- package/src/core/features/community.js +175 -0
- package/src/core/features/gitfiles.js +50 -0
- package/src/core/features/githooks.js +59 -0
- package/src/core/features/index.js +32 -0
- package/src/core/features/lint.js +76 -0
- package/src/core/features/meta.js +99 -0
- package/src/core/features/release.js +44 -0
- package/src/core/features/test.js +104 -0
- package/src/core/features/typescript.js +48 -0
- package/src/core/features/vscode.js +33 -0
- package/src/core/features/workflows.js +216 -0
- package/src/core/index.js +73 -0
- package/src/core/options.js +193 -0
- package/src/core/pkg.js +31 -0
- package/src/core/presets.js +23 -0
- package/src/core/render.js +35 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
id: 'community',
|
|
3
|
+
active: (cfg) => cfg.license !== 'none' || cfg.community,
|
|
4
|
+
apply(cfg) {
|
|
5
|
+
const files = {};
|
|
6
|
+
const year = new Date().getFullYear();
|
|
7
|
+
const holder = cfg.author || 'the authors';
|
|
8
|
+
|
|
9
|
+
if (cfg.license === 'MIT') files['LICENSE'] = mit(year, holder);
|
|
10
|
+
else if (cfg.license === 'ISC') files['LICENSE'] = isc(year, holder);
|
|
11
|
+
else if (cfg.license === 'Apache-2.0') files['LICENSE'] = apacheStub(year, holder);
|
|
12
|
+
|
|
13
|
+
if (cfg.community) {
|
|
14
|
+
files['CONTRIBUTING.md'] = contributing(cfg);
|
|
15
|
+
files['CODE_OF_CONDUCT.md'] = codeOfConduct(cfg);
|
|
16
|
+
files['SECURITY.md'] = security();
|
|
17
|
+
files['.github/ISSUE_TEMPLATE/bug_report.md'] = bugReport();
|
|
18
|
+
files['.github/ISSUE_TEMPLATE/feature_request.md'] = featureRequest();
|
|
19
|
+
files['.github/PULL_REQUEST_TEMPLATE.md'] = prTemplate();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return { files, pkg: {} };
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function mit(year, holder) {
|
|
27
|
+
return `MIT License
|
|
28
|
+
|
|
29
|
+
Copyright (c) ${year} ${holder}
|
|
30
|
+
|
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
32
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
33
|
+
in the Software without restriction, including without limitation the rights
|
|
34
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
35
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
36
|
+
furnished to do so, subject to the following conditions:
|
|
37
|
+
|
|
38
|
+
The above copyright notice and this permission notice shall be included in all
|
|
39
|
+
copies or substantial portions of the Software.
|
|
40
|
+
|
|
41
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
42
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
43
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
44
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
45
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
46
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
47
|
+
SOFTWARE.
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isc(year, holder) {
|
|
52
|
+
return `ISC License
|
|
53
|
+
|
|
54
|
+
Copyright (c) ${year} ${holder}
|
|
55
|
+
|
|
56
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
57
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
58
|
+
copyright notice and this permission notice appear in all copies.
|
|
59
|
+
|
|
60
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
61
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
62
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
63
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
64
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
65
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
66
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function apacheStub(year, holder) {
|
|
71
|
+
return `Copyright ${year} ${holder}
|
|
72
|
+
|
|
73
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
74
|
+
you may not use this file except in compliance with the License.
|
|
75
|
+
You may obtain a copy of the License at
|
|
76
|
+
|
|
77
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
78
|
+
|
|
79
|
+
Unless required by applicable law or agreed to in writing, software
|
|
80
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
81
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
82
|
+
See the License for the specific language governing permissions and
|
|
83
|
+
limitations under the License.
|
|
84
|
+
|
|
85
|
+
Full text: https://www.apache.org/licenses/LICENSE-2.0.txt
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function contributing(cfg) {
|
|
90
|
+
const pm = cfg.packageManager;
|
|
91
|
+
const install = pm === 'npm' ? 'npm install' : `${pm} install`;
|
|
92
|
+
return `# Contributing
|
|
93
|
+
|
|
94
|
+
Thanks for your interest in contributing!
|
|
95
|
+
|
|
96
|
+
## Development
|
|
97
|
+
|
|
98
|
+
\`\`\`sh
|
|
99
|
+
${install}
|
|
100
|
+
${pm === 'npm' ? 'npm test' : pm + ' test'}
|
|
101
|
+
\`\`\`
|
|
102
|
+
|
|
103
|
+
## Pull requests
|
|
104
|
+
|
|
105
|
+
- Create a branch, make your change, and open a PR against \`main\`.
|
|
106
|
+
- Make sure lint, types and tests pass.
|
|
107
|
+
${cfg.release === 'changesets' ? '- Run `npx changeset` to describe your change for the changelog.\n' : ''}
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function codeOfConduct() {
|
|
112
|
+
return `# Code of Conduct
|
|
113
|
+
|
|
114
|
+
This project follows the [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
|
|
115
|
+
By participating, you are expected to uphold this code. Report unacceptable
|
|
116
|
+
behavior to the maintainers.
|
|
117
|
+
`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function security() {
|
|
121
|
+
return `# Security Policy
|
|
122
|
+
|
|
123
|
+
If you discover a security vulnerability, please **do not** open a public issue.
|
|
124
|
+
Instead, report it privately to the maintainers (e.g. via GitHub Security
|
|
125
|
+
Advisories). We will respond as quickly as possible.
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function bugReport() {
|
|
130
|
+
return `---
|
|
131
|
+
name: Bug report
|
|
132
|
+
about: Report a problem
|
|
133
|
+
labels: bug
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
**Describe the bug**
|
|
137
|
+
|
|
138
|
+
**To reproduce**
|
|
139
|
+
|
|
140
|
+
**Expected behavior**
|
|
141
|
+
|
|
142
|
+
**Environment**
|
|
143
|
+
- Version:
|
|
144
|
+
- Node:
|
|
145
|
+
- OS:
|
|
146
|
+
`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function featureRequest() {
|
|
150
|
+
return `---
|
|
151
|
+
name: Feature request
|
|
152
|
+
about: Suggest an idea
|
|
153
|
+
labels: enhancement
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
**Problem**
|
|
157
|
+
|
|
158
|
+
**Proposed solution**
|
|
159
|
+
|
|
160
|
+
**Alternatives considered**
|
|
161
|
+
`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function prTemplate() {
|
|
165
|
+
return `## Summary
|
|
166
|
+
|
|
167
|
+
<!-- What does this change and why? -->
|
|
168
|
+
|
|
169
|
+
## Checklist
|
|
170
|
+
|
|
171
|
+
- [ ] Tests pass
|
|
172
|
+
- [ ] Lint & types pass
|
|
173
|
+
- [ ] Docs updated if needed
|
|
174
|
+
`;
|
|
175
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// .gitignore, .editorconfig, .npmrc — always-on repo hygiene.
|
|
2
|
+
|
|
3
|
+
const GITIGNORE = `# dependencies
|
|
4
|
+
node_modules/
|
|
5
|
+
.pnp.*
|
|
6
|
+
.yarn/*
|
|
7
|
+
|
|
8
|
+
# build output
|
|
9
|
+
dist/
|
|
10
|
+
coverage/
|
|
11
|
+
*.tsbuildinfo
|
|
12
|
+
|
|
13
|
+
# logs
|
|
14
|
+
*.log
|
|
15
|
+
npm-debug.log*
|
|
16
|
+
|
|
17
|
+
# env & editor
|
|
18
|
+
.env
|
|
19
|
+
.env.*
|
|
20
|
+
!.env.example
|
|
21
|
+
.DS_Store
|
|
22
|
+
.vscode/*
|
|
23
|
+
!.vscode/settings.json
|
|
24
|
+
!.vscode/extensions.json
|
|
25
|
+
.idea/
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const EDITORCONFIG = `root = true
|
|
29
|
+
|
|
30
|
+
[*]
|
|
31
|
+
charset = utf-8
|
|
32
|
+
end_of_line = lf
|
|
33
|
+
insert_final_newline = true
|
|
34
|
+
trim_trailing_whitespace = true
|
|
35
|
+
indent_style = tab
|
|
36
|
+
|
|
37
|
+
[*.{json,yml,yaml,md}]
|
|
38
|
+
indent_style = space
|
|
39
|
+
indent_size = 2
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
export default {
|
|
43
|
+
id: 'gitfiles',
|
|
44
|
+
active: () => true,
|
|
45
|
+
apply(cfg) {
|
|
46
|
+
const files = { '.gitignore': GITIGNORE };
|
|
47
|
+
if (cfg.editorconfig) files['.editorconfig'] = EDITORCONFIG;
|
|
48
|
+
return { files, pkg: {} };
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
id: 'githooks',
|
|
3
|
+
active: (cfg) => cfg.gitHooks !== 'none',
|
|
4
|
+
apply(cfg) {
|
|
5
|
+
const files = {};
|
|
6
|
+
const pkg = { scripts: {}, devDependencies: {} };
|
|
7
|
+
const codeGlob = cfg.isTs ? '*.{js,ts}' : '*.js';
|
|
8
|
+
|
|
9
|
+
// What runs on staged files depends on the linter choice.
|
|
10
|
+
const staged =
|
|
11
|
+
cfg.lint === 'biome'
|
|
12
|
+
? { [codeGlob]: 'biome check --write --no-errors-on-unmatched' }
|
|
13
|
+
: cfg.lint === 'eslint-prettier'
|
|
14
|
+
? { [codeGlob]: ['prettier --write', 'eslint --fix'], '*.{json,md,yml}': 'prettier --write' }
|
|
15
|
+
: cfg.lint === 'oxlint'
|
|
16
|
+
? { [codeGlob]: ['prettier --write', 'oxlint'], '*.{json,md,yml}': 'prettier --write' }
|
|
17
|
+
: null;
|
|
18
|
+
|
|
19
|
+
const needsLintStaged = cfg.gitHooks !== 'lefthook' && staged;
|
|
20
|
+
|
|
21
|
+
if (cfg.gitHooks === 'simple-git-hooks') {
|
|
22
|
+
pkg['simple-git-hooks'] = { 'pre-commit': needsLintStaged ? 'npx lint-staged' : 'npm test' };
|
|
23
|
+
pkg.scripts.prepare = 'simple-git-hooks';
|
|
24
|
+
pkg.devDependencies['simple-git-hooks'] = '^2.11.0';
|
|
25
|
+
} else if (cfg.gitHooks === 'husky') {
|
|
26
|
+
files['.husky/pre-commit'] = (needsLintStaged ? 'npx lint-staged\n' : 'npm test\n');
|
|
27
|
+
pkg.scripts.prepare = 'husky';
|
|
28
|
+
pkg.devDependencies.husky = '^9.1.0';
|
|
29
|
+
} else if (cfg.gitHooks === 'lefthook') {
|
|
30
|
+
files['lefthook.yml'] = lefthookYml(cfg, staged);
|
|
31
|
+
pkg.scripts.prepare = 'lefthook install';
|
|
32
|
+
pkg.devDependencies.lefthook = '^1.7.0';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (needsLintStaged) {
|
|
36
|
+
pkg['lint-staged'] = staged;
|
|
37
|
+
pkg.devDependencies['lint-staged'] = '^15.2.0';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return { files, pkg };
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
function lefthookYml(cfg, staged) {
|
|
45
|
+
const cmd =
|
|
46
|
+
cfg.lint === 'biome'
|
|
47
|
+
? 'biome check --write --no-errors-on-unmatched {staged_files}'
|
|
48
|
+
: cfg.lint === 'none'
|
|
49
|
+
? 'npm test'
|
|
50
|
+
: 'prettier --write {staged_files}';
|
|
51
|
+
return [
|
|
52
|
+
'pre-commit:',
|
|
53
|
+
' commands:',
|
|
54
|
+
' format:',
|
|
55
|
+
` glob: '*.{js,ts,json,md}'`,
|
|
56
|
+
` run: ${cmd}`,
|
|
57
|
+
'',
|
|
58
|
+
].join('\n');
|
|
59
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Feature registry. Order matters only for how package.json fragments merge
|
|
2
|
+
// (later features deep-merge over earlier ones); files are keyed by path.
|
|
3
|
+
|
|
4
|
+
import meta from './meta.js';
|
|
5
|
+
import bundler from './bundler.js';
|
|
6
|
+
import typescript from './typescript.js';
|
|
7
|
+
import test from './test.js';
|
|
8
|
+
import lint from './lint.js';
|
|
9
|
+
import githooks from './githooks.js';
|
|
10
|
+
import release from './release.js';
|
|
11
|
+
import cli from './cli.js';
|
|
12
|
+
import workflows from './workflows.js';
|
|
13
|
+
import community from './community.js';
|
|
14
|
+
import agents from './agents.js';
|
|
15
|
+
import vscode from './vscode.js';
|
|
16
|
+
import gitfiles from './gitfiles.js';
|
|
17
|
+
|
|
18
|
+
export default [
|
|
19
|
+
meta,
|
|
20
|
+
bundler,
|
|
21
|
+
typescript,
|
|
22
|
+
test,
|
|
23
|
+
lint,
|
|
24
|
+
githooks,
|
|
25
|
+
release,
|
|
26
|
+
cli,
|
|
27
|
+
workflows,
|
|
28
|
+
community,
|
|
29
|
+
agents,
|
|
30
|
+
vscode,
|
|
31
|
+
gitfiles,
|
|
32
|
+
];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { toJson } from '../render.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 'lint',
|
|
5
|
+
active: (cfg) => cfg.lint !== 'none',
|
|
6
|
+
apply(cfg) {
|
|
7
|
+
const files = {};
|
|
8
|
+
const pkg = { scripts: {}, devDependencies: {} };
|
|
9
|
+
|
|
10
|
+
if (cfg.lint === 'eslint-prettier' || cfg.lint === 'oxlint') {
|
|
11
|
+
// Prettier is shared by both.
|
|
12
|
+
files['.prettierrc.json'] = toJson({
|
|
13
|
+
useTabs: true,
|
|
14
|
+
singleQuote: true,
|
|
15
|
+
semi: true,
|
|
16
|
+
printWidth: 100,
|
|
17
|
+
trailingComma: 'all',
|
|
18
|
+
});
|
|
19
|
+
files['.prettierignore'] = 'dist\ncoverage\n';
|
|
20
|
+
pkg.scripts.format = 'prettier --write .';
|
|
21
|
+
pkg.scripts['format:check'] = 'prettier --check .';
|
|
22
|
+
pkg.devDependencies.prettier = '^3.3.0';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (cfg.lint === 'eslint-prettier') {
|
|
26
|
+
files['eslint.config.js'] = eslintFlatConfig(cfg);
|
|
27
|
+
pkg.scripts.lint = 'eslint .';
|
|
28
|
+
pkg.scripts['lint:fix'] = 'eslint . --fix';
|
|
29
|
+
pkg.devDependencies.eslint = '^9.0.0';
|
|
30
|
+
pkg.devDependencies['@eslint/js'] = '^9.0.0';
|
|
31
|
+
if (cfg.isTs) pkg.devDependencies['typescript-eslint'] = '^8.0.0';
|
|
32
|
+
} else if (cfg.lint === 'oxlint') {
|
|
33
|
+
pkg.scripts.lint = 'oxlint';
|
|
34
|
+
pkg.devDependencies.oxlint = '^0.9.0';
|
|
35
|
+
} else if (cfg.lint === 'biome') {
|
|
36
|
+
files['biome.json'] = toJson({
|
|
37
|
+
$schema: 'https://biomejs.dev/schemas/1.8.0/schema.json',
|
|
38
|
+
formatter: { enabled: true, indentStyle: 'tab', lineWidth: 100 },
|
|
39
|
+
linter: { enabled: true, rules: { recommended: true } },
|
|
40
|
+
javascript: { formatter: { quoteStyle: 'single', trailingCommas: 'all' } },
|
|
41
|
+
});
|
|
42
|
+
pkg.scripts.lint = 'biome check .';
|
|
43
|
+
pkg.scripts['lint:fix'] = 'biome check --write .';
|
|
44
|
+
pkg.scripts.format = 'biome format --write .';
|
|
45
|
+
pkg.devDependencies['@biomejs/biome'] = '^1.8.0';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return { files, pkg };
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
function eslintFlatConfig(cfg) {
|
|
53
|
+
if (cfg.isTs) {
|
|
54
|
+
return [
|
|
55
|
+
`import js from '@eslint/js';`,
|
|
56
|
+
`import tseslint from 'typescript-eslint';`,
|
|
57
|
+
``,
|
|
58
|
+
`export default tseslint.config(`,
|
|
59
|
+
`\tjs.configs.recommended,`,
|
|
60
|
+
`\t...tseslint.configs.recommended,`,
|
|
61
|
+
`\t{ ignores: ['dist', 'coverage'] },`,
|
|
62
|
+
`);`,
|
|
63
|
+
``,
|
|
64
|
+
].join('\n');
|
|
65
|
+
}
|
|
66
|
+
return [
|
|
67
|
+
`import js from '@eslint/js';`,
|
|
68
|
+
``,
|
|
69
|
+
`export default [`,
|
|
70
|
+
`\tjs.configs.recommended,`,
|
|
71
|
+
`\t{ languageOptions: { ecmaVersion: 'latest', sourceType: 'module' } },`,
|
|
72
|
+
`\t{ ignores: ['dist', 'coverage'] },`,
|
|
73
|
+
`];`,
|
|
74
|
+
``,
|
|
75
|
+
].join('\n');
|
|
76
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Always-on: base package.json descriptive fields + the source entry + README.
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 'meta',
|
|
5
|
+
active: () => true,
|
|
6
|
+
apply(cfg) {
|
|
7
|
+
const files = {};
|
|
8
|
+
const pkg = {
|
|
9
|
+
name: cfg.name,
|
|
10
|
+
version: '0.0.0',
|
|
11
|
+
description: cfg.description || '',
|
|
12
|
+
type: cfg.moduleFormat === 'cjs' ? 'commonjs' : 'module',
|
|
13
|
+
engines: { node: `>=${cfg.nodeVersion}` },
|
|
14
|
+
scripts: {},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const kw = String(cfg.keywords || '').split(',').map((s) => s.trim()).filter(Boolean);
|
|
18
|
+
if (kw.length) pkg.keywords = kw;
|
|
19
|
+
if (cfg.author) pkg.author = cfg.author;
|
|
20
|
+
if (cfg.repo) {
|
|
21
|
+
pkg.repository = { type: 'git', url: `git+${cfg.repo.replace(/\.git$/, '')}.git` };
|
|
22
|
+
pkg.bugs = { url: `${cfg.repo.replace(/\.git$/, '')}/issues` };
|
|
23
|
+
pkg.homepage = `${cfg.repo.replace(/\.git$/, '')}#readme`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Source entry point.
|
|
27
|
+
const ext = cfg.ext;
|
|
28
|
+
files[`src/index.${ext}`] = cfg.hasLibrary
|
|
29
|
+
? libraryEntry(cfg)
|
|
30
|
+
: `// ${cfg.name}\n`;
|
|
31
|
+
|
|
32
|
+
// README
|
|
33
|
+
files['README.md'] = readme(cfg);
|
|
34
|
+
|
|
35
|
+
// Node version pin
|
|
36
|
+
files['.nvmrc'] = `${cfg.nodeVersion}\n`;
|
|
37
|
+
|
|
38
|
+
// A typecheck script for TS projects regardless of bundler.
|
|
39
|
+
if (cfg.isTs) pkg.scripts.typecheck = 'tsc --noEmit';
|
|
40
|
+
|
|
41
|
+
return { files, pkg };
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function libraryEntry(cfg) {
|
|
46
|
+
if (cfg.isTs) {
|
|
47
|
+
return [
|
|
48
|
+
`/** Greet someone by name. */`,
|
|
49
|
+
`export function greet(name: string): string {`,
|
|
50
|
+
`\treturn \`Hello, \${name}!\`;`,
|
|
51
|
+
`}`,
|
|
52
|
+
``,
|
|
53
|
+
].join('\n');
|
|
54
|
+
}
|
|
55
|
+
return [
|
|
56
|
+
`/**`,
|
|
57
|
+
` * Greet someone by name.`,
|
|
58
|
+
` * @param {string} name`,
|
|
59
|
+
` * @returns {string}`,
|
|
60
|
+
` */`,
|
|
61
|
+
`export function greet(name) {`,
|
|
62
|
+
`\treturn \`Hello, \${name}!\`;`,
|
|
63
|
+
`}`,
|
|
64
|
+
``,
|
|
65
|
+
].join('\n');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function readme(cfg) {
|
|
69
|
+
const install = {
|
|
70
|
+
npm: `npm install ${cfg.name}`,
|
|
71
|
+
pnpm: `pnpm add ${cfg.name}`,
|
|
72
|
+
yarn: `yarn add ${cfg.name}`,
|
|
73
|
+
bun: `bun add ${cfg.name}`,
|
|
74
|
+
}[cfg.packageManager];
|
|
75
|
+
|
|
76
|
+
const lines = [
|
|
77
|
+
`# ${cfg.name}`,
|
|
78
|
+
'',
|
|
79
|
+
cfg.description || '_A modern package scaffolded with [Packkit](https://danmat.github.io/create-packkit/)._',
|
|
80
|
+
'',
|
|
81
|
+
'## Install',
|
|
82
|
+
'',
|
|
83
|
+
'```sh',
|
|
84
|
+
install,
|
|
85
|
+
'```',
|
|
86
|
+
'',
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
if (cfg.hasLibrary) {
|
|
90
|
+
const imp = cfg.isTs || cfg.hasEsm ? `import { greet } from '${cfg.name}';` : `const { greet } = require('${cfg.name}');`;
|
|
91
|
+
lines.push('## Usage', '', '```' + (cfg.isTs ? 'ts' : 'js'), imp, '', `greet('world'); // "Hello, world!"`, '```', '');
|
|
92
|
+
}
|
|
93
|
+
if (cfg.hasCli) {
|
|
94
|
+
lines.push('## CLI', '', '```sh', `npx ${cfg.name} --help`, '```', '');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
lines.push('## License', '', cfg.license === 'none' ? 'Unlicensed.' : `${cfg.license}${cfg.author ? ' © ' + cfg.author : ''}`, '');
|
|
98
|
+
return lines.join('\n');
|
|
99
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { toJson } from '../render.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 'release',
|
|
5
|
+
active: (cfg) => cfg.release !== 'none',
|
|
6
|
+
apply(cfg) {
|
|
7
|
+
const files = {};
|
|
8
|
+
const pkg = { scripts: {}, devDependencies: {} };
|
|
9
|
+
|
|
10
|
+
if (cfg.release === 'changesets') {
|
|
11
|
+
files['.changeset/config.json'] = toJson({
|
|
12
|
+
$schema: 'https://unpkg.com/@changesets/config@3.0.0/schema.json',
|
|
13
|
+
changelog: '@changesets/cli/changelog',
|
|
14
|
+
commit: false,
|
|
15
|
+
access: 'public',
|
|
16
|
+
baseBranch: 'main',
|
|
17
|
+
updateInternalDependencies: 'patch',
|
|
18
|
+
});
|
|
19
|
+
files['.changeset/README.md'] =
|
|
20
|
+
'# Changesets\n\nRun `npx changeset` to record a version bump for your next release.\n';
|
|
21
|
+
pkg.scripts.changeset = 'changeset';
|
|
22
|
+
pkg.scripts.version = 'changeset version';
|
|
23
|
+
pkg.scripts.release = `${buildThen(cfg)}changeset publish`;
|
|
24
|
+
pkg.devDependencies['@changesets/cli'] = '^2.27.0';
|
|
25
|
+
} else if (cfg.release === 'release-it') {
|
|
26
|
+
files['.release-it.json'] = toJson({
|
|
27
|
+
git: { commitMessage: 'chore: release v${version}' },
|
|
28
|
+
github: { release: true },
|
|
29
|
+
npm: { publish: true },
|
|
30
|
+
});
|
|
31
|
+
pkg.scripts.release = 'release-it';
|
|
32
|
+
pkg.devDependencies['release-it'] = '^17.0.0';
|
|
33
|
+
} else if (cfg.release === 'np') {
|
|
34
|
+
pkg.scripts.release = 'np';
|
|
35
|
+
pkg.devDependencies.np = '^10.0.0';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return { files, pkg };
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function buildThen(cfg) {
|
|
43
|
+
return cfg.bundler !== 'none' || cfg.isTs ? 'npm run build && ' : '';
|
|
44
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { toJson } from '../render.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 'test',
|
|
5
|
+
active: (cfg) => cfg.test !== 'none',
|
|
6
|
+
apply(cfg) {
|
|
7
|
+
const files = {};
|
|
8
|
+
const pkg = { scripts: {}, devDependencies: {} };
|
|
9
|
+
const ext = cfg.ext;
|
|
10
|
+
|
|
11
|
+
if (cfg.test === 'vitest') {
|
|
12
|
+
files[`vitest.config.${ext}`] = [
|
|
13
|
+
`import { defineConfig } from 'vitest/config';`,
|
|
14
|
+
``,
|
|
15
|
+
`export default defineConfig({`,
|
|
16
|
+
`\ttest: {`,
|
|
17
|
+
cfg.coverage ? `\t\tcoverage: { provider: 'v8', reporter: ['text', 'lcov'] },` : null,
|
|
18
|
+
`\t},`,
|
|
19
|
+
`});`,
|
|
20
|
+
``,
|
|
21
|
+
].filter((l) => l !== null).join('\n');
|
|
22
|
+
pkg.scripts.test = 'vitest run';
|
|
23
|
+
pkg.scripts['test:watch'] = 'vitest';
|
|
24
|
+
pkg.devDependencies.vitest = '^2.0.0';
|
|
25
|
+
if (cfg.coverage) {
|
|
26
|
+
pkg.scripts.coverage = 'vitest run --coverage';
|
|
27
|
+
pkg.devDependencies['@vitest/coverage-v8'] = '^2.0.0';
|
|
28
|
+
}
|
|
29
|
+
files[`src/index.test.${ext}`] = exampleTest('vitest', cfg);
|
|
30
|
+
} else if (cfg.test === 'jest') {
|
|
31
|
+
files['jest.config.js'] = jestConfig(cfg);
|
|
32
|
+
pkg.scripts.test = 'jest';
|
|
33
|
+
pkg.scripts['test:watch'] = 'jest --watch';
|
|
34
|
+
pkg.devDependencies.jest = '^29.0.0';
|
|
35
|
+
if (cfg.isTs) {
|
|
36
|
+
pkg.devDependencies['ts-jest'] = '^29.0.0';
|
|
37
|
+
pkg.devDependencies['@types/jest'] = '^29.0.0';
|
|
38
|
+
}
|
|
39
|
+
if (cfg.coverage) pkg.scripts.coverage = 'jest --coverage';
|
|
40
|
+
files[`src/index.test.${ext}`] = exampleTest('jest', cfg);
|
|
41
|
+
} else if (cfg.test === 'node') {
|
|
42
|
+
pkg.scripts.test = cfg.isTs ? 'node --import tsx --test "src/**/*.test.ts"' : 'node --test';
|
|
43
|
+
if (cfg.isTs) pkg.devDependencies.tsx = '^4.0.0';
|
|
44
|
+
files[`src/index.test.${ext}`] = exampleTest('node', cfg);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return { files, pkg };
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
function importPath(runner, cfg) {
|
|
52
|
+
if (!cfg.isTs) return './index.js';
|
|
53
|
+
if (runner === 'node') return './index.ts';
|
|
54
|
+
return './index.js';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function exampleTest(runner, cfg) {
|
|
58
|
+
const imp = importPath(runner, cfg);
|
|
59
|
+
if (runner === 'node') {
|
|
60
|
+
return [
|
|
61
|
+
`import { test } from 'node:test';`,
|
|
62
|
+
`import assert from 'node:assert/strict';`,
|
|
63
|
+
`import { greet } from '${imp}';`,
|
|
64
|
+
``,
|
|
65
|
+
`test('greet', () => {`,
|
|
66
|
+
`\tassert.equal(greet('world'), 'Hello, world!');`,
|
|
67
|
+
`});`,
|
|
68
|
+
``,
|
|
69
|
+
].join('\n');
|
|
70
|
+
}
|
|
71
|
+
const api = runner === 'jest' ? `` : `import { describe, it, expect } from 'vitest';\n`;
|
|
72
|
+
const expectApi = runner === 'jest' ? '' : '';
|
|
73
|
+
return [
|
|
74
|
+
api + `import { greet } from '${imp}';`,
|
|
75
|
+
``,
|
|
76
|
+
`describe('greet', () => {`,
|
|
77
|
+
`\tit('greets by name', () => {`,
|
|
78
|
+
`\t\texpect(greet('world')).toBe('Hello, world!');`,
|
|
79
|
+
`\t});`,
|
|
80
|
+
`});`,
|
|
81
|
+
``,
|
|
82
|
+
].join('\n');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function jestConfig(cfg) {
|
|
86
|
+
if (cfg.isTs) {
|
|
87
|
+
return [
|
|
88
|
+
`/** @type {import('jest').Config} */`,
|
|
89
|
+
`export default {`,
|
|
90
|
+
`\tpreset: 'ts-jest/presets/default-esm',`,
|
|
91
|
+
`\ttestEnvironment: 'node',`,
|
|
92
|
+
`\textensionsToTreatAsEsm: ['.ts'],`,
|
|
93
|
+
`};`,
|
|
94
|
+
``,
|
|
95
|
+
].join('\n');
|
|
96
|
+
}
|
|
97
|
+
return [
|
|
98
|
+
`/** @type {import('jest').Config} */`,
|
|
99
|
+
`export default {`,
|
|
100
|
+
`\ttestEnvironment: 'node',`,
|
|
101
|
+
`};`,
|
|
102
|
+
``,
|
|
103
|
+
].join('\n');
|
|
104
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { toJson } from '../render.js';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
id: 'typescript',
|
|
5
|
+
active: (cfg) => cfg.isTs,
|
|
6
|
+
apply(cfg) {
|
|
7
|
+
const noBuild = cfg.bundler === 'none';
|
|
8
|
+
const compilerOptions = {
|
|
9
|
+
target: 'ES2022',
|
|
10
|
+
module: 'ESNext',
|
|
11
|
+
moduleResolution: 'Bundler',
|
|
12
|
+
lib: ['ES2022'],
|
|
13
|
+
strict: true,
|
|
14
|
+
noUncheckedIndexedAccess: true,
|
|
15
|
+
esModuleInterop: true,
|
|
16
|
+
skipLibCheck: true,
|
|
17
|
+
forceConsistentCasingInFileNames: true,
|
|
18
|
+
verbatimModuleSyntax: cfg.bundler !== 'none',
|
|
19
|
+
declaration: true,
|
|
20
|
+
};
|
|
21
|
+
if (noBuild) {
|
|
22
|
+
// tsc is the build: emit to dist.
|
|
23
|
+
compilerOptions.moduleResolution = 'NodeNext';
|
|
24
|
+
compilerOptions.module = 'NodeNext';
|
|
25
|
+
compilerOptions.outDir = 'dist';
|
|
26
|
+
compilerOptions.rootDir = 'src';
|
|
27
|
+
} else {
|
|
28
|
+
compilerOptions.noEmit = true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
files: {
|
|
33
|
+
'tsconfig.json': toJson({
|
|
34
|
+
$schema: 'https://json.schemastore.org/tsconfig',
|
|
35
|
+
compilerOptions,
|
|
36
|
+
include: ['src'],
|
|
37
|
+
exclude: ['dist', 'node_modules'],
|
|
38
|
+
}),
|
|
39
|
+
},
|
|
40
|
+
pkg: {
|
|
41
|
+
devDependencies: {
|
|
42
|
+
typescript: '^5.5.0',
|
|
43
|
+
'@types/node': `^${cfg.nodeVersion}.0.0`,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
};
|