From c1c7930d8a7b0f53ed5429d0e77692a9a5715be8 Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Mon, 19 Mar 2018 17:23:05 +0200 Subject: [PATCH] isEmpty, type fix and minor tweaks (#137) --- index.d.ts | 4 ++++ src/Bundle.js | 27 +++++++++++++------------- src/MagicString.js | 47 ++++++++++++++++++++++++++++++++++++++------- test/MagicString.js | 19 ++++++++++++++++++ 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/index.d.ts b/index.d.ts index ec23bed..5d9e1e1 100644 --- a/index.d.ts +++ b/index.d.ts @@ -48,6 +48,7 @@ export class Bundle { trim(charType?: string): Bundle; trimStart(charType?: string): Bundle; trimEnd(charType?: string): Bundle; + isEmpty(): boolean; } export type ExclusionRange = [ number, number ]; @@ -90,6 +91,9 @@ export default class MagicString { remove(start: number, end: number): MagicString; slice(start: number, end: number): string; snip(start: number, end: number): MagicString; + trim(): MagicString; + + isEmpty(): boolean; original: string; } diff --git a/src/Bundle.js b/src/Bundle.js index 1ac6cdb..779676f 100644 --- a/src/Bundle.js +++ b/src/Bundle.js @@ -195,8 +195,7 @@ export default class Bundle { indentStart //: trailingNewline || /\r?\n$/.test( separator ) //true///\r?\n/.test( separator ) }); - // TODO this is a very slow way to determine this - trailingNewline = source.content.toString().slice(0, -1) === '\n'; + trailingNewline = source.content.lastChar() === '\n'; }); if (this.intro) { @@ -228,6 +227,14 @@ export default class Bundle { return this.intro + body; } + isEmpty () { + if (this.intro.length && this.intro.trim()) + return false; + if (this.sources.some(source => !source.content.isEmpty())) + return false; + return true; + } + trimLines() { return this.trim('[\\r\\n]'); } @@ -245,15 +252,11 @@ export default class Bundle { let i = 0; do { - source = this.sources[i]; - + source = this.sources[i++]; if (!source) { break; } - - source.content.trimStart(charType); - i += 1; - } while (source.content.toString() === ''); // TODO faster way to determine non-empty source? + } while (!source.content.trimStartAborted(charType)); } return this; @@ -266,16 +269,12 @@ export default class Bundle { let i = this.sources.length - 1; do { - source = this.sources[i]; - + source = this.sources[i--]; if (!source) { this.intro = this.intro.replace(rx, ''); break; } - - source.content.trimEnd(charType); - i -= 1; - } while (source.content.toString() === ''); // TODO faster way to determine non-empty source? + } while (!source.content.trimEndAborted(charType)); return this; } diff --git a/src/MagicString.js b/src/MagicString.js index 3aa65b9..e73353a 100644 --- a/src/MagicString.js +++ b/src/MagicString.js @@ -459,6 +459,19 @@ export default class MagicString { return this; } + lastChar() { + let chunk = this.lastChunk; + do { + if (chunk.outro.length) + return chunk.outro[chunk.outro.length - 1]; + if (chunk.content.length) + return chunk.content[chunk.content.length - 1]; + if (chunk.intro.length) + return chunk.intro[chunk.intro.length - 1]; + } while (chunk = chunk.previous); + return ''; + } + slice(start = 0, end = this.original.length) { while (start < 0) start += this.original.length; while (end < 0) end += this.original.length; @@ -568,6 +581,17 @@ export default class MagicString { return str + this.outro; } + isEmpty() { + let chunk = this.firstChunk; + do { + if (chunk.intro.length && chunk.intro.trim() || + chunk.content.length && chunk.content.trim() || + chunk.outro.length && chunk.outro.trim()) + return false; + } while (chunk = chunk.next); + return true; + } + trimLines() { return this.trim('[\\r\\n]'); } @@ -576,11 +600,11 @@ export default class MagicString { return this.trimStart(charType).trimEnd(charType); } - trimEnd(charType) { + trimEndAborted(charType) { const rx = new RegExp((charType || '\\s') + '+$'); this.outro = this.outro.replace(rx, ''); - if (this.outro.length) return this; + if (this.outro.length) return true; let chunk = this.lastChunk; @@ -599,18 +623,22 @@ export default class MagicString { this.byEnd[chunk.next.end] = chunk.next; } - if (aborted) return this; + if (aborted) return true; chunk = chunk.previous; } while (chunk); - return this; + return false; } - trimStart(charType) { + trimEnd(charType) { + this.trimEndAborted(charType); + return this; + } + trimStartAborted(charType) { const rx = new RegExp('^' + (charType || '\\s') + '+'); this.intro = this.intro.replace(rx, ''); - if (this.intro.length) return this; + if (this.intro.length) return true; let chunk = this.firstChunk; @@ -627,10 +655,15 @@ export default class MagicString { this.byEnd[chunk.next.end] = chunk.next; } - if (aborted) return this; + if (aborted) return true; chunk = chunk.next; } while (chunk); + return false; + } + + trimStart(charType) { + this.trimStartAborted(charType); return this; } } diff --git a/test/MagicString.js b/test/MagicString.js index d1e38f0..5726f8e 100644 --- a/test/MagicString.js +++ b/test/MagicString.js @@ -1172,4 +1172,23 @@ describe( 'MagicString', () => { assert.equal( s.toString(), ' abcdefghijkl ' ); }); }); + + describe( 'isEmpty', () => { + it( 'should support isEmpty', () => { + const s = new MagicString( ' abcde fghijkl ' ); + + assert.equal( s.isEmpty(), false ); + + s.prepend( ' ' ); + s.append( ' ' ); + s.remove( 1, 6 ); + s.remove( 9, 15 ); + + assert.equal( s.isEmpty(), false ); + + s.remove( 15, 16 ); + + assert.equal( s.isEmpty(), true ); + }); + }); });