@@ -86,31 +86,59 @@ function waitTimeMs(ms) {
86
86
} ) ;
87
87
}
88
88
89
- /**
90
- * Create isAliveURI function with options
91
- * @param {object } options
92
- * @returns {isAliveURI }
93
- */
94
- const createCheckAliveURL = ( options ) => {
95
- const keepAliveAgents = {
96
- http : new http . Agent ( { keepAlive : true } ) ,
97
- https : new https . Agent ( { keepAlive : true } ) ,
98
- } ;
89
+ const keepAliveAgents = {
90
+ http : new http . Agent ( { keepAlive : true } ) ,
91
+ https : new https . Agent ( { keepAlive : true } ) ,
92
+ } ;
93
+
94
+ const createFetchWithRuleDefaults = ( ruleOptions ) => {
99
95
/**
100
96
* Use library agent, avoid to use global.http(s)Agent
101
97
* Want to avoid Socket hang up
102
98
* @param parsedURL
103
99
* @returns {module:http.Agent|null|module:https.Agent }
104
100
*/
105
101
const getAgent = ( parsedURL ) => {
106
- if ( ! options . keepAlive ) {
102
+ if ( ! ruleOptions . keepAlive ) {
107
103
return null ;
108
104
}
109
105
if ( parsedURL . protocol === 'http:' ) {
110
106
return keepAliveAgents . http ;
111
107
}
112
108
return keepAliveAgents . https ;
113
109
} ;
110
+
111
+ return ( uri , fetchOptions ) => {
112
+ const { host } = URL . parse ( uri ) ;
113
+ return fetch ( uri , {
114
+ ...fetchOptions ,
115
+ // Disable gzip compression in Node.js
116
+ // to avoid the zlib's "unexpected end of file" error
117
+ // https://github.com/request/request/issues/2045
118
+ compress : false ,
119
+ // Some website require UserAgent and Accept header
120
+ // to avoid ECONNRESET error
121
+ // https://github.com/textlint-rule/textlint-rule-no-dead-link/issues/111
122
+ headers : {
123
+ 'User-Agent' : 'textlint-rule-no-dead-link/1.0' ,
124
+ 'Accept' : '*/*' ,
125
+ // Same host for target url
126
+ // https://github.com/textlint-rule/textlint-rule-no-dead-link/issues/111
127
+ 'Host' : host ,
128
+ } ,
129
+ // custom http(s).agent
130
+ agent : getAgent ,
131
+ } ) ;
132
+ } ;
133
+ } ;
134
+ /**
135
+ * Create isAliveURI function with ruleOptions
136
+ * @param {object } ruleOptions
137
+ * @returns {isAliveURI }
138
+ */
139
+ const createCheckAliveURL = ( ruleOptions ) => {
140
+ // Create fetch function for this rule
141
+ const fetchWithDefaults = createFetchWithRuleDefaults ( ruleOptions ) ;
114
142
/**
115
143
* Checks if a given URI is alive or not.
116
144
*
@@ -127,39 +155,21 @@ const createCheckAliveURL = (options) => {
127
155
* @return {{ ok: boolean, redirect?: string, message: string } }
128
156
*/
129
157
return async function isAliveURI ( uri , method = 'HEAD' , maxRetryCount = 3 , currentRetryCount = 0 ) {
130
- const { host } = URL . parse ( uri ) ;
131
-
132
158
const opts = {
133
159
method,
134
- // Disable gzip compression in Node.js
135
- // to avoid the zlib's "unexpected end of file" error
136
- // https://github.com/request/request/issues/2045
137
- compress : false ,
138
- // Some website require UserAgent and Accept header
139
- // to avoid ECONNRESET error
140
- // https://github.com/textlint-rule/textlint-rule-no-dead-link/issues/111
141
- headers : {
142
- 'User-Agent' : 'textlint-rule-no-dead-link/1.0' ,
143
- 'Accept' : '*/*' ,
144
- // Same host for target url
145
- // https://github.com/textlint-rule/textlint-rule-no-dead-link/issues/111
146
- 'Host' : host ,
147
- } ,
148
160
// Use `manual` redirect behaviour to get HTTP redirect status code
149
161
// and see what kind of redirect is occurring
150
162
redirect : 'manual' ,
151
- // custom http(s).agent
152
- agent : getAgent ,
153
163
} ;
154
164
try {
155
- const res = await fetch ( uri , opts ) ;
156
-
165
+ const res = await fetchWithDefaults ( uri , opts ) ;
166
+ // redirected
157
167
if ( isRedirect ( res . status ) ) {
158
- const finalRes = await fetch (
159
- uri ,
160
- Object . assign ( { } , opts , { redirect : 'follow' } ) ,
168
+ const redirectedUrl = res . headers . get ( 'Location' ) ;
169
+ const finalRes = await fetchWithDefaults (
170
+ redirectedUrl ,
171
+ { ...opts , redirect : 'follow' } ,
161
172
) ;
162
-
163
173
const { hash } = URL . parse ( uri ) ;
164
174
return {
165
175
ok : finalRes . ok ,
@@ -168,7 +178,7 @@ const createCheckAliveURL = (options) => {
168
178
message : `${ res . status } ${ res . statusText } ` ,
169
179
} ;
170
180
}
171
-
181
+ // retry if it is not ok when use head request
172
182
if ( ! res . ok && method === 'HEAD' && currentRetryCount < maxRetryCount ) {
173
183
return isAliveURI ( uri , 'GET' , maxRetryCount , currentRetryCount + 1 ) ;
174
184
}
@@ -222,8 +232,8 @@ async function isAliveLocalFile(filePath) {
222
232
function reporter ( context , options = { } ) {
223
233
const { Syntax, getSource, report, RuleError, fixer, getFilePath } = context ;
224
234
const helper = new RuleHelper ( context ) ;
225
- const opts = Object . assign ( { } , DEFAULT_OPTIONS , options ) ;
226
- const isAliveURI = createCheckAliveURL ( opts ) ;
235
+ const ruleOptions = { ... DEFAULT_OPTIONS , ... options } ;
236
+ const isAliveURI = createCheckAliveURL ( ruleOptions ) ;
227
237
// 30sec memorized
228
238
const memorizedIsAliveURI = pMemoize ( isAliveURI , {
229
239
maxAge : 30 * 1000 ,
@@ -236,17 +246,17 @@ function reporter(context, options = {}) {
236
246
* @param {number } maxRetryCount retry count of linting
237
247
*/
238
248
const lint = async ( { node, uri, index } , maxRetryCount ) => {
239
- if ( isIgnored ( uri , opts . ignore ) ) {
249
+ if ( isIgnored ( uri , ruleOptions . ignore ) ) {
240
250
return ;
241
251
}
242
252
243
253
if ( isRelative ( uri ) ) {
244
- if ( ! opts . checkRelative ) {
254
+ if ( ! ruleOptions . checkRelative ) {
245
255
return ;
246
256
}
247
257
248
258
const filePath = getFilePath ( ) ;
249
- const base = opts . baseURI || filePath ;
259
+ const base = ruleOptions . baseURI || filePath ;
250
260
if ( ! base ) {
251
261
const message =
252
262
'Unable to resolve the relative URI. Please check if the base URI is correctly specified.' ;
@@ -266,7 +276,7 @@ function reporter(context, options = {}) {
266
276
}
267
277
268
278
const method =
269
- opts . preferGET . filter (
279
+ ruleOptions . preferGET . filter (
270
280
( origin ) => getURLOrigin ( uri ) === getURLOrigin ( origin ) ,
271
281
) . length > 0
272
282
? 'GET'
@@ -280,7 +290,7 @@ function reporter(context, options = {}) {
280
290
if ( ! ok ) {
281
291
const lintMessage = `${ uri } is dead. (${ message } )` ;
282
292
report ( node , new RuleError ( lintMessage , { index } ) ) ;
283
- } else if ( redirected && ! opts . ignoreRedirects ) {
293
+ } else if ( redirected && ! ruleOptions . ignoreRedirects ) {
284
294
const lintMessage = `${ uri } is redirected to ${ redirectTo } . (${ message } )` ;
285
295
const fix = fixer . replaceTextRange (
286
296
[ index , index + uri . length ] ,
@@ -341,11 +351,11 @@ function reporter(context, options = {}) {
341
351
342
352
[ `${ context . Syntax . Document } :exit` ] ( ) {
343
353
const queue = new PQueue ( {
344
- concurrency : opts . concurrency ,
345
- intervalCap : opts . intervalCap ,
346
- interval : opts . interval
354
+ concurrency : ruleOptions . concurrency ,
355
+ intervalCap : ruleOptions . intervalCap ,
356
+ interval : ruleOptions . interval ,
347
357
} ) ;
348
- const linkTasks = URIs . map ( ( item ) => ( ) => lint ( item , opts . retry ) ) ;
358
+ const linkTasks = URIs . map ( ( item ) => ( ) => lint ( item , ruleOptions . retry ) ) ;
349
359
return queue . addAll ( linkTasks ) ;
350
360
} ,
351
361
} ;
0 commit comments