[Pkg-javascript-commits] [node-magic-string] 01/06: New upstream version 0.19.0

Julien Puydt julien.puydt at laposte.net
Wed Dec 7 07:23:28 UTC 2016


This is an automated email from the git hooks/post-receive script.

jpuydt-guest pushed a commit to branch master
in repository node-magic-string.

commit 948813531e8a2d7ca87a0b5ed0f75e75b31d7fba
Author: Julien Puydt <julien.puydt at laposte.net>
Date:   Mon Dec 5 10:20:15 2016 +0100

    New upstream version 0.19.0
---
 CHANGELOG.md                |   4 ++
 package.json                |   2 +-
 src/Bundle.js               |  71 +++++++++++++++--------
 src/MagicString.js          |  30 ++++++++--
 src/utils/Mappings.js       | 117 +++++++++++++++++++++++++++++++++++++
 src/utils/encodeMappings.js | 137 --------------------------------------------
 src/utils/getSemis.js       |   3 -
 test/MagicString.Bundle.js  | 102 ++++++++++++++++++++++++++++++++-
 8 files changed, 292 insertions(+), 174 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index fa2153f..c1f13db 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # magic-string changelog
 
+## 0.19.0
+
+* More accurate bundle sourcemaps ([#114](https://github.com/Rich-Harris/magic-string/pull/114))
+
 ## 0.18.0
 
 * Optimisation – remove empty chunks following `overwrite` or `remove` ([#113](https://github.com/Rich-Harris/magic-string/pull/113))
diff --git a/package.json b/package.json
index 486e862..245ac73 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "magic-string",
   "description": "Modify strings, generate sourcemaps",
   "author": "Rich Harris",
-  "version": "0.18.0",
+  "version": "0.19.0",
   "repository": "https://github.com/rich-harris/magic-string",
   "main": "dist/magic-string.cjs.js",
   "module": "dist/magic-string.es.js",
diff --git a/src/Bundle.js b/src/Bundle.js
index 0f3786a..8a11683 100644
--- a/src/Bundle.js
+++ b/src/Bundle.js
@@ -1,9 +1,10 @@
 import MagicString from './MagicString.js';
 import SourceMap from './utils/SourceMap.js';
-import getSemis from './utils/getSemis.js';
 import getRelativePath from './utils/getRelativePath.js';
 import hasOwnProp from './utils/hasOwnProp.js';
 import isObject from './utils/isObject.js';
+import getLocator from './utils/getLocator.js';
+import Mappings from './utils/Mappings.js';
 
 export default function Bundle ( options = {} ) {
 	this.intro = options.intro || '';
@@ -87,6 +88,50 @@ Bundle.prototype = {
 			});
 		});
 
+		const mappings = new Mappings( options.hires );
+
+		if ( this.intro ) {
+			mappings.advance( this.intro );
+		}
+
+		this.sources.forEach( ( source, i ) => {
+			if ( i > 0 ) {
+				mappings.advance( this.separator );
+			}
+
+			const sourceIndex = source.filename ? this.uniqueSourceIndexByFilename[ source.filename ] : -1;
+			const magicString = source.content;
+			const locate = getLocator( magicString.original );
+
+			if ( magicString.intro ) {
+				mappings.advance( magicString.intro );
+			}
+
+			magicString.firstChunk.eachNext( chunk => {
+				const loc = locate( chunk.start );
+
+				if ( chunk.intro.length ) mappings.advance( chunk.intro );
+
+				if ( source.filename ) {
+					if ( chunk.edited ) {
+						mappings.addEdit( sourceIndex, chunk.content, chunk.original, loc, chunk.storeName ? names.indexOf( chunk.original ) : -1 );
+					} else {
+						mappings.addUneditedChunk( sourceIndex, chunk, magicString.original, loc, magicString.sourcemapLocations );
+					}
+				}
+
+				else {
+					mappings.advance( chunk.content );
+				}
+
+				if ( chunk.outro.length ) mappings.advance( chunk.outro );
+			});
+
+			if ( magicString.outro ) {
+				mappings.advance( magicString.outro );
+			}
+		});
+
 		return new SourceMap({
 			file: ( options.file ? options.file.split( /[\/\\]/ ).pop() : null ),
 			sources: this.uniqueSources.map( source => {
@@ -96,32 +141,10 @@ Bundle.prototype = {
 				return options.includeContent ? source.content : null;
 			}),
 			names,
-			mappings: this.getMappings( options, names )
+			mappings: mappings.encode()
 		});
 	},
 
-	getMappings ( options, names ) {
-		const offsets = {};
-
-		return (
-			getSemis( this.intro ) +
-			this.sources.map( ( source, i ) => {
-				const prefix = ( i > 0 ) ? ( getSemis( source.separator ) || ',' ) : '';
-				let mappings;
-
-				// we don't bother encoding sources without a filename
-				if ( !source.filename ) {
-					mappings = getSemis( source.content.toString() );
-				} else {
-					const sourceIndex = this.uniqueSourceIndexByFilename[ source.filename ];
-					mappings = source.content.getMappings( options, sourceIndex, offsets, names );
-				}
-
-				return prefix + mappings;
-			}).join( '' )
-		);
-	},
-
 	getIndentString () {
 		const indentStringCounts = {};
 
diff --git a/src/MagicString.js b/src/MagicString.js
index 7fc93d1..af851f2 100644
--- a/src/MagicString.js
+++ b/src/MagicString.js
@@ -1,10 +1,10 @@
 import Chunk from './Chunk.js';
 import SourceMap from './utils/SourceMap.js';
 import guessIndent from './utils/guessIndent.js';
-import encodeMappings from './utils/encodeMappings.js';
 import getRelativePath from './utils/getRelativePath.js';
 import isObject from './utils/isObject.js';
 import getLocator from './utils/getLocator.js';
+import Mappings from './utils/Mappings.js';
 import Stats from './utils/Stats.js';
 
 const warned = {
@@ -130,7 +130,29 @@ MagicString.prototype = {
 	generateMap ( options ) {
 		options = options || {};
 
+		const sourceIndex = 0;
 		const names = Object.keys( this.storedNames );
+		const mappings = new Mappings( options.hires );
+
+		const locate = getLocator( this.original );
+
+		if ( this.intro ) {
+			mappings.advance( this.intro );
+		}
+
+		this.firstChunk.eachNext( chunk => {
+			const loc = locate( chunk.start );
+
+			if ( chunk.intro.length ) mappings.advance( chunk.intro );
+
+			if ( chunk.edited ) {
+				mappings.addEdit( sourceIndex, chunk.content, chunk.original, loc, chunk.storeName ? names.indexOf( chunk.original ) : -1 );
+			} else {
+				mappings.addUneditedChunk( sourceIndex, chunk, this.original, loc, this.sourcemapLocations );
+			}
+
+			if ( chunk.outro.length ) mappings.advance( chunk.outro );
+		});
 
 		if ( DEBUG ) this.stats.time( 'generateMap' );
 		const map = new SourceMap({
@@ -138,7 +160,7 @@ MagicString.prototype = {
 			sources: [ options.source ? getRelativePath( options.file || '', options.source ) : null ],
 			sourcesContent: options.includeContent ? [ this.original ] : [ null ],
 			names,
-			mappings: this.getMappings( options, 0, {}, names )
+			mappings: mappings.encode()
 		});
 		if ( DEBUG ) this.stats.timeEnd( 'generateMap' );
 
@@ -149,10 +171,6 @@ MagicString.prototype = {
 		return this.indentStr === null ? '\t' : this.indentStr;
 	},
 
-	getMappings ( options, sourceIndex, offsets, names ) {
-		return encodeMappings( this.original, this.intro, this.outro, this.firstChunk, options.hires, this.sourcemapLocations, sourceIndex, offsets, names );
-	},
-
 	indent ( indentStr, options ) {
 		const pattern = /^[^\r\n]/gm;
 
diff --git a/src/utils/Mappings.js b/src/utils/Mappings.js
new file mode 100644
index 0000000..b32cf0e
--- /dev/null
+++ b/src/utils/Mappings.js
@@ -0,0 +1,117 @@
+import { encode } from 'vlq';
+
+export default function Mappings ( hires ) {
+	const offsets = {
+		generatedCodeColumn: 0,
+		sourceIndex: 0,
+		sourceCodeLine: 0,
+		sourceCodeColumn: 0,
+		sourceCodeName: 0
+	};
+
+	let generatedCodeLine = 0;
+	let generatedCodeColumn = 0;
+
+	this.raw = [];
+	let rawSegments = this.raw[ generatedCodeLine ] = [];
+
+	let pending = null;
+
+	this.addEdit = ( sourceIndex, content, original, loc, nameIndex ) => {
+		if ( content.length ) {
+			rawSegments.push([
+				generatedCodeColumn,
+				sourceIndex,
+				loc.line,
+				loc.column,
+				nameIndex,
+			]);
+		} else if ( pending ) {
+			rawSegments.push( pending );
+		}
+
+		this.advance( content );
+		pending = null;
+	};
+
+	this.addUneditedChunk = ( sourceIndex, chunk, original, loc, sourcemapLocations ) => {
+		let originalCharIndex = chunk.start;
+		let first = true;
+
+		while ( originalCharIndex < chunk.end ) {
+			if ( hires || first || sourcemapLocations[ originalCharIndex ] ) {
+				rawSegments.push([
+					generatedCodeColumn,
+					sourceIndex,
+					loc.line,
+					loc.column,
+					-1
+				]);
+			}
+
+			if ( original[ originalCharIndex ] === '\n' ) {
+				loc.line += 1;
+				loc.column = 0;
+				generatedCodeLine += 1;
+				this.raw[ generatedCodeLine ] = rawSegments = [];
+				generatedCodeColumn = 0;
+			} else {
+				loc.column += 1;
+				generatedCodeColumn += 1;
+			}
+
+			originalCharIndex += 1;
+			first = false;
+		}
+
+		pending = [
+			generatedCodeColumn,
+			sourceIndex,
+			loc.line,
+			loc.column,
+			-1,
+		];
+	};
+
+	this.advance = str => {
+		if ( !str ) return;
+
+		const lines = str.split( '\n' );
+		const lastLine = lines.pop();
+
+		if ( lines.length ) {
+			generatedCodeLine += lines.length;
+			this.raw[ generatedCodeLine ] = rawSegments = [];
+			generatedCodeColumn = lastLine.length;
+		} else {
+			generatedCodeColumn += lastLine.length;
+		}
+	};
+
+	this.encode = () => {
+		return this.raw.map( segments => {
+			let generatedCodeColumn = 0;
+
+			return segments.map( segment => {
+				const arr = [
+					segment[0] - generatedCodeColumn,
+					segment[1] - offsets.sourceIndex,
+					segment[2] - offsets.sourceCodeLine,
+					segment[3] - offsets.sourceCodeColumn
+				];
+
+				generatedCodeColumn = segment[0];
+				offsets.sourceIndex = segment[1];
+				offsets.sourceCodeLine = segment[2];
+				offsets.sourceCodeColumn = segment[3];
+
+				if ( ~segment[4] ) {
+					arr.push( segment[4] - offsets.sourceCodeName );
+					offsets.sourceCodeName = segment[4];
+				}
+
+				return encode( arr );
+			}).join( ',' );
+		}).join( ';' );
+	};
+}
diff --git a/src/utils/encodeMappings.js b/src/utils/encodeMappings.js
deleted file mode 100644
index de210e0..0000000
--- a/src/utils/encodeMappings.js
+++ /dev/null
@@ -1,137 +0,0 @@
-import { encode } from 'vlq';
-import getSemis from './getSemis.js';
-import getLocator from './getLocator.js';
-
-const nonWhitespace = /\S/;
-
-export default function encodeMappings ( original, intro, outro, chunk, hires, sourcemapLocations, sourceIndex, offsets, names ) {
-	const rawLines = [];
-
-	let generatedCodeLine = intro.split( '\n' ).length - 1;
-	let rawSegments = rawLines[ generatedCodeLine ] = [];
-
-	let generatedCodeColumn = 0;
-
-	const locate = getLocator( original );
-
-	function addEdit ( content, original, loc, nameIndex, i ) {
-		if ( i || ( content.length && nonWhitespace.test( content ) ) ) {
-			rawSegments.push({
-				generatedCodeLine,
-				generatedCodeColumn,
-				sourceCodeLine: loc.line,
-				sourceCodeColumn: loc.column,
-				sourceCodeName: nameIndex,
-				sourceIndex
-			});
-		}
-
-		let lines = content.split( '\n' );
-		let lastLine = lines.pop();
-
-		if ( lines.length ) {
-			generatedCodeLine += lines.length;
-			rawLines[ generatedCodeLine ] = rawSegments = [];
-			generatedCodeColumn = lastLine.length;
-		} else {
-			generatedCodeColumn += lastLine.length;
-		}
-
-		lines = original.split( '\n' );
-		lastLine = lines.pop();
-
-		if ( lines.length ) {
-			loc.line += lines.length;
-			loc.column = lastLine.length;
-		} else {
-			loc.column += lastLine.length;
-		}
-	}
-
-	function addUneditedChunk ( chunk, loc ) {
-		let originalCharIndex = chunk.start;
-		let first = true;
-
-		while ( originalCharIndex < chunk.end ) {
-			if ( hires || first || sourcemapLocations[ originalCharIndex ] ) {
-				rawSegments.push({
-					generatedCodeLine,
-					generatedCodeColumn,
-					sourceCodeLine: loc.line,
-					sourceCodeColumn: loc.column,
-					sourceCodeName: -1,
-					sourceIndex
-				});
-			}
-
-			if ( original[ originalCharIndex ] === '\n' ) {
-				loc.line += 1;
-				loc.column = 0;
-				generatedCodeLine += 1;
-				rawLines[ generatedCodeLine ] = rawSegments = [];
-				generatedCodeColumn = 0;
-			} else {
-				loc.column += 1;
-				generatedCodeColumn += 1;
-			}
-
-			originalCharIndex += 1;
-			first = false;
-		}
-	}
-
-	let hasContent = false;
-
-	while ( chunk ) {
-		const loc = locate( chunk.start );
-
-		if ( chunk.intro.length ) {
-			addEdit( chunk.intro, '', loc, -1, hasContent );
-		}
-
-		if ( chunk.edited ) {
-			addEdit( chunk.content, chunk.original, loc, chunk.storeName ? names.indexOf( chunk.original ) : -1, hasContent );
-		} else {
-			addUneditedChunk( chunk, loc );
-		}
-
-		if ( chunk.outro.length ) {
-			addEdit( chunk.outro, '', loc, -1, hasContent );
-		}
-
-		if ( chunk.content || chunk.intro || chunk.outro ) hasContent = true;
-
-		const nextChunk = chunk.next;
-		chunk = nextChunk;
-	}
-
-	offsets.sourceIndex = offsets.sourceIndex || 0;
-	offsets.sourceCodeLine = offsets.sourceCodeLine || 0;
-	offsets.sourceCodeColumn = offsets.sourceCodeColumn || 0;
-	offsets.sourceCodeName = offsets.sourceCodeName || 0;
-
-	return rawLines.map( segments => {
-		let generatedCodeColumn = 0;
-
-		return segments.map( segment => {
-			const arr = [
-				segment.generatedCodeColumn - generatedCodeColumn,
-				segment.sourceIndex - offsets.sourceIndex,
-				segment.sourceCodeLine - offsets.sourceCodeLine,
-				segment.sourceCodeColumn - offsets.sourceCodeColumn
-			];
-
-			generatedCodeColumn = segment.generatedCodeColumn;
-			offsets.sourceIndex = segment.sourceIndex;
-			offsets.sourceCodeLine = segment.sourceCodeLine;
-			offsets.sourceCodeColumn = segment.sourceCodeColumn;
-
-			if ( ~segment.sourceCodeName ) {
-				arr.push( segment.sourceCodeName - offsets.sourceCodeName );
-				offsets.sourceCodeName = segment.sourceCodeName;
-			}
-
-			return encode( arr );
-		}).join( ',' );
-	}).join( ';' ) + getSemis(outro);
-}
diff --git a/src/utils/getSemis.js b/src/utils/getSemis.js
deleted file mode 100644
index 4ead76e..0000000
--- a/src/utils/getSemis.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export default function getSemis ( str ) {
-	return new Array( str.split( '\n' ).length ).join( ';' );
-}
diff --git a/test/MagicString.Bundle.js b/test/MagicString.Bundle.js
index 9033450..f0ce009 100644
--- a/test/MagicString.Bundle.js
+++ b/test/MagicString.Bundle.js
@@ -111,9 +111,6 @@ describe( 'MagicString.Bundle', () => {
 			assert.deepEqual( map.sources, [ 'foo.js', 'bar.js' ]);
 			assert.deepEqual( map.sourcesContent, [ 'var answer = 42;', 'console.log( answer );' ]);
 
-			assert.equal( map.toString(), '{"version":3,"file":"bundle.js","sources":["foo.js","bar.js"],"sourcesContent":["var answer = 42;","console.log( answer );"],"names":[],"mappings":"AAAA,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;ACAf,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}' );
-			assert.equal( map.toUrl(), 'data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVuZGxlLmpzIiwic291cmNlcyI6WyJmb28uanMiLCJiYXIuanMiXSwic291cmNlc0NvbnRlbnQiOlsidmFyIGFuc3dlciA9IDQyOyIsImNvbnNvbGUubG9nKCBhbnN3ZXIgKTsiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUNBZixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE [...]
-
 			const smc = new SourceMapConsumer( map );
 			let loc;
 
@@ -400,6 +397,105 @@ describe( 'MagicString.Bundle', () => {
 			loc = smc.originalPositionFor({ line: 3, column: 9 });
 			assert.equal( loc.source, 'two.js' );
 		});
+
+		it( 'should handle empty separator', () => {
+			const b = new MagicString.Bundle({
+				separator: ''
+			});
+
+			b.addSource({
+				content: new MagicString( 'if ( foo ) { ' )
+			});
+
+			const s = new MagicString( 'console.log( 42 );' );
+			s.addSourcemapLocation( 8 );
+			s.addSourcemapLocation( 15 );
+
+			b.addSource({
+				filename: 'input.js',
+				content: s
+			});
+
+			b.addSource({
+				content: new MagicString( ' }' )
+			});
+
+			assert.equal( b.toString(), 'if ( foo ) { console.log( 42 ); }' );
+
+			const map = b.generateMap({
+				file: 'output.js',
+				source: 'input.js',
+				includeContent: true
+			});
+
+			const smc = new SourceMapConsumer( map );
+			const loc = smc.originalPositionFor({ line: 1, column: 21 });
+
+			assert.deepEqual( loc, {
+				source: 'input.js',
+				name: null,
+				line: 1,
+				column: 8
+			});
+		});
+
+		// TODO tidy this up. is a recreation of a bug in Svelte
+		it( 'generates a correct sourcemap for a Svelte component', () => {
+			const b = new MagicString.Bundle({
+				separator: ''
+			});
+
+			const s = new MagicString( `
+<div></div>
+
+<script>
+	export default {
+		onrender () {
+			console.log( 42 );
+		}
+	}
+</script>`.trim() );
+
+			[ 21, 23, 38, 42, 50, 51, 54, 59, 66, 67, 70, 72, 74, 76, 77, 81, 84, 85 ].forEach( pos => {
+				s.addSourcemapLocation( pos );
+			});
+
+			s.remove( 0, 21 );
+			s.overwrite( 23, 38, 'return ' );
+			s.prependRight( 21, 'var template = (function () {' );
+			s.appendLeft( 85, '}());' );
+			s.overwrite( 85, 94, '' );
+
+			b.addSource({
+				content: s,
+				filename: 'input.js'
+			});
+
+			assert.equal( b.toString(), `
+var template = (function () {
+	return {
+		onrender () {
+			console.log( 42 );
+		}
+	}
+}());`.trim() );
+
+			const map = b.generateMap({
+				file: 'output.js',
+				source: 'input.js',
+				includeContent: true
+			});
+
+			const smc = new SourceMapConsumer( map );
+			const loc = smc.originalPositionFor({ line: 4, column: 16 });
+
+			assert.deepEqual( loc, {
+				source: 'input.js',
+				name: null,
+				line: 6,
+				column: 16
+			});
+		});
 	});
 
 	describe( 'indent', () => {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-magic-string.git



More information about the Pkg-javascript-commits mailing list