npm-packlist 10.0.4 → 11.1.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/README.md +45 -30
- package/lib/index.js +86 -47
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -30,11 +30,9 @@ arborist.loadActual().then((tree) => {
|
|
|
30
30
|
This uses the following rules:
|
|
31
31
|
|
|
32
32
|
1. If a `package.json` file is found, and it has a `files` list,
|
|
33
|
-
then ignore everything that isn't
|
|
34
|
-
readme, license, licence and copying files, if they exist, as well
|
|
35
|
-
as the package.json file itself.
|
|
36
|
-
copying files are included by default, but can be excluded using the
|
|
37
|
-
`files` list e.g. `"!readme"`.
|
|
33
|
+
then ignore everything that isn't matched by `files`. Always include the
|
|
34
|
+
root readme, license, licence and copying files, if they exist, as well
|
|
35
|
+
as the package.json file itself.
|
|
38
36
|
2. If there's no `package.json` file (or it has no `files` list), and
|
|
39
37
|
there is a `.npmignore` file, then ignore all the files in the
|
|
40
38
|
`.npmignore` file.
|
|
@@ -45,7 +43,7 @@ This uses the following rules:
|
|
|
45
43
|
bundled dependency. If it IS a bundled dependency, and it's a
|
|
46
44
|
symbolic link, then the target of the link is included, not the
|
|
47
45
|
symlink itself.
|
|
48
|
-
|
|
46
|
+
5. Unless they're explicitly included (by being in a `files` list, or
|
|
49
47
|
a `!negated` rule in a relevant `.npmignore` or `.gitignore`),
|
|
50
48
|
always ignore certain common cruft files:
|
|
51
49
|
|
|
@@ -58,48 +56,65 @@ This uses the following rules:
|
|
|
58
56
|
6. Darwin's `.DS_Store` files because wtf are those even
|
|
59
57
|
7. `npm-debug.log` files at the root of a project
|
|
60
58
|
|
|
61
|
-
You can explicitly re-include
|
|
62
|
-
|
|
59
|
+
You can explicitly re-include most of these with a negated ignore file rule.
|
|
60
|
+
A small set of files are always ignored regardless of `files` rules:
|
|
61
|
+
`.git`, `.npmrc`, and `node_modules`.
|
|
63
62
|
|
|
64
63
|
Only the `package.json` file in the very root of the project is ever
|
|
65
64
|
inspected for a `files` list. Below the top level of the root package,
|
|
66
65
|
`package.json` is treated as just another file, and no package-specific
|
|
67
66
|
semantics are applied.
|
|
68
67
|
|
|
69
|
-
###
|
|
68
|
+
### Interpretation of the `files` list
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
Each entry in the `package.json` `files` list is interpreted as a glob
|
|
71
|
+
pattern, expanded against the package root using node's built-in
|
|
72
|
+
[`fs.globSync`](https://nodejs.org/api/fs.html#fsglobsyncpattern-options).
|
|
73
|
+
Literal paths (`lib`, `src/index.js`) are valid globs and resolve to
|
|
74
|
+
themselves; pattern entries (`dist-*`, `**/*.js`) resolve to every
|
|
75
|
+
matching entry on disk; entries that match nothing are silently dropped.
|
|
74
76
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
When an entry matches a directory, the directory and all of its contents
|
|
78
|
+
are included. This is a documented convenience: writing
|
|
79
|
+
`"files": ["dist"]` does not require also writing `"dist/**"`.
|
|
77
80
|
|
|
78
|
-
|
|
81
|
+
A leading `!` makes the entry a negation, removing matches from the
|
|
82
|
+
result. Negations are evaluated in order, so a later positive entry
|
|
83
|
+
can re-include something a previous negation excluded.
|
|
79
84
|
|
|
80
|
-
|
|
85
|
+
#### Pattern semantics are anchored to the package root
|
|
81
86
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"files": [ "dir" ]
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
+
Glob patterns are evaluated as paths relative to the package root, not as
|
|
88
|
+
basename-anywhere matchers. In particular:
|
|
87
89
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
* `"*.js"` matches `.js` files at the package root, not at every depth.
|
|
91
|
+
Use `"**/*.js"` to match at every depth.
|
|
92
|
+
* `"!readme.md"` removes only the root `readme.md`. Use
|
|
93
|
+
`"!**/readme.md"` to remove `readme.md` at every depth.
|
|
91
94
|
|
|
92
|
-
|
|
95
|
+
Negations only exclude paths that exist on disk at packlist time: a `!path`
|
|
96
|
+
entry that matches nothing is silently dropped, same as a positive entry
|
|
97
|
+
that matches nothing. A typo'd negation has no effect.
|
|
93
98
|
|
|
94
|
-
|
|
99
|
+
#### Interaction with `.npmignore`
|
|
100
|
+
|
|
101
|
+
If a `package.json` `files` array is present, any **top-level**
|
|
102
|
+
`.npmignore` and `.gitignore` files are ignored: the `files` array is
|
|
103
|
+
the sole source of inclusion at the package root.
|
|
104
|
+
|
|
105
|
+
`.npmignore` files in subdirectories are still honored within their
|
|
106
|
+
subtree. For example, with this package.json:
|
|
107
|
+
|
|
108
|
+
```json
|
|
95
109
|
{
|
|
96
|
-
"files": ["dir
|
|
110
|
+
"files": [ "dir" ]
|
|
97
111
|
}
|
|
98
112
|
```
|
|
99
113
|
|
|
100
|
-
a `.npmignore`
|
|
101
|
-
|
|
102
|
-
|
|
114
|
+
a `.npmignore` at `dir/.npmignore` (and any nested subdirectory) will
|
|
115
|
+
be applied. This means a file listed both in `files` and excluded by a
|
|
116
|
+
nested `.npmignore` will be excluded from the tarball; if you need such
|
|
117
|
+
a file to ship, remove the `.npmignore` rule.
|
|
103
118
|
|
|
104
119
|
## API
|
|
105
120
|
|
package/lib/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { Walker: IgnoreWalker } = require('ignore-walk')
|
|
4
|
-
const {
|
|
5
|
-
const {
|
|
4
|
+
const { globSync } = require('glob')
|
|
5
|
+
const { readFileSync: readFile } = require('node:fs')
|
|
6
|
+
const { basename, dirname, extname, join, relative, resolve, sep } = require('node:path')
|
|
6
7
|
const { log } = require('proc-log')
|
|
7
8
|
|
|
8
9
|
// symbols used to represent synthetic rule sets
|
|
9
10
|
const defaultRules = Symbol('npm-packlist.rules.default')
|
|
11
|
+
const globalRules = Symbol('npm-packlist.rules.global')
|
|
10
12
|
const strictRules = Symbol('npm-packlist.rules.strict')
|
|
11
13
|
|
|
12
14
|
// There may be others, but :?|<> are handled by node-tar
|
|
@@ -83,13 +85,23 @@ class PackWalker extends IgnoreWalker {
|
|
|
83
85
|
follow: false,
|
|
84
86
|
// we path.resolve() here because ignore-walk doesn't do it and we want full paths
|
|
85
87
|
path: resolve(opts?.path || tree.path).replace(/\\/g, '/'),
|
|
86
|
-
|
|
88
|
+
// globalRules belongs on the root walker only. Child walkers reach it through
|
|
89
|
+
// parent.filterEntry, where package.json rules can still override it; reapplying
|
|
90
|
+
// globalRules at the child level would defeat that override.
|
|
91
|
+
ignoreFiles: opts?.ignoreFiles || (opts?.parent ? [
|
|
87
92
|
defaultRules,
|
|
88
93
|
'package.json',
|
|
89
94
|
'.npmignore',
|
|
90
95
|
'.gitignore',
|
|
91
96
|
strictRules,
|
|
92
|
-
]
|
|
97
|
+
] : [
|
|
98
|
+
defaultRules,
|
|
99
|
+
globalRules,
|
|
100
|
+
'package.json',
|
|
101
|
+
'.npmignore',
|
|
102
|
+
'.gitignore',
|
|
103
|
+
strictRules,
|
|
104
|
+
]),
|
|
93
105
|
}
|
|
94
106
|
|
|
95
107
|
super(options)
|
|
@@ -97,7 +109,8 @@ class PackWalker extends IgnoreWalker {
|
|
|
97
109
|
this.isPackage = options.isPackage
|
|
98
110
|
this.seen = options.seen || new Set()
|
|
99
111
|
this.tree = tree
|
|
100
|
-
this.
|
|
112
|
+
this.globalIgnoreFile = options.globalIgnoreFile || null
|
|
113
|
+
this.globalIgnoreRules = options.globalIgnoreRules || null
|
|
101
114
|
|
|
102
115
|
const additionalDefaults = []
|
|
103
116
|
if (options.prefix && options.workspaces) {
|
|
@@ -124,13 +137,34 @@ class PackWalker extends IgnoreWalker {
|
|
|
124
137
|
// go ahead and inject the default rules now
|
|
125
138
|
this.injectRules(defaultRules, [...defaults, ...additionalDefaults])
|
|
126
139
|
|
|
140
|
+
// inject the global rules from the user's ignore file. positioned between
|
|
141
|
+
// defaultRules and package.json so an explicit entry in the package "files"
|
|
142
|
+
// field can still override. only the root walker carries globalRules in its
|
|
143
|
+
// ignoreFiles list; child walkers see global exclusions via parent.filterEntry,
|
|
144
|
+
// which is what lets the package.json `!/path/**` override win.
|
|
145
|
+
if (this.globalIgnoreRules === null && this.globalIgnoreFile) {
|
|
146
|
+
try {
|
|
147
|
+
this.globalIgnoreRules = readFile(this.globalIgnoreFile, { encoding: 'utf8' })
|
|
148
|
+
} catch (err) {
|
|
149
|
+
// istanbul ignore next -- only ENOENT is expected here
|
|
150
|
+
if (err.code !== 'ENOENT') {
|
|
151
|
+
throw err
|
|
152
|
+
}
|
|
153
|
+
this.globalIgnoreRules = ''
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (this.globalIgnoreRules) {
|
|
157
|
+
this.injectRules(globalRules, [this.globalIgnoreRules])
|
|
158
|
+
// istanbul ignore else -- globalIgnoreRules without a filename only happens when
|
|
159
|
+
// a caller pre-populates rules directly instead of going through globalIgnoreFile
|
|
160
|
+
if (this.globalIgnoreFile) {
|
|
161
|
+
log.silly('global-ignore-file', `applied rules from ${this.globalIgnoreFile}`)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
127
165
|
if (!this.isPackage) {
|
|
128
|
-
// if this instance is not a package, then place some strict default rules
|
|
129
|
-
|
|
130
|
-
this.injectRules(strictRules, [
|
|
131
|
-
...strictDefaults,
|
|
132
|
-
...this.requiredFiles.map((file) => `!${file}`),
|
|
133
|
-
])
|
|
166
|
+
// if this instance is not a package, then place some strict default rules
|
|
167
|
+
this.injectRules(strictRules, [...strictDefaults])
|
|
134
168
|
}
|
|
135
169
|
}
|
|
136
170
|
|
|
@@ -234,15 +268,6 @@ class PackWalker extends IgnoreWalker {
|
|
|
234
268
|
return {
|
|
235
269
|
...super.walkerOpt(entry, opts),
|
|
236
270
|
ignoreFiles,
|
|
237
|
-
// we map over our own requiredFiles and pass ones that are within this entry
|
|
238
|
-
requiredFiles: this.requiredFiles
|
|
239
|
-
.map((file) => {
|
|
240
|
-
if (relative(file, entry) === '..') {
|
|
241
|
-
return relative(entry, file).replace(/\\/g, '/')
|
|
242
|
-
}
|
|
243
|
-
return false
|
|
244
|
-
})
|
|
245
|
-
.filter(Boolean),
|
|
246
271
|
}
|
|
247
272
|
}
|
|
248
273
|
|
|
@@ -295,46 +320,60 @@ class PackWalker extends IgnoreWalker {
|
|
|
295
320
|
'/node_modules',
|
|
296
321
|
'.npmrc',
|
|
297
322
|
'/package-lock.json',
|
|
323
|
+
'/npm-shrinkwrap.json',
|
|
298
324
|
'/yarn.lock',
|
|
299
325
|
'/pnpm-lock.yaml',
|
|
300
326
|
'/bun.lockb',
|
|
327
|
+
'/bun.lock',
|
|
301
328
|
]
|
|
302
329
|
|
|
303
330
|
// if we have a files array in our package, we need to pull rules from it
|
|
304
331
|
if (files) {
|
|
305
|
-
for (
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
332
|
+
for (const entry of files) {
|
|
333
|
+
const isNegation = entry.startsWith('!')
|
|
334
|
+
// normalize: strip leading `!`s, `./`, a single leading `/`, and trailing slashes.
|
|
335
|
+
// trailing slashes confuse glob; the leading forms are equivalent to their stripped versions for glob expansion.
|
|
336
|
+
const pattern = (isNegation ? entry.replace(/^!+/, '') : entry)
|
|
337
|
+
.replace(/^\.?\//, '')
|
|
338
|
+
.replace(/\/+$/, '')
|
|
339
|
+
if (!pattern) {
|
|
340
|
+
continue
|
|
309
341
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
342
|
+
|
|
343
|
+
// expand the entry as a glob against the package root.
|
|
344
|
+
// literal paths (e.g. `lib`, `lib/foo.js`) are valid globs and resolve to themselves;
|
|
345
|
+
// patterns (e.g. `dist-*`, `**/*.js`) resolve to all matching entries;
|
|
346
|
+
// typos and non-existent entries resolve to nothing.
|
|
347
|
+
let matches = []
|
|
314
348
|
try {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
349
|
+
matches = globSync(pattern, { cwd: this.path, withFileTypes: true, dot: true })
|
|
350
|
+
} catch {
|
|
351
|
+
// unparseable globs produce no matches and drop silently.
|
|
352
|
+
// (Pre-v11 instead fell through to push the raw entry as an ignore-walk pattern rule; we deliberately don't preserve that.)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// a positive entry produces `!path` rules (un-ignore from the surrounding `*` deny-all); a negation produces `path` rules (re-ignore them).
|
|
356
|
+
// directory matches expand to also include their contents; this is documented `files[]` behavior, not a glob hack.
|
|
357
|
+
const prefix = isNegation ? '' : '!'
|
|
358
|
+
for (const match of matches) {
|
|
359
|
+
const rel = match.relativePosix()
|
|
360
|
+
// istanbul ignore next -- defensive: glob with withFileTypes returns the cwd as an entry with an empty relative path; skip it.
|
|
361
|
+
if (!rel) {
|
|
362
|
+
continue
|
|
363
|
+
}
|
|
364
|
+
if (match.isDirectory()) {
|
|
365
|
+
ignores.push(`${prefix}/${rel}`)
|
|
366
|
+
ignores.push(`${prefix}/${rel}/**`)
|
|
367
|
+
continue
|
|
368
|
+
}
|
|
369
|
+
// istanbul ignore else -- non-file-non-dir matches (sockets, fifos, broken symlinks) drop silently.
|
|
370
|
+
if (match.isFile()) {
|
|
371
|
+
ignores.push(`${prefix}/${rel}`)
|
|
328
372
|
}
|
|
329
|
-
// if the thing exists, but is neither a file or a directory, we don't want it at all
|
|
330
|
-
} catch (err) {
|
|
331
|
-
// if lstat throws, then we assume we're looking at a pattern and treat it as a default
|
|
332
|
-
ignores.push(inverse)
|
|
333
373
|
}
|
|
334
374
|
}
|
|
335
375
|
|
|
336
|
-
// we prepend a '*' to exclude everything, followed by our inverted file rules
|
|
337
|
-
// which now mean to include those
|
|
376
|
+
// we prepend a '*' to exclude everything, followed by our inverted file rules which now mean to include those
|
|
338
377
|
this.injectRules('package.json', ['*', ...ignores])
|
|
339
378
|
}
|
|
340
379
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "npm-packlist",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.1.0",
|
|
4
4
|
"description": "Get a list of the files to add from a folder into an npm package",
|
|
5
5
|
"directories": {
|
|
6
6
|
"test": "test"
|
|
7
7
|
},
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"
|
|
11
|
-
"
|
|
10
|
+
"glob": "^13.0.6",
|
|
11
|
+
"ignore-walk": "^9.0.0",
|
|
12
|
+
"proc-log": "^7.0.0"
|
|
12
13
|
},
|
|
13
14
|
"author": "GitHub Inc.",
|
|
14
15
|
"license": "ISC",
|
|
@@ -18,8 +19,8 @@
|
|
|
18
19
|
],
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"@npmcli/arborist": "^9.0.0",
|
|
21
|
-
"@npmcli/eslint-config": "^
|
|
22
|
-
"@npmcli/template-oss": "
|
|
22
|
+
"@npmcli/eslint-config": "^7.0.0",
|
|
23
|
+
"@npmcli/template-oss": "5.1.0",
|
|
23
24
|
"mutate-fs": "^2.1.1",
|
|
24
25
|
"tap": "^16.0.1"
|
|
25
26
|
},
|
|
@@ -52,11 +53,12 @@
|
|
|
52
53
|
]
|
|
53
54
|
},
|
|
54
55
|
"engines": {
|
|
55
|
-
"node": "^
|
|
56
|
+
"node": "^22.22.2 || ^24.15.0 || >=26.0.0"
|
|
56
57
|
},
|
|
57
58
|
"templateOSS": {
|
|
58
59
|
"//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",
|
|
59
|
-
"version": "
|
|
60
|
-
"publish": true
|
|
60
|
+
"version": "5.1.0",
|
|
61
|
+
"publish": true,
|
|
62
|
+
"updateNpm": false
|
|
61
63
|
}
|
|
62
64
|
}
|