5
5
"use strict"
6
6
7
7
const path = require ( "path" )
8
+ const { accessSync, constants } = require ( "node:fs" )
9
+
8
10
const getConvertPath = require ( "../util/get-convert-path" )
9
11
const getPackageJson = require ( "../util/get-package-json" )
12
+ const getNpmignore = require ( "../util/get-npmignore" )
10
13
11
14
const NODE_SHEBANG = "#!/usr/bin/env node\n"
12
15
const SHEBANG_PATTERN = / ^ ( # ! .+ ?) ? ( \r ) ? \n / u
@@ -21,6 +24,15 @@ function simulateNodeResolutionAlgorithm(filePath, binField) {
21
24
return possibilities . includes ( binField )
22
25
}
23
26
27
+ function isExecutable ( path ) {
28
+ try {
29
+ accessSync ( path , constants . X_OK )
30
+ return true
31
+ } catch ( error ) {
32
+ return false
33
+ }
34
+ }
35
+
24
36
/**
25
37
* Checks whether or not a given path is a `bin` file.
26
38
*
@@ -95,26 +107,41 @@ module.exports = {
95
107
} ,
96
108
create ( context ) {
97
109
const sourceCode = context . sourceCode ?? context . getSourceCode ( ) // TODO: just use context.sourceCode when dropping eslint < v9
98
- let filePath = context . filename ?? context . getFilename ( )
110
+ const filePath = context . filename ?? context . getFilename ( )
99
111
if ( filePath === "<input>" ) {
100
112
return { }
101
113
}
102
- filePath = path . resolve ( filePath )
103
114
104
115
const p = getPackageJson ( filePath )
105
116
if ( ! p ) {
106
117
return { }
107
118
}
108
119
109
- const basedir = path . dirname ( p . filePath )
110
- filePath = path . join (
111
- basedir ,
112
- getConvertPath ( context ) (
113
- path . relative ( basedir , filePath ) . replace ( / \\ / gu, "/" )
114
- )
120
+ const packageDirectory = path . dirname ( p . filePath )
121
+
122
+ const originalAbsolutePath = path . resolve ( filePath )
123
+ const originalRelativePath = path
124
+ . relative ( packageDirectory , originalAbsolutePath )
125
+ . replace ( / \\ / gu, "/" )
126
+
127
+ const convertedRelativePath =
128
+ getConvertPath ( context ) ( originalRelativePath )
129
+ const convertedAbsolutePath = path . resolve (
130
+ packageDirectory ,
131
+ convertedRelativePath
132
+ )
133
+
134
+ const npmignore = getNpmignore ( convertedAbsolutePath )
135
+
136
+ const isFileBin = isBinFile (
137
+ convertedAbsolutePath ,
138
+ p . bin ,
139
+ packageDirectory
115
140
)
141
+ const isFileIgnored = npmignore . match ( convertedRelativePath )
142
+ const isFileExecutable = isExecutable ( originalAbsolutePath )
116
143
117
- const needsShebang = isBinFile ( filePath , p . bin , basedir )
144
+ const needsShebang = isFileBin || ( isFileIgnored && isFileExecutable )
118
145
const info = getShebangInfo ( sourceCode )
119
146
120
147
return {
0 commit comments