Skip to content

Commit 41673db

Browse files
authored
feat: support workspaces (#369)
* feat: workspaces sort * chore: add tests * fix: snapshot
1 parent 140fcaa commit 41673db

File tree

5 files changed

+92
-7
lines changed

5 files changed

+92
-7
lines changed

index.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,42 @@ const sortObjectByIdent = (a, b) => {
103103
// https://github.com/npm/package-json/blob/b6465f44c727d6513db6898c7cbe41dd355cebe8/lib/update-dependencies.js#L8-L21
104104
const sortDependenciesLikeNpm = sortObjectBy((a, b) => a.localeCompare(b, 'en'))
105105

106+
const sortWorkspaces = (workspaces) => {
107+
// workspaces can be an array (yarn classic) or an object (pnpm/bun)
108+
if (Array.isArray(workspaces)) {
109+
return uniqAndSortArray(workspaces)
110+
}
111+
112+
if (isPlainObject(workspaces)) {
113+
// Sort known properties in a specific order
114+
const sortedWorkspaces = {}
115+
116+
// First add packages if it exists
117+
if (workspaces.packages) {
118+
sortedWorkspaces.packages = uniqAndSortArray(workspaces.packages)
119+
}
120+
121+
// Then add catalog if it exists and sort it like dependencies
122+
if (workspaces.catalog) {
123+
sortedWorkspaces.catalog = sortDependenciesLikeNpm(workspaces.catalog)
124+
}
125+
126+
// Add any other properties in alphabetical order
127+
const knownKeys = ['packages', 'catalog']
128+
const otherKeys = Object.keys(workspaces)
129+
.filter((key) => !knownKeys.includes(key))
130+
.sort()
131+
132+
for (const key of otherKeys) {
133+
sortedWorkspaces[key] = workspaces[key]
134+
}
135+
136+
return sortedWorkspaces
137+
}
138+
139+
return workspaces
140+
}
141+
106142
// https://github.com/eslint/eslint/blob/acc0e47572a9390292b4e313b4a4bf360d236358/conf/config-schema.js
107143
const eslintBaseConfigProperties = [
108144
// `files` and `excludedFiles` are only on `overrides[]`
@@ -325,7 +361,7 @@ const fields = [
325361
{ key: 'man' },
326362
{ key: 'directories', over: sortDirectories },
327363
{ key: 'files', over: uniq },
328-
{ key: 'workspaces' },
364+
{ key: 'workspaces', over: sortWorkspaces },
329365
// node-pre-gyp https://www.npmjs.com/package/node-pre-gyp#1-add-new-entries-to-your-packagejson
330366
{
331367
key: 'binary',

tests/deps.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,29 @@ for (const field of [
2727
test('peerDependenciesMeta', macro.sortObjectAlphabetically, {
2828
path: 'peerDependenciesMeta',
2929
maxDepth: 2,
30-
// TODO: don't use snapshot, find a esaier way for review
30+
// TODO: don't use snapshot, find a easier way for review
3131
expect: 'snapshot',
3232
})
3333

3434
// dependenciesMeta
3535
test('dependenciesMeta', macro.sortObjectAlphabetically, {
3636
path: 'dependenciesMeta',
3737
maxDepth: 2,
38-
// TODO: don't use snapshot, find a esaier way for review
38+
// TODO: don't use snapshot, find a easier way for review
3939
expect: 'snapshot',
4040
})
4141

4242
test('dependenciesMetaRange', macro.sortObjectWithRangeAlphabetically, {
4343
path: 'dependenciesMeta',
4444
maxDepth: 2,
45-
// TODO: don't use snapshot, find a esaier way for review
45+
// TODO: don't use snapshot, find a easier way for review
4646
expect: 'snapshot',
4747
})
4848

4949
test('pnpm.overrides', macro.sortObjectWithRangeAlphabetically, {
5050
path: 'pnpm.overrides',
5151
maxDepth: 2,
52-
// TODO: don't use snapshot, find a esaier way for review
52+
// TODO: don't use snapshot, find a easier way for review
5353
expect: 'snapshot',
5454
})
5555

tests/fields.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ for (const field of [
3232
'examplestyle',
3333
'assets',
3434
'man',
35-
'workspaces',
3635
'pre-commit',
3736
'browserslist',
3837
'stylelint',

tests/snapshots/main.js.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@ Generated by [AVA](https://avajs.dev).
166166
"man": "man",␊
167167
"directories": "directories",␊
168168
"files": "files",␊
169-
"workspaces": "workspaces",␊
170169
"binary": "binary",␊
171170
"scripts": "scripts",␊
172171
"betterScripts": "betterScripts",␊

tests/workspaces.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import test from 'ava'
2+
import sortPackageJson from '../index.js'
3+
import { sortPackageJsonAsObject } from './_helpers.js'
4+
5+
test('workspaces array (yarn) should be sorted and unique', (t) => {
6+
const packageJson = {
7+
workspaces: ['packages/c', 'packages/a', 'packages/b', 'packages/a'],
8+
}
9+
const sorted = sortPackageJson(packageJson)
10+
t.deepEqual(sorted.workspaces, ['packages/a', 'packages/b', 'packages/c'])
11+
})
12+
13+
test('workspaces object should be sorted', (t) => {
14+
const sortedWorkspaces = sortPackageJsonAsObject({
15+
path: 'workspaces',
16+
value: {
17+
zoo: '*', // other property
18+
packages: ['packages/c', 'packages/a', 'packages/b', 'packages/a'],
19+
catalog: {
20+
'is-even': 'npm:is-even@1.0.0',
21+
'is-odd': 'npm:is-odd@3.0.1',
22+
'alpha-lib': 'npm:alpha-lib@1.0.0',
23+
},
24+
animal: '*', // other property
25+
},
26+
})
27+
28+
const expect = {
29+
packages: ['packages/a', 'packages/b', 'packages/c'],
30+
catalog: {
31+
'alpha-lib': 'npm:alpha-lib@1.0.0',
32+
'is-even': 'npm:is-even@1.0.0',
33+
'is-odd': 'npm:is-odd@3.0.1',
34+
},
35+
animal: '*',
36+
zoo: '*',
37+
}
38+
39+
t.deepEqual(sortedWorkspaces, expect)
40+
})
41+
42+
test('workspaces with other types should be kept as it is', (t) => {
43+
for (const value of ['string', false, 2020, undefined, null]) {
44+
const type = value === null ? 'null' : typeof value
45+
t.is(
46+
sortPackageJsonAsObject({ path: 'workspaces', value }),
47+
value,
48+
`Should keep ${type} type \`workspaces\` as it is.`,
49+
)
50+
}
51+
})

0 commit comments

Comments
 (0)