├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── appveyor.yml ├── bench ├── index.js ├── output │ ├── d3.js │ ├── d3.min.js │ ├── magic-string.js │ ├── magic-string.min.js │ ├── rollup.js │ └── rollup.min.js └── samples │ ├── d3.js │ ├── d3.min.js │ ├── magic-string.js │ ├── magic-string.min.js │ ├── rollup.js │ └── rollup.min.js ├── demos ├── README.md ├── build.js ├── dynamic-import │ ├── dynamic-import.js │ ├── index.html │ └── main.js ├── force-shimport │ ├── index.html │ ├── main.js │ └── other.js ├── index.html ├── load-from-unpkg │ ├── index.html │ └── main.js ├── static-imports │ ├── a.js │ ├── b.js │ ├── index.html │ └── main.js ├── styles.css ├── transform │ └── index.html └── web-worker │ ├── app │ ├── bar.js │ ├── foo.js │ └── main.js │ ├── index.html │ └── worker.js ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── index.ts ├── load.ts └── transform.ts ├── test ├── samples │ ├── dynamic-import-minified │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── dynamic-import-whitespace │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── dynamic-import │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-declaration │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-default-no-space │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-default-unnamed-class-extends │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-default-unnamed-class │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-default-unnamed-function │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-default │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-empty │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-from-minified │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-from │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-function │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-named-minified-b │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-named-minified │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-named │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── export-star-from │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── import-default-star │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── import-default │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── import-empty-minified │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── import-empty │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── import-meta-url │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── import-named-minified-b │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── import-named-minified │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── import-named-multiple │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── import-named │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── import-namespace │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── keyword-false-positive │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── template-string-dollar │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ ├── template-string-expression │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js │ └── unfinished │ │ ├── actual.js │ │ ├── input.js │ │ └── output.js └── test.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.d.ts 4 | /yarn.lock 5 | /dist 6 | /index.js 7 | /index.dev.js 8 | /test/samples/_ 9 | /demos/shimport.js 10 | /demos/shimport.dev.js -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | 5 | env: 6 | global: 7 | - BUILD_TIMEOUT=10000 8 | 9 | branches: 10 | only: 11 | - master 12 | 13 | install: npm ci || npm install 14 | 15 | after_success: npm run deploy -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Shimport changelog 2 | 3 | ## 2.0.5 4 | 5 | * Hoist imports ([#36](https://github.com/Rich-Harris/shimport/issues/36)) 6 | 7 | ## 2.0.4 8 | 9 | * Publish as ES5 so that browsers can use Shimport untranspiled ([#34](https://github.com/Rich-Harris/shimport/issues/34)) 10 | 11 | ## 2.0.3 12 | 13 | * Fall back to `eval` if `document` is undefined ([#26](https://github.com/Rich-Harris/shimport/issues/26)) 14 | 15 | ## 2.0.2 16 | 17 | * Coerce `id` to string ([#32](https://github.com/Rich-Harris/shimport/pull/32)) 18 | 19 | ## 2.0.1 20 | 21 | * Fix regex 22 | 23 | ## 2.0.0 24 | 25 | * Switch to MIT License ([#28](https://github.com/Rich-Harris/shimport/issues/28)) 26 | * Support `import.meta.url` ([#31](https://github.com/Rich-Harris/shimport/pull/31)) 27 | 28 | ## 1.0.1 29 | 30 | * Handle `export default` followed by non-whitespace character ([#22](https://github.com/Rich-Harris/shimport/issues/22)) 31 | 32 | ## 1.0.0 33 | 34 | * Stable release 35 | 36 | ## 0.0.16 37 | 38 | * Fix template string transformation ([#20](https://github.com/Rich-Harris/shimport/issues/20)) 39 | 40 | ## 0.0.15 41 | 42 | * Use blob URLs for stack traces ([#17](https://github.com/Rich-Harris/shimport/pull/17)) 43 | * Fix code transformation with `$` character in template strings ([#16](https://github.com/Rich-Harris/shimport/issues/16)) 44 | * Fix false positive keyword detection ([#8](https://github.com/Rich-Harris/shimport/issues/8)) 45 | 46 | ## 0.0.14 47 | 48 | * Handle anonymous `class extends` ([#13](https://github.com/Rich-Harris/shimport/issues/13)) 49 | 50 | ## 0.0.13 51 | 52 | * Handle anonymous default class/function exports ([#13](https://github.com/Rich-Harris/shimport/issues/13)) 53 | 54 | ## 0.0.12 55 | 56 | * Handle minified export-from declarations ([#12](https://github.com/Rich-Harris/shimport/pull/12)) 57 | 58 | ## 0.0.11 59 | 60 | * Handle minified bare imports 61 | * Ignore punctuators when determining declaration names ([#3](https://github.com/Rich-Harris/shimport/issues/3)) 62 | 63 | ## 0.0.10 64 | 65 | * Another minified dynamic import case 66 | * Use `getAttribute('data-main')` instead of `dataset.main` for older browsers 67 | * Avoid `[].find`, so it doesn't need polyfilling 68 | 69 | ## 0.0.9 70 | 71 | * Handle minified dynamic import 72 | 73 | ## 0.0.8 74 | 75 | * Add VERSION export 76 | 77 | ## 0.0.7 78 | 79 | * Handle semi-colon-separated declarations 80 | 81 | ## 0.0.6 82 | 83 | * Handle minified declarations 84 | 85 | ## 0.0.5 86 | 87 | * Handle empty imports/exports 88 | 89 | ## 0.0.4 90 | 91 | * Speed 92 | 93 | ## 0.0.3 94 | 95 | * More fixes 96 | 97 | ## 0.0.2 98 | 99 | * Various fixes 100 | 101 | ## 0.0.1 102 | 103 | * First (experimental) release 104 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-20 [these people](https://github.com/Rich-Harris/shimport/graphs/contributors) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shimport 2 | 3 | A 2kb shim for `import` and `export`. Allows you to use JavaScript modules in **all** browsers, including dynamic `import()`. 4 | 5 | 6 | ## Quick start 7 | 8 | Suppose you have a module called `js/app.js`. We want to: 9 | 10 | 1. check to see if modules are fully supported in the current browser, including dynamic imports 11 | 2. if they are, just use the native module loader 12 | 3. if not, use Shimport 13 | 14 | We can do this by adding a simple script tag to our `index.html` file: 15 | 16 | ```html 17 | 32 | ``` 33 | 34 | 35 | ## Installing locally 36 | 37 | In the example above we loaded Shimport from the unpkg CDN. You can also [grab the latest copy](https://unpkg.com/shimport) and include alongside your app's other files. 38 | 39 | You can also `npm install shimport`, in which case it will be available as `node_modules/shimport/index.js`. 40 | 41 | 42 | ## API 43 | 44 | Most of the time you won't need to interact directly with Shimport, but it's useful to understand how it works. The script creates a global variable, `__shimport__`, with the following methods: 45 | 46 | * `load(url: string) => Promise` — `url` must be fully qualified 47 | * `transform(source: string) => string` — converts a JavaScript module to a Shimport module 48 | * `define(id: string, deps: string[], factory: (...) => void)` — used internally to construct modules 49 | 50 | 51 | ## Using with Rollup and code-splitting 52 | 53 | Since [Rollup](https://rollupjs.org) can already output JavaScript modules, it's easy to use with Shimport. Just use the `esm` output format: 54 | 55 | ```js 56 | // rollup.config.js 57 | export default { 58 | input: 'src/app.js', 59 | output: { 60 | dir: 'js', 61 | format: 'esm' 62 | }, 63 | experimentalCodeSplitting: true 64 | }; 65 | ``` 66 | 67 | 68 | ## Skipping feature detection 69 | 70 | If you want to *always* use Shimport, regardless of environment, you can create a script that loads Shimport with a `data-main` attribute: 71 | 72 | ```html 73 | 74 | ``` 75 | 76 | 77 | ## Using with a web worker 78 | 79 | In a web worker environment, Shimport can't auto-start based on a script with `data-main`. Instead, use the API: 80 | 81 | ```js 82 | importScripts('path/to/shimport.js'); 83 | 84 | const { href } = new URL('path/to/my/module.js', location.href); 85 | __shimport__.load(href).then(mod => { 86 | // module is loaded 87 | }); 88 | ``` 89 | 90 | 91 | ## Is it fast? 92 | 93 | Blazingly. The code transformation is fast enough that you probably don't need to worry about it, unless you're shipping far too much JavaScript in the first place. 94 | 95 | A future version of Shimport may use web workers to do the transformation off the main thread. 96 | 97 | 98 | ## Browser support 99 | 100 | Shimport *only* transpiles the `import` and `export` statements in your code. If you want to use other features in browsers that do not support them, they will need to be transpiled separately. 101 | 102 | Shimport also expects to be able to use `Array.from`, `fetch`, `Map` and `URL`. On browsers like Internet Explorer, you will need to bring your own polyfills. 103 | 104 | 105 | ## Caveats 106 | 107 | The JavaScript module specification is complex, and extremely hard to implement completely with the techniques Shimport uses. It is designed to meet the 98% of cases you encounter in the real world, rather than covering the entire spec at the cost of becoming prohibitively slow and complex. 108 | 109 | Specifically, it will not correctly handle cyclical dependencies or live bindings. 110 | 111 | Because Shimport uses `fetch`, and evaluates the transformed result, it will not work with some CSP and CORS configurations. 112 | 113 | 114 | 115 | ## License 116 | 117 | [MIT](LICENSE) 118 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | version: "{build}" 4 | 5 | clone_depth: 10 6 | 7 | init: 8 | - git config --global core.autocrlf false 9 | 10 | environment: 11 | matrix: 12 | # node.js 13 | - nodejs_version: 8 14 | 15 | install: 16 | - ps: Install-Product node $env:nodejs_version 17 | - npm install 18 | 19 | build: off 20 | 21 | test_script: 22 | - node --version && npm --version 23 | - npm test 24 | 25 | matrix: 26 | fast_finish: false 27 | 28 | # cache: 29 | # - C:\Users\appveyor\AppData\Roaming\npm-cache -> package.json # npm cache 30 | # - node_modules -> package.json # local npm modules 31 | -------------------------------------------------------------------------------- /bench/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const ms = require('pretty-ms'); 3 | const c = require('kleur'); 4 | const { locate } = require('locate-character'); 5 | 6 | const shimport = `(function() { ${fs.readFileSync('index.dev.js', 'utf-8')}; return __shimport__; }())`; 7 | 8 | const n = 25; 9 | 10 | function test(file) { 11 | console.log(c.bold.cyan(file)); 12 | 13 | const __shimport__ = eval(shimport); 14 | const code = fs.readFileSync(file, 'utf-8'); 15 | 16 | let err; 17 | 18 | function run(code, file) { 19 | try { 20 | const start = process.hrtime(); 21 | const transformed = __shimport__.transform(code, file); 22 | const time = process.hrtime(start); 23 | 24 | const duration = time[0] * 1000 | time[1] / 1e6; 25 | 26 | return { duration, transformed }; 27 | } catch (e) { 28 | err = e; 29 | return null; 30 | } 31 | } 32 | 33 | const firstRun = run(code, file); 34 | 35 | if (firstRun === null) { 36 | const match = /Error parsing module at character (\d+)/.exec(err.message); 37 | if (match) { 38 | const { line, column } = locate(code, +match[1]); 39 | err.message += ` (${line}:${column})`; 40 | } 41 | console.log(c.bold.red(err.message)); 42 | console.log(err.stack); 43 | return; 44 | } 45 | 46 | console.log(`> Cold: ${c.bold.green(ms(firstRun.duration))}`); 47 | 48 | fs.writeFileSync(file.replace('/samples/', '/output/'), firstRun.transformed); 49 | 50 | // warm up 51 | let i = n; 52 | while (i--) run(code, file); 53 | 54 | // take average 55 | i = n; 56 | let total = 0; 57 | while (i--) total += run(code, file).duration; 58 | 59 | const avg = total / n; 60 | console.log(`> Warm: ${c.bold.green(ms(avg))} (average of ${n} runs)`); 61 | } 62 | 63 | let files = process.argv.slice(2); 64 | if (files.length === 0) { 65 | files = fs.readdirSync('bench/samples').map(f => `bench/samples/${f}`); 66 | } 67 | 68 | files.forEach(test); 69 | 70 | console.log(''); -------------------------------------------------------------------------------- /bench/output/magic-string.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('bench/samples/magic-string.js', ['sourcemap-codec'], function(__import, __exports, __dep_0){ var encode = __dep_0.encode; /*import { encode } from 'sourcemap-codec'*/; 2 | 3 | var Chunk = function Chunk(start, end, content) { 4 | this.start = start; 5 | this.end = end; 6 | this.original = content; 7 | 8 | this.intro = ''; 9 | this.outro = ''; 10 | 11 | this.content = content; 12 | this.storeName = false; 13 | this.edited = false; 14 | 15 | // we make these non-enumerable, for sanity while debugging 16 | Object.defineProperties(this, { 17 | previous: { writable: true, value: null }, 18 | next: { writable: true, value: null } 19 | }); 20 | }; 21 | 22 | Chunk.prototype.appendLeft = function appendLeft (content) { 23 | this.outro += content; 24 | }; 25 | 26 | Chunk.prototype.appendRight = function appendRight (content) { 27 | this.intro = this.intro + content; 28 | }; 29 | 30 | Chunk.prototype.clone = function clone () { 31 | var chunk = new Chunk(this.start, this.end, this.original); 32 | 33 | chunk.intro = this.intro; 34 | chunk.outro = this.outro; 35 | chunk.content = this.content; 36 | chunk.storeName = this.storeName; 37 | chunk.edited = this.edited; 38 | 39 | return chunk; 40 | }; 41 | 42 | Chunk.prototype.contains = function contains (index) { 43 | return this.start < index && index < this.end; 44 | }; 45 | 46 | Chunk.prototype.eachNext = function eachNext (fn) { 47 | var chunk = this; 48 | while (chunk) { 49 | fn(chunk); 50 | chunk = chunk.next; 51 | } 52 | }; 53 | 54 | Chunk.prototype.eachPrevious = function eachPrevious (fn) { 55 | var chunk = this; 56 | while (chunk) { 57 | fn(chunk); 58 | chunk = chunk.previous; 59 | } 60 | }; 61 | 62 | Chunk.prototype.edit = function edit (content, storeName, contentOnly) { 63 | this.content = content; 64 | if (!contentOnly) { 65 | this.intro = ''; 66 | this.outro = ''; 67 | } 68 | this.storeName = storeName; 69 | 70 | this.edited = true; 71 | 72 | return this; 73 | }; 74 | 75 | Chunk.prototype.prependLeft = function prependLeft (content) { 76 | this.outro = content + this.outro; 77 | }; 78 | 79 | Chunk.prototype.prependRight = function prependRight (content) { 80 | this.intro = content + this.intro; 81 | }; 82 | 83 | Chunk.prototype.split = function split (index) { 84 | var sliceIndex = index - this.start; 85 | 86 | var originalBefore = this.original.slice(0, sliceIndex); 87 | var originalAfter = this.original.slice(sliceIndex); 88 | 89 | this.original = originalBefore; 90 | 91 | var newChunk = new Chunk(index, this.end, originalAfter); 92 | newChunk.outro = this.outro; 93 | this.outro = ''; 94 | 95 | this.end = index; 96 | 97 | if (this.edited) { 98 | // TODO is this block necessary?... 99 | newChunk.edit('', false); 100 | this.content = ''; 101 | } else { 102 | this.content = originalBefore; 103 | } 104 | 105 | newChunk.next = this.next; 106 | if (newChunk.next) { newChunk.next.previous = newChunk; } 107 | newChunk.previous = this; 108 | this.next = newChunk; 109 | 110 | return newChunk; 111 | }; 112 | 113 | Chunk.prototype.toString = function toString () { 114 | return this.intro + this.content + this.outro; 115 | }; 116 | 117 | Chunk.prototype.trimEnd = function trimEnd (rx) { 118 | this.outro = this.outro.replace(rx, ''); 119 | if (this.outro.length) { return true; } 120 | 121 | var trimmed = this.content.replace(rx, ''); 122 | 123 | if (trimmed.length) { 124 | if (trimmed !== this.content) { 125 | this.split(this.start + trimmed.length).edit('', undefined, true); 126 | } 127 | return true; 128 | 129 | } else { 130 | this.edit('', undefined, true); 131 | 132 | this.intro = this.intro.replace(rx, ''); 133 | if (this.intro.length) { return true; } 134 | } 135 | }; 136 | 137 | Chunk.prototype.trimStart = function trimStart (rx) { 138 | this.intro = this.intro.replace(rx, ''); 139 | if (this.intro.length) { return true; } 140 | 141 | var trimmed = this.content.replace(rx, ''); 142 | 143 | if (trimmed.length) { 144 | if (trimmed !== this.content) { 145 | this.split(this.end - trimmed.length); 146 | this.edit('', undefined, true); 147 | } 148 | return true; 149 | 150 | } else { 151 | this.edit('', undefined, true); 152 | 153 | this.outro = this.outro.replace(rx, ''); 154 | if (this.outro.length) { return true; } 155 | } 156 | }; 157 | 158 | var btoa = function () { 159 | throw new Error('Unsupported environment: `window.btoa` or `Buffer` should be supported.'); 160 | }; 161 | if (typeof window !== 'undefined' && typeof window.btoa === 'function') { 162 | btoa = window.btoa; 163 | } else if (typeof Buffer === 'function') { 164 | btoa = function (str) { return new Buffer(str).toString('base64'); }; 165 | } 166 | 167 | var SourceMap = function SourceMap(properties) { 168 | this.version = 3; 169 | this.file = properties.file; 170 | this.sources = properties.sources; 171 | this.sourcesContent = properties.sourcesContent; 172 | this.names = properties.names; 173 | this.mappings = encode(properties.mappings); 174 | }; 175 | 176 | SourceMap.prototype.toString = function toString () { 177 | return JSON.stringify(this); 178 | }; 179 | 180 | SourceMap.prototype.toUrl = function toUrl () { 181 | return 'data:application/json;charset=utf-8;base64,' + btoa(this.toString()); 182 | }; 183 | 184 | function guessIndent(code) { 185 | var lines = code.split('\n'); 186 | 187 | var tabbed = lines.filter(function (line) { return /^\t+/.test(line); }); 188 | var spaced = lines.filter(function (line) { return /^ {2,}/.test(line); }); 189 | 190 | if (tabbed.length === 0 && spaced.length === 0) { 191 | return null; 192 | } 193 | 194 | // More lines tabbed than spaced? Assume tabs, and 195 | // default to tabs in the case of a tie (or nothing 196 | // to go on) 197 | if (tabbed.length >= spaced.length) { 198 | return '\t'; 199 | } 200 | 201 | // Otherwise, we need to guess the multiple 202 | var min = spaced.reduce(function (previous, current) { 203 | var numSpaces = /^ +/.exec(current)[0].length; 204 | return Math.min(numSpaces, previous); 205 | }, Infinity); 206 | 207 | return new Array(min + 1).join(' '); 208 | } 209 | 210 | function getRelativePath(from, to) { 211 | var fromParts = from.split(/[/\\]/); 212 | var toParts = to.split(/[/\\]/); 213 | 214 | fromParts.pop(); // get dirname 215 | 216 | while (fromParts[0] === toParts[0]) { 217 | fromParts.shift(); 218 | toParts.shift(); 219 | } 220 | 221 | if (fromParts.length) { 222 | var i = fromParts.length; 223 | while (i--) { fromParts[i] = '..'; } 224 | } 225 | 226 | return fromParts.concat(toParts).join('/'); 227 | } 228 | 229 | var toString = Object.prototype.toString; 230 | 231 | function isObject(thing) { 232 | return toString.call(thing) === '[object Object]'; 233 | } 234 | 235 | function getLocator(source) { 236 | var originalLines = source.split('\n'); 237 | var lineOffsets = []; 238 | 239 | for (var i = 0, pos = 0; i < originalLines.length; i++) { 240 | lineOffsets.push(pos); 241 | pos += originalLines[i].length + 1; 242 | } 243 | 244 | return function locate(index) { 245 | var i = 0; 246 | var j = lineOffsets.length; 247 | while (i < j) { 248 | var m = (i + j) >> 1; 249 | if (index < lineOffsets[m]) { 250 | j = m; 251 | } else { 252 | i = m + 1; 253 | } 254 | } 255 | var line = i - 1; 256 | var column = index - lineOffsets[line]; 257 | return { line: line, column: column }; 258 | }; 259 | } 260 | 261 | var Mappings = function Mappings(hires) { 262 | this.hires = hires; 263 | this.generatedCodeLine = 0; 264 | this.generatedCodeColumn = 0; 265 | this.raw = []; 266 | this.rawSegments = this.raw[this.generatedCodeLine] = []; 267 | this.pending = null; 268 | }; 269 | 270 | Mappings.prototype.addEdit = function addEdit (sourceIndex, content, loc, nameIndex) { 271 | if (content.length) { 272 | var segment = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column]; 273 | if (nameIndex >= 0) { 274 | segment.push(nameIndex); 275 | } 276 | this.rawSegments.push(segment); 277 | } else if (this.pending) { 278 | this.rawSegments.push(this.pending); 279 | } 280 | 281 | this.advance(content); 282 | this.pending = null; 283 | }; 284 | 285 | Mappings.prototype.addUneditedChunk = function addUneditedChunk (sourceIndex, chunk, original, loc, sourcemapLocations) { 286 | var this$1 = this; 287 | 288 | var originalCharIndex = chunk.start; 289 | var first = true; 290 | 291 | while (originalCharIndex < chunk.end) { 292 | if (this$1.hires || first || sourcemapLocations[originalCharIndex]) { 293 | this$1.rawSegments.push([this$1.generatedCodeColumn, sourceIndex, loc.line, loc.column]); 294 | } 295 | 296 | if (original[originalCharIndex] === '\n') { 297 | loc.line += 1; 298 | loc.column = 0; 299 | this$1.generatedCodeLine += 1; 300 | this$1.raw[this$1.generatedCodeLine] = this$1.rawSegments = []; 301 | this$1.generatedCodeColumn = 0; 302 | } else { 303 | loc.column += 1; 304 | this$1.generatedCodeColumn += 1; 305 | } 306 | 307 | originalCharIndex += 1; 308 | first = false; 309 | } 310 | 311 | this.pending = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column]; 312 | }; 313 | 314 | Mappings.prototype.advance = function advance (str) { 315 | var this$1 = this; 316 | 317 | if (!str) { return; } 318 | 319 | var lines = str.split('\n'); 320 | 321 | if (lines.length > 1) { 322 | for (var i = 0; i < lines.length - 1; i++) { 323 | this$1.generatedCodeLine++; 324 | this$1.raw[this$1.generatedCodeLine] = this$1.rawSegments = []; 325 | } 326 | this.generatedCodeColumn = 0; 327 | } 328 | 329 | this.generatedCodeColumn += lines[lines.length - 1].length; 330 | }; 331 | 332 | var n = '\n'; 333 | 334 | var warned = { 335 | insertLeft: false, 336 | insertRight: false, 337 | storeName: false 338 | }; 339 | 340 | var MagicString = function MagicString(string, options) { 341 | if ( options === void 0 ) options = {}; 342 | 343 | var chunk = new Chunk(0, string.length, string); 344 | 345 | Object.defineProperties(this, { 346 | original: { writable: true, value: string }, 347 | outro: { writable: true, value: '' }, 348 | intro: { writable: true, value: '' }, 349 | firstChunk: { writable: true, value: chunk }, 350 | lastChunk: { writable: true, value: chunk }, 351 | lastSearchedChunk: { writable: true, value: chunk }, 352 | byStart: { writable: true, value: {} }, 353 | byEnd: { writable: true, value: {} }, 354 | filename: { writable: true, value: options.filename }, 355 | indentExclusionRanges: { writable: true, value: options.indentExclusionRanges }, 356 | sourcemapLocations: { writable: true, value: {} }, 357 | storedNames: { writable: true, value: {} }, 358 | indentStr: { writable: true, value: guessIndent(string) } 359 | }); 360 | 361 | this.byStart[0] = chunk; 362 | this.byEnd[string.length] = chunk; 363 | }; 364 | 365 | MagicString.prototype.addSourcemapLocation = function addSourcemapLocation (char) { 366 | this.sourcemapLocations[char] = true; 367 | }; 368 | 369 | MagicString.prototype.append = function append (content) { 370 | if (typeof content !== 'string') { throw new TypeError('outro content must be a string'); } 371 | 372 | this.outro += content; 373 | return this; 374 | }; 375 | 376 | MagicString.prototype.appendLeft = function appendLeft (index, content) { 377 | if (typeof content !== 'string') { throw new TypeError('inserted content must be a string'); } 378 | 379 | this._split(index); 380 | 381 | var chunk = this.byEnd[index]; 382 | 383 | if (chunk) { 384 | chunk.appendLeft(content); 385 | } else { 386 | this.intro += content; 387 | } 388 | return this; 389 | }; 390 | 391 | MagicString.prototype.appendRight = function appendRight (index, content) { 392 | if (typeof content !== 'string') { throw new TypeError('inserted content must be a string'); } 393 | 394 | this._split(index); 395 | 396 | var chunk = this.byStart[index]; 397 | 398 | if (chunk) { 399 | chunk.appendRight(content); 400 | } else { 401 | this.outro += content; 402 | } 403 | return this; 404 | }; 405 | 406 | MagicString.prototype.clone = function clone () { 407 | var cloned = new MagicString(this.original, { filename: this.filename }); 408 | 409 | var originalChunk = this.firstChunk; 410 | var clonedChunk = (cloned.firstChunk = cloned.lastSearchedChunk = originalChunk.clone()); 411 | 412 | while (originalChunk) { 413 | cloned.byStart[clonedChunk.start] = clonedChunk; 414 | cloned.byEnd[clonedChunk.end] = clonedChunk; 415 | 416 | var nextOriginalChunk = originalChunk.next; 417 | var nextClonedChunk = nextOriginalChunk && nextOriginalChunk.clone(); 418 | 419 | if (nextClonedChunk) { 420 | clonedChunk.next = nextClonedChunk; 421 | nextClonedChunk.previous = clonedChunk; 422 | 423 | clonedChunk = nextClonedChunk; 424 | } 425 | 426 | originalChunk = nextOriginalChunk; 427 | } 428 | 429 | cloned.lastChunk = clonedChunk; 430 | 431 | if (this.indentExclusionRanges) { 432 | cloned.indentExclusionRanges = this.indentExclusionRanges.slice(); 433 | } 434 | 435 | Object.keys(this.sourcemapLocations).forEach(function (loc) { 436 | cloned.sourcemapLocations[loc] = true; 437 | }); 438 | 439 | return cloned; 440 | }; 441 | 442 | MagicString.prototype.generateDecodedMap = function generateDecodedMap (options) { 443 | var this$1 = this; 444 | 445 | options = options || {}; 446 | 447 | var sourceIndex = 0; 448 | var names = Object.keys(this.storedNames); 449 | var mappings = new Mappings(options.hires); 450 | 451 | var locate = getLocator(this.original); 452 | 453 | if (this.intro) { 454 | mappings.advance(this.intro); 455 | } 456 | 457 | this.firstChunk.eachNext(function (chunk) { 458 | var loc = locate(chunk.start); 459 | 460 | if (chunk.intro.length) { mappings.advance(chunk.intro); } 461 | 462 | if (chunk.edited) { 463 | mappings.addEdit( 464 | sourceIndex, 465 | chunk.content, 466 | loc, 467 | chunk.storeName ? names.indexOf(chunk.original) : -1 468 | ); 469 | } else { 470 | mappings.addUneditedChunk(sourceIndex, chunk, this$1.original, loc, this$1.sourcemapLocations); 471 | } 472 | 473 | if (chunk.outro.length) { mappings.advance(chunk.outro); } 474 | }); 475 | 476 | return { 477 | file: options.file ? options.file.split(/[/\\]/).pop() : null, 478 | sources: [options.source ? getRelativePath(options.file || '', options.source) : null], 479 | sourcesContent: options.includeContent ? [this.original] : [null], 480 | names: names, 481 | mappings: mappings.raw 482 | }; 483 | }; 484 | 485 | MagicString.prototype.generateMap = function generateMap (options) { 486 | return new SourceMap(this.generateDecodedMap(options)); 487 | }; 488 | 489 | MagicString.prototype.getIndentString = function getIndentString () { 490 | return this.indentStr === null ? '\t' : this.indentStr; 491 | }; 492 | 493 | MagicString.prototype.indent = function indent (indentStr, options) { 494 | var this$1 = this; 495 | 496 | var pattern = /^[^\r\n]/gm; 497 | 498 | if (isObject(indentStr)) { 499 | options = indentStr; 500 | indentStr = undefined; 501 | } 502 | 503 | indentStr = indentStr !== undefined ? indentStr : this.indentStr || '\t'; 504 | 505 | if (indentStr === '') { return this; } // noop 506 | 507 | options = options || {}; 508 | 509 | // Process exclusion ranges 510 | var isExcluded = {}; 511 | 512 | if (options.exclude) { 513 | var exclusions = 514 | typeof options.exclude[0] === 'number' ? [options.exclude] : options.exclude; 515 | exclusions.forEach(function (exclusion) { 516 | for (var i = exclusion[0]; i < exclusion[1]; i += 1) { 517 | isExcluded[i] = true; 518 | } 519 | }); 520 | } 521 | 522 | var shouldIndentNextCharacter = options.indentStart !== false; 523 | var replacer = function (match) { 524 | if (shouldIndentNextCharacter) { return ("" + indentStr + match); } 525 | shouldIndentNextCharacter = true; 526 | return match; 527 | }; 528 | 529 | this.intro = this.intro.replace(pattern, replacer); 530 | 531 | var charIndex = 0; 532 | var chunk = this.firstChunk; 533 | 534 | while (chunk) { 535 | var end = chunk.end; 536 | 537 | if (chunk.edited) { 538 | if (!isExcluded[charIndex]) { 539 | chunk.content = chunk.content.replace(pattern, replacer); 540 | 541 | if (chunk.content.length) { 542 | shouldIndentNextCharacter = chunk.content[chunk.content.length - 1] === '\n'; 543 | } 544 | } 545 | } else { 546 | charIndex = chunk.start; 547 | 548 | while (charIndex < end) { 549 | if (!isExcluded[charIndex]) { 550 | var char = this$1.original[charIndex]; 551 | 552 | if (char === '\n') { 553 | shouldIndentNextCharacter = true; 554 | } else if (char !== '\r' && shouldIndentNextCharacter) { 555 | shouldIndentNextCharacter = false; 556 | 557 | if (charIndex === chunk.start) { 558 | chunk.prependRight(indentStr); 559 | } else { 560 | this$1._splitChunk(chunk, charIndex); 561 | chunk = chunk.next; 562 | chunk.prependRight(indentStr); 563 | } 564 | } 565 | } 566 | 567 | charIndex += 1; 568 | } 569 | } 570 | 571 | charIndex = chunk.end; 572 | chunk = chunk.next; 573 | } 574 | 575 | this.outro = this.outro.replace(pattern, replacer); 576 | 577 | return this; 578 | }; 579 | 580 | MagicString.prototype.insert = function insert () { 581 | throw new Error('magicString.insert(...) is deprecated. Use prependRight(...) or appendLeft(...)'); 582 | }; 583 | 584 | MagicString.prototype.insertLeft = function insertLeft (index, content) { 585 | if (!warned.insertLeft) { 586 | console.warn('magicString.insertLeft(...) is deprecated. Use magicString.appendLeft(...) instead'); // eslint-disable-line no-console 587 | warned.insertLeft = true; 588 | } 589 | 590 | return this.appendLeft(index, content); 591 | }; 592 | 593 | MagicString.prototype.insertRight = function insertRight (index, content) { 594 | if (!warned.insertRight) { 595 | console.warn('magicString.insertRight(...) is deprecated. Use magicString.prependRight(...) instead'); // eslint-disable-line no-console 596 | warned.insertRight = true; 597 | } 598 | 599 | return this.prependRight(index, content); 600 | }; 601 | 602 | MagicString.prototype.move = function move (start, end, index) { 603 | if (index >= start && index <= end) { throw new Error('Cannot move a selection inside itself'); } 604 | 605 | this._split(start); 606 | this._split(end); 607 | this._split(index); 608 | 609 | var first = this.byStart[start]; 610 | var last = this.byEnd[end]; 611 | 612 | var oldLeft = first.previous; 613 | var oldRight = last.next; 614 | 615 | var newRight = this.byStart[index]; 616 | if (!newRight && last === this.lastChunk) { return this; } 617 | var newLeft = newRight ? newRight.previous : this.lastChunk; 618 | 619 | if (oldLeft) { oldLeft.next = oldRight; } 620 | if (oldRight) { oldRight.previous = oldLeft; } 621 | 622 | if (newLeft) { newLeft.next = first; } 623 | if (newRight) { newRight.previous = last; } 624 | 625 | if (!first.previous) { this.firstChunk = last.next; } 626 | if (!last.next) { 627 | this.lastChunk = first.previous; 628 | this.lastChunk.next = null; 629 | } 630 | 631 | first.previous = newLeft; 632 | last.next = newRight || null; 633 | 634 | if (!newLeft) { this.firstChunk = first; } 635 | if (!newRight) { this.lastChunk = last; } 636 | return this; 637 | }; 638 | 639 | MagicString.prototype.overwrite = function overwrite (start, end, content, options) { 640 | var this$1 = this; 641 | 642 | if (typeof content !== 'string') { throw new TypeError('replacement content must be a string'); } 643 | 644 | while (start < 0) { start += this$1.original.length; } 645 | while (end < 0) { end += this$1.original.length; } 646 | 647 | if (end > this.original.length) { throw new Error('end is out of bounds'); } 648 | if (start === end) 649 | { throw new Error('Cannot overwrite a zero-length range – use appendLeft or prependRight instead'); } 650 | 651 | this._split(start); 652 | this._split(end); 653 | 654 | if (options === true) { 655 | if (!warned.storeName) { 656 | console.warn('The final argument to magicString.overwrite(...) should be an options object. See https://github.com/rich-harris/magic-string'); // eslint-disable-line no-console 657 | warned.storeName = true; 658 | } 659 | 660 | options = { storeName: true }; 661 | } 662 | var storeName = options !== undefined ? options.storeName : false; 663 | var contentOnly = options !== undefined ? options.contentOnly : false; 664 | 665 | if (storeName) { 666 | var original = this.original.slice(start, end); 667 | this.storedNames[original] = true; 668 | } 669 | 670 | var first = this.byStart[start]; 671 | var last = this.byEnd[end]; 672 | 673 | if (first) { 674 | if (end > first.end && first.next !== this.byStart[first.end]) { 675 | throw new Error('Cannot overwrite across a split point'); 676 | } 677 | 678 | first.edit(content, storeName, contentOnly); 679 | 680 | if (first !== last) { 681 | var chunk = first.next; 682 | while (chunk !== last) { 683 | chunk.edit('', false); 684 | chunk = chunk.next; 685 | } 686 | 687 | chunk.edit('', false); 688 | } 689 | } else { 690 | // must be inserting at the end 691 | var newChunk = new Chunk(start, end, '').edit(content, storeName); 692 | 693 | // TODO last chunk in the array may not be the last chunk, if it's moved... 694 | last.next = newChunk; 695 | newChunk.previous = last; 696 | } 697 | return this; 698 | }; 699 | 700 | MagicString.prototype.prepend = function prepend (content) { 701 | if (typeof content !== 'string') { throw new TypeError('outro content must be a string'); } 702 | 703 | this.intro = content + this.intro; 704 | return this; 705 | }; 706 | 707 | MagicString.prototype.prependLeft = function prependLeft (index, content) { 708 | if (typeof content !== 'string') { throw new TypeError('inserted content must be a string'); } 709 | 710 | this._split(index); 711 | 712 | var chunk = this.byEnd[index]; 713 | 714 | if (chunk) { 715 | chunk.prependLeft(content); 716 | } else { 717 | this.intro = content + this.intro; 718 | } 719 | return this; 720 | }; 721 | 722 | MagicString.prototype.prependRight = function prependRight (index, content) { 723 | if (typeof content !== 'string') { throw new TypeError('inserted content must be a string'); } 724 | 725 | this._split(index); 726 | 727 | var chunk = this.byStart[index]; 728 | 729 | if (chunk) { 730 | chunk.prependRight(content); 731 | } else { 732 | this.outro = content + this.outro; 733 | } 734 | return this; 735 | }; 736 | 737 | MagicString.prototype.remove = function remove (start, end) { 738 | var this$1 = this; 739 | 740 | while (start < 0) { start += this$1.original.length; } 741 | while (end < 0) { end += this$1.original.length; } 742 | 743 | if (start === end) { return this; } 744 | 745 | if (start < 0 || end > this.original.length) { throw new Error('Character is out of bounds'); } 746 | if (start > end) { throw new Error('end must be greater than start'); } 747 | 748 | this._split(start); 749 | this._split(end); 750 | 751 | var chunk = this.byStart[start]; 752 | 753 | while (chunk) { 754 | chunk.intro = ''; 755 | chunk.outro = ''; 756 | chunk.edit(''); 757 | 758 | chunk = end > chunk.end ? this$1.byStart[chunk.end] : null; 759 | } 760 | return this; 761 | }; 762 | 763 | MagicString.prototype.lastChar = function lastChar () { 764 | if (this.outro.length) 765 | { return this.outro[this.outro.length - 1]; } 766 | var chunk = this.lastChunk; 767 | do { 768 | if (chunk.outro.length) 769 | { return chunk.outro[chunk.outro.length - 1]; } 770 | if (chunk.content.length) 771 | { return chunk.content[chunk.content.length - 1]; } 772 | if (chunk.intro.length) 773 | { return chunk.intro[chunk.intro.length - 1]; } 774 | } while (chunk = chunk.previous); 775 | if (this.intro.length) 776 | { return this.intro[this.intro.length - 1]; } 777 | return ''; 778 | }; 779 | 780 | MagicString.prototype.lastLine = function lastLine () { 781 | var lineIndex = this.outro.lastIndexOf(n); 782 | if (lineIndex !== -1) 783 | { return this.outro.substr(lineIndex + 1); } 784 | var lineStr = this.outro; 785 | var chunk = this.lastChunk; 786 | do { 787 | if (chunk.outro.length > 0) { 788 | lineIndex = chunk.outro.lastIndexOf(n); 789 | if (lineIndex !== -1) 790 | { return chunk.outro.substr(lineIndex + 1) + lineStr; } 791 | lineStr = chunk.outro + lineStr; 792 | } 793 | 794 | if (chunk.content.length > 0) { 795 | lineIndex = chunk.content.lastIndexOf(n); 796 | if (lineIndex !== -1) 797 | { return chunk.content.substr(lineIndex + 1) + lineStr; } 798 | lineStr = chunk.content + lineStr; 799 | } 800 | 801 | if (chunk.intro.length > 0) { 802 | lineIndex = chunk.intro.lastIndexOf(n); 803 | if (lineIndex !== -1) 804 | { return chunk.intro.substr(lineIndex + 1) + lineStr; } 805 | lineStr = chunk.intro + lineStr; 806 | } 807 | } while (chunk = chunk.previous); 808 | lineIndex = this.intro.lastIndexOf(n); 809 | if (lineIndex !== -1) 810 | { return this.intro.substr(lineIndex + 1) + lineStr; } 811 | return this.intro + lineStr; 812 | }; 813 | 814 | MagicString.prototype.slice = function slice (start, end) { 815 | var this$1 = this; 816 | if ( start === void 0 ) start = 0; 817 | if ( end === void 0 ) end = this.original.length; 818 | 819 | while (start < 0) { start += this$1.original.length; } 820 | while (end < 0) { end += this$1.original.length; } 821 | 822 | var result = ''; 823 | 824 | // find start chunk 825 | var chunk = this.firstChunk; 826 | while (chunk && (chunk.start > start || chunk.end <= start)) { 827 | // found end chunk before start 828 | if (chunk.start < end && chunk.end >= end) { 829 | return result; 830 | } 831 | 832 | chunk = chunk.next; 833 | } 834 | 835 | if (chunk && chunk.edited && chunk.start !== start) 836 | { throw new Error(("Cannot use replaced character " + start + " as slice start anchor.")); } 837 | 838 | var startChunk = chunk; 839 | while (chunk) { 840 | if (chunk.intro && (startChunk !== chunk || chunk.start === start)) { 841 | result += chunk.intro; 842 | } 843 | 844 | var containsEnd = chunk.start < end && chunk.end >= end; 845 | if (containsEnd && chunk.edited && chunk.end !== end) 846 | { throw new Error(("Cannot use replaced character " + end + " as slice end anchor.")); } 847 | 848 | var sliceStart = startChunk === chunk ? start - chunk.start : 0; 849 | var sliceEnd = containsEnd ? chunk.content.length + end - chunk.end : chunk.content.length; 850 | 851 | result += chunk.content.slice(sliceStart, sliceEnd); 852 | 853 | if (chunk.outro && (!containsEnd || chunk.end === end)) { 854 | result += chunk.outro; 855 | } 856 | 857 | if (containsEnd) { 858 | break; 859 | } 860 | 861 | chunk = chunk.next; 862 | } 863 | 864 | return result; 865 | }; 866 | 867 | // TODO deprecate this? not really very useful 868 | MagicString.prototype.snip = function snip (start, end) { 869 | var clone = this.clone(); 870 | clone.remove(0, start); 871 | clone.remove(end, clone.original.length); 872 | 873 | return clone; 874 | }; 875 | 876 | MagicString.prototype._split = function _split (index) { 877 | var this$1 = this; 878 | 879 | if (this.byStart[index] || this.byEnd[index]) { return; } 880 | 881 | var chunk = this.lastSearchedChunk; 882 | var searchForward = index > chunk.end; 883 | 884 | while (chunk) { 885 | if (chunk.contains(index)) { return this$1._splitChunk(chunk, index); } 886 | 887 | chunk = searchForward ? this$1.byStart[chunk.end] : this$1.byEnd[chunk.start]; 888 | } 889 | }; 890 | 891 | MagicString.prototype._splitChunk = function _splitChunk (chunk, index) { 892 | if (chunk.edited && chunk.content.length) { 893 | // zero-length edited chunks are a special case (overlapping replacements) 894 | var loc = getLocator(this.original)(index); 895 | throw new Error( 896 | ("Cannot split a chunk that has already been edited (" + (loc.line) + ":" + (loc.column) + " – \"" + (chunk.original) + "\")") 897 | ); 898 | } 899 | 900 | var newChunk = chunk.split(index); 901 | 902 | this.byEnd[index] = chunk; 903 | this.byStart[index] = newChunk; 904 | this.byEnd[newChunk.end] = newChunk; 905 | 906 | if (chunk === this.lastChunk) { this.lastChunk = newChunk; } 907 | 908 | this.lastSearchedChunk = chunk; 909 | return true; 910 | }; 911 | 912 | MagicString.prototype.toString = function toString () { 913 | var str = this.intro; 914 | 915 | var chunk = this.firstChunk; 916 | while (chunk) { 917 | str += chunk.toString(); 918 | chunk = chunk.next; 919 | } 920 | 921 | return str + this.outro; 922 | }; 923 | 924 | MagicString.prototype.isEmpty = function isEmpty () { 925 | var chunk = this.firstChunk; 926 | do { 927 | if (chunk.intro.length && chunk.intro.trim() || 928 | chunk.content.length && chunk.content.trim() || 929 | chunk.outro.length && chunk.outro.trim()) 930 | { return false; } 931 | } while (chunk = chunk.next); 932 | return true; 933 | }; 934 | 935 | MagicString.prototype.length = function length () { 936 | var chunk = this.firstChunk; 937 | var length = 0; 938 | do { 939 | length += chunk.intro.length + chunk.content.length + chunk.outro.length; 940 | } while (chunk = chunk.next); 941 | return length; 942 | }; 943 | 944 | MagicString.prototype.trimLines = function trimLines () { 945 | return this.trim('[\\r\\n]'); 946 | }; 947 | 948 | MagicString.prototype.trim = function trim (charType) { 949 | return this.trimStart(charType).trimEnd(charType); 950 | }; 951 | 952 | MagicString.prototype.trimEndAborted = function trimEndAborted (charType) { 953 | var this$1 = this; 954 | 955 | var rx = new RegExp((charType || '\\s') + '+$'); 956 | 957 | this.outro = this.outro.replace(rx, ''); 958 | if (this.outro.length) { return true; } 959 | 960 | var chunk = this.lastChunk; 961 | 962 | do { 963 | var end = chunk.end; 964 | var aborted = chunk.trimEnd(rx); 965 | 966 | // if chunk was trimmed, we have a new lastChunk 967 | if (chunk.end !== end) { 968 | if (this$1.lastChunk === chunk) { 969 | this$1.lastChunk = chunk.next; 970 | } 971 | 972 | this$1.byEnd[chunk.end] = chunk; 973 | this$1.byStart[chunk.next.start] = chunk.next; 974 | this$1.byEnd[chunk.next.end] = chunk.next; 975 | } 976 | 977 | if (aborted) { return true; } 978 | chunk = chunk.previous; 979 | } while (chunk); 980 | 981 | return false; 982 | }; 983 | 984 | MagicString.prototype.trimEnd = function trimEnd (charType) { 985 | this.trimEndAborted(charType); 986 | return this; 987 | }; 988 | MagicString.prototype.trimStartAborted = function trimStartAborted (charType) { 989 | var this$1 = this; 990 | 991 | var rx = new RegExp('^' + (charType || '\\s') + '+'); 992 | 993 | this.intro = this.intro.replace(rx, ''); 994 | if (this.intro.length) { return true; } 995 | 996 | var chunk = this.firstChunk; 997 | 998 | do { 999 | var end = chunk.end; 1000 | var aborted = chunk.trimStart(rx); 1001 | 1002 | if (chunk.end !== end) { 1003 | // special case... 1004 | if (chunk === this$1.lastChunk) { this$1.lastChunk = chunk.next; } 1005 | 1006 | this$1.byEnd[chunk.end] = chunk; 1007 | this$1.byStart[chunk.next.start] = chunk.next; 1008 | this$1.byEnd[chunk.next.end] = chunk.next; 1009 | } 1010 | 1011 | if (aborted) { return true; } 1012 | chunk = chunk.next; 1013 | } while (chunk); 1014 | 1015 | return false; 1016 | }; 1017 | 1018 | MagicString.prototype.trimStart = function trimStart (charType) { 1019 | this.trimStartAborted(charType); 1020 | return this; 1021 | }; 1022 | 1023 | var hasOwnProp = Object.prototype.hasOwnProperty; 1024 | 1025 | var Bundle = function Bundle(options) { 1026 | if ( options === void 0 ) options = {}; 1027 | 1028 | this.intro = options.intro || ''; 1029 | this.separator = options.separator !== undefined ? options.separator : '\n'; 1030 | this.sources = []; 1031 | this.uniqueSources = []; 1032 | this.uniqueSourceIndexByFilename = {}; 1033 | }; 1034 | 1035 | Bundle.prototype.addSource = function addSource (source) { 1036 | if (source instanceof MagicString) { 1037 | return this.addSource({ 1038 | content: source, 1039 | filename: source.filename, 1040 | separator: this.separator 1041 | }); 1042 | } 1043 | 1044 | if (!isObject(source) || !source.content) { 1045 | throw new Error('bundle.addSource() takes an object with a `content` property, which should be an instance of MagicString, and an optional `filename`'); 1046 | } 1047 | 1048 | ['filename', 'indentExclusionRanges', 'separator'].forEach(function (option) { 1049 | if (!hasOwnProp.call(source, option)) { source[option] = source.content[option]; } 1050 | }); 1051 | 1052 | if (source.separator === undefined) { 1053 | // TODO there's a bunch of this sort of thing, needs cleaning up 1054 | source.separator = this.separator; 1055 | } 1056 | 1057 | if (source.filename) { 1058 | if (!hasOwnProp.call(this.uniqueSourceIndexByFilename, source.filename)) { 1059 | this.uniqueSourceIndexByFilename[source.filename] = this.uniqueSources.length; 1060 | this.uniqueSources.push({ filename: source.filename, content: source.content.original }); 1061 | } else { 1062 | var uniqueSource = this.uniqueSources[this.uniqueSourceIndexByFilename[source.filename]]; 1063 | if (source.content.original !== uniqueSource.content) { 1064 | throw new Error(("Illegal source: same filename (" + (source.filename) + "), different contents")); 1065 | } 1066 | } 1067 | } 1068 | 1069 | this.sources.push(source); 1070 | return this; 1071 | }; 1072 | 1073 | Bundle.prototype.append = function append (str, options) { 1074 | this.addSource({ 1075 | content: new MagicString(str), 1076 | separator: (options && options.separator) || '' 1077 | }); 1078 | 1079 | return this; 1080 | }; 1081 | 1082 | Bundle.prototype.clone = function clone () { 1083 | var bundle = new Bundle({ 1084 | intro: this.intro, 1085 | separator: this.separator 1086 | }); 1087 | 1088 | this.sources.forEach(function (source) { 1089 | bundle.addSource({ 1090 | filename: source.filename, 1091 | content: source.content.clone(), 1092 | separator: source.separator 1093 | }); 1094 | }); 1095 | 1096 | return bundle; 1097 | }; 1098 | 1099 | Bundle.prototype.generateDecodedMap = function generateDecodedMap (options) { 1100 | var this$1 = this; 1101 | if ( options === void 0 ) options = {}; 1102 | 1103 | var names = []; 1104 | this.sources.forEach(function (source) { 1105 | Object.keys(source.content.storedNames).forEach(function (name) { 1106 | if (!~names.indexOf(name)) { names.push(name); } 1107 | }); 1108 | }); 1109 | 1110 | var mappings = new Mappings(options.hires); 1111 | 1112 | if (this.intro) { 1113 | mappings.advance(this.intro); 1114 | } 1115 | 1116 | this.sources.forEach(function (source, i) { 1117 | if (i > 0) { 1118 | mappings.advance(this$1.separator); 1119 | } 1120 | 1121 | var sourceIndex = source.filename ? this$1.uniqueSourceIndexByFilename[source.filename] : -1; 1122 | var magicString = source.content; 1123 | var locate = getLocator(magicString.original); 1124 | 1125 | if (magicString.intro) { 1126 | mappings.advance(magicString.intro); 1127 | } 1128 | 1129 | magicString.firstChunk.eachNext(function (chunk) { 1130 | var loc = locate(chunk.start); 1131 | 1132 | if (chunk.intro.length) { mappings.advance(chunk.intro); } 1133 | 1134 | if (source.filename) { 1135 | if (chunk.edited) { 1136 | mappings.addEdit( 1137 | sourceIndex, 1138 | chunk.content, 1139 | loc, 1140 | chunk.storeName ? names.indexOf(chunk.original) : -1 1141 | ); 1142 | } else { 1143 | mappings.addUneditedChunk( 1144 | sourceIndex, 1145 | chunk, 1146 | magicString.original, 1147 | loc, 1148 | magicString.sourcemapLocations 1149 | ); 1150 | } 1151 | } else { 1152 | mappings.advance(chunk.content); 1153 | } 1154 | 1155 | if (chunk.outro.length) { mappings.advance(chunk.outro); } 1156 | }); 1157 | 1158 | if (magicString.outro) { 1159 | mappings.advance(magicString.outro); 1160 | } 1161 | }); 1162 | 1163 | return { 1164 | file: options.file ? options.file.split(/[/\\]/).pop() : null, 1165 | sources: this.uniqueSources.map(function (source) { 1166 | return options.file ? getRelativePath(options.file, source.filename) : source.filename; 1167 | }), 1168 | sourcesContent: this.uniqueSources.map(function (source) { 1169 | return options.includeContent ? source.content : null; 1170 | }), 1171 | names: names, 1172 | mappings: mappings.raw 1173 | }; 1174 | }; 1175 | 1176 | Bundle.prototype.generateMap = function generateMap (options) { 1177 | return new SourceMap(this.generateDecodedMap(options)); 1178 | }; 1179 | 1180 | Bundle.prototype.getIndentString = function getIndentString () { 1181 | var indentStringCounts = {}; 1182 | 1183 | this.sources.forEach(function (source) { 1184 | var indentStr = source.content.indentStr; 1185 | 1186 | if (indentStr === null) { return; } 1187 | 1188 | if (!indentStringCounts[indentStr]) { indentStringCounts[indentStr] = 0; } 1189 | indentStringCounts[indentStr] += 1; 1190 | }); 1191 | 1192 | return ( 1193 | Object.keys(indentStringCounts).sort(function (a, b) { 1194 | return indentStringCounts[a] - indentStringCounts[b]; 1195 | })[0] || '\t' 1196 | ); 1197 | }; 1198 | 1199 | Bundle.prototype.indent = function indent (indentStr) { 1200 | var this$1 = this; 1201 | 1202 | if (!arguments.length) { 1203 | indentStr = this.getIndentString(); 1204 | } 1205 | 1206 | if (indentStr === '') { return this; } // noop 1207 | 1208 | var trailingNewline = !this.intro || this.intro.slice(-1) === '\n'; 1209 | 1210 | this.sources.forEach(function (source, i) { 1211 | var separator = source.separator !== undefined ? source.separator : this$1.separator; 1212 | var indentStart = trailingNewline || (i > 0 && /\r?\n$/.test(separator)); 1213 | 1214 | source.content.indent(indentStr, { 1215 | exclude: source.indentExclusionRanges, 1216 | indentStart: indentStart //: trailingNewline || /\r?\n$/.test( separator ) //true///\r?\n/.test( separator ) 1217 | }); 1218 | 1219 | trailingNewline = source.content.lastChar() === '\n'; 1220 | }); 1221 | 1222 | if (this.intro) { 1223 | this.intro = 1224 | indentStr + 1225 | this.intro.replace(/^[^\n]/gm, function (match, index) { 1226 | return index > 0 ? indentStr + match : match; 1227 | }); 1228 | } 1229 | 1230 | return this; 1231 | }; 1232 | 1233 | Bundle.prototype.prepend = function prepend (str) { 1234 | this.intro = str + this.intro; 1235 | return this; 1236 | }; 1237 | 1238 | Bundle.prototype.toString = function toString () { 1239 | var this$1 = this; 1240 | 1241 | var body = this.sources 1242 | .map(function (source, i) { 1243 | var separator = source.separator !== undefined ? source.separator : this$1.separator; 1244 | var str = (i > 0 ? separator : '') + source.content.toString(); 1245 | 1246 | return str; 1247 | }) 1248 | .join(''); 1249 | 1250 | return this.intro + body; 1251 | }; 1252 | 1253 | Bundle.prototype.isEmpty = function isEmpty () { 1254 | if (this.intro.length && this.intro.trim()) 1255 | { return false; } 1256 | if (this.sources.some(function (source) { return !source.content.isEmpty(); })) 1257 | { return false; } 1258 | return true; 1259 | }; 1260 | 1261 | Bundle.prototype.length = function length () { 1262 | return this.sources.reduce(function (length, source) { return length + source.content.length(); }, this.intro.length); 1263 | }; 1264 | 1265 | Bundle.prototype.trimLines = function trimLines () { 1266 | return this.trim('[\\r\\n]'); 1267 | }; 1268 | 1269 | Bundle.prototype.trim = function trim (charType) { 1270 | return this.trimStart(charType).trimEnd(charType); 1271 | }; 1272 | 1273 | Bundle.prototype.trimStart = function trimStart (charType) { 1274 | var this$1 = this; 1275 | 1276 | var rx = new RegExp('^' + (charType || '\\s') + '+'); 1277 | this.intro = this.intro.replace(rx, ''); 1278 | 1279 | if (!this.intro) { 1280 | var source; 1281 | var i = 0; 1282 | 1283 | do { 1284 | source = this$1.sources[i++]; 1285 | if (!source) { 1286 | break; 1287 | } 1288 | } while (!source.content.trimStartAborted(charType)); 1289 | } 1290 | 1291 | return this; 1292 | }; 1293 | 1294 | Bundle.prototype.trimEnd = function trimEnd (charType) { 1295 | var this$1 = this; 1296 | 1297 | var rx = new RegExp((charType || '\\s') + '+$'); 1298 | 1299 | var source; 1300 | var i = this.sources.length - 1; 1301 | 1302 | do { 1303 | source = this$1.sources[i--]; 1304 | if (!source) { 1305 | this$1.intro = this$1.intro.replace(rx, ''); 1306 | break; 1307 | } 1308 | } while (!source.content.trimEndAborted(charType)); 1309 | 1310 | return this; 1311 | }; 1312 | 1313 | __exports.default = MagicString; 1314 | __exports.Bundle = Bundle; __exports.SourceMap = SourceMap; /*export { Bundle, SourceMap }*/; 1315 | //# sourceMappingURL=magic-string.es.js.map 1316 | }); 1317 | //# sourceURL=bench/samples/magic-string.js -------------------------------------------------------------------------------- /bench/output/magic-string.min.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('bench/samples/magic-string.min.js', [], function(__import, __exports){ import{encode}from"sourcemap-codec";var Chunk=function(t,n,e){this.start=t,this.end=n,this.original=e,this.intro="",this.outro="",this.content=e,this.storeName=!1,this.edited=!1,Object.defineProperties(this,{previous:{writable:!0,value:null},next:{writable:!0,value:null}})};Chunk.prototype.appendLeft=function(t){this.outro+=t},Chunk.prototype.appendRight=function(t){this.intro=this.intro+t},Chunk.prototype.clone=function(){var t=new Chunk(this.start,this.end,this.original);return t.intro=this.intro,t.outro=this.outro,t.content=this.content,t.storeName=this.storeName,t.edited=this.edited,t},Chunk.prototype.contains=function(t){return this.start=i.length)return"\t";var r=i.reduce(function(t,n){var e=/^ +/.exec(n)[0].length;return Math.min(e,t)},1/0);return new Array(r+1).join(" ")}function getRelativePath(t,n){var e=t.split(/[\/\\]/),i=n.split(/[\/\\]/);for(e.pop();e[0]===i[0];)e.shift(),i.shift();if(e.length)for(var r=e.length;r--;)e[r]="..";return e.concat(i).join("/")}SourceMap.prototype.toString=function(){return JSON.stringify(this)},SourceMap.prototype.toUrl=function(){return"data:application/json;charset=utf-8;base64,"+btoa(this.toString())};var toString=Object.prototype.toString;function isObject(t){return"[object Object]"===toString.call(t)}function getLocator(t){for(var n=t.split("\n"),e=[],i=0,r=0;i>1;t=0&&r.push(i),this.rawSegments.push(r)}else this.pending&&this.rawSegments.push(this.pending);this.advance(n),this.pending=null},Mappings.prototype.addUneditedChunk=function(t,n,e,i,r){for(var o=n.start,s=!0;o1){for(var e=0;e=t&&e<=n)throw new Error("Cannot move a selection inside itself");this._split(t),this._split(n),this._split(e);var i=this.byStart[t],r=this.byEnd[n],o=i.previous,s=r.next,a=this.byStart[e];if(!a&&r===this.lastChunk)return this;var h=a?a.previous:this.lastChunk;return o&&(o.next=s),s&&(s.previous=o),h&&(h.next=i),a&&(a.previous=r),i.previous||(this.firstChunk=r.next),r.next||(this.lastChunk=i.previous,this.lastChunk.next=null),i.previous=h,r.next=a||null,h||(this.firstChunk=i),a||(this.lastChunk=r),this},MagicString.prototype.overwrite=function(t,n,e,i){if("string"!=typeof e)throw new TypeError("replacement content must be a string");for(;t<0;)t+=this.original.length;for(;n<0;)n+=this.original.length;if(n>this.original.length)throw new Error("end is out of bounds");if(t===n)throw new Error("Cannot overwrite a zero-length range – use appendLeft or prependRight instead");this._split(t),this._split(n),!0===i&&(warned.storeName||(console.warn("The final argument to magicString.overwrite(...) should be an options object. See https://github.com/rich-harris/magic-string"),warned.storeName=!0),i={storeName:!0});var r=void 0!==i&&i.storeName,o=void 0!==i&&i.contentOnly;if(r){var s=this.original.slice(t,n);this.storedNames[s]=!0}var a=this.byStart[t],h=this.byEnd[n];if(a){if(n>a.end&&a.next!==this.byStart[a.end])throw new Error("Cannot overwrite across a split point");if(a.edit(e,r,o),a!==h){for(var u=a.next;u!==h;)u.edit("",!1),u=u.next;u.edit("",!1)}}else{var c=new Chunk(t,n,"").edit(e,r);h.next=c,c.previous=h}return this},MagicString.prototype.prepend=function(t){if("string"!=typeof t)throw new TypeError("outro content must be a string");return this.intro=t+this.intro,this},MagicString.prototype.prependLeft=function(t,n){if("string"!=typeof n)throw new TypeError("inserted content must be a string");this._split(t);var e=this.byEnd[t];return e?e.prependLeft(n):this.intro=n+this.intro,this},MagicString.prototype.prependRight=function(t,n){if("string"!=typeof n)throw new TypeError("inserted content must be a string");this._split(t);var e=this.byStart[t];return e?e.prependRight(n):this.outro=n+this.outro,this},MagicString.prototype.remove=function(t,n){for(;t<0;)t+=this.original.length;for(;n<0;)n+=this.original.length;if(t===n)return this;if(t<0||n>this.original.length)throw new Error("Character is out of bounds");if(t>n)throw new Error("end must be greater than start");this._split(t),this._split(n);for(var e=this.byStart[t];e;)e.intro="",e.outro="",e.edit(""),e=n>e.end?this.byStart[e.end]:null;return this},MagicString.prototype.lastChar=function(){if(this.outro.length)return this.outro[this.outro.length-1];var t=this.lastChunk;do{if(t.outro.length)return t.outro[t.outro.length-1];if(t.content.length)return t.content[t.content.length-1];if(t.intro.length)return t.intro[t.intro.length-1]}while(t=t.previous);return this.intro.length?this.intro[this.intro.length-1]:""},MagicString.prototype.lastLine=function(){var t=this.outro.lastIndexOf(n);if(-1!==t)return this.outro.substr(t+1);var e=this.outro,i=this.lastChunk;do{if(i.outro.length>0){if(-1!==(t=i.outro.lastIndexOf(n)))return i.outro.substr(t+1)+e;e=i.outro+e}if(i.content.length>0){if(-1!==(t=i.content.lastIndexOf(n)))return i.content.substr(t+1)+e;e=i.content+e}if(i.intro.length>0){if(-1!==(t=i.intro.lastIndexOf(n)))return i.intro.substr(t+1)+e;e=i.intro+e}}while(i=i.previous);return-1!==(t=this.intro.lastIndexOf(n))?this.intro.substr(t+1)+e:this.intro+e},MagicString.prototype.slice=function(t,n){for(void 0===t&&(t=0),void 0===n&&(n=this.original.length);t<0;)t+=this.original.length;for(;n<0;)n+=this.original.length;for(var e="",i=this.firstChunk;i&&(i.start>t||i.end<=t);){if(i.start=n)return e;i=i.next}if(i&&i.edited&&i.start!==t)throw new Error("Cannot use replaced character "+t+" as slice start anchor.");for(var r=i;i;){!i.intro||r===i&&i.start!==t||(e+=i.intro);var o=i.start=n;if(o&&i.edited&&i.end!==n)throw new Error("Cannot use replaced character "+n+" as slice end anchor.");var s=r===i?t-i.start:0,a=o?i.content.length+n-i.end:i.content.length;if(e+=i.content.slice(s,a),!i.outro||o&&i.end!==n||(e+=i.outro),o)break;i=i.next}return e},MagicString.prototype.snip=function(t,n){var e=this.clone();return e.remove(0,t),e.remove(n,e.original.length),e},MagicString.prototype._split=function(t){if(!this.byStart[t]&&!this.byEnd[t])for(var n=this.lastSearchedChunk,e=t>n.end;n;){if(n.contains(t))return this._splitChunk(n,t);n=e?this.byStart[n.end]:this.byEnd[n.start]}},MagicString.prototype._splitChunk=function(t,n){if(t.edited&&t.content.length){var e=getLocator(this.original)(n);throw new Error("Cannot split a chunk that has already been edited ("+e.line+":"+e.column+' – "'+t.original+'")')}var i=t.split(n);return this.byEnd[n]=t,this.byStart[n]=i,this.byEnd[i.end]=i,t===this.lastChunk&&(this.lastChunk=i),this.lastSearchedChunk=t,!0},MagicString.prototype.toString=function(){for(var t=this.intro,n=this.firstChunk;n;)t+=n.toString(),n=n.next;return t+this.outro},MagicString.prototype.isEmpty=function(){var t=this.firstChunk;do{if(t.intro.length&&t.intro.trim()||t.content.length&&t.content.trim()||t.outro.length&&t.outro.trim())return!1}while(t=t.next);return!0},MagicString.prototype.length=function(){var t=this.firstChunk,n=0;do{n+=t.intro.length+t.content.length+t.outro.length}while(t=t.next);return n},MagicString.prototype.trimLines=function(){return this.trim("[\\r\\n]")},MagicString.prototype.trim=function(t){return this.trimStart(t).trimEnd(t)},MagicString.prototype.trimEndAborted=function(t){var n=new RegExp((t||"\\s")+"+$");if(this.outro=this.outro.replace(n,""),this.outro.length)return!0;var e=this.lastChunk;do{var i=e.end,r=e.trimEnd(n);if(e.end!==i&&(this.lastChunk===e&&(this.lastChunk=e.next),this.byEnd[e.end]=e,this.byStart[e.next.start]=e.next,this.byEnd[e.next.end]=e.next),r)return!0;e=e.previous}while(e);return!1},MagicString.prototype.trimEnd=function(t){return this.trimEndAborted(t),this},MagicString.prototype.trimStartAborted=function(t){var n=new RegExp("^"+(t||"\\s")+"+");if(this.intro=this.intro.replace(n,""),this.intro.length)return!0;var e=this.firstChunk;do{var i=e.end,r=e.trimStart(n);if(e.end!==i&&(e===this.lastChunk&&(this.lastChunk=e.next),this.byEnd[e.end]=e,this.byStart[e.next.start]=e.next,this.byEnd[e.next.end]=e.next),r)return!0;e=e.next}while(e);return!1},MagicString.prototype.trimStart=function(t){return this.trimStartAborted(t),this};var hasOwnProp=Object.prototype.hasOwnProperty,Bundle=function(t){void 0===t&&(t={}),this.intro=t.intro||"",this.separator=void 0!==t.separator?t.separator:"\n",this.sources=[],this.uniqueSources=[],this.uniqueSourceIndexByFilename={}};Bundle.prototype.addSource=function(t){if(t instanceof MagicString)return this.addSource({content:t,filename:t.filename,separator:this.separator});if(!isObject(t)||!t.content)throw new Error("bundle.addSource() takes an object with a `content` property, which should be an instance of MagicString, and an optional `filename`");if(["filename","indentExclusionRanges","separator"].forEach(function(n){hasOwnProp.call(t,n)||(t[n]=t.content[n])}),void 0===t.separator&&(t.separator=this.separator),t.filename)if(hasOwnProp.call(this.uniqueSourceIndexByFilename,t.filename)){var n=this.uniqueSources[this.uniqueSourceIndexByFilename[t.filename]];if(t.content.original!==n.content)throw new Error("Illegal source: same filename ("+t.filename+"), different contents")}else this.uniqueSourceIndexByFilename[t.filename]=this.uniqueSources.length,this.uniqueSources.push({filename:t.filename,content:t.content.original});return this.sources.push(t),this},Bundle.prototype.append=function(t,n){return this.addSource({content:new MagicString(t),separator:n&&n.separator||""}),this},Bundle.prototype.clone=function(){var t=new Bundle({intro:this.intro,separator:this.separator});return this.sources.forEach(function(n){t.addSource({filename:n.filename,content:n.content.clone(),separator:n.separator})}),t},Bundle.prototype.generateDecodedMap=function(t){var n=this;void 0===t&&(t={});var e=[];this.sources.forEach(function(t){Object.keys(t.content.storedNames).forEach(function(t){~e.indexOf(t)||e.push(t)})});var i=new Mappings(t.hires);return this.intro&&i.advance(this.intro),this.sources.forEach(function(t,r){r>0&&i.advance(n.separator);var o=t.filename?n.uniqueSourceIndexByFilename[t.filename]:-1,s=t.content,a=getLocator(s.original);s.intro&&i.advance(s.intro),s.firstChunk.eachNext(function(n){var r=a(n.start);n.intro.length&&i.advance(n.intro),t.filename?n.edited?i.addEdit(o,n.content,r,n.storeName?e.indexOf(n.original):-1):i.addUneditedChunk(o,n,s.original,r,s.sourcemapLocations):i.advance(n.content),n.outro.length&&i.advance(n.outro)}),s.outro&&i.advance(s.outro)}),{file:t.file?t.file.split(/[\/\\]/).pop():null,sources:this.uniqueSources.map(function(n){return t.file?getRelativePath(t.file,n.filename):n.filename}),sourcesContent:this.uniqueSources.map(function(n){return t.includeContent?n.content:null}),names:e,mappings:i.raw}},Bundle.prototype.generateMap=function(t){return new SourceMap(this.generateDecodedMap(t))},Bundle.prototype.getIndentString=function(){var t={};return this.sources.forEach(function(n){var e=n.content.indentStr;null!==e&&(t[e]||(t[e]=0),t[e]+=1)}),Object.keys(t).sort(function(n,e){return t[n]-t[e]})[0]||"\t"},Bundle.prototype.indent=function(t){var n=this;if(arguments.length||(t=this.getIndentString()),""===t)return this;var e=!this.intro||"\n"===this.intro.slice(-1);return this.sources.forEach(function(i,r){var o=void 0!==i.separator?i.separator:n.separator,s=e||r>0&&/\r?\n$/.test(o);i.content.indent(t,{exclude:i.indentExclusionRanges,indentStart:s}),e="\n"===i.content.lastChar()}),this.intro&&(this.intro=t+this.intro.replace(/^[^\n]/gm,function(n,e){return e>0?t+n:n})),this},Bundle.prototype.prepend=function(t){return this.intro=t+this.intro,this},Bundle.prototype.toString=function(){var t=this,n=this.sources.map(function(n,e){var i=void 0!==n.separator?n.separator:t.separator;return(e>0?i:"")+n.content.toString()}).join("");return this.intro+n},Bundle.prototype.isEmpty=function(){return(!this.intro.length||!this.intro.trim())&&!this.sources.some(function(t){return!t.content.isEmpty()})},Bundle.prototype.length=function(){return this.sources.reduce(function(t,n){return t+n.content.length()},this.intro.length)},Bundle.prototype.trimLines=function(){return this.trim("[\\r\\n]")},Bundle.prototype.trim=function(t){return this.trimStart(t).trimEnd(t)},Bundle.prototype.trimStart=function(t){var n=new RegExp("^"+(t||"\\s")+"+");if(this.intro=this.intro.replace(n,""),!this.intro){var e,i=0;do{if(!(e=this.sources[i++]))break}while(!e.content.trimStartAborted(t))}return this},Bundle.prototype.trimEnd=function(t){var n,e=new RegExp((t||"\\s")+"+$"),i=this.sources.length-1;do{if(!(n=this.sources[i--])){this.intro=this.intro.replace(e,"");break}}while(!n.content.trimEndAborted(t));return this};export default MagicString;export{Bundle,SourceMap}; 2 | 3 | }); 4 | //# sourceURL=bench/samples/magic-string.min.js -------------------------------------------------------------------------------- /bench/samples/magic-string.js: -------------------------------------------------------------------------------- 1 | import { encode } from 'sourcemap-codec'; 2 | 3 | var Chunk = function Chunk(start, end, content) { 4 | this.start = start; 5 | this.end = end; 6 | this.original = content; 7 | 8 | this.intro = ''; 9 | this.outro = ''; 10 | 11 | this.content = content; 12 | this.storeName = false; 13 | this.edited = false; 14 | 15 | // we make these non-enumerable, for sanity while debugging 16 | Object.defineProperties(this, { 17 | previous: { writable: true, value: null }, 18 | next: { writable: true, value: null } 19 | }); 20 | }; 21 | 22 | Chunk.prototype.appendLeft = function appendLeft (content) { 23 | this.outro += content; 24 | }; 25 | 26 | Chunk.prototype.appendRight = function appendRight (content) { 27 | this.intro = this.intro + content; 28 | }; 29 | 30 | Chunk.prototype.clone = function clone () { 31 | var chunk = new Chunk(this.start, this.end, this.original); 32 | 33 | chunk.intro = this.intro; 34 | chunk.outro = this.outro; 35 | chunk.content = this.content; 36 | chunk.storeName = this.storeName; 37 | chunk.edited = this.edited; 38 | 39 | return chunk; 40 | }; 41 | 42 | Chunk.prototype.contains = function contains (index) { 43 | return this.start < index && index < this.end; 44 | }; 45 | 46 | Chunk.prototype.eachNext = function eachNext (fn) { 47 | var chunk = this; 48 | while (chunk) { 49 | fn(chunk); 50 | chunk = chunk.next; 51 | } 52 | }; 53 | 54 | Chunk.prototype.eachPrevious = function eachPrevious (fn) { 55 | var chunk = this; 56 | while (chunk) { 57 | fn(chunk); 58 | chunk = chunk.previous; 59 | } 60 | }; 61 | 62 | Chunk.prototype.edit = function edit (content, storeName, contentOnly) { 63 | this.content = content; 64 | if (!contentOnly) { 65 | this.intro = ''; 66 | this.outro = ''; 67 | } 68 | this.storeName = storeName; 69 | 70 | this.edited = true; 71 | 72 | return this; 73 | }; 74 | 75 | Chunk.prototype.prependLeft = function prependLeft (content) { 76 | this.outro = content + this.outro; 77 | }; 78 | 79 | Chunk.prototype.prependRight = function prependRight (content) { 80 | this.intro = content + this.intro; 81 | }; 82 | 83 | Chunk.prototype.split = function split (index) { 84 | var sliceIndex = index - this.start; 85 | 86 | var originalBefore = this.original.slice(0, sliceIndex); 87 | var originalAfter = this.original.slice(sliceIndex); 88 | 89 | this.original = originalBefore; 90 | 91 | var newChunk = new Chunk(index, this.end, originalAfter); 92 | newChunk.outro = this.outro; 93 | this.outro = ''; 94 | 95 | this.end = index; 96 | 97 | if (this.edited) { 98 | // TODO is this block necessary?... 99 | newChunk.edit('', false); 100 | this.content = ''; 101 | } else { 102 | this.content = originalBefore; 103 | } 104 | 105 | newChunk.next = this.next; 106 | if (newChunk.next) { newChunk.next.previous = newChunk; } 107 | newChunk.previous = this; 108 | this.next = newChunk; 109 | 110 | return newChunk; 111 | }; 112 | 113 | Chunk.prototype.toString = function toString () { 114 | return this.intro + this.content + this.outro; 115 | }; 116 | 117 | Chunk.prototype.trimEnd = function trimEnd (rx) { 118 | this.outro = this.outro.replace(rx, ''); 119 | if (this.outro.length) { return true; } 120 | 121 | var trimmed = this.content.replace(rx, ''); 122 | 123 | if (trimmed.length) { 124 | if (trimmed !== this.content) { 125 | this.split(this.start + trimmed.length).edit('', undefined, true); 126 | } 127 | return true; 128 | 129 | } else { 130 | this.edit('', undefined, true); 131 | 132 | this.intro = this.intro.replace(rx, ''); 133 | if (this.intro.length) { return true; } 134 | } 135 | }; 136 | 137 | Chunk.prototype.trimStart = function trimStart (rx) { 138 | this.intro = this.intro.replace(rx, ''); 139 | if (this.intro.length) { return true; } 140 | 141 | var trimmed = this.content.replace(rx, ''); 142 | 143 | if (trimmed.length) { 144 | if (trimmed !== this.content) { 145 | this.split(this.end - trimmed.length); 146 | this.edit('', undefined, true); 147 | } 148 | return true; 149 | 150 | } else { 151 | this.edit('', undefined, true); 152 | 153 | this.outro = this.outro.replace(rx, ''); 154 | if (this.outro.length) { return true; } 155 | } 156 | }; 157 | 158 | var btoa = function () { 159 | throw new Error('Unsupported environment: `window.btoa` or `Buffer` should be supported.'); 160 | }; 161 | if (typeof window !== 'undefined' && typeof window.btoa === 'function') { 162 | btoa = window.btoa; 163 | } else if (typeof Buffer === 'function') { 164 | btoa = function (str) { return new Buffer(str).toString('base64'); }; 165 | } 166 | 167 | var SourceMap = function SourceMap(properties) { 168 | this.version = 3; 169 | this.file = properties.file; 170 | this.sources = properties.sources; 171 | this.sourcesContent = properties.sourcesContent; 172 | this.names = properties.names; 173 | this.mappings = encode(properties.mappings); 174 | }; 175 | 176 | SourceMap.prototype.toString = function toString () { 177 | return JSON.stringify(this); 178 | }; 179 | 180 | SourceMap.prototype.toUrl = function toUrl () { 181 | return 'data:application/json;charset=utf-8;base64,' + btoa(this.toString()); 182 | }; 183 | 184 | function guessIndent(code) { 185 | var lines = code.split('\n'); 186 | 187 | var tabbed = lines.filter(function (line) { return /^\t+/.test(line); }); 188 | var spaced = lines.filter(function (line) { return /^ {2,}/.test(line); }); 189 | 190 | if (tabbed.length === 0 && spaced.length === 0) { 191 | return null; 192 | } 193 | 194 | // More lines tabbed than spaced? Assume tabs, and 195 | // default to tabs in the case of a tie (or nothing 196 | // to go on) 197 | if (tabbed.length >= spaced.length) { 198 | return '\t'; 199 | } 200 | 201 | // Otherwise, we need to guess the multiple 202 | var min = spaced.reduce(function (previous, current) { 203 | var numSpaces = /^ +/.exec(current)[0].length; 204 | return Math.min(numSpaces, previous); 205 | }, Infinity); 206 | 207 | return new Array(min + 1).join(' '); 208 | } 209 | 210 | function getRelativePath(from, to) { 211 | var fromParts = from.split(/[/\\]/); 212 | var toParts = to.split(/[/\\]/); 213 | 214 | fromParts.pop(); // get dirname 215 | 216 | while (fromParts[0] === toParts[0]) { 217 | fromParts.shift(); 218 | toParts.shift(); 219 | } 220 | 221 | if (fromParts.length) { 222 | var i = fromParts.length; 223 | while (i--) { fromParts[i] = '..'; } 224 | } 225 | 226 | return fromParts.concat(toParts).join('/'); 227 | } 228 | 229 | var toString = Object.prototype.toString; 230 | 231 | function isObject(thing) { 232 | return toString.call(thing) === '[object Object]'; 233 | } 234 | 235 | function getLocator(source) { 236 | var originalLines = source.split('\n'); 237 | var lineOffsets = []; 238 | 239 | for (var i = 0, pos = 0; i < originalLines.length; i++) { 240 | lineOffsets.push(pos); 241 | pos += originalLines[i].length + 1; 242 | } 243 | 244 | return function locate(index) { 245 | var i = 0; 246 | var j = lineOffsets.length; 247 | while (i < j) { 248 | var m = (i + j) >> 1; 249 | if (index < lineOffsets[m]) { 250 | j = m; 251 | } else { 252 | i = m + 1; 253 | } 254 | } 255 | var line = i - 1; 256 | var column = index - lineOffsets[line]; 257 | return { line: line, column: column }; 258 | }; 259 | } 260 | 261 | var Mappings = function Mappings(hires) { 262 | this.hires = hires; 263 | this.generatedCodeLine = 0; 264 | this.generatedCodeColumn = 0; 265 | this.raw = []; 266 | this.rawSegments = this.raw[this.generatedCodeLine] = []; 267 | this.pending = null; 268 | }; 269 | 270 | Mappings.prototype.addEdit = function addEdit (sourceIndex, content, loc, nameIndex) { 271 | if (content.length) { 272 | var segment = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column]; 273 | if (nameIndex >= 0) { 274 | segment.push(nameIndex); 275 | } 276 | this.rawSegments.push(segment); 277 | } else if (this.pending) { 278 | this.rawSegments.push(this.pending); 279 | } 280 | 281 | this.advance(content); 282 | this.pending = null; 283 | }; 284 | 285 | Mappings.prototype.addUneditedChunk = function addUneditedChunk (sourceIndex, chunk, original, loc, sourcemapLocations) { 286 | var this$1 = this; 287 | 288 | var originalCharIndex = chunk.start; 289 | var first = true; 290 | 291 | while (originalCharIndex < chunk.end) { 292 | if (this$1.hires || first || sourcemapLocations[originalCharIndex]) { 293 | this$1.rawSegments.push([this$1.generatedCodeColumn, sourceIndex, loc.line, loc.column]); 294 | } 295 | 296 | if (original[originalCharIndex] === '\n') { 297 | loc.line += 1; 298 | loc.column = 0; 299 | this$1.generatedCodeLine += 1; 300 | this$1.raw[this$1.generatedCodeLine] = this$1.rawSegments = []; 301 | this$1.generatedCodeColumn = 0; 302 | } else { 303 | loc.column += 1; 304 | this$1.generatedCodeColumn += 1; 305 | } 306 | 307 | originalCharIndex += 1; 308 | first = false; 309 | } 310 | 311 | this.pending = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column]; 312 | }; 313 | 314 | Mappings.prototype.advance = function advance (str) { 315 | var this$1 = this; 316 | 317 | if (!str) { return; } 318 | 319 | var lines = str.split('\n'); 320 | 321 | if (lines.length > 1) { 322 | for (var i = 0; i < lines.length - 1; i++) { 323 | this$1.generatedCodeLine++; 324 | this$1.raw[this$1.generatedCodeLine] = this$1.rawSegments = []; 325 | } 326 | this.generatedCodeColumn = 0; 327 | } 328 | 329 | this.generatedCodeColumn += lines[lines.length - 1].length; 330 | }; 331 | 332 | var n = '\n'; 333 | 334 | var warned = { 335 | insertLeft: false, 336 | insertRight: false, 337 | storeName: false 338 | }; 339 | 340 | var MagicString = function MagicString(string, options) { 341 | if ( options === void 0 ) options = {}; 342 | 343 | var chunk = new Chunk(0, string.length, string); 344 | 345 | Object.defineProperties(this, { 346 | original: { writable: true, value: string }, 347 | outro: { writable: true, value: '' }, 348 | intro: { writable: true, value: '' }, 349 | firstChunk: { writable: true, value: chunk }, 350 | lastChunk: { writable: true, value: chunk }, 351 | lastSearchedChunk: { writable: true, value: chunk }, 352 | byStart: { writable: true, value: {} }, 353 | byEnd: { writable: true, value: {} }, 354 | filename: { writable: true, value: options.filename }, 355 | indentExclusionRanges: { writable: true, value: options.indentExclusionRanges }, 356 | sourcemapLocations: { writable: true, value: {} }, 357 | storedNames: { writable: true, value: {} }, 358 | indentStr: { writable: true, value: guessIndent(string) } 359 | }); 360 | 361 | this.byStart[0] = chunk; 362 | this.byEnd[string.length] = chunk; 363 | }; 364 | 365 | MagicString.prototype.addSourcemapLocation = function addSourcemapLocation (char) { 366 | this.sourcemapLocations[char] = true; 367 | }; 368 | 369 | MagicString.prototype.append = function append (content) { 370 | if (typeof content !== 'string') { throw new TypeError('outro content must be a string'); } 371 | 372 | this.outro += content; 373 | return this; 374 | }; 375 | 376 | MagicString.prototype.appendLeft = function appendLeft (index, content) { 377 | if (typeof content !== 'string') { throw new TypeError('inserted content must be a string'); } 378 | 379 | this._split(index); 380 | 381 | var chunk = this.byEnd[index]; 382 | 383 | if (chunk) { 384 | chunk.appendLeft(content); 385 | } else { 386 | this.intro += content; 387 | } 388 | return this; 389 | }; 390 | 391 | MagicString.prototype.appendRight = function appendRight (index, content) { 392 | if (typeof content !== 'string') { throw new TypeError('inserted content must be a string'); } 393 | 394 | this._split(index); 395 | 396 | var chunk = this.byStart[index]; 397 | 398 | if (chunk) { 399 | chunk.appendRight(content); 400 | } else { 401 | this.outro += content; 402 | } 403 | return this; 404 | }; 405 | 406 | MagicString.prototype.clone = function clone () { 407 | var cloned = new MagicString(this.original, { filename: this.filename }); 408 | 409 | var originalChunk = this.firstChunk; 410 | var clonedChunk = (cloned.firstChunk = cloned.lastSearchedChunk = originalChunk.clone()); 411 | 412 | while (originalChunk) { 413 | cloned.byStart[clonedChunk.start] = clonedChunk; 414 | cloned.byEnd[clonedChunk.end] = clonedChunk; 415 | 416 | var nextOriginalChunk = originalChunk.next; 417 | var nextClonedChunk = nextOriginalChunk && nextOriginalChunk.clone(); 418 | 419 | if (nextClonedChunk) { 420 | clonedChunk.next = nextClonedChunk; 421 | nextClonedChunk.previous = clonedChunk; 422 | 423 | clonedChunk = nextClonedChunk; 424 | } 425 | 426 | originalChunk = nextOriginalChunk; 427 | } 428 | 429 | cloned.lastChunk = clonedChunk; 430 | 431 | if (this.indentExclusionRanges) { 432 | cloned.indentExclusionRanges = this.indentExclusionRanges.slice(); 433 | } 434 | 435 | Object.keys(this.sourcemapLocations).forEach(function (loc) { 436 | cloned.sourcemapLocations[loc] = true; 437 | }); 438 | 439 | return cloned; 440 | }; 441 | 442 | MagicString.prototype.generateDecodedMap = function generateDecodedMap (options) { 443 | var this$1 = this; 444 | 445 | options = options || {}; 446 | 447 | var sourceIndex = 0; 448 | var names = Object.keys(this.storedNames); 449 | var mappings = new Mappings(options.hires); 450 | 451 | var locate = getLocator(this.original); 452 | 453 | if (this.intro) { 454 | mappings.advance(this.intro); 455 | } 456 | 457 | this.firstChunk.eachNext(function (chunk) { 458 | var loc = locate(chunk.start); 459 | 460 | if (chunk.intro.length) { mappings.advance(chunk.intro); } 461 | 462 | if (chunk.edited) { 463 | mappings.addEdit( 464 | sourceIndex, 465 | chunk.content, 466 | loc, 467 | chunk.storeName ? names.indexOf(chunk.original) : -1 468 | ); 469 | } else { 470 | mappings.addUneditedChunk(sourceIndex, chunk, this$1.original, loc, this$1.sourcemapLocations); 471 | } 472 | 473 | if (chunk.outro.length) { mappings.advance(chunk.outro); } 474 | }); 475 | 476 | return { 477 | file: options.file ? options.file.split(/[/\\]/).pop() : null, 478 | sources: [options.source ? getRelativePath(options.file || '', options.source) : null], 479 | sourcesContent: options.includeContent ? [this.original] : [null], 480 | names: names, 481 | mappings: mappings.raw 482 | }; 483 | }; 484 | 485 | MagicString.prototype.generateMap = function generateMap (options) { 486 | return new SourceMap(this.generateDecodedMap(options)); 487 | }; 488 | 489 | MagicString.prototype.getIndentString = function getIndentString () { 490 | return this.indentStr === null ? '\t' : this.indentStr; 491 | }; 492 | 493 | MagicString.prototype.indent = function indent (indentStr, options) { 494 | var this$1 = this; 495 | 496 | var pattern = /^[^\r\n]/gm; 497 | 498 | if (isObject(indentStr)) { 499 | options = indentStr; 500 | indentStr = undefined; 501 | } 502 | 503 | indentStr = indentStr !== undefined ? indentStr : this.indentStr || '\t'; 504 | 505 | if (indentStr === '') { return this; } // noop 506 | 507 | options = options || {}; 508 | 509 | // Process exclusion ranges 510 | var isExcluded = {}; 511 | 512 | if (options.exclude) { 513 | var exclusions = 514 | typeof options.exclude[0] === 'number' ? [options.exclude] : options.exclude; 515 | exclusions.forEach(function (exclusion) { 516 | for (var i = exclusion[0]; i < exclusion[1]; i += 1) { 517 | isExcluded[i] = true; 518 | } 519 | }); 520 | } 521 | 522 | var shouldIndentNextCharacter = options.indentStart !== false; 523 | var replacer = function (match) { 524 | if (shouldIndentNextCharacter) { return ("" + indentStr + match); } 525 | shouldIndentNextCharacter = true; 526 | return match; 527 | }; 528 | 529 | this.intro = this.intro.replace(pattern, replacer); 530 | 531 | var charIndex = 0; 532 | var chunk = this.firstChunk; 533 | 534 | while (chunk) { 535 | var end = chunk.end; 536 | 537 | if (chunk.edited) { 538 | if (!isExcluded[charIndex]) { 539 | chunk.content = chunk.content.replace(pattern, replacer); 540 | 541 | if (chunk.content.length) { 542 | shouldIndentNextCharacter = chunk.content[chunk.content.length - 1] === '\n'; 543 | } 544 | } 545 | } else { 546 | charIndex = chunk.start; 547 | 548 | while (charIndex < end) { 549 | if (!isExcluded[charIndex]) { 550 | var char = this$1.original[charIndex]; 551 | 552 | if (char === '\n') { 553 | shouldIndentNextCharacter = true; 554 | } else if (char !== '\r' && shouldIndentNextCharacter) { 555 | shouldIndentNextCharacter = false; 556 | 557 | if (charIndex === chunk.start) { 558 | chunk.prependRight(indentStr); 559 | } else { 560 | this$1._splitChunk(chunk, charIndex); 561 | chunk = chunk.next; 562 | chunk.prependRight(indentStr); 563 | } 564 | } 565 | } 566 | 567 | charIndex += 1; 568 | } 569 | } 570 | 571 | charIndex = chunk.end; 572 | chunk = chunk.next; 573 | } 574 | 575 | this.outro = this.outro.replace(pattern, replacer); 576 | 577 | return this; 578 | }; 579 | 580 | MagicString.prototype.insert = function insert () { 581 | throw new Error('magicString.insert(...) is deprecated. Use prependRight(...) or appendLeft(...)'); 582 | }; 583 | 584 | MagicString.prototype.insertLeft = function insertLeft (index, content) { 585 | if (!warned.insertLeft) { 586 | console.warn('magicString.insertLeft(...) is deprecated. Use magicString.appendLeft(...) instead'); // eslint-disable-line no-console 587 | warned.insertLeft = true; 588 | } 589 | 590 | return this.appendLeft(index, content); 591 | }; 592 | 593 | MagicString.prototype.insertRight = function insertRight (index, content) { 594 | if (!warned.insertRight) { 595 | console.warn('magicString.insertRight(...) is deprecated. Use magicString.prependRight(...) instead'); // eslint-disable-line no-console 596 | warned.insertRight = true; 597 | } 598 | 599 | return this.prependRight(index, content); 600 | }; 601 | 602 | MagicString.prototype.move = function move (start, end, index) { 603 | if (index >= start && index <= end) { throw new Error('Cannot move a selection inside itself'); } 604 | 605 | this._split(start); 606 | this._split(end); 607 | this._split(index); 608 | 609 | var first = this.byStart[start]; 610 | var last = this.byEnd[end]; 611 | 612 | var oldLeft = first.previous; 613 | var oldRight = last.next; 614 | 615 | var newRight = this.byStart[index]; 616 | if (!newRight && last === this.lastChunk) { return this; } 617 | var newLeft = newRight ? newRight.previous : this.lastChunk; 618 | 619 | if (oldLeft) { oldLeft.next = oldRight; } 620 | if (oldRight) { oldRight.previous = oldLeft; } 621 | 622 | if (newLeft) { newLeft.next = first; } 623 | if (newRight) { newRight.previous = last; } 624 | 625 | if (!first.previous) { this.firstChunk = last.next; } 626 | if (!last.next) { 627 | this.lastChunk = first.previous; 628 | this.lastChunk.next = null; 629 | } 630 | 631 | first.previous = newLeft; 632 | last.next = newRight || null; 633 | 634 | if (!newLeft) { this.firstChunk = first; } 635 | if (!newRight) { this.lastChunk = last; } 636 | return this; 637 | }; 638 | 639 | MagicString.prototype.overwrite = function overwrite (start, end, content, options) { 640 | var this$1 = this; 641 | 642 | if (typeof content !== 'string') { throw new TypeError('replacement content must be a string'); } 643 | 644 | while (start < 0) { start += this$1.original.length; } 645 | while (end < 0) { end += this$1.original.length; } 646 | 647 | if (end > this.original.length) { throw new Error('end is out of bounds'); } 648 | if (start === end) 649 | { throw new Error('Cannot overwrite a zero-length range – use appendLeft or prependRight instead'); } 650 | 651 | this._split(start); 652 | this._split(end); 653 | 654 | if (options === true) { 655 | if (!warned.storeName) { 656 | console.warn('The final argument to magicString.overwrite(...) should be an options object. See https://github.com/rich-harris/magic-string'); // eslint-disable-line no-console 657 | warned.storeName = true; 658 | } 659 | 660 | options = { storeName: true }; 661 | } 662 | var storeName = options !== undefined ? options.storeName : false; 663 | var contentOnly = options !== undefined ? options.contentOnly : false; 664 | 665 | if (storeName) { 666 | var original = this.original.slice(start, end); 667 | this.storedNames[original] = true; 668 | } 669 | 670 | var first = this.byStart[start]; 671 | var last = this.byEnd[end]; 672 | 673 | if (first) { 674 | if (end > first.end && first.next !== this.byStart[first.end]) { 675 | throw new Error('Cannot overwrite across a split point'); 676 | } 677 | 678 | first.edit(content, storeName, contentOnly); 679 | 680 | if (first !== last) { 681 | var chunk = first.next; 682 | while (chunk !== last) { 683 | chunk.edit('', false); 684 | chunk = chunk.next; 685 | } 686 | 687 | chunk.edit('', false); 688 | } 689 | } else { 690 | // must be inserting at the end 691 | var newChunk = new Chunk(start, end, '').edit(content, storeName); 692 | 693 | // TODO last chunk in the array may not be the last chunk, if it's moved... 694 | last.next = newChunk; 695 | newChunk.previous = last; 696 | } 697 | return this; 698 | }; 699 | 700 | MagicString.prototype.prepend = function prepend (content) { 701 | if (typeof content !== 'string') { throw new TypeError('outro content must be a string'); } 702 | 703 | this.intro = content + this.intro; 704 | return this; 705 | }; 706 | 707 | MagicString.prototype.prependLeft = function prependLeft (index, content) { 708 | if (typeof content !== 'string') { throw new TypeError('inserted content must be a string'); } 709 | 710 | this._split(index); 711 | 712 | var chunk = this.byEnd[index]; 713 | 714 | if (chunk) { 715 | chunk.prependLeft(content); 716 | } else { 717 | this.intro = content + this.intro; 718 | } 719 | return this; 720 | }; 721 | 722 | MagicString.prototype.prependRight = function prependRight (index, content) { 723 | if (typeof content !== 'string') { throw new TypeError('inserted content must be a string'); } 724 | 725 | this._split(index); 726 | 727 | var chunk = this.byStart[index]; 728 | 729 | if (chunk) { 730 | chunk.prependRight(content); 731 | } else { 732 | this.outro = content + this.outro; 733 | } 734 | return this; 735 | }; 736 | 737 | MagicString.prototype.remove = function remove (start, end) { 738 | var this$1 = this; 739 | 740 | while (start < 0) { start += this$1.original.length; } 741 | while (end < 0) { end += this$1.original.length; } 742 | 743 | if (start === end) { return this; } 744 | 745 | if (start < 0 || end > this.original.length) { throw new Error('Character is out of bounds'); } 746 | if (start > end) { throw new Error('end must be greater than start'); } 747 | 748 | this._split(start); 749 | this._split(end); 750 | 751 | var chunk = this.byStart[start]; 752 | 753 | while (chunk) { 754 | chunk.intro = ''; 755 | chunk.outro = ''; 756 | chunk.edit(''); 757 | 758 | chunk = end > chunk.end ? this$1.byStart[chunk.end] : null; 759 | } 760 | return this; 761 | }; 762 | 763 | MagicString.prototype.lastChar = function lastChar () { 764 | if (this.outro.length) 765 | { return this.outro[this.outro.length - 1]; } 766 | var chunk = this.lastChunk; 767 | do { 768 | if (chunk.outro.length) 769 | { return chunk.outro[chunk.outro.length - 1]; } 770 | if (chunk.content.length) 771 | { return chunk.content[chunk.content.length - 1]; } 772 | if (chunk.intro.length) 773 | { return chunk.intro[chunk.intro.length - 1]; } 774 | } while (chunk = chunk.previous); 775 | if (this.intro.length) 776 | { return this.intro[this.intro.length - 1]; } 777 | return ''; 778 | }; 779 | 780 | MagicString.prototype.lastLine = function lastLine () { 781 | var lineIndex = this.outro.lastIndexOf(n); 782 | if (lineIndex !== -1) 783 | { return this.outro.substr(lineIndex + 1); } 784 | var lineStr = this.outro; 785 | var chunk = this.lastChunk; 786 | do { 787 | if (chunk.outro.length > 0) { 788 | lineIndex = chunk.outro.lastIndexOf(n); 789 | if (lineIndex !== -1) 790 | { return chunk.outro.substr(lineIndex + 1) + lineStr; } 791 | lineStr = chunk.outro + lineStr; 792 | } 793 | 794 | if (chunk.content.length > 0) { 795 | lineIndex = chunk.content.lastIndexOf(n); 796 | if (lineIndex !== -1) 797 | { return chunk.content.substr(lineIndex + 1) + lineStr; } 798 | lineStr = chunk.content + lineStr; 799 | } 800 | 801 | if (chunk.intro.length > 0) { 802 | lineIndex = chunk.intro.lastIndexOf(n); 803 | if (lineIndex !== -1) 804 | { return chunk.intro.substr(lineIndex + 1) + lineStr; } 805 | lineStr = chunk.intro + lineStr; 806 | } 807 | } while (chunk = chunk.previous); 808 | lineIndex = this.intro.lastIndexOf(n); 809 | if (lineIndex !== -1) 810 | { return this.intro.substr(lineIndex + 1) + lineStr; } 811 | return this.intro + lineStr; 812 | }; 813 | 814 | MagicString.prototype.slice = function slice (start, end) { 815 | var this$1 = this; 816 | if ( start === void 0 ) start = 0; 817 | if ( end === void 0 ) end = this.original.length; 818 | 819 | while (start < 0) { start += this$1.original.length; } 820 | while (end < 0) { end += this$1.original.length; } 821 | 822 | var result = ''; 823 | 824 | // find start chunk 825 | var chunk = this.firstChunk; 826 | while (chunk && (chunk.start > start || chunk.end <= start)) { 827 | // found end chunk before start 828 | if (chunk.start < end && chunk.end >= end) { 829 | return result; 830 | } 831 | 832 | chunk = chunk.next; 833 | } 834 | 835 | if (chunk && chunk.edited && chunk.start !== start) 836 | { throw new Error(("Cannot use replaced character " + start + " as slice start anchor.")); } 837 | 838 | var startChunk = chunk; 839 | while (chunk) { 840 | if (chunk.intro && (startChunk !== chunk || chunk.start === start)) { 841 | result += chunk.intro; 842 | } 843 | 844 | var containsEnd = chunk.start < end && chunk.end >= end; 845 | if (containsEnd && chunk.edited && chunk.end !== end) 846 | { throw new Error(("Cannot use replaced character " + end + " as slice end anchor.")); } 847 | 848 | var sliceStart = startChunk === chunk ? start - chunk.start : 0; 849 | var sliceEnd = containsEnd ? chunk.content.length + end - chunk.end : chunk.content.length; 850 | 851 | result += chunk.content.slice(sliceStart, sliceEnd); 852 | 853 | if (chunk.outro && (!containsEnd || chunk.end === end)) { 854 | result += chunk.outro; 855 | } 856 | 857 | if (containsEnd) { 858 | break; 859 | } 860 | 861 | chunk = chunk.next; 862 | } 863 | 864 | return result; 865 | }; 866 | 867 | // TODO deprecate this? not really very useful 868 | MagicString.prototype.snip = function snip (start, end) { 869 | var clone = this.clone(); 870 | clone.remove(0, start); 871 | clone.remove(end, clone.original.length); 872 | 873 | return clone; 874 | }; 875 | 876 | MagicString.prototype._split = function _split (index) { 877 | var this$1 = this; 878 | 879 | if (this.byStart[index] || this.byEnd[index]) { return; } 880 | 881 | var chunk = this.lastSearchedChunk; 882 | var searchForward = index > chunk.end; 883 | 884 | while (chunk) { 885 | if (chunk.contains(index)) { return this$1._splitChunk(chunk, index); } 886 | 887 | chunk = searchForward ? this$1.byStart[chunk.end] : this$1.byEnd[chunk.start]; 888 | } 889 | }; 890 | 891 | MagicString.prototype._splitChunk = function _splitChunk (chunk, index) { 892 | if (chunk.edited && chunk.content.length) { 893 | // zero-length edited chunks are a special case (overlapping replacements) 894 | var loc = getLocator(this.original)(index); 895 | throw new Error( 896 | ("Cannot split a chunk that has already been edited (" + (loc.line) + ":" + (loc.column) + " – \"" + (chunk.original) + "\")") 897 | ); 898 | } 899 | 900 | var newChunk = chunk.split(index); 901 | 902 | this.byEnd[index] = chunk; 903 | this.byStart[index] = newChunk; 904 | this.byEnd[newChunk.end] = newChunk; 905 | 906 | if (chunk === this.lastChunk) { this.lastChunk = newChunk; } 907 | 908 | this.lastSearchedChunk = chunk; 909 | return true; 910 | }; 911 | 912 | MagicString.prototype.toString = function toString () { 913 | var str = this.intro; 914 | 915 | var chunk = this.firstChunk; 916 | while (chunk) { 917 | str += chunk.toString(); 918 | chunk = chunk.next; 919 | } 920 | 921 | return str + this.outro; 922 | }; 923 | 924 | MagicString.prototype.isEmpty = function isEmpty () { 925 | var chunk = this.firstChunk; 926 | do { 927 | if (chunk.intro.length && chunk.intro.trim() || 928 | chunk.content.length && chunk.content.trim() || 929 | chunk.outro.length && chunk.outro.trim()) 930 | { return false; } 931 | } while (chunk = chunk.next); 932 | return true; 933 | }; 934 | 935 | MagicString.prototype.length = function length () { 936 | var chunk = this.firstChunk; 937 | var length = 0; 938 | do { 939 | length += chunk.intro.length + chunk.content.length + chunk.outro.length; 940 | } while (chunk = chunk.next); 941 | return length; 942 | }; 943 | 944 | MagicString.prototype.trimLines = function trimLines () { 945 | return this.trim('[\\r\\n]'); 946 | }; 947 | 948 | MagicString.prototype.trim = function trim (charType) { 949 | return this.trimStart(charType).trimEnd(charType); 950 | }; 951 | 952 | MagicString.prototype.trimEndAborted = function trimEndAborted (charType) { 953 | var this$1 = this; 954 | 955 | var rx = new RegExp((charType || '\\s') + '+$'); 956 | 957 | this.outro = this.outro.replace(rx, ''); 958 | if (this.outro.length) { return true; } 959 | 960 | var chunk = this.lastChunk; 961 | 962 | do { 963 | var end = chunk.end; 964 | var aborted = chunk.trimEnd(rx); 965 | 966 | // if chunk was trimmed, we have a new lastChunk 967 | if (chunk.end !== end) { 968 | if (this$1.lastChunk === chunk) { 969 | this$1.lastChunk = chunk.next; 970 | } 971 | 972 | this$1.byEnd[chunk.end] = chunk; 973 | this$1.byStart[chunk.next.start] = chunk.next; 974 | this$1.byEnd[chunk.next.end] = chunk.next; 975 | } 976 | 977 | if (aborted) { return true; } 978 | chunk = chunk.previous; 979 | } while (chunk); 980 | 981 | return false; 982 | }; 983 | 984 | MagicString.prototype.trimEnd = function trimEnd (charType) { 985 | this.trimEndAborted(charType); 986 | return this; 987 | }; 988 | MagicString.prototype.trimStartAborted = function trimStartAborted (charType) { 989 | var this$1 = this; 990 | 991 | var rx = new RegExp('^' + (charType || '\\s') + '+'); 992 | 993 | this.intro = this.intro.replace(rx, ''); 994 | if (this.intro.length) { return true; } 995 | 996 | var chunk = this.firstChunk; 997 | 998 | do { 999 | var end = chunk.end; 1000 | var aborted = chunk.trimStart(rx); 1001 | 1002 | if (chunk.end !== end) { 1003 | // special case... 1004 | if (chunk === this$1.lastChunk) { this$1.lastChunk = chunk.next; } 1005 | 1006 | this$1.byEnd[chunk.end] = chunk; 1007 | this$1.byStart[chunk.next.start] = chunk.next; 1008 | this$1.byEnd[chunk.next.end] = chunk.next; 1009 | } 1010 | 1011 | if (aborted) { return true; } 1012 | chunk = chunk.next; 1013 | } while (chunk); 1014 | 1015 | return false; 1016 | }; 1017 | 1018 | MagicString.prototype.trimStart = function trimStart (charType) { 1019 | this.trimStartAborted(charType); 1020 | return this; 1021 | }; 1022 | 1023 | var hasOwnProp = Object.prototype.hasOwnProperty; 1024 | 1025 | var Bundle = function Bundle(options) { 1026 | if ( options === void 0 ) options = {}; 1027 | 1028 | this.intro = options.intro || ''; 1029 | this.separator = options.separator !== undefined ? options.separator : '\n'; 1030 | this.sources = []; 1031 | this.uniqueSources = []; 1032 | this.uniqueSourceIndexByFilename = {}; 1033 | }; 1034 | 1035 | Bundle.prototype.addSource = function addSource (source) { 1036 | if (source instanceof MagicString) { 1037 | return this.addSource({ 1038 | content: source, 1039 | filename: source.filename, 1040 | separator: this.separator 1041 | }); 1042 | } 1043 | 1044 | if (!isObject(source) || !source.content) { 1045 | throw new Error('bundle.addSource() takes an object with a `content` property, which should be an instance of MagicString, and an optional `filename`'); 1046 | } 1047 | 1048 | ['filename', 'indentExclusionRanges', 'separator'].forEach(function (option) { 1049 | if (!hasOwnProp.call(source, option)) { source[option] = source.content[option]; } 1050 | }); 1051 | 1052 | if (source.separator === undefined) { 1053 | // TODO there's a bunch of this sort of thing, needs cleaning up 1054 | source.separator = this.separator; 1055 | } 1056 | 1057 | if (source.filename) { 1058 | if (!hasOwnProp.call(this.uniqueSourceIndexByFilename, source.filename)) { 1059 | this.uniqueSourceIndexByFilename[source.filename] = this.uniqueSources.length; 1060 | this.uniqueSources.push({ filename: source.filename, content: source.content.original }); 1061 | } else { 1062 | var uniqueSource = this.uniqueSources[this.uniqueSourceIndexByFilename[source.filename]]; 1063 | if (source.content.original !== uniqueSource.content) { 1064 | throw new Error(("Illegal source: same filename (" + (source.filename) + "), different contents")); 1065 | } 1066 | } 1067 | } 1068 | 1069 | this.sources.push(source); 1070 | return this; 1071 | }; 1072 | 1073 | Bundle.prototype.append = function append (str, options) { 1074 | this.addSource({ 1075 | content: new MagicString(str), 1076 | separator: (options && options.separator) || '' 1077 | }); 1078 | 1079 | return this; 1080 | }; 1081 | 1082 | Bundle.prototype.clone = function clone () { 1083 | var bundle = new Bundle({ 1084 | intro: this.intro, 1085 | separator: this.separator 1086 | }); 1087 | 1088 | this.sources.forEach(function (source) { 1089 | bundle.addSource({ 1090 | filename: source.filename, 1091 | content: source.content.clone(), 1092 | separator: source.separator 1093 | }); 1094 | }); 1095 | 1096 | return bundle; 1097 | }; 1098 | 1099 | Bundle.prototype.generateDecodedMap = function generateDecodedMap (options) { 1100 | var this$1 = this; 1101 | if ( options === void 0 ) options = {}; 1102 | 1103 | var names = []; 1104 | this.sources.forEach(function (source) { 1105 | Object.keys(source.content.storedNames).forEach(function (name) { 1106 | if (!~names.indexOf(name)) { names.push(name); } 1107 | }); 1108 | }); 1109 | 1110 | var mappings = new Mappings(options.hires); 1111 | 1112 | if (this.intro) { 1113 | mappings.advance(this.intro); 1114 | } 1115 | 1116 | this.sources.forEach(function (source, i) { 1117 | if (i > 0) { 1118 | mappings.advance(this$1.separator); 1119 | } 1120 | 1121 | var sourceIndex = source.filename ? this$1.uniqueSourceIndexByFilename[source.filename] : -1; 1122 | var magicString = source.content; 1123 | var locate = getLocator(magicString.original); 1124 | 1125 | if (magicString.intro) { 1126 | mappings.advance(magicString.intro); 1127 | } 1128 | 1129 | magicString.firstChunk.eachNext(function (chunk) { 1130 | var loc = locate(chunk.start); 1131 | 1132 | if (chunk.intro.length) { mappings.advance(chunk.intro); } 1133 | 1134 | if (source.filename) { 1135 | if (chunk.edited) { 1136 | mappings.addEdit( 1137 | sourceIndex, 1138 | chunk.content, 1139 | loc, 1140 | chunk.storeName ? names.indexOf(chunk.original) : -1 1141 | ); 1142 | } else { 1143 | mappings.addUneditedChunk( 1144 | sourceIndex, 1145 | chunk, 1146 | magicString.original, 1147 | loc, 1148 | magicString.sourcemapLocations 1149 | ); 1150 | } 1151 | } else { 1152 | mappings.advance(chunk.content); 1153 | } 1154 | 1155 | if (chunk.outro.length) { mappings.advance(chunk.outro); } 1156 | }); 1157 | 1158 | if (magicString.outro) { 1159 | mappings.advance(magicString.outro); 1160 | } 1161 | }); 1162 | 1163 | return { 1164 | file: options.file ? options.file.split(/[/\\]/).pop() : null, 1165 | sources: this.uniqueSources.map(function (source) { 1166 | return options.file ? getRelativePath(options.file, source.filename) : source.filename; 1167 | }), 1168 | sourcesContent: this.uniqueSources.map(function (source) { 1169 | return options.includeContent ? source.content : null; 1170 | }), 1171 | names: names, 1172 | mappings: mappings.raw 1173 | }; 1174 | }; 1175 | 1176 | Bundle.prototype.generateMap = function generateMap (options) { 1177 | return new SourceMap(this.generateDecodedMap(options)); 1178 | }; 1179 | 1180 | Bundle.prototype.getIndentString = function getIndentString () { 1181 | var indentStringCounts = {}; 1182 | 1183 | this.sources.forEach(function (source) { 1184 | var indentStr = source.content.indentStr; 1185 | 1186 | if (indentStr === null) { return; } 1187 | 1188 | if (!indentStringCounts[indentStr]) { indentStringCounts[indentStr] = 0; } 1189 | indentStringCounts[indentStr] += 1; 1190 | }); 1191 | 1192 | return ( 1193 | Object.keys(indentStringCounts).sort(function (a, b) { 1194 | return indentStringCounts[a] - indentStringCounts[b]; 1195 | })[0] || '\t' 1196 | ); 1197 | }; 1198 | 1199 | Bundle.prototype.indent = function indent (indentStr) { 1200 | var this$1 = this; 1201 | 1202 | if (!arguments.length) { 1203 | indentStr = this.getIndentString(); 1204 | } 1205 | 1206 | if (indentStr === '') { return this; } // noop 1207 | 1208 | var trailingNewline = !this.intro || this.intro.slice(-1) === '\n'; 1209 | 1210 | this.sources.forEach(function (source, i) { 1211 | var separator = source.separator !== undefined ? source.separator : this$1.separator; 1212 | var indentStart = trailingNewline || (i > 0 && /\r?\n$/.test(separator)); 1213 | 1214 | source.content.indent(indentStr, { 1215 | exclude: source.indentExclusionRanges, 1216 | indentStart: indentStart //: trailingNewline || /\r?\n$/.test( separator ) //true///\r?\n/.test( separator ) 1217 | }); 1218 | 1219 | trailingNewline = source.content.lastChar() === '\n'; 1220 | }); 1221 | 1222 | if (this.intro) { 1223 | this.intro = 1224 | indentStr + 1225 | this.intro.replace(/^[^\n]/gm, function (match, index) { 1226 | return index > 0 ? indentStr + match : match; 1227 | }); 1228 | } 1229 | 1230 | return this; 1231 | }; 1232 | 1233 | Bundle.prototype.prepend = function prepend (str) { 1234 | this.intro = str + this.intro; 1235 | return this; 1236 | }; 1237 | 1238 | Bundle.prototype.toString = function toString () { 1239 | var this$1 = this; 1240 | 1241 | var body = this.sources 1242 | .map(function (source, i) { 1243 | var separator = source.separator !== undefined ? source.separator : this$1.separator; 1244 | var str = (i > 0 ? separator : '') + source.content.toString(); 1245 | 1246 | return str; 1247 | }) 1248 | .join(''); 1249 | 1250 | return this.intro + body; 1251 | }; 1252 | 1253 | Bundle.prototype.isEmpty = function isEmpty () { 1254 | if (this.intro.length && this.intro.trim()) 1255 | { return false; } 1256 | if (this.sources.some(function (source) { return !source.content.isEmpty(); })) 1257 | { return false; } 1258 | return true; 1259 | }; 1260 | 1261 | Bundle.prototype.length = function length () { 1262 | return this.sources.reduce(function (length, source) { return length + source.content.length(); }, this.intro.length); 1263 | }; 1264 | 1265 | Bundle.prototype.trimLines = function trimLines () { 1266 | return this.trim('[\\r\\n]'); 1267 | }; 1268 | 1269 | Bundle.prototype.trim = function trim (charType) { 1270 | return this.trimStart(charType).trimEnd(charType); 1271 | }; 1272 | 1273 | Bundle.prototype.trimStart = function trimStart (charType) { 1274 | var this$1 = this; 1275 | 1276 | var rx = new RegExp('^' + (charType || '\\s') + '+'); 1277 | this.intro = this.intro.replace(rx, ''); 1278 | 1279 | if (!this.intro) { 1280 | var source; 1281 | var i = 0; 1282 | 1283 | do { 1284 | source = this$1.sources[i++]; 1285 | if (!source) { 1286 | break; 1287 | } 1288 | } while (!source.content.trimStartAborted(charType)); 1289 | } 1290 | 1291 | return this; 1292 | }; 1293 | 1294 | Bundle.prototype.trimEnd = function trimEnd (charType) { 1295 | var this$1 = this; 1296 | 1297 | var rx = new RegExp((charType || '\\s') + '+$'); 1298 | 1299 | var source; 1300 | var i = this.sources.length - 1; 1301 | 1302 | do { 1303 | source = this$1.sources[i--]; 1304 | if (!source) { 1305 | this$1.intro = this$1.intro.replace(rx, ''); 1306 | break; 1307 | } 1308 | } while (!source.content.trimEndAborted(charType)); 1309 | 1310 | return this; 1311 | }; 1312 | 1313 | export default MagicString; 1314 | export { Bundle, SourceMap }; 1315 | //# sourceMappingURL=magic-string.es.js.map -------------------------------------------------------------------------------- /bench/samples/magic-string.min.js: -------------------------------------------------------------------------------- 1 | import{encode}from"sourcemap-codec";var Chunk=function(t,n,e){this.start=t,this.end=n,this.original=e,this.intro="",this.outro="",this.content=e,this.storeName=!1,this.edited=!1,Object.defineProperties(this,{previous:{writable:!0,value:null},next:{writable:!0,value:null}})};Chunk.prototype.appendLeft=function(t){this.outro+=t},Chunk.prototype.appendRight=function(t){this.intro=this.intro+t},Chunk.prototype.clone=function(){var t=new Chunk(this.start,this.end,this.original);return t.intro=this.intro,t.outro=this.outro,t.content=this.content,t.storeName=this.storeName,t.edited=this.edited,t},Chunk.prototype.contains=function(t){return this.start=i.length)return"\t";var r=i.reduce(function(t,n){var e=/^ +/.exec(n)[0].length;return Math.min(e,t)},1/0);return new Array(r+1).join(" ")}function getRelativePath(t,n){var e=t.split(/[\/\\]/),i=n.split(/[\/\\]/);for(e.pop();e[0]===i[0];)e.shift(),i.shift();if(e.length)for(var r=e.length;r--;)e[r]="..";return e.concat(i).join("/")}SourceMap.prototype.toString=function(){return JSON.stringify(this)},SourceMap.prototype.toUrl=function(){return"data:application/json;charset=utf-8;base64,"+btoa(this.toString())};var toString=Object.prototype.toString;function isObject(t){return"[object Object]"===toString.call(t)}function getLocator(t){for(var n=t.split("\n"),e=[],i=0,r=0;i>1;t=0&&r.push(i),this.rawSegments.push(r)}else this.pending&&this.rawSegments.push(this.pending);this.advance(n),this.pending=null},Mappings.prototype.addUneditedChunk=function(t,n,e,i,r){for(var o=n.start,s=!0;o1){for(var e=0;e=t&&e<=n)throw new Error("Cannot move a selection inside itself");this._split(t),this._split(n),this._split(e);var i=this.byStart[t],r=this.byEnd[n],o=i.previous,s=r.next,a=this.byStart[e];if(!a&&r===this.lastChunk)return this;var h=a?a.previous:this.lastChunk;return o&&(o.next=s),s&&(s.previous=o),h&&(h.next=i),a&&(a.previous=r),i.previous||(this.firstChunk=r.next),r.next||(this.lastChunk=i.previous,this.lastChunk.next=null),i.previous=h,r.next=a||null,h||(this.firstChunk=i),a||(this.lastChunk=r),this},MagicString.prototype.overwrite=function(t,n,e,i){if("string"!=typeof e)throw new TypeError("replacement content must be a string");for(;t<0;)t+=this.original.length;for(;n<0;)n+=this.original.length;if(n>this.original.length)throw new Error("end is out of bounds");if(t===n)throw new Error("Cannot overwrite a zero-length range – use appendLeft or prependRight instead");this._split(t),this._split(n),!0===i&&(warned.storeName||(console.warn("The final argument to magicString.overwrite(...) should be an options object. See https://github.com/rich-harris/magic-string"),warned.storeName=!0),i={storeName:!0});var r=void 0!==i&&i.storeName,o=void 0!==i&&i.contentOnly;if(r){var s=this.original.slice(t,n);this.storedNames[s]=!0}var a=this.byStart[t],h=this.byEnd[n];if(a){if(n>a.end&&a.next!==this.byStart[a.end])throw new Error("Cannot overwrite across a split point");if(a.edit(e,r,o),a!==h){for(var u=a.next;u!==h;)u.edit("",!1),u=u.next;u.edit("",!1)}}else{var c=new Chunk(t,n,"").edit(e,r);h.next=c,c.previous=h}return this},MagicString.prototype.prepend=function(t){if("string"!=typeof t)throw new TypeError("outro content must be a string");return this.intro=t+this.intro,this},MagicString.prototype.prependLeft=function(t,n){if("string"!=typeof n)throw new TypeError("inserted content must be a string");this._split(t);var e=this.byEnd[t];return e?e.prependLeft(n):this.intro=n+this.intro,this},MagicString.prototype.prependRight=function(t,n){if("string"!=typeof n)throw new TypeError("inserted content must be a string");this._split(t);var e=this.byStart[t];return e?e.prependRight(n):this.outro=n+this.outro,this},MagicString.prototype.remove=function(t,n){for(;t<0;)t+=this.original.length;for(;n<0;)n+=this.original.length;if(t===n)return this;if(t<0||n>this.original.length)throw new Error("Character is out of bounds");if(t>n)throw new Error("end must be greater than start");this._split(t),this._split(n);for(var e=this.byStart[t];e;)e.intro="",e.outro="",e.edit(""),e=n>e.end?this.byStart[e.end]:null;return this},MagicString.prototype.lastChar=function(){if(this.outro.length)return this.outro[this.outro.length-1];var t=this.lastChunk;do{if(t.outro.length)return t.outro[t.outro.length-1];if(t.content.length)return t.content[t.content.length-1];if(t.intro.length)return t.intro[t.intro.length-1]}while(t=t.previous);return this.intro.length?this.intro[this.intro.length-1]:""},MagicString.prototype.lastLine=function(){var t=this.outro.lastIndexOf(n);if(-1!==t)return this.outro.substr(t+1);var e=this.outro,i=this.lastChunk;do{if(i.outro.length>0){if(-1!==(t=i.outro.lastIndexOf(n)))return i.outro.substr(t+1)+e;e=i.outro+e}if(i.content.length>0){if(-1!==(t=i.content.lastIndexOf(n)))return i.content.substr(t+1)+e;e=i.content+e}if(i.intro.length>0){if(-1!==(t=i.intro.lastIndexOf(n)))return i.intro.substr(t+1)+e;e=i.intro+e}}while(i=i.previous);return-1!==(t=this.intro.lastIndexOf(n))?this.intro.substr(t+1)+e:this.intro+e},MagicString.prototype.slice=function(t,n){for(void 0===t&&(t=0),void 0===n&&(n=this.original.length);t<0;)t+=this.original.length;for(;n<0;)n+=this.original.length;for(var e="",i=this.firstChunk;i&&(i.start>t||i.end<=t);){if(i.start=n)return e;i=i.next}if(i&&i.edited&&i.start!==t)throw new Error("Cannot use replaced character "+t+" as slice start anchor.");for(var r=i;i;){!i.intro||r===i&&i.start!==t||(e+=i.intro);var o=i.start=n;if(o&&i.edited&&i.end!==n)throw new Error("Cannot use replaced character "+n+" as slice end anchor.");var s=r===i?t-i.start:0,a=o?i.content.length+n-i.end:i.content.length;if(e+=i.content.slice(s,a),!i.outro||o&&i.end!==n||(e+=i.outro),o)break;i=i.next}return e},MagicString.prototype.snip=function(t,n){var e=this.clone();return e.remove(0,t),e.remove(n,e.original.length),e},MagicString.prototype._split=function(t){if(!this.byStart[t]&&!this.byEnd[t])for(var n=this.lastSearchedChunk,e=t>n.end;n;){if(n.contains(t))return this._splitChunk(n,t);n=e?this.byStart[n.end]:this.byEnd[n.start]}},MagicString.prototype._splitChunk=function(t,n){if(t.edited&&t.content.length){var e=getLocator(this.original)(n);throw new Error("Cannot split a chunk that has already been edited ("+e.line+":"+e.column+' – "'+t.original+'")')}var i=t.split(n);return this.byEnd[n]=t,this.byStart[n]=i,this.byEnd[i.end]=i,t===this.lastChunk&&(this.lastChunk=i),this.lastSearchedChunk=t,!0},MagicString.prototype.toString=function(){for(var t=this.intro,n=this.firstChunk;n;)t+=n.toString(),n=n.next;return t+this.outro},MagicString.prototype.isEmpty=function(){var t=this.firstChunk;do{if(t.intro.length&&t.intro.trim()||t.content.length&&t.content.trim()||t.outro.length&&t.outro.trim())return!1}while(t=t.next);return!0},MagicString.prototype.length=function(){var t=this.firstChunk,n=0;do{n+=t.intro.length+t.content.length+t.outro.length}while(t=t.next);return n},MagicString.prototype.trimLines=function(){return this.trim("[\\r\\n]")},MagicString.prototype.trim=function(t){return this.trimStart(t).trimEnd(t)},MagicString.prototype.trimEndAborted=function(t){var n=new RegExp((t||"\\s")+"+$");if(this.outro=this.outro.replace(n,""),this.outro.length)return!0;var e=this.lastChunk;do{var i=e.end,r=e.trimEnd(n);if(e.end!==i&&(this.lastChunk===e&&(this.lastChunk=e.next),this.byEnd[e.end]=e,this.byStart[e.next.start]=e.next,this.byEnd[e.next.end]=e.next),r)return!0;e=e.previous}while(e);return!1},MagicString.prototype.trimEnd=function(t){return this.trimEndAborted(t),this},MagicString.prototype.trimStartAborted=function(t){var n=new RegExp("^"+(t||"\\s")+"+");if(this.intro=this.intro.replace(n,""),this.intro.length)return!0;var e=this.firstChunk;do{var i=e.end,r=e.trimStart(n);if(e.end!==i&&(e===this.lastChunk&&(this.lastChunk=e.next),this.byEnd[e.end]=e,this.byStart[e.next.start]=e.next,this.byEnd[e.next.end]=e.next),r)return!0;e=e.next}while(e);return!1},MagicString.prototype.trimStart=function(t){return this.trimStartAborted(t),this};var hasOwnProp=Object.prototype.hasOwnProperty,Bundle=function(t){void 0===t&&(t={}),this.intro=t.intro||"",this.separator=void 0!==t.separator?t.separator:"\n",this.sources=[],this.uniqueSources=[],this.uniqueSourceIndexByFilename={}};Bundle.prototype.addSource=function(t){if(t instanceof MagicString)return this.addSource({content:t,filename:t.filename,separator:this.separator});if(!isObject(t)||!t.content)throw new Error("bundle.addSource() takes an object with a `content` property, which should be an instance of MagicString, and an optional `filename`");if(["filename","indentExclusionRanges","separator"].forEach(function(n){hasOwnProp.call(t,n)||(t[n]=t.content[n])}),void 0===t.separator&&(t.separator=this.separator),t.filename)if(hasOwnProp.call(this.uniqueSourceIndexByFilename,t.filename)){var n=this.uniqueSources[this.uniqueSourceIndexByFilename[t.filename]];if(t.content.original!==n.content)throw new Error("Illegal source: same filename ("+t.filename+"), different contents")}else this.uniqueSourceIndexByFilename[t.filename]=this.uniqueSources.length,this.uniqueSources.push({filename:t.filename,content:t.content.original});return this.sources.push(t),this},Bundle.prototype.append=function(t,n){return this.addSource({content:new MagicString(t),separator:n&&n.separator||""}),this},Bundle.prototype.clone=function(){var t=new Bundle({intro:this.intro,separator:this.separator});return this.sources.forEach(function(n){t.addSource({filename:n.filename,content:n.content.clone(),separator:n.separator})}),t},Bundle.prototype.generateDecodedMap=function(t){var n=this;void 0===t&&(t={});var e=[];this.sources.forEach(function(t){Object.keys(t.content.storedNames).forEach(function(t){~e.indexOf(t)||e.push(t)})});var i=new Mappings(t.hires);return this.intro&&i.advance(this.intro),this.sources.forEach(function(t,r){r>0&&i.advance(n.separator);var o=t.filename?n.uniqueSourceIndexByFilename[t.filename]:-1,s=t.content,a=getLocator(s.original);s.intro&&i.advance(s.intro),s.firstChunk.eachNext(function(n){var r=a(n.start);n.intro.length&&i.advance(n.intro),t.filename?n.edited?i.addEdit(o,n.content,r,n.storeName?e.indexOf(n.original):-1):i.addUneditedChunk(o,n,s.original,r,s.sourcemapLocations):i.advance(n.content),n.outro.length&&i.advance(n.outro)}),s.outro&&i.advance(s.outro)}),{file:t.file?t.file.split(/[\/\\]/).pop():null,sources:this.uniqueSources.map(function(n){return t.file?getRelativePath(t.file,n.filename):n.filename}),sourcesContent:this.uniqueSources.map(function(n){return t.includeContent?n.content:null}),names:e,mappings:i.raw}},Bundle.prototype.generateMap=function(t){return new SourceMap(this.generateDecodedMap(t))},Bundle.prototype.getIndentString=function(){var t={};return this.sources.forEach(function(n){var e=n.content.indentStr;null!==e&&(t[e]||(t[e]=0),t[e]+=1)}),Object.keys(t).sort(function(n,e){return t[n]-t[e]})[0]||"\t"},Bundle.prototype.indent=function(t){var n=this;if(arguments.length||(t=this.getIndentString()),""===t)return this;var e=!this.intro||"\n"===this.intro.slice(-1);return this.sources.forEach(function(i,r){var o=void 0!==i.separator?i.separator:n.separator,s=e||r>0&&/\r?\n$/.test(o);i.content.indent(t,{exclude:i.indentExclusionRanges,indentStart:s}),e="\n"===i.content.lastChar()}),this.intro&&(this.intro=t+this.intro.replace(/^[^\n]/gm,function(n,e){return e>0?t+n:n})),this},Bundle.prototype.prepend=function(t){return this.intro=t+this.intro,this},Bundle.prototype.toString=function(){var t=this,n=this.sources.map(function(n,e){var i=void 0!==n.separator?n.separator:t.separator;return(e>0?i:"")+n.content.toString()}).join("");return this.intro+n},Bundle.prototype.isEmpty=function(){return(!this.intro.length||!this.intro.trim())&&!this.sources.some(function(t){return!t.content.isEmpty()})},Bundle.prototype.length=function(){return this.sources.reduce(function(t,n){return t+n.content.length()},this.intro.length)},Bundle.prototype.trimLines=function(){return this.trim("[\\r\\n]")},Bundle.prototype.trim=function(t){return this.trimStart(t).trimEnd(t)},Bundle.prototype.trimStart=function(t){var n=new RegExp("^"+(t||"\\s")+"+");if(this.intro=this.intro.replace(n,""),!this.intro){var e,i=0;do{if(!(e=this.sources[i++]))break}while(!e.content.trimStartAborted(t))}return this},Bundle.prototype.trimEnd=function(t){var n,e=new RegExp((t||"\\s")+"+$"),i=this.sources.length-1;do{if(!(n=this.sources[i--])){this.intro=this.intro.replace(e,"");break}}while(!n.content.trimEndAborted(t));return this};export default MagicString;export{Bundle,SourceMap}; 2 | -------------------------------------------------------------------------------- /demos/README.md: -------------------------------------------------------------------------------- 1 | # shimport-demos 2 | 3 | Demos for [Shimport](https://github.com/Rich-Harris/shimport). https://shimport-demos.surge.sh -------------------------------------------------------------------------------- /demos/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | process.chdir(__dirname); 4 | 5 | const html = fs.readFileSync('index.html', 'utf-8'); 6 | 7 | const dirs = fs.readdirSync('.').filter(file => { 8 | if (file === 'node_modules') return; 9 | if (file[0] === '.') return; 10 | 11 | return fs.statSync(file).isDirectory(); 12 | }); 13 | 14 | fs.writeFileSync('index.html', html 15 | .replace(/
    ([\s\S]*)<\/ul>/, `
      ${ 16 | dirs.map(dir => `\n\t\t
    • ${dir}
    • `).join('') 17 | }\n\t
    `)); -------------------------------------------------------------------------------- /demos/dynamic-import/dynamic-import.js: -------------------------------------------------------------------------------- 1 | export const message = 'this module was loaded dynamically with import()'; -------------------------------------------------------------------------------- /demos/dynamic-import/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dynamic import 7 | 8 | 9 | 10 |

    Dynamic import

    11 | 12 |
    13 | 14 |

    ...

    15 |
    16 | 17 | 31 | 32 | -------------------------------------------------------------------------------- /demos/dynamic-import/main.js: -------------------------------------------------------------------------------- 1 | document.querySelector('button').addEventListener('click', () => { 2 | import('./dynamic-import.js').then(({ message }) => { 3 | document.querySelector('p').innerHTML = message; 4 | }); 5 | }); -------------------------------------------------------------------------------- /demos/force-shimport/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Force Shimport 7 | 8 | 9 | 10 |

    Force Shimport

    11 | 12 |
    13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /demos/force-shimport/main.js: -------------------------------------------------------------------------------- 1 | import * as other from './other.js'; 2 | 3 | const main = document.querySelector('main'); 4 | main.innerHTML = other.message; -------------------------------------------------------------------------------- /demos/force-shimport/other.js: -------------------------------------------------------------------------------- 1 | const message = ` 2 |

    Normally, you'd use Shimport with a snippet like the following:

    3 | 4 |
     5 | var __s = document.createElement('script');
     6 | try {
     7 | 	new Function('import("")');
     8 | 	__s.type = 'module';
     9 | 	__s.src = './main.js';
    10 | } catch (e) {
    11 | 	__s.src = 'https://unpkg.com/shimport'
    12 | 	__s.dataset.main = './main.js';
    13 | }
    14 | 
    15 | document.head.appendChild(__s);
    16 | 
    17 | 18 |

    With this code, Shimport is only used if the browser doesn't support modules (or dynamic import).

    19 | 20 |

    You might want to always use Shimport, regardless of support — e.g. for testing or performance profiling. In those cases, you can simply add a <script> tag that loads Shimport and tells it where to find your app:

    21 | 22 |
    23 | <script src="https://unpkg.com/shimport" data-main="./main.js"></script>
    24 | 
    25 | `; 26 | 27 | export { message }; -------------------------------------------------------------------------------- /demos/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Shimport demos 7 | 8 | 9 | 10 |

    Shimport demos

    11 | 12 |

    Use JavaScript modules in all browsers, today — including dynamic import().

    13 |

    Info: github.com/rich-harris/shimport

    14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /demos/load-from-unpkg/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Load from unpkg.com 7 | 8 | 9 | 10 |

    Load from unpkg.com

    11 | 12 |
    13 |

    loading unpkg.com/lodash-es/range.js...

    14 |
    15 | 16 | 30 | 31 | -------------------------------------------------------------------------------- /demos/load-from-unpkg/main.js: -------------------------------------------------------------------------------- 1 | import range from 'https://unpkg.com/lodash-es/range.js?module'; 2 | 3 | document.querySelector('main').innerHTML += ` 4 |
     5 | range(1, 10)
     6 | -> ${range(1, 10).join(', ')}
     7 | 
    8 | 9 |

    You might have noticed this took a few moments to appear.

    10 | 11 |

    If you look at the network tab in your devtools and reload, you'll see why: range.js depends on many other modules in the lodash-es package, which must be downloaded individually.

    12 | 13 |

    This is why, in production, you should use a bundler to combine the individual modules in your app into a few coarse-grained chunks. Rollup can do this for you, and will output native JavaScript modules that can be used with Shimport.

    14 | `; -------------------------------------------------------------------------------- /demos/static-imports/a.js: -------------------------------------------------------------------------------- 1 | export default 'hello from a.js! this is a default export'; -------------------------------------------------------------------------------- /demos/static-imports/b.js: -------------------------------------------------------------------------------- 1 | export const message = 'hello from b.js! this is a named export'; -------------------------------------------------------------------------------- /demos/static-imports/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Static imports 7 | 8 | 9 | 10 |

    Static imports

    11 | 12 |
    13 | 14 | 28 | 29 | -------------------------------------------------------------------------------- /demos/static-imports/main.js: -------------------------------------------------------------------------------- 1 | import a from './a.js'; 2 | import { message } from './b.js'; 3 | 4 | document.body.innerHTML += ` 5 |

    ${a}

    6 |

    ${message}

    7 | `; -------------------------------------------------------------------------------- /demos/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; 3 | max-width: 800px; 4 | margin: 0 auto; 5 | padding: 2em 1em; 6 | line-height: 1.5; 7 | } 8 | 9 | button { 10 | font-family: inherit; 11 | font-size: inherit; 12 | padding: 0.5em 1em; 13 | background-color: #333; 14 | color: white; 15 | border: none; 16 | border-radius: 2px; 17 | cursor: pointer; 18 | } 19 | 20 | button:hover { 21 | background-color: #555; 22 | } 23 | 24 | pre { 25 | tab-size: 2; 26 | background-color: #f4f4f4; 27 | padding: 0.5em; 28 | border-radius: 2px; 29 | } 30 | 31 | code { 32 | position: relative; 33 | background-color: #f4f4f4; 34 | padding: 0.3em 0.6em; 35 | top: -0.1em; 36 | line-height: 1; 37 | border-radius: 2px; 38 | } -------------------------------------------------------------------------------- /demos/transform/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Transform 7 | 8 | 9 | 56 | 57 | 58 |

    Transform

    59 | 60 |
    61 |
    62 | 63 | 64 |
    65 | 66 | 67 |
    68 | 69 | 70 | 105 | 106 | -------------------------------------------------------------------------------- /demos/web-worker/app/bar.js: -------------------------------------------------------------------------------- 1 | export const bar = `hello from ${location.origin}/web-worker/app/bar.js!`; -------------------------------------------------------------------------------- /demos/web-worker/app/foo.js: -------------------------------------------------------------------------------- 1 | export const foo = `hello from ${location.origin}/web-worker/app/foo.js!`; -------------------------------------------------------------------------------- /demos/web-worker/app/main.js: -------------------------------------------------------------------------------- 1 | import { foo } from './foo.js'; 2 | 3 | console.log(foo); 4 | 5 | import('./bar.js').then(({ bar }) => { 6 | console.log(bar); 7 | }); -------------------------------------------------------------------------------- /demos/web-worker/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Web workers 7 | 8 | 9 | 10 |

    Web workers

    11 | 12 |

    You can use Shimport in web workers via importScripts. This is the code inside worker.js — you can see the output by opening the console.

    13 | 14 |

    worker.js

    15 |
    16 | importScripts('../shimport.js');
    17 | __shimport__.load('./app/main.js', location.href);
    18 | 19 |

    app/main.js

    20 |
    21 | import { foo } from './foo.js';
    22 | 
    23 | console.log(foo);
    24 | 
    25 | import('./bar.js').then(({ bar }) => {
    26 | 	console.log(bar);
    27 | });
    28 | 29 |

    app/foo.js

    30 |
    31 | export const foo = `hello from ${location.origin}/web-worker/app/foo.js!`;
    32 | 33 |

    app/bar.js

    34 |
    35 | export const bar = `hello from ${location.origin}/web-worker/app/bar.js!`;
    36 | 37 | 40 | 41 | -------------------------------------------------------------------------------- /demos/web-worker/worker.js: -------------------------------------------------------------------------------- 1 | importScripts('../shimport.dev.js'); 2 | 3 | const main = new URL('./app/main.js', location.href); 4 | __shimport__.load(main.href); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shimport", 3 | "description": "Shim for dynamic import()", 4 | "version": "2.0.5", 5 | "repository": "Rich-Harris/shimport", 6 | "main": "index.js", 7 | "files": [ 8 | "index.js", 9 | "index.dev.js" 10 | ], 11 | "devDependencies": { 12 | "@rollup/plugin-replace": "^2.3.3", 13 | "@rollup/plugin-typescript": "^6.0.0", 14 | "@types/mocha": "^8.0.3", 15 | "@types/node": "^14.11.1", 16 | "kleur": "^4.1.1", 17 | "locate-character": "^2.0.5", 18 | "pretty-ms": "^7.0.0", 19 | "rollup": "^2.27.1", 20 | "rollup-plugin-terser": "^7.0.2", 21 | "sirv-cli": "^1.0.6", 22 | "sucrase": "^3.15.0", 23 | "surge": "^0.21.6", 24 | "typescript": "^4.0.3", 25 | "uvu": "^0.3.3" 26 | }, 27 | "scripts": { 28 | "dev": "rollup -cw", 29 | "build": "rollup -c", 30 | "test": "uvu -r sucrase/register/ts test test.ts", 31 | "prepublishOnly": "npm test && npm run build", 32 | "deploy": "npm run build && npm run demos:build && surge demos --domain shimport-demos.surge.sh", 33 | "demos:build": "cp index.js demos/shimport.js && cp index.dev.js demos/shimport.dev.js && node demos/build.js", 34 | "demos:start": "sirv demos --dev" 35 | }, 36 | "license": "MIT" 37 | } 38 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from '@rollup/plugin-typescript'; 2 | import replace from '@rollup/plugin-replace'; 3 | import { terser } from 'rollup-plugin-terser'; 4 | import pkg from './package.json'; 5 | 6 | const config = dev => ({ 7 | input: 'src/index.ts', 8 | output: [ 9 | { 10 | file: dev ? 'index.dev.js' : pkg.main, 11 | format: 'iife', 12 | name: '__shimport__' 13 | } 14 | ], 15 | plugins: [ 16 | replace({ 17 | __VERSION__: pkg.version 18 | }), 19 | typescript({ 20 | typescript: require('typescript') 21 | }), 22 | !dev && terser({ 23 | output: { 24 | comments: false 25 | } 26 | }) 27 | ] 28 | }) 29 | 30 | export default [ 31 | config(false), 32 | config(true) 33 | ]; -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { transform } from './transform'; 2 | import { define, load } from './load'; 3 | 4 | interface Script extends Element { 5 | dataset: Record; 6 | } 7 | 8 | if (typeof document !== 'undefined') { 9 | const scr: Script = document.querySelector('[data-main]'); 10 | if (scr) { 11 | load(new URL(scr.getAttribute('data-main'), document.baseURI)); 12 | } 13 | } 14 | 15 | const VERSION = "__VERSION__"; 16 | 17 | export { transform, define, load, VERSION }; -------------------------------------------------------------------------------- /src/load.ts: -------------------------------------------------------------------------------- 1 | import { transform } from './transform'; 2 | 3 | const promises: Record> = {}; 4 | 5 | type __Import = (id: string) => Promise; 6 | type __Exports = Record; 7 | 8 | export function define( 9 | id: string, 10 | deps: string[], 11 | factory: (__import: __Import, __exports: __Exports, ...deps: any[]) => void 12 | ) { 13 | const __import = (dep: string) => load(new URL(dep, id)); 14 | 15 | return Promise.all(deps.map(__import)).then(__deps => { 16 | const __exports = {}; 17 | 18 | factory(__import, __exports, ...__deps); 19 | return __exports; 20 | }); 21 | } 22 | 23 | export function load(url: string | URL) { 24 | return promises[url] || ( 25 | promises[url] = fetch(url) 26 | .then(r => r.text()) 27 | .then(text => evaluate(transform(text, url))) 28 | ); 29 | } 30 | 31 | let uid = 1; 32 | 33 | function evaluate(code: string) { 34 | if (typeof document !== 'undefined' && typeof URL !== 'undefined') { 35 | return new Promise(fulfil => { 36 | const id = `__shimport__${uid++}`; 37 | 38 | // creating a script tag gives us proper stack traces 39 | const blob = new Blob([`${id}=${code}`], { 40 | type: 'application/javascript' 41 | }); 42 | 43 | const script = document.createElement('script'); 44 | script.src = URL.createObjectURL(blob); 45 | 46 | script.onload = () => { 47 | fulfil((window as any)[id]); 48 | delete (window as any)[id]; 49 | }; 50 | 51 | document.head.appendChild(script); 52 | }); 53 | 54 | } else { 55 | // for browsers without `URL` 56 | return (0,eval)(code); 57 | } 58 | } -------------------------------------------------------------------------------- /src/transform.ts: -------------------------------------------------------------------------------- 1 | type State = { 2 | name?: string; 3 | pattern: RegExp; 4 | handlers: Array<(i?: number, token?: string) => State | void> 5 | }; 6 | 7 | type Specifier = { 8 | name: string; 9 | as: string; 10 | } 11 | 12 | interface Range { 13 | start: number; 14 | end: number; 15 | [key: string]: any; 16 | } 17 | 18 | function get_alias(specifiers: Specifier[], name: string) { 19 | let i = specifiers.length; 20 | while (i--) { 21 | if (specifiers[i].name === name) return specifiers[i].as; 22 | } 23 | } 24 | 25 | function importDecl(str: string, start: number, end: number, specifiers: Specifier[], source: string) { 26 | const name = get_alias(specifiers, '*') || get_alias(specifiers, 'default'); 27 | 28 | return { 29 | start, 30 | end, 31 | source, 32 | name, 33 | specifiers, 34 | toString() { 35 | return `/*${str.slice(start, end)}*/`; 36 | } 37 | }; 38 | } 39 | 40 | function exportDefaultDeclaration(str: string, start: number, end: number) { 41 | const match = /^\s*(?:(class)(\s+extends|\s*{)|(function)\s*\()/.exec(str.slice(end)); 42 | 43 | if (match) { 44 | // anonymous class declaration 45 | end += match[0].length; 46 | 47 | const name = '__default_export'; 48 | 49 | return { 50 | start, 51 | end, 52 | name, 53 | as: 'default', 54 | toString() { 55 | return match[1] 56 | ? `class ${name}${match[2]}` 57 | : `function ${name}(`; 58 | } 59 | }; 60 | } 61 | 62 | return { 63 | start, 64 | end, 65 | toString() { 66 | return `__exports.default =`; 67 | } 68 | }; 69 | } 70 | 71 | function exportSpecifiersDeclaration(str: string, start: number, specifiersStart: number, specifiersEnd: number, end: number, source: string) { 72 | const specifiers = processSpecifiers(str.slice(specifiersStart + 1, specifiersEnd - 1).trim()); 73 | 74 | return { 75 | start, 76 | end, 77 | source, 78 | toString(nameBySource: Map) { 79 | const name = source && nameBySource.get(source); 80 | 81 | return specifiers 82 | .map(s => { 83 | return `__exports.${s.as} = ${name ? `${name}.${s.name}` : s.name}; `; 84 | }) 85 | .join('') + `/*${str.slice(start, end)}*/` 86 | } 87 | }; 88 | } 89 | 90 | function exportDecl(str: string, start: number, c: number) { 91 | const end = c; 92 | 93 | while (str[c] && /\S/.test(str[c])) c += 1; 94 | while (str[c] && !/\S/.test(str[c])) c += 1; 95 | 96 | const nameStart = c; 97 | while (str[c] && !punctuatorChars.test(str[c]) && !isWhitespace(str[c])) c += 1; 98 | const nameEnd = c; 99 | 100 | const name = str.slice(nameStart, nameEnd); 101 | 102 | return { 103 | start, 104 | end, 105 | name, 106 | toString() { 107 | return ''; 108 | } 109 | }; 110 | } 111 | 112 | function exportStarDeclaration(str: string, start: number, end: number, source: string) { 113 | return { 114 | start, 115 | end, 116 | source, 117 | toString(nameBySource: Map) { 118 | return `Object.assign(__exports, ${nameBySource.get(source)}); /*${str.slice(start, end)}*/`; 119 | } 120 | }; 121 | } 122 | 123 | const keywords = /\b(case|default|delete|do|else|in|instanceof|new|return|throw|typeof|void)\s*$/; 124 | const punctuators = /(^|\{|\(|\[\.|;|,|<|>|<=|>=|==|!=|===|!==|\+|-|\*\%|<<|>>|>>>|&|\||\^|!|~|&&|\|\||\?|:|=|\+=|-=|\*=|%=|<<=|>>=|>>>=|&=|\|=|\^=|\/=|\/)\s*$/; 125 | const ambiguous = /(\}|\)|\+\+|--)\s*$/; 126 | 127 | const punctuatorChars = /[{}()[.;,<>=+\-*%&|\^!~?:/]/; 128 | const keywordChars = /[a-zA-Z_$0-9]/; 129 | 130 | const whitespace_obj = { ' ': 1, '\t': 1, '\n': 1, '\r': 1, '\f': 1, '\v': 1, '\u00A0': 1, '\u2028': 1, '\u2029': 1 }; 131 | 132 | function isWhitespace(char: string) { 133 | // this is faster than testing a regex 134 | return char in whitespace_obj; 135 | } 136 | 137 | function isQuote(char: string) { 138 | return char === "'" || char === '"'; 139 | } 140 | 141 | const namespaceImport = /^\*\s+as\s+(\w+)$/; 142 | const defaultAndStarImport = /(\w+)\s*,\s*\*\s*as\s*(\w+)$/; 143 | const defaultAndNamedImport = /(\w+)\s*,\s*{(.+)}$/; 144 | 145 | function processImportSpecifiers(str: string): Specifier[] { 146 | let match = namespaceImport.exec(str); 147 | if (match) { 148 | return [{ name: '*', as: match[1] }]; 149 | } 150 | 151 | match = defaultAndStarImport.exec(str); 152 | if (match) { 153 | return [{ name: 'default', as: match[1] }, { name: '*', as: match[2] }]; 154 | } 155 | 156 | match = defaultAndNamedImport.exec(str); 157 | if (match) { 158 | return [{ name: 'default', as: match[1] }].concat(processSpecifiers(match[2].trim())); 159 | } 160 | 161 | if (str[0] === '{') return processSpecifiers(str.slice(1, -1).trim()); 162 | 163 | if (str) return [{ name: 'default', as: str }]; 164 | 165 | return []; 166 | } 167 | 168 | function processSpecifiers(str: string) { 169 | return str 170 | ? str.split(',').map(part => { 171 | const [name, , as] = part.trim().split(/[^\S]+/); 172 | return { name, as: as || name }; 173 | }) 174 | : []; 175 | } 176 | 177 | function getImportDeclaration(str: string, i: number) { 178 | const start = i; 179 | 180 | const specifierStart = i += 6; 181 | while (str[i] && isWhitespace(str[i])) i += 1; 182 | while (str[i] && !isQuote(str[i])) i += 1; 183 | const specifierEnd = i; 184 | 185 | const sourceStart = i += 1; 186 | while (str[i] && !isQuote(str[i])) i += 1; 187 | const sourceEnd = i++; 188 | 189 | return importDecl( 190 | str, 191 | start, 192 | i, 193 | processImportSpecifiers(str.slice(specifierStart, specifierEnd).replace(/from\s*$/, '').trim()), 194 | str.slice(sourceStart, sourceEnd) 195 | ); 196 | } 197 | 198 | function getImportStatement(i: number) { 199 | return { 200 | start: i, 201 | end: i + 6, 202 | toString() { 203 | return '__import' 204 | } 205 | }; 206 | } 207 | 208 | const importMetaUrlPattern = /^import\s*\.\s*meta\s*\.\s*url/; 209 | 210 | function getImportMetaUrl(str: string, start: number, id: string) { 211 | const match = importMetaUrlPattern.exec(str.slice(start)); 212 | if (match) { 213 | return { 214 | start, 215 | end: start + match[0].length, 216 | toString() { 217 | return JSON.stringify('' + id); 218 | } 219 | } 220 | } 221 | } 222 | 223 | function getExportDeclaration(str: string, i: number) { 224 | const start = i; 225 | 226 | i += 6; 227 | while (str[i] && isWhitespace(str[i])) i += 1; 228 | 229 | const declarationStart = i; 230 | 231 | if (str[i] === '{') { 232 | while (str[i] !== '}') i += 1; 233 | i += 1; 234 | 235 | const specifiersEnd = i; 236 | 237 | let source = null; 238 | 239 | while (isWhitespace(str[i])) i += 1; 240 | if (/^from[\s\n'"]/.test(str.slice(i, i + 5))) { 241 | i += 4; 242 | while (isWhitespace(str[i])) i += 1; 243 | 244 | while (str[i] && !isQuote(str[i])) i += 1; 245 | const sourceStart = i += 1; 246 | while (str[i] && !isQuote(str[i])) i += 1; 247 | 248 | source = str.slice(sourceStart, i); 249 | i += 1; 250 | } 251 | 252 | return exportSpecifiersDeclaration( 253 | str, 254 | start, 255 | declarationStart, 256 | specifiersEnd, 257 | i, 258 | source 259 | ); 260 | } 261 | 262 | if (str[i] === '*') { 263 | i += 1; 264 | while (isWhitespace(str[i])) i += 1; 265 | i += 4; 266 | while (str[i] && !isQuote(str[i])) i += 1; 267 | 268 | const sourceStart = i += 1; 269 | while (str[i] && !isQuote(str[i])) i += 1; 270 | const sourceEnd = i++; 271 | 272 | return exportStarDeclaration( 273 | str, 274 | start, 275 | i, 276 | str.slice(sourceStart, sourceEnd) 277 | ); 278 | } 279 | 280 | if (/^default\b/.test(str.slice(i, i + 8))) { 281 | return exportDefaultDeclaration( 282 | str, 283 | start, 284 | declarationStart + 7 285 | ); 286 | } 287 | 288 | return exportDecl( 289 | str, 290 | start, 291 | declarationStart 292 | ); 293 | } 294 | 295 | function find(str: string, id: string): [Range[], Range[], Range[], Range[]] { 296 | let escapedFrom: State; 297 | let regexEnabled = true; 298 | let pfixOp = false; 299 | 300 | const stack: State[] = []; 301 | 302 | let lsci = -1; // last significant character index 303 | const lsc = () => str[lsci]; 304 | 305 | var parenMatches: Record = {}; 306 | var openingParenPositions: Record = {}; 307 | var parenDepth = 0; 308 | 309 | const importDeclarations: Range[] = []; 310 | const importStatements: Range[] = []; 311 | const importMetaUrls: Range[] = []; 312 | const exportDeclarations: Range[] = []; 313 | 314 | function tokenClosesExpression() { 315 | if (lsc() === ')') { 316 | var c = parenMatches[lsci]; 317 | while (isWhitespace(str[c - 1])) { 318 | c -= 1; 319 | } 320 | 321 | // if parenthesized expression is immediately preceded by `if`/`while`, it's not closing an expression 322 | return !/(if|while)$/.test(str.slice(c - 5, c)); 323 | } 324 | 325 | // TODO handle }, ++ and -- tokens immediately followed by / character 326 | return true; 327 | } 328 | 329 | const base: State = { 330 | pattern: /(?:(\()|(\))|({)|(})|(")|(')|(\/\/)|(\/\*)|(\/)|(`)|(import)|(export)|(\+\+|--))/g, 331 | 332 | handlers: [ 333 | // ( 334 | (i: number) => { 335 | lsci = i; 336 | openingParenPositions[parenDepth++] = i; 337 | }, 338 | 339 | // ) 340 | (i: number) => { 341 | lsci = i; 342 | parenMatches[i] = openingParenPositions[--parenDepth]; 343 | }, 344 | 345 | // { 346 | (i: number) => { 347 | lsci = i; 348 | stack.push(base); 349 | }, 350 | 351 | // } 352 | (i: number) => { 353 | lsci = i; 354 | return stack.pop(); 355 | }, 356 | 357 | // " 358 | (i: number) => { 359 | stack.push(base); 360 | return double_quoted; 361 | }, 362 | 363 | // ' 364 | (i: number) => { 365 | stack.push(base); 366 | return single_quoted; 367 | }, 368 | 369 | // // 370 | (i: number) => line_comment, 371 | 372 | // /* 373 | (i: number) => block_comment, 374 | 375 | // / 376 | (i: number) => { 377 | // could be start of regex literal OR division punctuator. Solution via 378 | // http://stackoverflow.com/questions/5519596/when-parsing-javascript-what-determines-the-meaning-of-a-slash/27120110#27120110 379 | 380 | var b = i; 381 | while (b > 0 && isWhitespace(str[b - 1])) { 382 | b -= 1; 383 | } 384 | 385 | if (b > 0) { 386 | var a = b; 387 | 388 | if (punctuatorChars.test(str[a - 1])) { 389 | while (a > 0 && punctuatorChars.test(str[a - 1])) { 390 | a -= 1; 391 | } 392 | } else { 393 | while (a > 0 && keywordChars.test(str[a - 1])) { 394 | a -= 1; 395 | } 396 | } 397 | 398 | var token = str.slice(a, b); 399 | 400 | regexEnabled = token 401 | ? keywords.test(token) || 402 | punctuators.test(token) || 403 | (ambiguous.test(token) && !tokenClosesExpression()) 404 | : false; 405 | } else { 406 | regexEnabled = true; 407 | } 408 | 409 | return slash; 410 | }, 411 | 412 | // ` 413 | (i: number) => template_string, 414 | 415 | // import 416 | (i: number) => { 417 | if (i === 0 || isWhitespace(str[i - 1]) || punctuatorChars.test(str[i - 1])) { 418 | let j = i + 6; 419 | let char; 420 | 421 | do { 422 | char = str[j++]; 423 | } while (isWhitespace(char)); 424 | 425 | const hasWhitespace = j > i + 7; 426 | 427 | if (/^['"{*]$/.test(char) || (hasWhitespace && /^[a-zA-Z_$]$/.test(char))) { 428 | const d = getImportDeclaration(str, i); 429 | importDeclarations.push(d); 430 | p = d.end; 431 | } 432 | 433 | else if (char === '(') { 434 | const s = getImportStatement(i); 435 | importStatements.push(s); 436 | p = s.end; 437 | } 438 | 439 | else if (char === '.') { 440 | const u = getImportMetaUrl(str, i, id); 441 | if (u) { 442 | importMetaUrls.push(u); 443 | p = u.end; 444 | } 445 | } 446 | } 447 | }, 448 | 449 | // export 450 | (i: number) => { 451 | if (i === 0 || isWhitespace(str[i - 1]) || punctuatorChars.test(str[i - 1])) { 452 | if (/export[\s\n{]/.test(str.slice(i, i + 7))) { 453 | const d = getExportDeclaration(str, i); 454 | exportDeclarations.push(d); 455 | p = d.end; 456 | } 457 | } 458 | }, 459 | 460 | // ++/-- 461 | (i: number) => { 462 | pfixOp = (!pfixOp && str[i - 1] === '+'); 463 | } 464 | ] 465 | }; 466 | 467 | const slash: State = { 468 | pattern: /(?:(\[)|(\\)|(.))/g, 469 | 470 | handlers: [ 471 | // [ 472 | (i: number) => regexEnabled ? regex_character : base, 473 | 474 | // \\ 475 | (i: number) => ((escapedFrom = regex), escaped), 476 | 477 | // anything else 478 | (i: number) => regexEnabled && !pfixOp ? regex : base 479 | ] 480 | }; 481 | 482 | const regex: State = { 483 | pattern: /(?:(\[)|(\\)|(\/))/g, 484 | 485 | handlers: [ 486 | // [ 487 | () => regex_character, 488 | 489 | // \\ 490 | () => ((escapedFrom = regex), escaped), 491 | 492 | // / 493 | () => base 494 | ] 495 | }; 496 | 497 | const regex_character: State = { 498 | pattern: /(?:(\])|(\\))/g, 499 | 500 | handlers: [ 501 | // ] 502 | () => regex, 503 | 504 | // \\ 505 | () => ((escapedFrom = regex_character), escaped) 506 | ] 507 | }; 508 | 509 | const double_quoted: State = { 510 | pattern: /(?:(\\)|("))/g, 511 | 512 | handlers: [ 513 | // \\ 514 | () => ((escapedFrom = double_quoted), escaped), 515 | 516 | // " 517 | () => stack.pop() 518 | ] 519 | }; 520 | 521 | const single_quoted: State = { 522 | pattern: /(?:(\\)|('))/g, 523 | 524 | handlers: [ 525 | // \\ 526 | () => ((escapedFrom = single_quoted), escaped), 527 | 528 | // ' 529 | () => stack.pop() 530 | ] 531 | }; 532 | 533 | const escaped: State = { 534 | pattern: /(.)/g, 535 | 536 | handlers: [ 537 | () => escapedFrom 538 | ] 539 | }; 540 | 541 | const template_string: State = { 542 | pattern: /(?:(\${)|(\\)|(`))/g, 543 | 544 | handlers: [ 545 | // ${ 546 | () => { 547 | stack.push(template_string); 548 | return base; 549 | }, 550 | 551 | // \\ 552 | () => ((escapedFrom = template_string), escaped), 553 | 554 | // ` 555 | () => base 556 | ] 557 | }; 558 | 559 | const line_comment = { 560 | pattern: /((?:\n|$))/g, 561 | 562 | handlers: [ 563 | // \n 564 | () => base 565 | ] 566 | }; 567 | 568 | const block_comment = { 569 | pattern: /(\*\/)/g, 570 | 571 | handlers: [ 572 | // \n 573 | () => base 574 | ] 575 | }; 576 | 577 | let state = base; 578 | 579 | let p = 0; 580 | 581 | while (p < str.length) { 582 | state.pattern.lastIndex = p; 583 | const match = state.pattern.exec(str); 584 | 585 | if (!match) { 586 | if (stack.length > 0 || state !== base) { 587 | throw new Error(`Unexpected end of file`); 588 | } 589 | 590 | break; 591 | } 592 | 593 | p = match.index + match[0].length; 594 | 595 | for (let j = 1; j < match.length; j += 1) { 596 | if (match[j]) { 597 | state = state.handlers[j - 1](match.index) || state; 598 | break; 599 | } 600 | } 601 | } 602 | 603 | return [ 604 | importDeclarations, 605 | importStatements, 606 | importMetaUrls, 607 | exportDeclarations 608 | ]; 609 | } 610 | 611 | export function transform(source: string, id: string) { 612 | const [ 613 | importDeclarations, 614 | importStatements, 615 | importMetaUrls, 616 | exportDeclarations 617 | ] = find(source, id); 618 | 619 | const nameBySource = new Map(); 620 | 621 | importDeclarations.forEach(d => { 622 | if (nameBySource.has(d.source)) return; 623 | nameBySource.set(d.source, d.name || `__dep_${nameBySource.size}`); 624 | }); 625 | 626 | exportDeclarations.forEach(d => { 627 | if (!d.source) return; 628 | if (nameBySource.has(d.source)) return; 629 | nameBySource.set(d.source, d.name || `__dep_${nameBySource.size}`); 630 | }); 631 | 632 | const deps = Array.from(nameBySource.keys()) 633 | .map(s => `'${s}'`) 634 | .join(', '); 635 | 636 | const names = ['__import', '__exports'].concat(Array.from(nameBySource.values())) 637 | .join(', '); 638 | 639 | const hoisted: string[] = []; 640 | importDeclarations.forEach(decl => { 641 | const name = nameBySource.get(decl.source); 642 | 643 | decl.specifiers 644 | .sort((a: Specifier, b: Specifier) => { 645 | if (a.name === 'default') return 1; 646 | if (b.name === 'default') return -1; 647 | }) 648 | .forEach((s: Specifier) => { 649 | if (s.name !== '*') { 650 | const assignment = (s.name === 'default' && s.as === name) 651 | ? `${s.as} = ${name}.default; ` 652 | : `var ${s.as} = ${name}.${s.name}; `; 653 | 654 | hoisted.push(assignment); 655 | } 656 | }); 657 | }); 658 | 659 | let transformed = `__shimport__.define('${id}', [${deps}], function(${names}){ ${hoisted.join('')}`; 660 | 661 | const ranges: any[] = [ 662 | ...importDeclarations, 663 | ...importStatements, 664 | ...importMetaUrls, 665 | ...exportDeclarations 666 | ].sort((a, b) => a.start - b.start); 667 | 668 | let c = 0; 669 | 670 | for (let i = 0; i < ranges.length; i += 1) { 671 | const range = ranges[i]; 672 | transformed += ( 673 | source.slice(c, range.start) + 674 | range.toString(nameBySource) 675 | ); 676 | 677 | c = range.end; 678 | } 679 | 680 | transformed += source.slice(c); 681 | 682 | exportDeclarations.forEach(d => { 683 | if (d.name) transformed += `\n__exports.${d.as || d.name} = ${d.name};`; 684 | }); 685 | 686 | transformed += `\n});\n//# sourceURL=${id}`; 687 | 688 | return transformed; 689 | } 690 | -------------------------------------------------------------------------------- /test/samples/dynamic-import-minified/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./dynamic-import-minified/input.js', [], function(__import, __exports){ showFoo=()=>__import('./foo.js').then(foo => { 2 | console.log(foo); 3 | }); 4 | }); 5 | //# sourceURL=./dynamic-import-minified/input.js -------------------------------------------------------------------------------- /test/samples/dynamic-import-minified/input.js: -------------------------------------------------------------------------------- 1 | showFoo=()=>import('./foo.js').then(foo => { 2 | console.log(foo); 3 | }); -------------------------------------------------------------------------------- /test/samples/dynamic-import-minified/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./dynamic-import-minified/input.js', [], function(__import, __exports){ showFoo=()=>__import('./foo.js').then(foo => { 2 | console.log(foo); 3 | }); 4 | }); 5 | //# sourceURL=./dynamic-import-minified/input.js -------------------------------------------------------------------------------- /test/samples/dynamic-import-whitespace/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./dynamic-import-whitespace/input.js', [], function(__import, __exports){ __import ('./foo.js').then(foo => { 2 | console.log(foo); 3 | }); 4 | }); 5 | //# sourceURL=./dynamic-import-whitespace/input.js -------------------------------------------------------------------------------- /test/samples/dynamic-import-whitespace/input.js: -------------------------------------------------------------------------------- 1 | import ('./foo.js').then(foo => { 2 | console.log(foo); 3 | }); -------------------------------------------------------------------------------- /test/samples/dynamic-import-whitespace/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./dynamic-import-whitespace/input.js', [], function(__import, __exports){ __import ('./foo.js').then(foo => { 2 | console.log(foo); 3 | }); 4 | }); 5 | //# sourceURL=./dynamic-import-whitespace/input.js -------------------------------------------------------------------------------- /test/samples/dynamic-import/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./dynamic-import/input.js', [], function(__import, __exports){ __import('./foo.js').then(foo => { 2 | console.log(foo); 3 | }); 4 | }); 5 | //# sourceURL=./dynamic-import/input.js -------------------------------------------------------------------------------- /test/samples/dynamic-import/input.js: -------------------------------------------------------------------------------- 1 | import('./foo.js').then(foo => { 2 | console.log(foo); 3 | }); -------------------------------------------------------------------------------- /test/samples/dynamic-import/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./dynamic-import/input.js', [], function(__import, __exports){ __import('./foo.js').then(foo => { 2 | console.log(foo); 3 | }); 4 | }); 5 | //# sourceURL=./dynamic-import/input.js -------------------------------------------------------------------------------- /test/samples/export-declaration/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-declaration/input.js', [], function(__import, __exports){ const foo = 42; 2 | __exports.foo = foo; 3 | }); 4 | //# sourceURL=./export-declaration/input.js -------------------------------------------------------------------------------- /test/samples/export-declaration/input.js: -------------------------------------------------------------------------------- 1 | export const foo = 42; -------------------------------------------------------------------------------- /test/samples/export-declaration/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-declaration/input.js', [], function(__import, __exports){ const foo = 42; 2 | __exports.foo = foo; 3 | }); 4 | //# sourceURL=./export-declaration/input.js -------------------------------------------------------------------------------- /test/samples/export-default-no-space/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-default-no-space/input.js', [], function(__import, __exports){ __exports.default =[42]; 2 | }); 3 | //# sourceURL=./export-default-no-space/input.js -------------------------------------------------------------------------------- /test/samples/export-default-no-space/input.js: -------------------------------------------------------------------------------- 1 | export default[42]; -------------------------------------------------------------------------------- /test/samples/export-default-no-space/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-default-no-space/input.js', [], function(__import, __exports){ __exports.default =[42]; 2 | }); 3 | //# sourceURL=./export-default-no-space/input.js -------------------------------------------------------------------------------- /test/samples/export-default-unnamed-class-extends/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-default-unnamed-class-extends/input.js', [], function(__import, __exports){ class __default_export extends bar{}foo=42 2 | __exports.default = __default_export; 3 | }); 4 | //# sourceURL=./export-default-unnamed-class-extends/input.js -------------------------------------------------------------------------------- /test/samples/export-default-unnamed-class-extends/input.js: -------------------------------------------------------------------------------- 1 | export default class extends bar{}foo=42 -------------------------------------------------------------------------------- /test/samples/export-default-unnamed-class-extends/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-default-unnamed-class-extends/input.js', [], function(__import, __exports){ class __default_export extends bar{}foo=42 2 | __exports.default = __default_export; 3 | }); 4 | //# sourceURL=./export-default-unnamed-class-extends/input.js -------------------------------------------------------------------------------- /test/samples/export-default-unnamed-class/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-default-unnamed-class/input.js', [], function(__import, __exports){ class __default_export{}foo=42 2 | __exports.default = __default_export; 3 | }); 4 | //# sourceURL=./export-default-unnamed-class/input.js -------------------------------------------------------------------------------- /test/samples/export-default-unnamed-class/input.js: -------------------------------------------------------------------------------- 1 | export default class{}foo=42 -------------------------------------------------------------------------------- /test/samples/export-default-unnamed-class/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-default-unnamed-class/input.js', [], function(__import, __exports){ class __default_export{}foo=42 2 | __exports.default = __default_export; 3 | }); 4 | //# sourceURL=./export-default-unnamed-class/input.js -------------------------------------------------------------------------------- /test/samples/export-default-unnamed-function/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-default-unnamed-function/input.js', [], function(__import, __exports){ function __default_export(){}foo=42 2 | __exports.default = __default_export; 3 | }); 4 | //# sourceURL=./export-default-unnamed-function/input.js -------------------------------------------------------------------------------- /test/samples/export-default-unnamed-function/input.js: -------------------------------------------------------------------------------- 1 | export default function(){}foo=42 -------------------------------------------------------------------------------- /test/samples/export-default-unnamed-function/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-default-unnamed-function/input.js', [], function(__import, __exports){ function __default_export(){}foo=42 2 | __exports.default = __default_export; 3 | }); 4 | //# sourceURL=./export-default-unnamed-function/input.js -------------------------------------------------------------------------------- /test/samples/export-default/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-default/input.js', [], function(__import, __exports){ __exports.default = 42; 2 | }); 3 | //# sourceURL=./export-default/input.js -------------------------------------------------------------------------------- /test/samples/export-default/input.js: -------------------------------------------------------------------------------- 1 | export default 42; -------------------------------------------------------------------------------- /test/samples/export-default/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-default/input.js', [], function(__import, __exports){ __exports.default = 42; 2 | }); 3 | //# sourceURL=./export-default/input.js -------------------------------------------------------------------------------- /test/samples/export-empty/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-empty/input.js', [], function(__import, __exports){ // unambiguous grammar 2 | /*export {}*/; 3 | }); 4 | //# sourceURL=./export-empty/input.js -------------------------------------------------------------------------------- /test/samples/export-empty/input.js: -------------------------------------------------------------------------------- 1 | // unambiguous grammar 2 | export {}; -------------------------------------------------------------------------------- /test/samples/export-empty/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-empty/input.js', [], function(__import, __exports){ // unambiguous grammar 2 | /*export {}*/; 3 | }); 4 | //# sourceURL=./export-empty/input.js -------------------------------------------------------------------------------- /test/samples/export-from-minified/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-from-minified/input.js', ['./foo.js'], function(__import, __exports, __dep_0){ __exports.foo = __dep_0.foo; /*export{foo}from'./foo.js'*/; 2 | }); 3 | //# sourceURL=./export-from-minified/input.js -------------------------------------------------------------------------------- /test/samples/export-from-minified/input.js: -------------------------------------------------------------------------------- 1 | export{foo}from'./foo.js'; -------------------------------------------------------------------------------- /test/samples/export-from-minified/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-from-minified/input.js', ['./foo.js'], function(__import, __exports, __dep_0){ __exports.foo = __dep_0.foo; /*export{foo}from'./foo.js'*/; 2 | }); 3 | //# sourceURL=./export-from-minified/input.js -------------------------------------------------------------------------------- /test/samples/export-from/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-from/input.js', ['./foo.js'], function(__import, __exports, __dep_0){ __exports.foo = __dep_0.foo; /*export { foo } from './foo.js'*/; 2 | }); 3 | //# sourceURL=./export-from/input.js -------------------------------------------------------------------------------- /test/samples/export-from/input.js: -------------------------------------------------------------------------------- 1 | export { foo } from './foo.js'; -------------------------------------------------------------------------------- /test/samples/export-from/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-from/input.js', ['./foo.js'], function(__import, __exports, __dep_0){ __exports.foo = __dep_0.foo; /*export { foo } from './foo.js'*/; 2 | }); 3 | //# sourceURL=./export-from/input.js -------------------------------------------------------------------------------- /test/samples/export-function/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-function/input.js', [], function(__import, __exports){ function foo(a) {} 2 | __exports.foo = foo; 3 | }); 4 | //# sourceURL=./export-function/input.js -------------------------------------------------------------------------------- /test/samples/export-function/input.js: -------------------------------------------------------------------------------- 1 | export function foo(a) {} -------------------------------------------------------------------------------- /test/samples/export-function/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-function/input.js', [], function(__import, __exports){ function foo(a) {} 2 | __exports.foo = foo; 3 | }); 4 | //# sourceURL=./export-function/input.js -------------------------------------------------------------------------------- /test/samples/export-named-minified-b/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-named-minified-b/input.js', [], function(__import, __exports){ const foo = 42; 2 | const bar = 43; 3 | const baz = 44; 4 | __exports.foo = foo; /*export{foo}*/;__exports.bar = bar; /*export{bar}*/;if(x){}__exports.baz = baz; /*export{baz}*/ 5 | }); 6 | //# sourceURL=./export-named-minified-b/input.js -------------------------------------------------------------------------------- /test/samples/export-named-minified-b/input.js: -------------------------------------------------------------------------------- 1 | const foo = 42; 2 | const bar = 43; 3 | const baz = 44; 4 | export{foo};export{bar};if(x){}export{baz} -------------------------------------------------------------------------------- /test/samples/export-named-minified-b/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-named-minified-b/input.js', [], function(__import, __exports){ const foo = 42; 2 | const bar = 43; 3 | const baz = 44; 4 | __exports.foo = foo; /*export{foo}*/;__exports.bar = bar; /*export{bar}*/;if(x){}__exports.baz = baz; /*export{baz}*/ 5 | }); 6 | //# sourceURL=./export-named-minified-b/input.js -------------------------------------------------------------------------------- /test/samples/export-named-minified/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-named-minified/input.js', [], function(__import, __exports){ const foo = 42; 2 | __exports.foo = foo; /*export{foo}*/; 3 | }); 4 | //# sourceURL=./export-named-minified/input.js -------------------------------------------------------------------------------- /test/samples/export-named-minified/input.js: -------------------------------------------------------------------------------- 1 | const foo = 42; 2 | export{foo}; -------------------------------------------------------------------------------- /test/samples/export-named-minified/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-named-minified/input.js', [], function(__import, __exports){ const foo = 42; 2 | __exports.foo = foo; /*export{foo}*/; 3 | }); 4 | //# sourceURL=./export-named-minified/input.js -------------------------------------------------------------------------------- /test/samples/export-named/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-named/input.js', [], function(__import, __exports){ const foo = 42; 2 | __exports.foo = foo; /*export { foo }*/; 3 | }); 4 | //# sourceURL=./export-named/input.js -------------------------------------------------------------------------------- /test/samples/export-named/input.js: -------------------------------------------------------------------------------- 1 | const foo = 42; 2 | export { foo }; -------------------------------------------------------------------------------- /test/samples/export-named/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-named/input.js', [], function(__import, __exports){ const foo = 42; 2 | __exports.foo = foo; /*export { foo }*/; 3 | }); 4 | //# sourceURL=./export-named/input.js -------------------------------------------------------------------------------- /test/samples/export-star-from/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-star-from/input.js', ['./foo.js'], function(__import, __exports, __dep_0){ Object.assign(__exports, __dep_0); /*export * from './foo.js'*/; 2 | }); 3 | //# sourceURL=./export-star-from/input.js -------------------------------------------------------------------------------- /test/samples/export-star-from/input.js: -------------------------------------------------------------------------------- 1 | export * from './foo.js'; -------------------------------------------------------------------------------- /test/samples/export-star-from/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./export-star-from/input.js', ['./foo.js'], function(__import, __exports, __dep_0){ Object.assign(__exports, __dep_0); /*export * from './foo.js'*/; 2 | }); 3 | //# sourceURL=./export-star-from/input.js -------------------------------------------------------------------------------- /test/samples/import-default-star/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-default-star/input.js', ['./x.js'], function(__import, __exports, bar){ var foo = bar.default; /*import foo, * as bar from './x.js'*/; 2 | 3 | console.log(foo, bar); 4 | }); 5 | //# sourceURL=./import-default-star/input.js -------------------------------------------------------------------------------- /test/samples/import-default-star/input.js: -------------------------------------------------------------------------------- 1 | import foo, * as bar from './x.js'; 2 | 3 | console.log(foo, bar); -------------------------------------------------------------------------------- /test/samples/import-default-star/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-default-star/input.js', ['./x.js'], function(__import, __exports, bar){ var foo = bar.default; /*import foo, * as bar from './x.js'*/; 2 | 3 | console.log(foo, bar); 4 | }); 5 | //# sourceURL=./import-default-star/input.js -------------------------------------------------------------------------------- /test/samples/import-default/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-default/input.js', ['./foo.js'], function(__import, __exports, foo){ foo = foo.default; /*import foo from './foo.js'*/; 2 | 3 | console.log(foo); 4 | }); 5 | //# sourceURL=./import-default/input.js -------------------------------------------------------------------------------- /test/samples/import-default/input.js: -------------------------------------------------------------------------------- 1 | import foo from './foo.js'; 2 | 3 | console.log(foo); -------------------------------------------------------------------------------- /test/samples/import-default/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-default/input.js', ['./foo.js'], function(__import, __exports, foo){ foo = foo.default; /*import foo from './foo.js'*/; 2 | 3 | console.log(foo); 4 | }); 5 | //# sourceURL=./import-default/input.js -------------------------------------------------------------------------------- /test/samples/import-empty-minified/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-empty-minified/input.js', ['./foo-polyfill.js'], function(__import, __exports, __dep_0){ /*import'./foo-polyfill.js'*/; 2 | 3 | console.log(window.foo); 4 | }); 5 | //# sourceURL=./import-empty-minified/input.js -------------------------------------------------------------------------------- /test/samples/import-empty-minified/input.js: -------------------------------------------------------------------------------- 1 | import'./foo-polyfill.js'; 2 | 3 | console.log(window.foo); -------------------------------------------------------------------------------- /test/samples/import-empty-minified/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-empty-minified/input.js', ['./foo-polyfill.js'], function(__import, __exports, __dep_0){ /*import'./foo-polyfill.js'*/; 2 | 3 | console.log(window.foo); 4 | }); 5 | //# sourceURL=./import-empty-minified/input.js -------------------------------------------------------------------------------- /test/samples/import-empty/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-empty/input.js', ['./foo-polyfill.js'], function(__import, __exports, __dep_0){ /*import './foo-polyfill.js'*/; 2 | 3 | console.log(window.foo); 4 | }); 5 | //# sourceURL=./import-empty/input.js -------------------------------------------------------------------------------- /test/samples/import-empty/input.js: -------------------------------------------------------------------------------- 1 | import './foo-polyfill.js'; 2 | 3 | console.log(window.foo); -------------------------------------------------------------------------------- /test/samples/import-empty/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-empty/input.js', ['./foo-polyfill.js'], function(__import, __exports, __dep_0){ /*import './foo-polyfill.js'*/; 2 | 3 | console.log(window.foo); 4 | }); 5 | //# sourceURL=./import-empty/input.js -------------------------------------------------------------------------------- /test/samples/import-meta-url/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-meta-url/input.js', [], function(__import, __exports){ console.log("./import-meta-url/input.js"); 2 | }); 3 | //# sourceURL=./import-meta-url/input.js -------------------------------------------------------------------------------- /test/samples/import-meta-url/input.js: -------------------------------------------------------------------------------- 1 | console.log(import.meta.url); -------------------------------------------------------------------------------- /test/samples/import-meta-url/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-meta-url/input.js', [], function(__import, __exports){ console.log("./import-meta-url/input.js"); 2 | }); 3 | //# sourceURL=./import-meta-url/input.js -------------------------------------------------------------------------------- /test/samples/import-named-minified-b/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-named-minified-b/input.js', ['./foo.js', './bar.js'], function(__import, __exports, __dep_0, __dep_1){ var foo = __dep_0.foo; var bar = __dep_1.bar; /*import{foo}from './foo.js'*/;/*import{bar}from './bar.js'*/; 2 | 3 | console.log(foo, bar); 4 | }); 5 | //# sourceURL=./import-named-minified-b/input.js -------------------------------------------------------------------------------- /test/samples/import-named-minified-b/input.js: -------------------------------------------------------------------------------- 1 | import{foo}from './foo.js';import{bar}from './bar.js'; 2 | 3 | console.log(foo, bar); -------------------------------------------------------------------------------- /test/samples/import-named-minified-b/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-named-minified-b/input.js', ['./foo.js', './bar.js'], function(__import, __exports, __dep_0, __dep_1){ var foo = __dep_0.foo; var bar = __dep_1.bar; /*import{foo}from './foo.js'*/;/*import{bar}from './bar.js'*/; 2 | 3 | console.log(foo, bar); 4 | }); 5 | //# sourceURL=./import-named-minified-b/input.js -------------------------------------------------------------------------------- /test/samples/import-named-minified/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-named-minified/input.js', ['./foo.js'], function(__import, __exports, __dep_0){ var foo = __dep_0.foo; /*import{foo}from './foo.js'*/; 2 | 3 | console.log(foo); 4 | }); 5 | //# sourceURL=./import-named-minified/input.js -------------------------------------------------------------------------------- /test/samples/import-named-minified/input.js: -------------------------------------------------------------------------------- 1 | import{foo}from './foo.js'; 2 | 3 | console.log(foo); -------------------------------------------------------------------------------- /test/samples/import-named-minified/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-named-minified/input.js', ['./foo.js'], function(__import, __exports, __dep_0){ var foo = __dep_0.foo; /*import{foo}from './foo.js'*/; 2 | 3 | console.log(foo); 4 | }); 5 | //# sourceURL=./import-named-minified/input.js -------------------------------------------------------------------------------- /test/samples/import-named-multiple/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-named-multiple/input.js', ['./x.js'], function(__import, __exports, __dep_0){ var foo = __dep_0.foo; var bar = __dep_0.bar; /*import { foo, bar } from './x.js'*/; 2 | 3 | console.log(foo, bar); 4 | }); 5 | //# sourceURL=./import-named-multiple/input.js -------------------------------------------------------------------------------- /test/samples/import-named-multiple/input.js: -------------------------------------------------------------------------------- 1 | import { foo, bar } from './x.js'; 2 | 3 | console.log(foo, bar); -------------------------------------------------------------------------------- /test/samples/import-named-multiple/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-named-multiple/input.js', ['./x.js'], function(__import, __exports, __dep_0){ var foo = __dep_0.foo; var bar = __dep_0.bar; /*import { foo, bar } from './x.js'*/; 2 | 3 | console.log(foo, bar); 4 | }); 5 | //# sourceURL=./import-named-multiple/input.js -------------------------------------------------------------------------------- /test/samples/import-named/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-named/input.js', ['./foo.js'], function(__import, __exports, __dep_0){ var foo = __dep_0.foo; console.log(foo); 2 | /*import { foo } from './foo.js'*/; 3 | }); 4 | //# sourceURL=./import-named/input.js -------------------------------------------------------------------------------- /test/samples/import-named/input.js: -------------------------------------------------------------------------------- 1 | console.log(foo); 2 | import { foo } from './foo.js'; -------------------------------------------------------------------------------- /test/samples/import-named/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-named/input.js', ['./foo.js'], function(__import, __exports, __dep_0){ var foo = __dep_0.foo; console.log(foo); 2 | /*import { foo } from './foo.js'*/; 3 | }); 4 | //# sourceURL=./import-named/input.js -------------------------------------------------------------------------------- /test/samples/import-namespace/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-namespace/input.js', ['./foo.js'], function(__import, __exports, foo){ /*import * as foo from './foo.js'*/; 2 | 3 | console.log(foo); 4 | }); 5 | //# sourceURL=./import-namespace/input.js -------------------------------------------------------------------------------- /test/samples/import-namespace/input.js: -------------------------------------------------------------------------------- 1 | import * as foo from './foo.js'; 2 | 3 | console.log(foo); -------------------------------------------------------------------------------- /test/samples/import-namespace/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./import-namespace/input.js', ['./foo.js'], function(__import, __exports, foo){ /*import * as foo from './foo.js'*/; 2 | 3 | console.log(foo); 4 | }); 5 | //# sourceURL=./import-namespace/input.js -------------------------------------------------------------------------------- /test/samples/keyword-false-positive/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./keyword-false-positive/input.js', [], function(__import, __exports){ a * Min / x; 2 | }); 3 | //# sourceURL=./keyword-false-positive/input.js -------------------------------------------------------------------------------- /test/samples/keyword-false-positive/input.js: -------------------------------------------------------------------------------- 1 | a * Min / x; -------------------------------------------------------------------------------- /test/samples/keyword-false-positive/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./keyword-false-positive/input.js', [], function(__import, __exports){ a * Min / x; 2 | }); 3 | //# sourceURL=./keyword-false-positive/input.js -------------------------------------------------------------------------------- /test/samples/template-string-dollar/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./template-string-dollar/input.js', [], function(__import, __exports){ let foo = `$`; 2 | }); 3 | //# sourceURL=./template-string-dollar/input.js -------------------------------------------------------------------------------- /test/samples/template-string-dollar/input.js: -------------------------------------------------------------------------------- 1 | let foo = `$`; -------------------------------------------------------------------------------- /test/samples/template-string-dollar/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./template-string-dollar/input.js', [], function(__import, __exports){ let foo = `$`; 2 | }); 3 | //# sourceURL=./template-string-dollar/input.js -------------------------------------------------------------------------------- /test/samples/template-string-expression/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./template-string-expression/input.js', [], function(__import, __exports){ let foo = `${42}`; 2 | }); 3 | //# sourceURL=./template-string-expression/input.js -------------------------------------------------------------------------------- /test/samples/template-string-expression/input.js: -------------------------------------------------------------------------------- 1 | let foo = `${42}`; -------------------------------------------------------------------------------- /test/samples/template-string-expression/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./template-string-expression/input.js', [], function(__import, __exports){ let foo = `${42}`; 2 | }); 3 | //# sourceURL=./template-string-expression/input.js -------------------------------------------------------------------------------- /test/samples/unfinished/actual.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./unfinished/input.js', [], function(__import, __exports){ import /*wut*/ 2 | }); 3 | //# sourceURL=./unfinished/input.js -------------------------------------------------------------------------------- /test/samples/unfinished/input.js: -------------------------------------------------------------------------------- 1 | import /*wut*/ -------------------------------------------------------------------------------- /test/samples/unfinished/output.js: -------------------------------------------------------------------------------- 1 | __shimport__.define('./unfinished/input.js', [], function(__import, __exports){ import /*wut*/ 2 | }); 3 | //# sourceURL=./unfinished/input.js -------------------------------------------------------------------------------- /test/test.ts: -------------------------------------------------------------------------------- 1 | import { test } from 'uvu'; 2 | import * as fs from 'fs'; 3 | import * as assert from 'assert'; 4 | import * as shimport from '../src/index'; 5 | 6 | fs.readdirSync('test/samples').forEach(dir => { 7 | if (dir[0] === '.') return; 8 | 9 | test(dir, () => { 10 | const input = fs.readFileSync(`test/samples/${dir}/input.js`, 'utf-8'); 11 | const actual = shimport.transform(input, `./${dir}/input.js`); 12 | fs.writeFileSync(`test/samples/${dir}/actual.js`, actual); 13 | 14 | const expected = fs.readFileSync(`test/samples/${dir}/output.js`, 'utf-8'); 15 | 16 | assert.equal(actual, expected); 17 | }); 18 | }); 19 | 20 | test.run(); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": true, 4 | "diagnostics": true, 5 | "noImplicitThis": true, 6 | "noEmitOnError": true, 7 | "lib": ["es5", "es6", "dom"] 8 | }, 9 | "target": "ES5", 10 | "module": "ES6", 11 | "include": [ 12 | "src" 13 | ], 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } --------------------------------------------------------------------------------