jiek 1.0.0 → 1.0.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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/bin/jiek.js +13 -0
  4. package/dist/cli.cjs +5041 -0
  5. package/dist/cli.d.cts +112 -0
  6. package/dist/cli.d.ts +112 -0
  7. package/dist/cli.js +5010 -0
  8. package/dist/cli.min.cjs +19 -0
  9. package/dist/cli.min.js +19 -0
  10. package/dist/index.cjs +5 -0
  11. package/dist/index.d.cts +73 -0
  12. package/dist/index.d.ts +73 -0
  13. package/dist/index.js +3 -0
  14. package/dist/index.min.cjs +1 -0
  15. package/dist/index.min.js +1 -0
  16. package/dist/rollup/index.cjs +4688 -0
  17. package/dist/rollup/index.d.cts +53 -0
  18. package/dist/rollup/index.d.ts +53 -0
  19. package/dist/rollup/index.js +4673 -0
  20. package/dist/rollup/index.min.cjs +19 -0
  21. package/dist/rollup/index.min.js +19 -0
  22. package/package.json +89 -4
  23. package/src/cli.ts +9 -0
  24. package/src/commands/base.ts +8 -0
  25. package/src/commands/build.ts +158 -0
  26. package/src/commands/init.ts +373 -0
  27. package/src/commands/publish.ts +170 -0
  28. package/src/index.ts +8 -0
  29. package/src/inner.ts +11 -0
  30. package/src/merge-package-json.ts +75 -0
  31. package/src/rollup/base.ts +72 -0
  32. package/src/rollup/index.ts +422 -0
  33. package/src/rollup/plugins/globals.ts +34 -0
  34. package/src/rollup/plugins/progress.ts +26 -0
  35. package/src/rollup/plugins/skip.ts +23 -0
  36. package/src/rollup/utils/commonOptions.ts +9 -0
  37. package/src/rollup/utils/externalResolver.ts +21 -0
  38. package/src/rollup/utils/globalResolver.ts +13 -0
  39. package/src/rollup/utils/withMinify.ts +18 -0
  40. package/src/utils/filterSupport.ts +84 -0
  41. package/src/utils/getExports.ts +104 -0
  42. package/src/utils/getRoot.ts +16 -0
  43. package/src/utils/getWD.ts +31 -0
  44. package/src/utils/loadConfig.ts +93 -0
  45. package/src/utils/tsRegister.ts +26 -0
  46. package/index.js +0 -1
