@@ -27,6 +27,10 @@ const FB_PRETTIER_OPTIONS = {
27
27
28
28
const LINE_ENDING_RE = / \r \n | [ \r \n \u2028 \u2029 ] / ;
29
29
30
+ const OPERATION_INSERT = 'insert' ;
31
+ const OPERATION_DELETE = 'delete' ;
32
+ const OPERATION_REPLACE = 'replace' ;
33
+
30
34
// ------------------------------------------------------------------------------
31
35
// Privates
32
36
// ------------------------------------------------------------------------------
@@ -104,18 +108,13 @@ function showInvisibles(str) {
104
108
return ret ;
105
109
}
106
110
107
- // ------------------------------------------------------------------------------
108
- // Rule Definition
109
- // ------------------------------------------------------------------------------
110
-
111
111
/**
112
- * Reports issues where the context's source code differs from the Prettier
113
- formatted version.
114
- * @param {RuleContext } context - The ESLint rule context.
112
+ * Generate results for differences between source code and formatted version.
113
+ * @param {string } source - The original source.
115
114
* @param {string } prettierSource - The Prettier formatted source.
116
- * @returns {void }
115
+ * @returns {Array } - An array contains { operation, offset, insertText, deleteText }
117
116
*/
118
- function reportDifferences ( context , prettierSource ) {
117
+ function generateDifferences ( source , prettierSource ) {
119
118
// fast-diff returns the differences between two texts as a series of
120
119
// INSERT, DELETE or EQUAL operations. The results occur only in these
121
120
// sequences:
@@ -130,8 +129,8 @@ function reportDifferences(context, prettierSource) {
130
129
// and another's beginning does not have line endings (i.e. issues that occur
131
130
// on contiguous lines).
132
131
133
- const source = context . getSourceCode ( ) . text ;
134
132
const results = diff ( source , prettierSource ) ;
133
+ const differences = [ ] ;
135
134
136
135
const batch = [ ] ;
137
136
let offset = 0 ; // NOTE: INSERT never advances the offset.
@@ -166,6 +165,8 @@ function reportDifferences(context, prettierSource) {
166
165
}
167
166
}
168
167
168
+ return differences ;
169
+
169
170
function flush ( ) {
170
171
let aheadDeleteText = '' ;
171
172
let aheadInsertText = '' ;
@@ -187,16 +188,33 @@ function reportDifferences(context, prettierSource) {
187
188
}
188
189
}
189
190
if ( aheadDeleteText && aheadInsertText ) {
190
- reportReplace ( context , offset , aheadDeleteText , aheadInsertText ) ;
191
+ differences . push ( {
192
+ offset,
193
+ operation : OPERATION_REPLACE ,
194
+ insertText : aheadInsertText ,
195
+ deleteText : aheadDeleteText
196
+ } ) ;
191
197
} else if ( ! aheadDeleteText && aheadInsertText ) {
192
- reportInsert ( context , offset , aheadInsertText ) ;
198
+ differences . push ( {
199
+ offset,
200
+ operation : OPERATION_INSERT ,
201
+ insertText : aheadInsertText
202
+ } ) ;
193
203
} else if ( aheadDeleteText && ! aheadInsertText ) {
194
- reportDelete ( context , offset , aheadDeleteText ) ;
204
+ differences . push ( {
205
+ offset,
206
+ operation : OPERATION_DELETE ,
207
+ deleteText : aheadDeleteText
208
+ } ) ;
195
209
}
196
210
offset += aheadDeleteText . length ;
197
211
}
198
212
}
199
213
214
+ // ------------------------------------------------------------------------------
215
+ // Rule Definition
216
+ // ------------------------------------------------------------------------------
217
+
200
218
/**
201
219
* Reports an "Insert ..." issue where text must be inserted.
202
220
* @param {RuleContext } context - The ESLint rule context.
@@ -268,68 +286,99 @@ function reportReplace(context, offset, deleteText, insertText) {
268
286
// Module Definition
269
287
// ------------------------------------------------------------------------------
270
288
271
- module . exports . rules = {
272
- prettier : {
273
- meta : {
274
- fixable : 'code' ,
275
- schema : [
276
- // Prettier options:
277
- {
278
- anyOf : [
279
- { enum : [ null , 'fb' ] } ,
280
- { type : 'object' , properties : { } , additionalProperties : true }
281
- ]
282
- } ,
283
- // Pragma:
284
- { type : 'string' , pattern : '^@\\w+$' }
285
- ]
286
- } ,
287
- create ( context ) {
288
- const prettierOptions = context . options [ 0 ] === 'fb'
289
- ? FB_PRETTIER_OPTIONS
290
- : context . options [ 0 ] ;
291
-
292
- const pragma = context . options [ 1 ]
293
- ? context . options [ 1 ] . slice ( 1 ) // Remove leading @
294
- : null ;
289
+ module . exports = {
290
+ showInvisibles,
291
+ generateDifferences,
292
+ rules : {
293
+ prettier : {
294
+ meta : {
295
+ fixable : 'code' ,
296
+ schema : [
297
+ // Prettier options:
298
+ {
299
+ anyOf : [
300
+ { enum : [ null , 'fb' ] } ,
301
+ { type : 'object' , properties : { } , additionalProperties : true }
302
+ ]
303
+ } ,
304
+ // Pragma:
305
+ { type : 'string' , pattern : '^@\\w+$' }
306
+ ]
307
+ } ,
308
+ create ( context ) {
309
+ const prettierOptions = context . options [ 0 ] === 'fb'
310
+ ? FB_PRETTIER_OPTIONS
311
+ : context . options [ 0 ] ;
295
312
296
- const sourceCode = context . getSourceCode ( ) ;
297
- const source = sourceCode . text ;
313
+ const pragma = context . options [ 1 ]
314
+ ? context . options [ 1 ] . slice ( 1 ) // Remove leading @
315
+ : null ;
298
316
299
- // The pragma is only valid if it is found in a block comment at the very
300
- // start of the file.
301
- if ( pragma ) {
302
- // ESLint 3.x reports the shebang as a "Line" node, while ESLint 4.x
303
- // reports it as a "Shebang" node. This works for both versions:
304
- const hasShebang = source . startsWith ( '#!' ) ;
305
- const allComments = sourceCode . getAllComments ( ) ;
306
- const firstComment = hasShebang ? allComments [ 1 ] : allComments [ 0 ] ;
307
- if (
308
- ! ( firstComment &&
309
- firstComment . type === 'Block' &&
310
- firstComment . loc . start . line === ( hasShebang ? 2 : 1 ) &&
311
- firstComment . loc . start . column === 0 )
312
- ) {
313
- return { } ;
314
- }
315
- const parsed = docblock . parse ( firstComment . value ) ;
316
- if ( parsed [ pragma ] !== '' ) {
317
- return { } ;
318
- }
319
- }
317
+ const sourceCode = context . getSourceCode ( ) ;
318
+ const source = sourceCode . text ;
320
319
321
- return {
322
- Program ( ) {
323
- if ( ! prettier ) {
324
- // Prettier is expensive to load, so only load it if needed.
325
- prettier = require ( 'prettier' ) ;
320
+ // The pragma is only valid if it is found in a block comment at the very
321
+ // start of the file.
322
+ if ( pragma ) {
323
+ // ESLint 3.x reports the shebang as a "Line" node, while ESLint 4.x
324
+ // reports it as a "Shebang" node. This works for both versions:
325
+ const hasShebang = source . startsWith ( '#!' ) ;
326
+ const allComments = sourceCode . getAllComments ( ) ;
327
+ const firstComment = hasShebang ? allComments [ 1 ] : allComments [ 0 ] ;
328
+ if (
329
+ ! ( firstComment &&
330
+ firstComment . type === 'Block' &&
331
+ firstComment . loc . start . line === ( hasShebang ? 2 : 1 ) &&
332
+ firstComment . loc . start . column === 0 )
333
+ ) {
334
+ return { } ;
326
335
}
327
- const prettierSource = prettier . format ( source , prettierOptions ) ;
328
- if ( source !== prettierSource ) {
329
- reportDifferences ( context , prettierSource ) ;
336
+ const parsed = docblock . parse ( firstComment . value ) ;
337
+ if ( parsed [ pragma ] !== '' ) {
338
+ return { } ;
330
339
}
331
340
}
332
- } ;
341
+
342
+ return {
343
+ Program ( ) {
344
+ if ( ! prettier ) {
345
+ // Prettier is expensive to load, so only load it if needed.
346
+ prettier = require ( 'prettier' ) ;
347
+ }
348
+ const prettierSource = prettier . format ( source , prettierOptions ) ;
349
+ if ( source !== prettierSource ) {
350
+ const differences = generateDifferences ( source , prettierSource ) ;
351
+
352
+ differences . forEach ( difference => {
353
+ switch ( difference . operation ) {
354
+ case OPERATION_INSERT :
355
+ reportInsert (
356
+ context ,
357
+ difference . offset ,
358
+ difference . insertText
359
+ ) ;
360
+ break ;
361
+ case OPERATION_DELETE :
362
+ reportDelete (
363
+ context ,
364
+ difference . offset ,
365
+ difference . deleteText
366
+ ) ;
367
+ break ;
368
+ case OPERATION_REPLACE :
369
+ reportReplace (
370
+ context ,
371
+ difference . offset ,
372
+ difference . deleteText ,
373
+ difference . insertText
374
+ ) ;
375
+ break ;
376
+ }
377
+ } ) ;
378
+ }
379
+ }
380
+ } ;
381
+ }
333
382
}
334
383
}
335
384
} ;
0 commit comments