Skip to content
This repository was archived by the owner on Jan 19, 2022. It is now read-only.

Commit 973970b

Browse files
eridalclaudiahdz
authored andcommitted
Sorted tarball contents
This will make `npm pack` output the tarball contents in an alphabetically and natural sort order. The current implementation uses `localeCompare` with the following options: 1. **sensitivity**: `base`, to correctly handle non-ascii letters using their base ascii, so that `á`,`â`, `ä`, `ã`, `å` are all handled like `a` 1. **numbers**: `true`, to handle numeric filenames as natural ascending order so that, for instance, file `10.txt` appears after `9.txt` --- Convo from npm/rfcs#96 cc @ruyadorno @isaacs
1 parent 68f3130 commit 973970b

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

test/index.js

+57
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,60 @@ t.test('packs from registry spec', async t => {
180180
await rimraf(testDir)
181181
})
182182
})
183+
184+
t.test('files packed are alphabetically sorted', async (t) => {
185+
const testDir = t.testdir({
186+
index: 'index',
187+
dist: {
188+
'foo.js': 'foo',
189+
'foo.ts': 'foo',
190+
bar: 'bar',
191+
baz: 'baz'
192+
},
193+
numbers: {
194+
1: '1',
195+
11: '1',
196+
'01': '0',
197+
20: '2',
198+
2: '2',
199+
10: '1',
200+
0: '0'
201+
},
202+
'package.json': JSON.stringify({
203+
name: 'pkg'
204+
}),
205+
lib: {
206+
'index.js': 'lib/index',
207+
'foo.js': 'lib/foo'
208+
},
209+
'README.md': 'readme-1',
210+
'readme.txt': 'readme-2'
211+
})
212+
213+
const target = `${testDir}/my-cool-pkg-1.0.0.tgz`
214+
const tarContents = await pack(testDir, { target })
215+
const tarFilePaths = tarContents.files.map(file => file.path)
216+
const expectedOrder = [
217+
'README.md',
218+
'dist/bar',
219+
'dist/baz',
220+
'dist/foo.js',
221+
'dist/foo.ts',
222+
'index',
223+
'lib/foo.js',
224+
'lib/index.js',
225+
'numbers/0',
226+
'numbers/01',
227+
'numbers/1',
228+
'numbers/2',
229+
'numbers/10',
230+
'numbers/11',
231+
'numbers/20',
232+
'package.json',
233+
'readme.txt'
234+
]
235+
236+
t.deepEqual(tarFilePaths, expectedOrder,
237+
'files packed matches order expectations'
238+
)
239+
})

utils/tar.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,24 @@ async function getContents (manifest, target) {
8686
})
8787
])
8888

89+
const comparator = (a, b) => {
90+
return a.path.localeCompare(b.path, undefined, {
91+
sensitivity: 'case',
92+
numeric: true
93+
})
94+
}
95+
96+
const isUpper = (str) => {
97+
const ch = str.charAt(0)
98+
return ch >= 'A' && ch <= 'Z'
99+
}
100+
101+
const uppers = files.filter(file => isUpper(file.path))
102+
const others = files.filter(file => !isUpper(file.path))
103+
104+
uppers.sort(comparator)
105+
others.sort(comparator)
106+
89107
const shasum = integrity.sha1[0].hexDigest()
90108
return {
91109
id: manifest._id || `${manifest.name}@${manifest.version}`,
@@ -96,7 +114,7 @@ async function getContents (manifest, target) {
96114
shasum,
97115
integrity: ssri.parse(integrity.sha512[0]),
98116
filename: `${manifest.name}-${manifest.version}.tgz`,
99-
files,
117+
files: uppers.concat(others),
100118
entryCount: totalEntries,
101119
bundled: Array.from(bundled)
102120
}

0 commit comments

Comments
 (0)