Rich-Harris / shimport

Use JavaScript modules in all browsers, including dynamic imports

Home Page:https://shimport-demos.surge.sh

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Found a piece of valid code where shimport fails

ilblog opened this issue · comments

Was debugging a lot and seems to me that regEx patterns failed on this code. AST parser (respectively eslint) considers this valid code, so far I failed to pass it through shimport.

import render from 'render'
import glAnimation from 'glAnimation'
import particles from 'particles'
import _ from 'utils'
import GlObj from 'GlObj'
import LRUCache from 'lruCache'
import DataTiler from 'DataTiler'

const glVectors = DataTiler.instance({

	// Holder of glCanvas layer
	glCanvas: null,

	// particles local incrementing counter, that keeps
	// @getTiles and @tilesReady in sync
	syncCounter: 0,

	// Major flag, that cancell was requested
	cancelRqstd: false,

	// Latest used parameters
	latestParams: null,

	// Inhibts overlay
	enabled: true,

	// cache for tranformed vector tiles
	tileCache: new LRUCache( 16 ),

	// Cancelling of ongoing tasks. By increasing sync
	// counter, we make sure, that resolved dataTiles will not be
	// in sync with counter
	cancelTasks() {
		this.syncCounter++
	},

	// Called with all data tiles nicelly sorted
	tilesReady( dTiles,mapParams,params ) {

		// TODO: Here is a BUG. mapParams can be changed
		// dusring loading process, so cancelling task is
		// necessary here

		_.include(mapParams, params);

		mapParams.partObj = particles[ params.particlesIdent ] // Particles obj

		var transformParams = {
			width: this.width,
			height: this.height,
			offsetX: this.offsetX,
			offsetY: this.offsetY,
			trans: this.trans
		};

		this.processTiles( dTiles, mapParams, transformParams );
	},

	// Called upon change of map
	redrawVectors() {
		this.mapMoved = true;
		if(this.latestParams) this.getTiles(this.latestParams)
	},

	// Init whenever params are ready
	init( _glCanvas, params) {

		this.glCanvas = _glCanvas

		this.latestParams = _.clone(params);
		this.redrawVectors();
	},

	// Called upon change of params
	paramsChanged(params) {
        if(!this.latestParams
            || this.latestParams.fullPath !== params.fullPath
            || this.latestParams.overlay !== params.overlay ) {
            this.latestParams = _.clone(params);
            this.getTiles(this.latestParams);
        }
	},

	// @dTiles .. meteo data tiles (array of arrays)
	// @mapParams
	// @transformParams .. extra params for glParticles
	processTiles( dTiles, mapParams, transformParams ) {

		//if(DEBUG) console.time('prepare wind texture data');

		const tileSize = 256

		let tilesCountY = dTiles.length
		, tilesCountX = tilesCountY ? dTiles[0].length : 0;

		if( tilesCountY === 0 || tilesCountY === 0 ) return

		var instance = mapParams.partObj
		, blueMask = mapParams.JPGtransparency
		, textureTiles = []
		, textureTilesPos = []
		, dataRowSize = tileSize * 2 // luminance + alpha format (2 bytes per texel)
		, dataSize = tileSize * dataRowSize
		, j, i, x, y, scale;

		var altitudeFactor = instance.level2reduce[ mapParams.level ] // 1.0 .. 0.35
		, zoomFactor = instance.zoom2speed[ mapParams.zoom ]
		, speedMul = altitudeFactor / instance.glMaxSpeedParam;

		for( j = 0; j < tilesCountY; j++ ) {
			for( i = 0; i < tilesCountX; i++ ) {
				var tile = dTiles[j][i];
				var data = new Uint8ClampedArray( dataSize );
				if( tile ) {
					var textureTile = this.tileCache.get( tile.url, null );
					if( !textureTile ) {
						var srcData = tile.data    // data: Uint8ClampedArray[272420]
						, src = 8224 // source data byte offset (head skip)
						, dst = 0
						, speedMin = speedMul * instance.glMinSpeedParam
						, speedMin2 = speedMin * speedMin
						, e = 0.000001
						, c256 = 256
						, c128 = 128
						, c1 = 1
						, c2 = 2
						, c3 = 3
						, c4 = 4
						, cPow = 0.5 * instance.glSpeedCurvePowParam;
						//var blueMask = true;

						if( blueMask ) { // (wind)
							for( y = 0; y < c256; y++ ) {
								for( x = 0; x < c256; x++ ) {
									if( srcData[ src + c2 ] > c128 ) { // blue > 128 .. set zero vector
										data[ dst++ ] = c128;
										data[ dst++ ] = c128;
									}
									else {
										var u = tile.decodeR( srcData[ src ] ) * speedMul
										, v = tile.decodeG( srcData[ src + c1 ] ) * speedMul
										, d2 = u * u + v * v;
										if( d2 > speedMin2 ) {
											scale = c128 * Math.pow( d2, cPow ) / Math.sqrt( d2 );
											u *= scale;
											v *= scale;
										}
										else if( d2 > e ) {
											scale = c128 * speedMin / Math.sqrt( d2 );
											u *= scale;
											v *= scale;
										}
										else {
											u = 0;
											v = 0;
										}
										data[ dst++ ] = c128 + Math.round( u );
										data[ dst++ ] = c128 + Math.round( v );
									}
									src += c4;
								}
								src += c4; // skip last pixel (resX === 257)
							}
						}
						else { // alpha mask (waves, currents)
							for( y = 0; y < c256; y++ ) {
								for( x = 0; x < c256; x++ ) {
									if( srcData[ src + c3 ] < c128 ) { // alpha < 128 .. set zero vector
										data[ dst++ ] = c128;
										data[ dst++ ] = c128;
									}
									else {
										u = tile.decodeR( srcData[ src ] ) * speedMul;
										v = tile.decodeG( srcData[ src + c1 ] ) * speedMul;
										d2 = u * u + v * v;
										if( d2 > speedMin2 ) {
											scale = c128 * Math.pow( d2, cPow ) / Math.sqrt( d2 );
											u *= scale;
											v *= scale;
										}
										else if( d2 > e ) {
											scale = c128 * speedMin / Math.sqrt( d2 );
											u *= scale;
											v *= scale;
										}
										else {
											u = 0;
											v = 0;
										}
										data[ dst++ ] = c128 + Math.round( u );
										data[ dst++ ] = c128 + Math.round( v );
									}
									src += c4;
								}
								src += c4; // skip last pixel (resX === 257)
							}
						}

                        textureTile = {
                        	url: tile.url,
                        	tileSize: tileSize,
                        	data: new Uint8Array(data),
                        };

                        this.tileCache.put( tile.url, textureTile );
                    }
                    // textureTile
                    textureTiles.push( textureTile );
                    textureTilesPos.push( { x: i * tileSize, y: j * tileSize } );
                }
            }
        }
        // if there is only one tile use it again (for wraping)
        if( textureTiles.length === 1 ) {
        	var tile0 = textureTiles[0]
        	, tilePos0 = textureTilesPos[0];
        	textureTiles.push( {
				url: tile0.url,
				tileSize: tile0.tileSize,
				data: tile0.data,
			} );
			textureTilesPos.push( { x: tilePos0.x + tile0.tileSize, y: tilePos0.y } );
			tilesCountX++;
        }

        var textureSizeX = GlObj.getNextPowerOf2Size( tilesCountX ) * tileSize
		, textureSizeY = GlObj.getNextPowerOf2Size( tilesCountY ) * tileSize;

		transformParams.tilesDX = tilesCountX * tileSize;
		transformParams.tilesDY = tilesCountY * tileSize;
		transformParams.relativeDX = 1.0 * tilesCountX * tileSize / textureSizeX;
		transformParams.relativeDY = 1.0 * tilesCountY * tileSize / textureSizeY;
		transformParams.zoomWindFactor = zoomFactor;

		if( this.glCanvas ) {

			this.glCanvas.setNewWindData( {
				sizeX: textureSizeX,
				sizeY: textureSizeY,
				textureTiles: textureTiles,
				textureTilesPos: textureTilesPos,
				transformParams: transformParams,
				mapParams: mapParams
			});

			glAnimation.run();

		}

        render.emit('rendered','particles' );

	    //if(DEBUG) console.timeEnd('prepare wind texture data');
	}

})


export default glVectors

This was a wild ride. Turned out the offending line was this one:

scale = c128 * speedMin / Math.sqrt( d2 );

Shimport saw the / character and began the process of figuring out whether it was a division operator or the start of a regex, by backtracking character-by-character. Long story short, it thought the / character was preceded by the in keyword, because it thought the M (not being a lowercase character between a and z) couldn't be part of a keyword. Which is true, except that it's the wrong thing to test for — it needs to test that it's not part of an identifier.

Should be fixed in 0.0.15! Thanks