@@ -27,6 +27,10 @@ const FB_PRETTIER_OPTIONS = {
2727
2828const LINE_ENDING_RE = / \r \n | [ \r \n \u2028 \u2029 ] / ;
2929
30+ const OPERATION_INSERT = 'insert' ;
31+ const OPERATION_DELETE = 'delete' ;
32+ const OPERATION_REPLACE = 'replace' ;
33+
3034// ------------------------------------------------------------------------------
3135// Privates
3236// ------------------------------------------------------------------------------
@@ -104,18 +108,13 @@ function showInvisibles(str) {
104108 return ret ;
105109}
106110
107- // ------------------------------------------------------------------------------
108- // Rule Definition
109- // ------------------------------------------------------------------------------
110-
111111/**
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.
115114 * @param {string } prettierSource - The Prettier formatted source.
116- * @returns {void }
115+ * @returns {Array } - An array contains { operation, offset, insertText, deleteText }
117116 */
118- function reportDifferences ( context , prettierSource ) {
117+ function generateDifferences ( source , prettierSource ) {
119118 // fast-diff returns the differences between two texts as a series of
120119 // INSERT, DELETE or EQUAL operations. The results occur only in these
121120 // sequences:
@@ -130,8 +129,8 @@ function reportDifferences(context, prettierSource) {
130129 // and another's beginning does not have line endings (i.e. issues that occur
131130 // on contiguous lines).
132131
133- const source = context . getSourceCode ( ) . text ;
134132 const results = diff ( source , prettierSource ) ;
133+ const differences = [ ] ;
135134
136135 const batch = [ ] ;
137136 let offset = 0 ; // NOTE: INSERT never advances the offset.
@@ -166,6 +165,8 @@ function reportDifferences(context, prettierSource) {
166165 }
167166 }
168167
168+ return differences ;
169+
169170 function flush ( ) {
170171 let aheadDeleteText = '' ;
171172 let aheadInsertText = '' ;
@@ -187,16 +188,33 @@ function reportDifferences(context, prettierSource) {
187188 }
188189 }
189190 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+ } ) ;
191197 } else if ( ! aheadDeleteText && aheadInsertText ) {
192- reportInsert ( context , offset , aheadInsertText ) ;
198+ differences . push ( {
199+ offset,
200+ operation : OPERATION_INSERT ,
201+ insertText : aheadInsertText
202+ } ) ;
193203 } else if ( aheadDeleteText && ! aheadInsertText ) {
194- reportDelete ( context , offset , aheadDeleteText ) ;
204+ differences . push ( {
205+ offset,
206+ operation : OPERATION_DELETE ,
207+ deleteText : aheadDeleteText
208+ } ) ;
195209 }
196210 offset += aheadDeleteText . length ;
197211 }
198212}
199213
214+ // ------------------------------------------------------------------------------
215+ // Rule Definition
216+ // ------------------------------------------------------------------------------
217+
200218/**
201219 * Reports an "Insert ..." issue where text must be inserted.
202220 * @param {RuleContext } context - The ESLint rule context.
@@ -268,68 +286,99 @@ function reportReplace(context, offset, deleteText, insertText) {
268286// Module Definition
269287// ------------------------------------------------------------------------------
270288
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 ] ;
295312
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 ;
298316
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 ;
320319
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 { } ;
326335 }
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 { } ;
330339 }
331340 }
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+ }
333382 }
334383 }
335384} ;
0 commit comments