@@ -0,0 +1,422 @@
1
+ import '../rollup/base'
2
+
3
+ import fs from 'node:fs'
4
+ import { dirname, relative, resolve } from 'node:path'
5
+
6
+ import type { RecursiveRecord } from '@jiek/pkger/entrypoints'
7
+ import { getAllLeafs } from '@jiek/pkger/entrypoints'
8
+ import { dts } from '@jiek/rollup-plugin-dts'
9
+ import { getWorkspaceDir } from '@jiek/utils/getWorkspaceDir'
10
+ import commonjs from '@rollup/plugin-commonjs'
11
+ import json from '@rollup/plugin-json'
12
+ import { nodeResolve } from '@rollup/plugin-node-resolve'
13
+ import terser from '@rollup/plugin-terser'
14
+ import { sendMessage } from 'execa'
15
+ import { parse } from 'jsonc-parser'
16
+ import { isMatch } from 'micromatch'
17
+ import type { OutputOptions, OutputPlugin, RollupOptions } from 'rollup'
18
+ import esbuild from 'rollup-plugin-esbuild'
19
+ import ts from 'typescript'
20
+
21
+ import { getExports } from '../utils/getExports'
22
+ import { loadConfig } from '../utils/loadConfig'
23
+ import type { RollupProgressEvent, TemplateOptions } from './base'
24
+ import progress from './plugins/progress'
25
+ import skip from './plugins/skip'
26
+ import externalResolver from './utils/externalResolver'
27
+
28
+ interface PackageJSON {
29
+ name?: string
30
+ type?: string
31
+ exports?: Record<string, unknown> | string | string[]
32
+ }
33
+
34
+ const {
35
+ JIEK_ROOT,
36
+ JIEK_ENTRIES
37
+ } = process.env
38
+ const WORKSPACE_ROOT = JIEK_ROOT ?? getWorkspaceDir()
39
+ const COMMON_OPTIONS = {} satisfies RollupOptions
40
+ const COMMON_PLUGINS = [
41
+ json()
42
+ ]
43
+
44
+ const config = loadConfig() ?? {}
45
+ const { build = {} } = config
46
+ const jsOutdir = `./${
47
+ relative(
48
+ process.cwd(),
49
+ resolve(
50
+ (
51
+ typeof build?.output?.dir === 'object'
52
+ // the outdir only affect js output in this function
53
+ ? build.output.dir.js
54
+ : build?.output?.dir
55
+ ) ?? 'dist'
56
+ )
57
+ )
58
+ }`
59
+
60
+ const STYLE_REGEXP = /\.(css|s[ac]ss|less|styl)$/
61
+
62
+ // eslint-disable-next-line unused-imports/no-unused-vars
63
+ const debug = (...args: unknown[]) => sendMessage({ type: 'debug', data: args } satisfies RollupProgressEvent)
64
+
65
+ const resolveWorkspacePath = (p: string) => resolve(WORKSPACE_ROOT, p)
66
+
67
+ const pascalCase = (str: string) =>
68
+ str
69
+ .replace(/[@|/-](\w)/g, (_, $1) => $1.toUpperCase())
70
+ .replace(/(?:^|-)(\w)/g, (_, $1) => $1.toUpperCase())
71
+
72
+ const reveal = (obj: string | Record<string, unknown>, keys: string[]) =>
73
+ keys.reduce((acc, key) => {
74
+ if (typeof acc === 'string') throw new Error('key not found in exports')
75
+ if (!(key in acc)) throw new Error(`key ${key} not found in exports`)
76
+ return acc[key] as string | Record<string, unknown>
77
+ }, obj)
78
+
79
+ const withMinify = (
80
+ output: OutputOptions & {
81
+ plugins?: OutputPlugin[]
82
+ },
83
+ minify = build?.output?.minify
84
+ ) =>
85
+ minify === false
86
+ ? [output]
87
+ : minify === 'only-minify'
88
+ ? [{
89
+ ...output,
90
+ // TODO replace suffix when pubish to npm and the `build.output.minify` is 'only-minify'
91
+ // TODO resolve dts output file name
92
+ file: output.file?.replace(/(\.[cm]?js)$/, '.min$1'),
93
+ plugins: [
94
+ ...(output.plugins ?? []),
95
+ terser()
96
+ ]
97
+ }]
98
+ : [
99
+ output,
100
+ {
101
+ ...output,
102
+ file: output.file?.replace(/(\.[cm]?js)$/, '.min$1'),
103
+ plugins: [
104
+ ...(output.plugins ?? []),
105
+ terser()
106
+ ]
107
+ }
108
+ ]
109
+
110
+ type TSConfig = {
111
+ extends?: string | string[]
112
+ compilerOptions?: Record<string, unknown>
113
+ references?: { path: string }[]
114
+ files?: string[]
115
+ include?: string[]
116
+ exclude?: string[]
117
+ }
118
+
119
+ const getTSConfig = (p: string): TSConfig =>
120
+ !fs.existsSync(p) || !fs.statSync(p).isFile()
121
+ ? {}
122
+ : parse(fs.readFileSync(p, 'utf-8'), [], { allowTrailingComma: true, allowEmptyContent: true })
123
+
124
+ const getExtendTSConfig = (tsconfigPath: string): TSConfig => {
125
+ tsconfigPath = resolve(tsconfigPath)
126
+ const tsconfigPathDirname = dirname(tsconfigPath)
127
+ const { extends: exts, ...tsconfig } = getTSConfig(tsconfigPath)
128
+ const resolvePaths = (paths: string[] | undefined) => paths?.map(p => resolve(tsconfigPathDirname, p)) ?? []
129
+
130
+ const extendsPaths = resolvePaths(
131
+ exts ? Array.isArray(exts) ? exts : [exts] : []
132
+ )
133
+ if (extendsPaths.length === 0) return tsconfig
134
+ return extendsPaths
135
+ .map(getExtendTSConfig)
136
+ .concat(tsconfig)
137
+ // https://www.typescriptlang.org/tsconfig/#files:~:text=Currently%2C%20the%20only%20top%2Dlevel%20property%20that%20is%20excluded%20from%20inheritance%20is%20references.
138
+ // Currently, the only top-level property that is excluded from inheritance is references.
139
+ .reduce((acc, { compilerOptions = {}, references: _, ...curr }) => ({
140
+ ...acc,
141
+ ...curr,
142
+ compilerOptions: {
143
+ ...acc.compilerOptions,
144
+ ...compilerOptions
145
+ }
146
+ }), {})
147
+ }
148
+
149
+ const getCompilerOptionsByFilePath = (tsconfigPath: string, filePath: string): Record<string, unknown> | undefined => {
150
+ tsconfigPath = resolve(tsconfigPath)
151
+ filePath = resolve(filePath)
152
+ const tsconfigPathDirname = dirname(tsconfigPath)
153
+ // https://www.typescriptlang.org/tsconfig/#files:~:text=It%E2%80%99s%20worth%20noting%20that%20files%2C%20include%2C%20and%20exclude%20from%20the%20inheriting%20config%20file%20overwrite%20those%20from%20the%20base%20config%20file%2C%20and%20that%20circularity%20between%20configuration%20files%20is%20not%20allowed.
154
+ // It’s worth noting that files, include, and exclude from the inheriting config file overwrite
155
+ // those from the base config file, and that circularity between configuration files is not allowed.
156
+ const tsconfig = getExtendTSConfig(tsconfigPath)
157
+
158
+ const resolvePaths = (paths: string[] | undefined) => paths?.map(p => resolve(tsconfigPathDirname, p)) ?? []
159
+
160
+ const [
161
+ references,
162
+ files,
163
+ include,
164
+ exclude
165
+ ] = [
166
+ tsconfig.references?.map(({ path }) => path),
167
+ tsconfig.files,
168
+ tsconfig.include,
169
+ tsconfig.exclude
170
+ ].map(resolvePaths)
171
+ if (exclude.length > 0 && exclude.some(i => isMatch(filePath, i))) return
172
+
173
+ // when files or include is not empty, the tsconfig should be ignored
174
+ if (tsconfig.files?.length === 0 && tsconfig.include?.length === 0) return
175
+ let isInclude = false
176
+ isInclude ||= files.length > 0 && files.includes(filePath)
177
+ isInclude ||= include.length > 0 && include.some(i => isMatch(filePath, i))
178
+ if (isInclude) {
179
+ return tsconfig.compilerOptions ?? {}
180
+ } else {
181
+ // when files or include is not empty, but the file is not matched, the tsconfig should be ignored
182
+ if (
183
+ (tsconfig.files && tsconfig.files.length > 0)
184
+ || (tsconfig.include && tsconfig.include.length > 0)
185
+ ) return
186
+ }
187
+
188
+ references.reverse()
189
+ for (const ref of references) {
190
+ const compilerOptions = getCompilerOptionsByFilePath(ref, filePath)
191
+ if (compilerOptions) return compilerOptions
192
+ }
193
+ return tsconfig.compilerOptions
194
+ }
195
+
196
+ const generateConfigs = ({
197
+ path,
198
+ name,
199
+ input,
200
+ output,
201
+ external,
202
+ pkgIsModule,
203
+ conditionals
204
+ }: {
205
+ path: string
206
+ name: string
207
+ input: string
208
+ output: string
209
+ external: (string | RegExp)[]
210
+ pkgIsModule: boolean
211
+ conditionals: string[]
212
+ }, options: TemplateOptions = {}): RollupOptions[] => {
213
+ const isModule = conditionals.includes('import')
214
+ const isCommonJS = conditionals.includes('require')
215
+ const isBrowser = conditionals.includes('browser')
216
+ const dtsTSConfigPaths = [
217
+ resolveWorkspacePath('tsconfig.json'),
218
+ resolveWorkspacePath('tsconfig.dts.json')
219
+ ]
220
+ let dtsTSConfigPath: string | undefined
221
+ dtsTSConfigPaths.forEach(p => {
222
+ if (fs.existsSync(p) && fs.statSync(p).isFile()) {
223
+ dtsTSConfigPath = p
224
+ }
225
+ })
226
+ let compilerOptions: ts.CompilerOptions = {}
227
+ if (dtsTSConfigPath) {
228
+ const jsonCompilerOptions = getCompilerOptionsByFilePath(dtsTSConfigPath, resolve(input))
229
+ const { options, errors } = ts.convertCompilerOptionsFromJson(
230
+ jsonCompilerOptions,
231
+ dirname(dtsTSConfigPath)
232
+ )
233
+ if (errors.length > 0) {
234
+ throw new Error(errors.map(e => e.messageText).join('\n'))
235
+ }
236
+ compilerOptions = options
237
+ }
238
+ const exportConditions = [...conditionals, ...(compilerOptions.customConditions ?? [])]
239
+ const throughEventProps: RollupProgressEvent & { type: 'progress' } = {
240
+ type: 'progress',
241
+ data: { name, path, exportConditions, input }
242
+ }
243
+ const outdir = options?.output?.dir
244
+ return [
245
+ {
246
+ input,
247
+ external,
248
+ output: [
249
+ ...withMinify({
250
+ file: output,
251
+ name,
252
+ interop: 'auto',
253
+ sourcemap: typeof options?.output?.sourcemap === 'object'
254
+ ? options.output.sourcemap.js
255
+ : options?.output?.sourcemap,
256
+ format: isModule ? 'esm' : (
257
+ isCommonJS ? 'cjs' : (
258
+ isBrowser ? 'umd' : (
259
+ pkgIsModule ? 'esm' : 'cjs'
260
+ )
261
+ )
262
+ ),
263
+ strict: typeof options?.output?.strict === 'object'
264
+ ? options.output.strict.js
265
+ : options?.output?.strict
266
+ })
267
+ ],
268
+ plugins: [
269
+ nodeResolve({ exportConditions }),
270
+ import('rollup-plugin-postcss')
271
+ .then(({ default: postcss }) =>
272
+ postcss({
273
+ extract: resolve(output.replace(/\.[cm]?js$/, '.css')),
274
+ minimize: true
275
+ })
276
+ )
277
+ .catch(() => void 0),
278
+ esbuild(),
279
+ commonjs(),
280
+ progress({
281
+ onEvent: (event, message) =>
282
+ sendMessage(
283
+ {
284
+ ...throughEventProps,
285
+ data: { ...throughEventProps.data, event, message, tags: ['js'] }
286
+ } satisfies RollupProgressEvent
287
+ )
288
+ })
289
+ ]
290
+ },
291
+ {
292
+ input,
293
+ external,
294
+ output: [
295
+ {
296
+ dir: resolve((typeof outdir === 'object' ? outdir.dts : outdir) ?? 'dist'),
297
+ sourcemap: typeof options?.output?.sourcemap === 'object'
298
+ ? options.output.sourcemap.dts
299
+ : options?.output?.sourcemap,
300
+ entryFileNames: () =>
301
+ output
302
+ .replace(`${jsOutdir}/`, '')
303
+ .replace(/(\.[cm]?)js$/, '.d$1ts'),
304
+ strict: typeof options?.output?.strict === 'object'
305
+ ? options.output.strict.dts
306
+ : options?.output?.strict
307
+ }
308
+ ],
309
+ plugins: [
310
+ nodeResolve({ exportConditions }),
311
+ skip({ patterns: [STYLE_REGEXP] }),
312
+ dts({
313
+ respectExternal: true,
314
+ compilerOptions
315
+ }),
316
+ progress({
317
+ onEvent: (event, message) =>
318
+ sendMessage(
319
+ {
320
+ ...throughEventProps,
321
+ data: { ...throughEventProps.data, event, message, tags: ['dts'] }
322
+ } satisfies RollupProgressEvent
323
+ )
324
+ })
325
+ ]
326
+ }
327
+ ]
328
+ }
329
+
330
+ export function template(packageJSON: PackageJSON): RollupOptions[] {
331
+ const { name, type, exports: entrypoints } = packageJSON
332
+ const pkgIsModule = type === 'module'
333
+ if (!name) throw new Error('package.json name is required')
334
+ if (!entrypoints) throw new Error('package.json exports is required')
335
+
336
+ const entries = JIEK_ENTRIES
337
+ ?.split(',')
338
+ .map(e => e.trim())
339
+ .map(e => ({
340
+ 'index': '.'
341
+ }[e] ?? e))
342
+
343
+ const packageName = pascalCase(name)
344
+
345
+ const external = externalResolver(packageJSON as Record<string, unknown>)
346
+
347
+ const [filteredResolvedEntrypoints, exports] = getExports({
348
+ entrypoints,
349
+ pkgIsModule,
350
+ entries,
351
+ config
352
+ })
353
+
354
+ const leafMap = new Map<string, string[][]>()
355
+ getAllLeafs(filteredResolvedEntrypoints as RecursiveRecord<string>, ({ keys, value }) => {
356
+ if (typeof value === 'string') {
357
+ const keysArr = leafMap.get(value) ?? []
358
+ leafMap.set(value, keysArr)
359
+ keysArr.push(keys)
360
+ }
361
+ return false
362
+ })
363
+
364
+ const configs: RollupOptions[] = []
365
+ leafMap.forEach((keysArr, input) =>
366
+ keysArr.forEach((keys) => {
367
+ const [path, ...conditionals] = keys
368
+
369
+ const name = packageName + (path === '.' ? '' : pascalCase(path))
370
+ const keyExports = reveal(exports, keys)
371
+ const commonOptions = {
372
+ path,
373
+ name,
374
+ input,
375
+ external,
376
+ pkgIsModule
377
+ }
378
+
379
+ switch (typeof keyExports) {
380
+ case 'string': {
381
+ configs.push(...generateConfigs({
382
+ ...commonOptions,
383
+ output: keyExports,
384
+ conditionals
385
+ }, build))
386
+ break
387
+ }
388
+ case 'object': {
389
+ getAllLeafs(keyExports as RecursiveRecord<string>, ({ keys: nextKeys, value }) => {
390
+ const allConditionals = [...new Set([...conditionals, ...nextKeys])]
391
+ if (typeof value === 'string') {
392
+ configs.push(...generateConfigs({
393
+ ...commonOptions,
394
+ output: value,
395
+ conditionals: allConditionals
396
+ }, build))
397
+ }
398
+ return false
399
+ })
400
+ break
401
+ }
402
+ }
403
+ })
404
+ )
405
+ sendMessage(
406
+ {
407
+ type: 'init',
408
+ data: {
409
+ leafMap,
410
+ targetsLength: configs.length
411
+ }
412
+ } satisfies RollupProgressEvent
413
+ )
414
+ return configs.map(c => ({
415
+ ...COMMON_OPTIONS,
416
+ ...c,
417
+ plugins: [
418
+ ...COMMON_PLUGINS,
419
+ c.plugins
420
+ ]
421
+ }))
422
+ }
@@ -0,0 +1,34 @@
1
+ import type { Plugin, PluginImpl } from 'rollup'
2
+
3
+ import globalResolver from '../utils/globalResolver'
4
+
5
+ interface GlobalsOptions {
6
+ external?: (string | RegExp)[]
7
+ }
8
+
9
+ export function createGlobalsLinkage() {
10
+ let globals = {}
11
+ const dependencies = new Set<string>([])
12
+ return [
13
+ (({ external } = {}) => {
14
+ return {
15
+ name: 'globals',
16
+ resolveId(id) {
17
+ if (external?.some(dep => dep instanceof RegExp ? dep.test(id) : dep === id)) {
18
+ dependencies.add(id)
19
+ return { id, external: true }
20
+ }
21
+ return null
22
+ },
23
+ outputOptions(options) {
24
+ globals = [...dependencies].reduce((acc, value) => ({
25
+ ...acc,
26
+ [value]: globalResolver(value)
27
+ }), {})
28
+ return { ...options, globals }
29
+ }
30
+ }
31
+ }) as PluginImpl<GlobalsOptions>,
32
+ { outputOptions: options => ({ ...options, globals }) } as Plugin
33
+ ] as const
34
+ }
@@ -0,0 +1,26 @@
1
+ import type { PluginImpl } from 'rollup'
2
+
3
+ interface Options {
4
+ onEvent?: (event: string, message?: string) => void
5
+ }
6
+
7
+ export default ((options = {}) => {
8
+ const { onEvent } = options
9
+ return {
10
+ name: 'progress',
11
+ buildStart: () => onEvent?.('start', 'Start building...'),
12
+ buildEnd: () => onEvent?.('end', 'Build completed!'),
13
+ resolveId: {
14
+ order: 'post',
15
+ handler: source => onEvent?.('resolve', `Resolving ${source}...`)
16
+ },
17
+ load: {
18
+ order: 'post',
19
+ handler: id => onEvent?.('load', `Loading ${id}...`)
20
+ },
21
+ transform: {
22
+ order: 'post',
23
+ handler: (_, id) => onEvent?.('transform', `Transforming ${id}...`)
24
+ }
25
+ }
26
+ }) as PluginImpl<Options>
@@ -0,0 +1,23 @@
1
+ import type { PluginImpl } from 'rollup'
2
+
3
+ interface Options {
4
+ patterns?: (string | RegExp)[]
5
+ }
6
+
7
+ export default ((options = {}) => {
8
+ return {
9
+ name: 'skip',
10
+ // skip the specified files by `options.patterns`
11
+ load(id) {
12
+ if (
13
+ options.patterns?.some((pattern) =>
14
+ typeof pattern === 'string'
15
+ ? id.includes(pattern)
16
+ : pattern.test(id)
17
+ )
18
+ ) {
19
+ return ''
20
+ }
21
+ }
22
+ }
23
+ }) as PluginImpl<Options>
@@ -0,0 +1,9 @@
1
+ import type { OutputOptions } from 'rollup'
2
+
3
+ const defineOutput = <O extends OutputOptions>(output: O) => output
4
+
5
+ export const commonOutputOptions = defineOutput({
6
+ exports: 'named',
7
+ interop: 'auto',
8
+ sourcemap: true
9
+ })
@@ -0,0 +1,21 @@
1
+ import fs from 'node:fs'
2
+
3
+ export default function(json: Record<string, unknown>): (string | RegExp)[]
4
+ export default function(path?: string): (string | RegExp)[]
5
+ export default function(jsonOrPath: string | Record<string, unknown> = process.cwd()): (string | RegExp)[] {
6
+ const pkg = typeof jsonOrPath === 'string'
7
+ ? fs.existsSync(`${jsonOrPath}/package.json`)
8
+ ? JSON.parse(fs.readFileSync(`${jsonOrPath}/package.json`, 'utf-8'))
9
+ : {}
10
+ : jsonOrPath
11
+ const { dependencies = {}, peerDependencies = {}, optionalDependencies = {} } = pkg
12
+ const external = <(string | RegExp)[]> Object
13
+ .keys(dependencies)
14
+ .concat(Object.keys(peerDependencies))
15
+ .concat(Object.keys(optionalDependencies))
16
+ return external
17
+ .map(dep => new RegExp(`^${dep}(/.*)?$`))
18
+ .concat([
19
+ /^node:/
20
+ ])
21
+ }
@@ -0,0 +1,13 @@
1
+ export default function (external: string) {
2
+ // a/b => AB
3
+ // a-b => AB
4
+ // a@b => AB
5
+ // a@b/c => ABC
6
+ // node:a => a
7
+ // node:a_b => a_b
8
+ if (external.startsWith('node:')) {
9
+ return external.slice(5)
10
+ }
11
+ return external
12
+ .replace(/[@|/-](\w)/g, (_, $1) => $1.toUpperCase())
13
+ }
@@ -0,0 +1,18 @@
1
+ import terser from '@rollup/plugin-terser'
2
+ import type { OutputOptions, OutputPlugin } from 'rollup'
3
+
4
+ export default function(
5
+ output: OutputOptions & {
6
+ entryFileNames?: string
7
+ plugins?: OutputPlugin[]
8
+ }
9
+ ): OutputOptions[] {
10
+ return [
11
+ output,
12
+ {
13
+ ...output,
14
+ entryFileNames: output.entryFileNames?.replace(/(\.[cm]?js)$/, '.min$1'),
15
+ plugins: [...(output.plugins ?? []), terser()]
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,84 @@
1
+ import fs from 'node:fs'
2
+ import { createRequire } from 'node:module'
3
+ import path from 'node:path'
4
+
5
+ import { filterPackagesFromDir } from '@pnpm/filter-workspace-packages'
6
+ import { program } from 'commander'
7
+ import { load } from 'js-yaml'
8
+
9
+ import { getRoot } from './getRoot'
10
+ import { getWD } from './getWD'
11
+
12
+ export let type = ''
13
+
14
+ try {
15
+ const require = createRequire(import.meta.url)
16
+ require.resolve('@pnpm/filter-workspace-packages')
17
+ type = 'pnpm'
18
+ } catch { /* empty */ }
19
+ if (type !== '') {
20
+ program
21
+ .option('-f, --filter <filter>', 'filter packages')
22
+ }
23
+
24
+ interface ProjectsGraph {
25
+ wd: string
26
+ root: string
27
+ value?: Record<string, {
28
+ name?: string
29
+ type?: string
30
+ exports?: string | string[] | Record<string, unknown>
31
+ }>
32
+ }
33
+
34
+ export async function getSelectedProjectsGraph(): Promise<ProjectsGraph> {
35
+ let filter = program.getOptionValue('filter')
36
+ const root = getRoot()
37
+ const { wd, notWorkspace } = getWD()
38
+ if (!notWorkspace && type === 'pnpm') {
39
+ const pnpmWorkspaceFilePath = path.resolve(wd, 'pnpm-workspace.yaml')
40
+ const pnpmWorkspaceFileContent = fs.readFileSync(pnpmWorkspaceFilePath, 'utf-8')
41
+ const pnpmWorkspace = load(pnpmWorkspaceFileContent) as {
42
+ packages: string[]
43
+ }
44
+ if (root === wd && !filter) {
45
+ throw new Error('root path is workspace root, please provide a filter')
46
+ // TODO inquirer prompt support user select packages
47
+ }
48
+ if (root !== wd && !filter) {
49
+ const packageJSONIsExist = fs.existsSync(path.resolve(root, 'package.json'))
50
+ if (!packageJSONIsExist) {
51
+ throw new Error('root path is not workspace root, please provide a filter')
52
+ }
53
+ const packageJSON = JSON.parse(fs.readFileSync(path.resolve(root, 'package.json'), 'utf-8'))
54
+ if (!packageJSON.name) {
55
+ throw new Error('root path is not workspace root, please provide a filter')
56
+ }
57
+ filter = packageJSON.name
58
+ }
59
+ const { selectedProjectsGraph } = await filterPackagesFromDir(wd, [{
60
+ filter: filter ?? '',
61
+ followProdDepsOnly: true
62
+ }], {
63
+ prefix: root,
64
+ workspaceDir: wd,
65
+ patterns: pnpmWorkspace.packages
66
+ })
67
+ return {
68
+ wd,
69
+ root,
70
+ value: Object.entries(selectedProjectsGraph)
71
+ .reduce((acc, [key, value]) => {
72
+ acc[key] = value.package.manifest
73
+ return acc
74
+ }, {} as NonNullable<ProjectsGraph['value']>)
75
+ }
76
+ }
77
+ return {
78
+ wd,
79
+ root,
80
+ value: {
81
+ [wd]: JSON.parse(fs.readFileSync(path.resolve(wd, 'package.json'), 'utf-8'))
82
+ }
83
+ }
84
+ }