@jcoreio/toolchain 4.1.0 → 4.3.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jcoreio/toolchain",
3
- "version": "4.1.0",
3
+ "version": "4.3.0",
4
4
  "description": "base JS build toolchain",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,7 +12,7 @@
12
12
  "bugs": {
13
13
  "url": "https://github.com/jcoreio/toolchains/issues"
14
14
  },
15
- "homepage": "https://github.com/jcoreio/toolchains/tree/beta/packages/base",
15
+ "homepage": "https://github.com/jcoreio/toolchains/tree/main/packages/base",
16
16
  "dependencies": {
17
17
  "@jcoreio/eslint-plugin-implicit-dependencies": "^1.1.1",
18
18
  "chalk": "^4.0.0",
@@ -2,6 +2,7 @@ const { name } = require('../package.json')
2
2
  const dedent = require('dedent-js')
3
3
  const fs = require('../util/projectFs.cjs')
4
4
  const JSON5 = require('json5')
5
+ const { isMonorepoSubpackage } = require('../util/findUps.cjs')
5
6
  const getPluginsArraySync = require('../util/getPluginsArraySync.cjs')
6
7
 
7
8
  async function getRootEslintConfig() {
@@ -17,6 +18,9 @@ module.exports = [
17
18
  async function getConfigFiles() {
18
19
  const { env, rules } = (await getRootEslintConfig()) || {}
19
20
  const files = {
21
+ '.npmrc': dedent`
22
+ optional=false
23
+ `,
20
24
  '.eslintrc.cjs': (prev) =>
21
25
  prev
22
26
  ? prev.replace(
@@ -60,7 +64,7 @@ module.exports = [
60
64
  },
61
65
  }
62
66
  for (const file of [
63
- 'githooks.cjs',
67
+ ...(isMonorepoSubpackage ? [] : ['githooks.cjs']),
64
68
  'lint-staged.config.cjs',
65
69
  'prettier.config.cjs',
66
70
  ]) {
@@ -1,25 +1,41 @@
1
1
  const path = require('path')
2
2
  const execa = require('../util/execa.cjs')
3
3
  const ChdirFs = require('../util/ChdirFs.cjs')
4
- const pkgName = require('../package.json').name
4
+ const pkg = require('../package.json')
5
5
  const dedent = require('dedent-js')
6
+ const parseRepositoryUrl = require('../util/parseRepositoryUrl.cjs')
6
7
 
7
8
  async function create(args = []) {
8
9
  const prompt = require('prompts')
9
10
 
11
+ let monorepoPackageJson, monorepoProjectDir
12
+ try {
13
+ ;({
14
+ monorepoPackageJson,
15
+ monorepoProjectDir,
16
+ } = require('../util/findUps.cjs'))
17
+ } catch (error) {
18
+ if (!error.message.startsWith('failed to find project package.json')) {
19
+ throw error
20
+ }
21
+ }
22
+
10
23
  const required = (s) => Boolean(s) || 'required'
11
24
 
12
25
  let defaultAuthor
13
- try {
14
- defaultAuthor = (
15
- await execa('git', ['config', 'user.name'], {
16
- stdio: 'pipe',
17
- maxBuffer: 1024,
18
- encoding: 'utf8',
19
- })
20
- ).stdout.trim()
21
- } catch (error) {
22
- // ignore
26
+ if (monorepoPackageJson) defaultAuthor = monorepoPackageJson.author
27
+ else {
28
+ try {
29
+ defaultAuthor = (
30
+ await execa('git', ['config', 'user.name'], {
31
+ stdio: 'pipe',
32
+ maxBuffer: 1024,
33
+ encoding: 'utf8',
34
+ })
35
+ ).stdout.trim()
36
+ } catch (error) {
37
+ // ignore
38
+ }
23
39
  }
24
40
 
25
41
  const questions = [
@@ -53,25 +69,29 @@ async function create(args = []) {
53
69
  type: 'text',
54
70
  name: 'keywords',
55
71
  message: 'Package keywords:',
56
- format: (text) => text.split(/\s*,\s*|\s+/g),
57
- },
58
- {
59
- type: 'text',
60
- name: 'organization',
61
- initial: (prev, { name }) => {
62
- const match = /^@(.*?)\//.exec(name)
63
- if (match) return match[1]
64
- },
65
- message: 'GitHub organization:',
66
- validate: required,
67
- },
68
- {
69
- type: 'text',
70
- name: 'repo',
71
- message: 'GitHub repo:',
72
- initial: (prev, { name }) => name.replace(/^@(.*?)\//, ''),
73
- validate: required,
72
+ format: (text) => (text || '').split(/\s*,\s*|\s+/g),
74
73
  },
74
+ ...(monorepoPackageJson
75
+ ? []
76
+ : [
77
+ {
78
+ type: 'text',
79
+ name: 'organization',
80
+ initial: (prev, { name }) => {
81
+ const match = /^@(.*?)\//.exec(name)
82
+ if (match) return match[1]
83
+ },
84
+ message: 'GitHub organization:',
85
+ validate: required,
86
+ },
87
+ {
88
+ type: 'text',
89
+ name: 'repo',
90
+ message: 'GitHub repo:',
91
+ initial: (prev, { name }) => name.replace(/^@(.*?)\//, ''),
92
+ validate: required,
93
+ },
94
+ ]),
75
95
  {
76
96
  type: 'select',
77
97
  name: 'license',
@@ -116,26 +136,45 @@ async function create(args = []) {
116
136
  keywords,
117
137
  license,
118
138
  copyrightHolder,
119
- organization,
120
- repo,
121
139
  } = answers
122
140
 
141
+ const { organization, repo } = monorepoPackageJson
142
+ ? parseRepositoryUrl(monorepoPackageJson.repository.url)
143
+ : answers
144
+
123
145
  const cwd = path.resolve(directory)
124
146
 
125
147
  await require('fs-extra').mkdirs(path.join(cwd, 'src'))
126
148
 
127
149
  const fs = ChdirFs(cwd)
128
150
 
151
+ const subpackagePath = monorepoProjectDir
152
+ ? path.relative(monorepoProjectDir, cwd)
153
+ : undefined
154
+
155
+ const branch = subpackagePath
156
+ ? (
157
+ await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
158
+ stdio: 'pipe',
159
+ encoding: 'utf8',
160
+ maxBuffer: 1024,
161
+ })
162
+ ).stdout.trim()
163
+ : ''
164
+
129
165
  const packageJson = {
130
166
  name,
131
167
  description,
132
168
  repository: {
133
169
  type: 'git',
134
170
  url: `https://github.com/${organization}/${repo}.git`,
171
+ ...(subpackagePath ? { directory: subpackagePath } : {}),
135
172
  },
136
- homepage: `https://github.com/${organization}/${repo}`,
173
+ homepage: `https://github.com/${organization}/${repo}${
174
+ subpackagePath ? `/tree/${branch}/${subpackagePath}` : ''
175
+ }`,
137
176
  bugs: {
138
- url: `https://github.com/${organization}/${repo}`,
177
+ url: `https://github.com/${organization}/${repo}/issues`,
139
178
  },
140
179
  author,
141
180
  license,
@@ -173,21 +212,41 @@ async function create(args = []) {
173
212
  })
174
213
  )
175
214
 
176
- await execa('git', ['init'], { cwd })
177
- await execa('git', ['remote', 'add', 'origin', packageJson.repository.url], {
178
- cwd,
179
- })
215
+ if (!monorepoPackageJson) {
216
+ await execa('git', ['init'], { cwd })
217
+ await execa(
218
+ 'git',
219
+ ['remote', 'add', 'origin', packageJson.repository.url],
220
+ {
221
+ cwd,
222
+ }
223
+ )
224
+ }
225
+
226
+ const isTest = Boolean(process.env.JCOREIO_TOOLCHAIN_SELF_TEST)
227
+
180
228
  await execa(
181
229
  'pnpm',
182
- ['add', '-D', '--prefer-offline', '--no-optional', pkgName],
230
+ [
231
+ 'add',
232
+ '-D',
233
+ '--prefer-offline',
234
+ `${pkg.name}@${isTest ? 'workspace:*' : pkg.version}`,
235
+ ],
183
236
  { cwd }
184
237
  )
185
238
  await execa('pnpm', ['exec', 'tc', 'init'], { cwd })
186
239
 
187
- await execa('git', ['add', '.'], { cwd })
188
- await execa('git', ['commit', '-m', 'chore: initial commit from tc create'], {
189
- cwd,
190
- })
240
+ if (!monorepoPackageJson) {
241
+ await execa('git', ['add', '.'], { cwd })
242
+ await execa(
243
+ 'git',
244
+ ['commit', '-m', 'chore: initial commit from tc create'],
245
+ {
246
+ cwd,
247
+ }
248
+ )
249
+ }
191
250
  }
192
251
 
193
252
  exports.description = 'create a new toolchain project'
package/scripts/init.cjs CHANGED
@@ -47,6 +47,7 @@ async function init(args = []) {
47
47
  'react',
48
48
  'circle',
49
49
  'semantic-release',
50
+ 'aws-lambda',
50
51
  ].map((value) => ({
51
52
  title: `${name}-${value}`,
52
53
  value: `${name}-${value}`,
@@ -69,7 +70,6 @@ async function init(args = []) {
69
70
  await execa('pnpm', [
70
71
  'add',
71
72
  '-D',
72
- '--no-optional',
73
73
  '--prefer-offline',
74
74
  ...(isMonorepoRoot ? ['-w'] : []),
75
75
  isTest ? '../packages/base' : `${name}@^${version}`,
@@ -34,7 +34,6 @@ async function migrate(args = []) {
34
34
  if (!args.includes('--config-only')) {
35
35
  await execa('pnpm', [
36
36
  'i',
37
- '--no-optional',
38
37
  '--prefer-offline',
39
38
  '--fix-lockfile',
40
39
  ...(isMonorepoRoot ? ['-w'] : []),
@@ -1,12 +1,17 @@
1
1
  const execa = require('../util/execa.cjs')
2
+ const { isMonorepoRoot, packageJson } = require('../util/findUps.cjs')
2
3
 
3
4
  exports.run = async function (args = []) {
4
- const { scripts } = require('./toolchain.cjs')
5
- await execa('tc', ['check'])
6
- if (scripts.coverage) await execa('tc', ['coverage'])
7
- if (scripts['test:esm']) await execa('tc', ['test:esm'])
8
- await execa('tc', ['build'])
9
- await execa('tc', ['build:smoke-test'])
5
+ if (isMonorepoRoot && packageJson.name !== '@jcoreio/toolchains') {
6
+ await execa('pnpm', ['run', '-r', 'prepublish'])
7
+ } else {
8
+ const { scripts } = require('./toolchain.cjs')
9
+ await execa('tc', ['check'])
10
+ if (scripts.coverage) await execa('tc', ['coverage'])
11
+ if (scripts['test:esm']) await execa('tc', ['test:esm'])
12
+ await execa('tc', ['build'])
13
+ await execa('tc', ['build:smoke-test'])
14
+ }
10
15
  }
11
16
 
12
17
  exports.description = 'run check, coverage, and build'
@@ -5,9 +5,9 @@ const chalk = require('chalk')
5
5
  const getPluginsObjectSync = require('../util/getPluginsObjectSync.cjs')
6
6
  const execa = require('../util/execa.cjs')
7
7
 
8
- let toolchainConfig
8
+ let toolchainConfig, isMonorepoRoot
9
9
  try {
10
- ;({ toolchainConfig } = require('../util/findUps.cjs'))
10
+ ;({ toolchainConfig, isMonorepoRoot } = require('../util/findUps.cjs'))
11
11
  } catch (error) {
12
12
  if (!error.message.startsWith('failed to find project package.json')) {
13
13
  throw error
@@ -36,6 +36,7 @@ const scripts = toolchainConfig
36
36
  },
37
37
  },
38
38
  'install-git-hooks': require('./install-git-hooks.cjs'),
39
+ ...(isMonorepoRoot ? { create: require('./create.cjs') } : {}),
39
40
  ...getPluginsObjectSync('scripts'),
40
41
  ...Object.fromEntries(
41
42
  Object.entries(toolchainConfig.scripts || {}).map(([name, script]) => [
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { packageJson, isMonorepoRoot } = require('../util/findUps.cjs')
3
+ const { packageJson, monorepoProjectDir } = require('../util/findUps.cjs')
4
4
  const execa = require('../util/execa.cjs')
5
5
  const { name } = require('../package.json')
6
6
 
@@ -19,18 +19,27 @@ async function upgrade([version] = []) {
19
19
  ).stdout.trim()
20
20
  }
21
21
 
22
- await execa('pnpm', [
23
- 'add',
24
- '-D',
25
- '--no-optional',
26
- '--prefer-offline',
27
- ...(isMonorepoRoot ? ['-w'] : []),
28
- isTest ? '../packages/base' : `${name}@^${version}`,
29
- ...(isTest
30
- ? toolchains.map((t) => t.replace(`${name}-`, '../packages/'))
31
- : toolchains.map((t) => `${t}@^${version}`)),
32
- ])
33
- await execa('tc', ['migrate'])
22
+ await execa(
23
+ 'pnpm',
24
+ isTest
25
+ ? [
26
+ ...(monorepoProjectDir ? ['-r'] : []),
27
+ 'add',
28
+ '-D',
29
+ '--prefer-offline',
30
+ '../packages/base',
31
+ ...toolchains.map((t) => t.replace(`${name}-`, '../packages/')),
32
+ ]
33
+ : [
34
+ ...(monorepoProjectDir ? ['-r'] : []),
35
+ 'update',
36
+ '--prefer-offline',
37
+ `${name}@^${version}`,
38
+ toolchains.map((t) => `${t}@^${version}`),
39
+ ]
40
+ )
41
+ if (monorepoProjectDir) await execa('pnpm', ['-r', 'run', 'tc', 'migrate'])
42
+ else await execa('tc', ['migrate'])
34
43
  }
35
44
 
36
45
  exports.description = 'upgrade toolchains and migrate'
package/util/ChdirFs.cjs CHANGED
@@ -10,6 +10,10 @@ function ChdirFs(cwd) {
10
10
  emptyDir: (path, ...args) => fs.emptyDir(resolve(cwd, path), ...args),
11
11
  emptyDirSync: (path, ...args) =>
12
12
  fs.emptyDirSync(resolve(cwd, path), ...args),
13
+ ensureSymlink: (src, dest, ...args) =>
14
+ fs.ensureSymlink(resolve(cwd, src), resolve(cwd, dest), ...args),
15
+ ensureSymlinkSync: (src, dest, ...args) =>
16
+ fs.ensureSymlinkSync(resolve(cwd, src), resolve(cwd, dest), ...args),
13
17
  lstat: (path, ...args) => fs.lstat(resolve(cwd, path), ...args),
14
18
  stat: (path, ...args) => fs.stat(resolve(cwd, path), ...args),
15
19
  lstatSync: (path, ...args) => fs.lstatSync(resolve(cwd, path), ...args),
package/util/execa.cjs CHANGED
@@ -37,8 +37,8 @@ function getExecaArgs(command, args, options, ...rest) {
37
37
 
38
38
  const opts = {
39
39
  stdio: 'inherit',
40
- cwd: projectDir,
41
40
  ...options,
41
+ cwd: options.cwd ? Path.resolve(projectDir, options.cwd) : projectDir,
42
42
  env: {
43
43
  ...process.env,
44
44
  ...options.env,
package/util/findUps.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  const findUp = require('find-up')
2
2
  const Path = require('path')
3
3
  const fs = require('fs-extra')
4
+ const glob = require('glob')
4
5
  const merge = require('./merge.cjs')
5
6
  const once = require('./once.cjs')
6
7
  const { name } = require('../package.json')
@@ -59,6 +60,16 @@ exports.monorepoPackageJson = monorepoPackageJsonFile
59
60
  ? fs.readJsonSync(monorepoPackageJsonFile)
60
61
  : undefined
61
62
 
63
+ exports.monorepoSubpackageJsonFiles = pnpmWorkspace
64
+ ? [
65
+ ...new Set(
66
+ pnpmWorkspace.packages.flatMap((p) =>
67
+ glob.sync(Path.join(p, 'package.json'), { cwd: monorepoProjectDir })
68
+ )
69
+ ),
70
+ ].map((f) => Path.resolve(monorepoProjectDir, f))
71
+ : undefined
72
+
62
73
  const findGitDir = once(function findGitDir(cwd = process.cwd()) {
63
74
  let stopAt = Path.dirname(monorepoProjectDir || projectDir)
64
75
  if (stopAt === '/') stopAt = undefined
@@ -0,0 +1,11 @@
1
+ const { parse: parseUrl } = require('url')
2
+
3
+ const repoRegExp = new RegExp('^/(.+?)/([^/.]+)')
4
+
5
+ module.exports = function parseRepositoryUrl(url) {
6
+ const parsed = parseUrl(url)
7
+ const match = repoRegExp.exec(parsed.path || '')
8
+ if (!match) throw new Error(`unsupported source repository url: ${url}`)
9
+ const [organization, repo] = match.slice(1)
10
+ return { ...parsed, organization, repo }
11
+ }