├── .eslintrc.json ├── .gitignore ├── .travis.yml ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── appveyor.yml ├── bin └── reverse.js ├── index.js ├── package.json └── tests ├── cli_test.js ├── expected ├── _svg.scss ├── stretchy.js └── stretchy.scss ├── fixtures ├── stretchy-inline.css.map ├── stretchy-with-sources.min.js.map ├── stretchy.css.map └── stretchy.min.js.map └── index_test.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-console": 0, 4 | "no-process-exit": 0 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.lcov 2 | tmp 3 | .sass-cache 4 | 5 | # Logs 6 | logs 7 | *.log 8 | 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage* 19 | .nyc_output 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/Release 26 | 27 | # Dependency directory 28 | # Commenting this out is preferred by some people, see 29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 30 | node_modules 31 | 32 | # Users Environment Variables 33 | .lock-wscript 34 | flow 35 | 36 | *.cpuprofile 37 | *.heapsnapshot 38 | memwatch.* 39 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "8" 5 | cache: 6 | directories: 7 | - node_modules 8 | script: 9 | - npm run lint 10 | - npm test 11 | matrix: 12 | fast_finish: true 13 | after_script: "npm run coverage" 14 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Expected behaviour 2 | 3 | What it should have accomplished. 4 | 5 | ### Actual behaviour 6 | 7 | How to reproduce with minimal working example. 8 | 9 | ### Versions and environment 10 | 11 | * Operating system: 12 | * Node.js: 13 | * npm: 14 | * shuji: 15 | 16 | Thank you and have some :stew:. 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Juga Paazmaya (https://paazmaya.fi) 4 | Copyright (c) David Kevork (https://davidkevork.me) 5 | 6 | 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: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | 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. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # reverse-sourcemap 2 | 3 | > Reverse engineering JavaScript and CSS sources from sourcemaps 4 | 5 | 6 | ## Getting started 7 | 8 | Install the `reverse-sourcemap` command line utility globally with [npm](https://www.npmjs.com/). 9 | Elevated privileges might be needed via `sudo`, depending on the platform. In most cases just: 10 | 11 | ```sh 12 | npm install --global reverse-sourcemap 13 | ``` 14 | 15 | Please note that the minimum supported version of [Node.js](https://nodejs.org/en/) is `8.11.1`, which is [the active Long Term Support (LTS) version](https://github.com/nodejs/Release#release-schedule). 16 | 17 | ## Command line options 18 | 19 | The output of `reverse-sourcemap --help` pretty much covers all the options: 20 | 21 | ```sh 22 | reverse-sourcemap - Reverse engineering JavaScript and CSS sources from sourcemaps 23 | Usage: reverse-sourcemap [options] 24 | 25 | -h, --help Help and usage instructions 26 | -V, --version Version number 27 | -v, --verbose Verbose output, will print which file is currently being processed 28 | -o, --output-dir String Output directory - default: . 29 | -M, --match String Regular expression for matching and filtering files - default: \.map$ 30 | -r, --recursive Recursively search matching files 31 | 32 | Version 0.4.0 33 | ``` 34 | 35 | ## Testing 36 | 37 | Test files are generated with [UglifyJS2](https://github.com/mishoo/UglifyJS2) and 38 | [`sass`](http://sass-lang.com) 39 | by using files from the [stretchy](https://github.com/LeaVerou/stretchy) project, 40 | with the following commands: 41 | 42 | ```sh 43 | uglifyjs stretchy.js --compress --mangle \ 44 | -o stretchy.min.js --source-map stretchy.min.js.map 45 | 46 | uglifyjs stretchy.js --compress --mangle \ 47 | -o stretchy.min.js --source-map stretchy-with-sources.min.js.map \ 48 | --source-map-include-sources 49 | 50 | sass stretchy.scss:stretchy.css 51 | 52 | sass stretchy.scss:stretchy.css --sourcemap=inline 53 | ``` 54 | 55 | Unit tests are written with [`tape`](https://github.com/substack/tape) and can be executed with `npm test`. 56 | Code coverage is inspected with [`nyc`](https://github.com/istanbuljs/nyc) and 57 | can be executed with `npm run coverage` after running `npm test`. 58 | Please make sure it is over 90% at all times. 59 | 60 | ## Contributing 61 | 62 | ["A Beginner's Guide to Open Source: The Best Advice for Making your First Contribution"](http://www.erikaheidi.com/blog/a-beginners-guide-to-open-source-the-best-advice-for-making-your-first-contribution/). 63 | 64 | [Also there is a blog post about "45 Github Issues Dos and Don’ts"](https://davidwalsh.name/45-github-issues-dos-donts). 65 | 66 | Linting is done with [ESLint](http://eslint.org) and can be executed with `npm run lint`. 67 | There should be no errors appearing after any JavaScript file changes. 68 | 69 | Please note that any features or changed will not be merged without working unit tests. 70 | 71 | ## License 72 | 73 | Copyright (c) [Juga Paazmaya](https://paazmaya.fi) 74 | Copyright (c) [David Kevork](https://davidkevork.me) 75 | 76 | Licensed under [the MIT license](./LICENSE). 77 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # http://www.appveyor.com/docs/appveyor-yml 2 | 3 | environment: 4 | matrix: 5 | - nodejs_version: "8" 6 | 7 | version: "{build}-{branch}" 8 | 9 | init: 10 | - git config --global core.longpaths true 11 | 12 | clone_depth: 1 13 | 14 | matrix: 15 | fast_finish: true 16 | 17 | cache: 18 | - node_modules 19 | 20 | install: 21 | - ps: Install-Product node $env:nodejs_version 22 | - npm install 23 | 24 | test_script: 25 | - node --version 26 | - npm --version 27 | - npm run lint 28 | - npm test 29 | 30 | build: off 31 | -------------------------------------------------------------------------------- /bin/reverse.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * rreverse-sourcemap 5 | * https://github.com/davidkevork/reverse-sourcemap 6 | * 7 | * Reverse engineering JavaScript and CSS sources from sourcemaps 8 | * 9 | * Copyright (c) Juga Paazmaya (https://paazmaya.fi) 10 | * Copyright (c) David Kevork (https://davidkevork.me) 11 | * Licensed under the MIT license 12 | */ 13 | 14 | 'use strict'; 15 | 16 | const path = require('path'); 17 | const optionator = require('optionator'); 18 | const fs = require('fs-extra'); 19 | const reverse = require('../index'); 20 | 21 | let pkg; 22 | 23 | try { 24 | const packageJson = fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'); 25 | pkg = JSON.parse(packageJson); 26 | } 27 | catch (error) { 28 | console.error('Could not read/parse "package.json", quite strange...'); 29 | console.error(error); 30 | process.exit(1); 31 | } 32 | 33 | const optsParser = optionator({ 34 | prepend: `Usage: ${pkg.name} [options] `, 35 | append: `Version ${pkg.version}`, 36 | options: [ 37 | { 38 | option: 'help', 39 | alias: 'h', 40 | type: 'Boolean', 41 | default: false, 42 | description: 'Help and usage instructions' 43 | }, 44 | { 45 | option: 'version', 46 | alias: 'V', 47 | type: 'Boolean', 48 | default: false, 49 | description: 'Version number' 50 | }, 51 | { 52 | option: 'verbose', 53 | alias: 'v', 54 | type: 'Boolean', 55 | default: false, 56 | description: 'Verbose output, will print which file is currently being processed' 57 | }, 58 | { 59 | option: 'output-dir', 60 | alias: 'o', 61 | type: 'String', 62 | default: '.', 63 | description: 'Output directory' 64 | }, 65 | { 66 | option: 'match', 67 | alias: 'M', 68 | type: 'String', 69 | default: '\\.map$', 70 | description: 'Regular expression for matching and filtering files' 71 | }, 72 | { 73 | option: 'recursive', 74 | alias: 'r', 75 | type: 'Boolean', 76 | default: false, 77 | description: 'Recursively search matching files' 78 | } 79 | ] 80 | }); 81 | 82 | let opts; 83 | 84 | try { 85 | opts = optsParser.parse(process.argv); 86 | } 87 | catch (error) { 88 | console.error(error.message); 89 | process.exit(1); 90 | } 91 | 92 | if (opts.version) { 93 | console.log((opts.verbose ? pkg.name + ' v' : '') + pkg.version); 94 | process.exit(); 95 | } 96 | 97 | console.log(`${pkg.name} - ${pkg.description}`); 98 | 99 | if (opts.help || opts._.length === 0) { 100 | console.log(optsParser.generateHelp()); 101 | process.exit(); 102 | } 103 | 104 | // List of files that will be processed 105 | const fileList = []; 106 | 107 | // Expression to match file paths against 108 | const matcher = new RegExp(opts.match); 109 | 110 | /** 111 | * Determine if the given existing filepath is a file or directory 112 | * and continue with filtering and recursive when needed. 113 | * 114 | * @param {string} filepath Relative filepath that exists 115 | * @param {bool} recurse Should a directory be entered 116 | * @returns {void} 117 | */ 118 | const handleFilepath = (filepath, recurse) => { 119 | const stat = fs.statSync(filepath); 120 | if (stat.isDirectory() && recurse) { 121 | const list = fs.readdirSync(filepath); 122 | 123 | list.forEach((item) => { 124 | handleFilepath(path.join(filepath, item), opts.recursive); 125 | }); 126 | } 127 | else if (filepath.match(matcher) && stat.isFile()) { 128 | fileList.push(filepath); 129 | } 130 | }; 131 | 132 | opts._.forEach((item) => { 133 | if (!fs.existsSync(item)) { 134 | console.error(`File (${item}) not found`); 135 | } 136 | else { 137 | // It is ok to enter the directory on the first level 138 | handleFilepath(item, true); 139 | } 140 | }); 141 | 142 | if (opts.verbose) { 143 | console.log(`Going to process total of ${fileList.length} files`); 144 | } 145 | 146 | const outputDir = path.resolve(opts.outputDir); 147 | 148 | if (opts.verbose) { 149 | console.log(`Outputting to directory: ${outputDir}`); 150 | } 151 | 152 | if (!fs.existsSync(outputDir)) { 153 | fs.ensureDirSync(outputDir); 154 | } 155 | 156 | // Process then... 157 | fileList.forEach((filepath) => { 158 | if (opts.verbose) { 159 | console.log(`Processing file ${filepath}`); 160 | } 161 | 162 | const input = fs.readFileSync(filepath, 'utf8'); 163 | const outdir = path.join(outputDir, path.dirname(filepath)); 164 | const output = reverse(input, { verbose: typeof opts.verbose === 'boolean' ? opts.verbose : false }); 165 | 166 | fs.ensureDirSync(outdir); 167 | output.then((output) => { 168 | Object.keys(output).forEach((item) => { 169 | const outfile = path.join(outdir, item); 170 | 171 | if (opts.verbose) { 172 | console.log(`Writing to file ${outfile}`); 173 | } 174 | 175 | if (fs.existsSync(outfile)) { 176 | console.error('File existed, skipping!'); 177 | } else { 178 | let dir = path.dirname(outfile); 179 | fs.ensureDirSync(dir); 180 | fs.writeFileSync(outfile, output[item], 'utf8'); 181 | } 182 | 183 | }); 184 | }); 185 | 186 | }); 187 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * reverse-sourcemap 3 | * https://github.com/davidkevork/reverse-sourcemap 4 | * 5 | * Reverse engineering JavaScript and CSS sources from sourcemaps 6 | * 7 | * Copyright (c) Juga Paazmaya (https://paazmaya.fi) 8 | * Copyright (c) David Kevork (https://davidkevork.me) 9 | * Licensed under the MIT license 10 | */ 11 | 12 | 'use strict'; 13 | 14 | const path = require('path'); 15 | const sourceMap = require('source-map'); 16 | 17 | /** 18 | * @param {string} input Contents of the sourcemap file 19 | * @param {object} options Object {verbose: boolean} 20 | * 21 | * @returns {object} Source contents mapped to file names 22 | */ 23 | module.exports = (input, options) => { 24 | 25 | const consumer = new sourceMap.SourceMapConsumer(input); 26 | 27 | return consumer.then((response) => { 28 | let map = {}; 29 | if (response.hasContentsOfAllSources()) { 30 | if (options.verbose) { 31 | console.log('All sources were included in the sourcemap'); 32 | } 33 | 34 | response.sources.forEach((source) => { 35 | const contents = response.sourceContentFor(source); 36 | map[path.normalize(source).replace(/^(\.\.[/\\])+/, '').replace(/[|\&#,+()?$~%'":*?<>{}]/g, '').replace(' ', '.')] = contents; 37 | }); 38 | } else if (options.verbose) { 39 | console.log('Not all sources were included in the sourcemap'); 40 | } 41 | return map; 42 | }).catch((e) => { 43 | console.log(e); 44 | return {}; 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reverse-sourcemap", 3 | "version": "1.0.4", 4 | "description": "Reverse engineering JavaScript and CSS sources from sourcemaps", 5 | "main": "index.js", 6 | "bin": "bin/reverse.js", 7 | "scripts": { 8 | "lint": "eslint index.js bin/reverse-sourcemap", 9 | "test": "nyc --exclude tests tape tests/*_test.js && rm -rf tmp", 10 | "coverage": "nyc --exclude tests report --reporter=text-lcov > coverage.lcov && codecov" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+ssh://git@github.com/davidkevork/reverse-sourcemap.git" 15 | }, 16 | "keywords": [ 17 | "sourcemap", 18 | "reverse", 19 | "engineering", 20 | "reverse-sourcemap" 21 | ], 22 | "files": [ 23 | "bin", 24 | "LICENSE", 25 | "README.md", 26 | "index.js" 27 | ], 28 | "author": "Juga Paazmaya (https://paazmaya.fi)", 29 | "contributors": [ 30 | "David Kevork (https://davidkevork.me)" 31 | ], 32 | "license": "MIT", 33 | "bugs": { 34 | "url": "https://github.com/davidkevork/reverse-sourcemap/issues" 35 | }, 36 | "engines": { 37 | "node": ">=8.11.1" 38 | }, 39 | "homepage": "https://github.com/davidkevork/reverse-sourcemap#readme", 40 | "dependencies": { 41 | "fs-extra": "^5.0.0", 42 | "optionator": "^0.8.2", 43 | "source-map": "^0.7.3" 44 | }, 45 | "devDependencies": { 46 | "babel-eslint": "^8.2.2", 47 | "codecov": "^3.0.0", 48 | "eslint": "^4.19.0", 49 | "nyc": "^11.6.0", 50 | "tape": "^4.9.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/cli_test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * reverse.js 3 | * https://github.com/davidkevork/reverse 4 | * 5 | * Reverse engineering JavaScript and CSS sources from sourcemaps 6 | * 7 | * Copyright (c) Juga Paazmaya (https://paazmaya.fi) 8 | * Copyright (c) David Kevork (https://davidkevork.me) 9 | * Licensed under the MIT license 10 | */ 11 | 'use strict'; 12 | 13 | const fs = require('fs'); 14 | const path = require('path'); 15 | const execFile = require('child_process').execFile; 16 | 17 | const tape = require('tape'); 18 | 19 | const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8')); 20 | 21 | tape('cli should output version number', (test) => { 22 | test.plan(1); 23 | 24 | execFile('node', [pkg.bin, '-V'], null, (err, stdout) => { 25 | test.equals(stdout.trim(), pkg.version, 'Version is the same as in package.json'); 26 | }); 27 | 28 | }); 29 | 30 | tape('cli should output help by default', (test) => { 31 | test.plan(1); 32 | 33 | execFile('node', [pkg.bin], null, (err, stdout) => { 34 | test.ok(stdout.trim().indexOf('shuji [options] ') !== -1, 'Help appeared'); 35 | }); 36 | 37 | }); 38 | 39 | tape('cli should output help when requested', (test) => { 40 | test.plan(1); 41 | 42 | execFile('node', [pkg.bin, '--help'], null, (err, stdout) => { 43 | test.ok(stdout.trim().indexOf('shuji [options] ') !== -1, 'Help appeared'); 44 | }); 45 | 46 | }); 47 | 48 | tape('cli should create folder for output', (test) => { 49 | test.plan(1); 50 | 51 | execFile('node', [pkg.bin, '-o', 'tmp', 'tests/fixtures'], null, (err, stdout) => { 52 | test.ok(fs.existsSync('tmp'), 'Temporary folder exists'); 53 | }); 54 | 55 | }); 56 | -------------------------------------------------------------------------------- /tests/expected/_svg.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Cascading Graphics Sheets: Generate SVG data URIs in SCSS! 3 | * By Lea Verou — http://lea.verou.me 4 | * Do not use yet, API *will* change. 5 | */ 6 | 7 | /* Helper functions */ 8 | 9 | // Replace all instances of $search in $string with $replace 10 | @function str-replace($string, $search, $replace) { 11 | $length: str-length($search); 12 | $index: str-index($string, $search); 13 | $slice: $string; 14 | 15 | @while $index != null { 16 | $start: if($index > 1, str-slice($slice, 1, $index - 1), ''); 17 | $slice: $start + $replace + str-slice($slice, $index + $length); 18 | 19 | $index: str-index($slice, $search); 20 | } 21 | 22 | @return $slice; 23 | } 24 | 25 | // Create an inline SVG data URI 26 | @function svg($content, $viewBox: "0 0 100 100") { 27 | $content: str-replace($content, '#', '%23'); // Firefox needs this 28 | 29 | @return url('data:image/svg+xml,#{$content}'); 30 | } 31 | 32 | @function svg-polygon($fill, $points) { 33 | @return unquote(''); 34 | } 35 | 36 | @function svg-path($fill, $d) { 37 | @return unquote(''); 38 | } 39 | 40 | @function svg-rect($fill, $width: '100%', $height: '100%', $x: '0', $y: '0', $attr:'') { 41 | @return unquote(''); 42 | } 43 | 44 | @function svg-square($fill, $width: '100%', $x: '0', $y: '0') { 45 | @return svg-rect($fill, $width, $width, $x, $y); 46 | } 47 | 48 | @function svg-circle($fill, $r: '50%', $cx: '50%', $cy: '50%') { 49 | @return unquote(''); 50 | } 51 | 52 | @function svg-line($stroke, $x1: 0, $y1: 0, $x2: 100, $y2: 100, $width: '1pt') { 53 | @return unquote(''); 54 | } 55 | 56 | @function svg-text($text, $y: 1.2em, $style:'', $x:0) { 57 | @return unquote('#{$text}'); 58 | } -------------------------------------------------------------------------------- /tests/expected/stretchy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Stretchy: Form element autosizing, the way it should be. 3 | * by Lea Verou http://lea.verou.me 4 | * MIT license 5 | */ 6 | (function() { 7 | 8 | if (!self.Element) { 9 | return; // super old browser 10 | } 11 | 12 | if (!Element.prototype.matches) { 13 | Element.prototype.matches = Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || null; 14 | } 15 | 16 | if (!Element.prototype.matches) { 17 | return; 18 | } 19 | 20 | function $$(expr, con) { 21 | return expr instanceof Node || expr instanceof Window? [expr] : 22 | [].slice.call(typeof expr == "string"? (con || document).querySelectorAll(expr) : expr || []); 23 | } 24 | 25 | var _ = self.Stretchy = { 26 | selectors: { 27 | base: 'textarea, select:not([size]), input:not([type]), input[type="' + "text url email tel".split(" ").join('"], input[type="') + '"]', 28 | filter: "*" 29 | }, 30 | 31 | // Script element this was included with, if any 32 | script: document.currentScript || $$("script").pop(), 33 | 34 | // Autosize one element. The core of Stretchy. 35 | resize: function(element) { 36 | if (!_.resizes(element)) { 37 | return; 38 | } 39 | 40 | var cs = getComputedStyle(element); 41 | var offset = 0; 42 | 43 | if (!element.value && element.placeholder) { 44 | var empty = true; 45 | element.value = element.placeholder; 46 | } 47 | 48 | var type = element.nodeName.toLowerCase(); 49 | 50 | if (type == "textarea") { 51 | element.style.height = "0"; 52 | 53 | if (cs.boxSizing == "border-box") { 54 | offset = element.offsetHeight; 55 | } 56 | else if (cs.boxSizing == "content-box") { 57 | offset = -element.clientHeight; 58 | } 59 | 60 | element.style.height = element.scrollHeight + offset + "px"; 61 | } 62 | else if(type == "input") { 63 | element.style.width = "0"; 64 | 65 | if (cs.boxSizing == "border-box") { 66 | offset = element.offsetWidth; 67 | } 68 | else if (cs.boxSizing == "padding-box") { 69 | offset = element.clientWidth; 70 | } 71 | 72 | // Safari misreports scrollWidth, so we will instead set scrollLeft to a 73 | // huge number, and read that back to see what it was clipped to 74 | element.scrollLeft = 1e+10; 75 | 76 | var width = Math.max(element.scrollLeft + offset, element.scrollWidth - element.clientWidth); 77 | 78 | element.style.width = width + "px"; 79 | } 80 | else if (type == "select") { 81 | // Need to use dummy element to measure :( 82 | var option = document.createElement("_"); 83 | option.textContent = element.options[element.selectedIndex].textContent; 84 | element.parentNode.insertBefore(option, element.nextSibling); 85 | 86 | // The name of the appearance property, as it might be prefixed 87 | var appearance; 88 | 89 | for (var property in cs) { 90 | if (!/^(width|webkitLogicalWidth)$/.test(property)) { 91 | //console.log(property, option.offsetWidth, cs[property]); 92 | option.style[property] = cs[property]; 93 | 94 | if (/appearance$/i.test(property)) { 95 | appearance = property; 96 | } 97 | } 98 | } 99 | 100 | option.style.width = ""; 101 | 102 | if (option.offsetWidth > 0) { 103 | element.style.width = option.offsetWidth + "px"; 104 | 105 | if (!cs[appearance] || cs[appearance] !== "none") { 106 | // Account for arrow 107 | element.style.width = "calc(" + element.style.width + " + 2em)"; 108 | } 109 | } 110 | 111 | option.parentNode.removeChild(option); 112 | option = null; 113 | } 114 | 115 | if (empty) { 116 | element.value = ""; 117 | } 118 | }, 119 | 120 | // Autosize multiple elements 121 | resizeAll: function(elements) { 122 | $$(elements || _.selectors.base).forEach(function (element) { 123 | _.resize(element); 124 | }); 125 | }, 126 | 127 | active: true, 128 | 129 | // Will stretchy do anything for this element? 130 | resizes: function(element) { 131 | return element && 132 | element.parentNode && 133 | element.matches && 134 | element.matches(_.selectors.base) && 135 | element.matches(_.selectors.filter); 136 | }, 137 | 138 | init: function(){ 139 | _.selectors.filter = _.script.getAttribute("data-filter") || 140 | ($$("[data-stretchy-filter]").pop() || document.body).getAttribute("data-stretchy-filter") || Stretchy.selectors.filter || "*"; 141 | 142 | _.resizeAll(); 143 | }, 144 | 145 | $$: $$ 146 | }; 147 | 148 | // Autosize all elements once the DOM is loaded 149 | 150 | // DOM already loaded? 151 | if (document.readyState !== "loading") { 152 | _.init(); 153 | } 154 | else { 155 | // Wait for it 156 | document.addEventListener("DOMContentLoaded", _.init); 157 | } 158 | 159 | // Listen for changes 160 | var listener = function(evt) { 161 | if (_.active) { 162 | _.resize(evt.target); 163 | } 164 | }; 165 | 166 | document.body.addEventListener("input", listener); 167 | 168 | // Firefox fires a change event instead of an input event 169 | document.body.addEventListener("change", listener); 170 | 171 | // Listen for new elements 172 | if (self.MutationObserver) { 173 | (new MutationObserver(function(mutations) { 174 | if (_.active) { 175 | mutations.forEach(function(mutation) { 176 | if (mutation.type == "childList") { 177 | Stretchy.resizeAll(mutation.addedNodes); 178 | } 179 | }); 180 | } 181 | })).observe(document.body, { 182 | childList: true, 183 | subtree: true 184 | }); 185 | } 186 | 187 | })(); 188 | -------------------------------------------------------------------------------- /tests/expected/stretchy.scss: -------------------------------------------------------------------------------- 1 | // Colors 2 | $accent1: hsl(185, 40%, 50%); // turquoise 3 | $accent2: hsl(10, 50%, 40%); // dark red 4 | $base: hsl(40, 60%, 90%); // beige 5 | 6 | @import url(https://fonts.googleapis.com/css?family=Arvo:400,700|Damion); 7 | @import "_svg"; 8 | 9 | body { 10 | font: 100%/1.5 Rockwell, Arvo, Helvetica Neue, sans-serif; 11 | margin: 0; 12 | } 13 | 14 | code, pre { 15 | font-family: Consolas, Monaco, Ubuntu Mono, monospace; 16 | } 17 | 18 | input, textarea, select { 19 | border: 2px solid; 20 | padding: .1em .3em; 21 | font: inherit; 22 | background: transparent; 23 | color: inherit; 24 | box-sizing: border-box; 25 | } 26 | 27 | ::-webkit-input-placeholder { color: hsla(0,0%,100%,.5); } 28 | ::-moz-placeholder { color: hsla(0,0%,100%,.5); } 29 | 30 | h1 { 31 | margin: 0; 32 | font: 300% Damion, cursive; 33 | } 34 | 35 | a { 36 | color: inherit; 37 | } 38 | 39 | header, section, footer { 40 | max-width: 900px; 41 | padding: 1.5em calc(50% - 450px); 42 | background: $accent1; 43 | color: $base; 44 | } 45 | 46 | @media (max-width: 950px) { 47 | header, section, footer { 48 | padding: 1.5em 2em; 49 | } 50 | } 51 | 52 | header { 53 | display: -webkit-flex; 54 | display: flex; 55 | 56 | & > h1 { 57 | display: inline-block; 58 | width: 350px; 59 | margin-bottom: -.66em; 60 | margin-left: -2em; 61 | } 62 | 63 | iframe { 64 | display: block; 65 | width: 100%; 66 | border: 0; 67 | } 68 | 69 | & > div { 70 | display: -webkit-flex; 71 | display: flex; 72 | -webkit-flex-flow: column; 73 | flex-flow: column; 74 | -webkit-flex: 1; 75 | flex: 1; 76 | text-align: right; 77 | margin: 0; 78 | } 79 | 80 | p { 81 | -webkit-flex: 1; 82 | flex: 1; 83 | margin: 0; 84 | font-size: 150%; 85 | line-height: 1.2; 86 | font-weight: bold; 87 | letter-spacing: -.03em; 88 | } 89 | 90 | nav { 91 | font: 160% Damion, cursive; 92 | 93 | ul { 94 | margin: 0; 95 | } 96 | 97 | li { 98 | display: inline; 99 | list-style: none; 100 | } 101 | 102 | a { 103 | display: inline-block; 104 | padding: .15em .4em .15em .3em; 105 | border-radius: .3em; 106 | text-decoration: none; 107 | border: .12em solid transparent; 108 | line-height: 1; 109 | } 110 | 111 | a[href="stretchy.js"], 112 | a:hover { 113 | border-color: $base; 114 | } 115 | 116 | a:hover { 117 | background: $base; 118 | color: $accent1; 119 | } 120 | } 121 | } 122 | 123 | section:nth-of-type(odd) { 124 | background: $base; 125 | color: black; 126 | 127 | h1 { 128 | color: $accent2; 129 | } 130 | } 131 | 132 | section:nth-of-type(even) { 133 | padding-top: 2em; 134 | padding-bottom: 2em; 135 | background: svg(svg-polygon($base, "0,0 100,100 200,0"), "0 0 200 100") top / 1em auto repeat-x, 136 | svg(svg-polygon($base, "0,100 100,0 200,100"), "0 0 200 100") bottom / 1em auto repeat-x; 137 | background-color: $accent2; 138 | 139 | h1 { 140 | color: $base; 141 | } 142 | 143 | &:last-of-type { 144 | background-image: svg(svg-polygon($base, "0,0 100,100 200,0"), "0 0 200 100"), 145 | svg(svg-polygon($accent1, "0,100 100,0 200,100"), "0 0 200 100"); 146 | } 147 | } 148 | 149 | #features { 150 | ul { 151 | padding: 0; 152 | list-style: none; 153 | } 154 | 155 | @media (min-width: 600px) { 156 | ul { 157 | -webkit-columns: 2; 158 | -moz-columns: 2; 159 | columns: 2; 160 | } 161 | } 162 | 163 | li { 164 | position: relative; 165 | break-inside: avoid; 166 | -webkit-column-break-inside: avoid; 167 | font-size: 70%; 168 | margin: 0 0 1em 2.5em; 169 | } 170 | li::before { 171 | content: "✓"; 172 | position: absolute; 173 | top: .05em; 174 | right: 100%; 175 | margin-right: .1em; 176 | font-size: 320%; 177 | line-height: 1; 178 | color: $accent1; 179 | } 180 | 181 | li strong { 182 | display: block; 183 | font-size: 150%; 184 | 185 | a:not(:hover) { 186 | text-decoration: none; 187 | } 188 | } 189 | } 190 | 191 | #examples { 192 | overflow: hidden; 193 | 194 | label, 195 | textarea { 196 | display: block; 197 | } 198 | 199 | textarea { 200 | 201 | } 202 | 203 | label:first-of-type { 204 | float: right; 205 | margin-top: -.6em; 206 | } 207 | 208 | label { 209 | margin: 1em 0; 210 | } 211 | } 212 | 213 | #api { 214 | dt { 215 | font-weight: bold; 216 | } 217 | 218 | dd + dt { 219 | margin-top: 1em; 220 | } 221 | } 222 | 223 | footer { 224 | background: $accent1 url(logo.svg) right / auto 100% no-repeat; 225 | background-origin: content-box; 226 | } 227 | 228 | .github-ribbon { 229 | position: absolute; 230 | top: 0; 231 | left: 0; 232 | transform: rotate(90deg) translateX(70.71067814%) rotate(-90deg) rotate(-45deg) translateY(-100%); 233 | transform-origin: 0 0; 234 | padding: .4em 3em; 235 | background: $accent2; 236 | text-decoration: none; 237 | color: $base; 238 | box-shadow: 0 .1em 0 .1em rgba(0,0,0,.15); 239 | 240 | &:hover { 241 | background: black; 242 | color: white; 243 | } 244 | } 245 | 246 | .social-media { 247 | 248 | 249 | @media (min-width: 1150px) { 250 | & { 251 | position: absolute; 252 | top: 1em; 253 | right: 1em; 254 | width: -webkit-min-content; 255 | width: -moz-min-content; 256 | width: min-content; 257 | } 258 | } 259 | } 260 | 261 | #carbonads { 262 | position: absolute; 263 | top: 75vh; 264 | right: 1em; 265 | max-width: 130px; 266 | padding: 1em; 267 | border: 1px solid silver; 268 | font-size: 50%; 269 | line-height: 1.5; 270 | background: hsla(0,0%,100%,.9); 271 | } 272 | 273 | @media (max-width: 950px) { 274 | #carbonads { 275 | display: none; 276 | } 277 | } 278 | 279 | .carbon-text { 280 | display: block; 281 | text-decoration: none; 282 | } -------------------------------------------------------------------------------- /tests/fixtures/stretchy-inline.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "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", 4 | "sources": ["stretchy.scss","_svg.scss"], 5 | "sourcesContent": ["// Colors\n$accent1: hsl(185, 40%, 50%); // turquoise\n$accent2: hsl(10, 50%, 40%); // dark red\n$base: hsl(40, 60%, 90%); // beige\n\n@import url(https://fonts.googleapis.com/css?family=Arvo:400,700|Damion);\n@import \"_svg\";\n\nbody {\n\tfont: 100%/1.5 Rockwell, Arvo, Helvetica Neue, sans-serif;\n\tmargin: 0;\n}\n\ncode, pre {\n\tfont-family: Consolas, Monaco, Ubuntu Mono, monospace;\n}\n\ninput, textarea, select {\n\tborder: 2px solid;\n\tpadding: .1em .3em;\n\tfont: inherit;\n\tbackground: transparent;\n\tcolor: inherit;\n\tbox-sizing: border-box;\n}\n\n::-webkit-input-placeholder { color: hsla(0,0%,100%,.5); }\n::-moz-placeholder { color: hsla(0,0%,100%,.5); }\n\nh1 {\n\tmargin: 0;\n\tfont: 300% Damion, cursive;\n}\n\na {\n\tcolor: inherit;\n}\n\nheader, section, footer {\n\tmax-width: 900px;\n\tpadding: 1.5em calc(50% - 450px);\n\tbackground: $accent1;\n\tcolor: $base;\n}\n\n@media (max-width: 950px) {\n\theader, section, footer {\n\t\tpadding: 1.5em 2em;\n\t}\n}\n\nheader {\n\tdisplay: -webkit-flex;\n\tdisplay: flex;\n\n\t& > h1 {\n\t\tdisplay: inline-block;\n\t\twidth: 350px;\n\t\tmargin-bottom: -.66em;\n\t\tmargin-left: -2em;\n\t}\n\n\tiframe {\n\t\tdisplay: block;\n\t\twidth: 100%;\n\t\tborder: 0;\n\t}\n\n\t& > div {\n\t\tdisplay: -webkit-flex;\n\t\tdisplay: flex;\n\t\t-webkit-flex-flow: column;\n\t\tflex-flow: column;\n\t\t-webkit-flex: 1;\n\t\tflex: 1;\n\t\ttext-align: right;\n\t\tmargin: 0;\n\t}\n\n\t\tp {\n\t\t\t-webkit-flex: 1;\n\t\t\tflex: 1;\n\t\t\tmargin: 0;\n\t\t\tfont-size: 150%;\n\t\t\tline-height: 1.2;\n\t\t\tfont-weight: bold;\n\t\t\tletter-spacing: -.03em;\n\t\t}\n\n\t\tnav {\n\t\t\tfont: 160% Damion, cursive;\n\n\t\t\tul {\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\tli {\n\t\t\t\tdisplay: inline;\n\t\t\t\tlist-style: none;\n\t\t\t}\n\n\t\t\ta {\n\t\t\t\tdisplay: inline-block;\n\t\t\t\tpadding: .15em .4em .15em .3em;\n\t\t\t\tborder-radius: .3em;\n\t\t\t\ttext-decoration: none;\n\t\t\t\tborder: .12em solid transparent;\n\t\t\t\tline-height: 1;\n\t\t\t}\n\n\t\t\ta[href=\"stretchy.js\"],\n\t\t\ta:hover {\n\t\t\t\tborder-color: $base;\n\t\t\t}\n\n\t\t\ta:hover {\n\t\t\t\tbackground: $base;\n\t\t\t\tcolor: $accent1;\n\t\t\t}\n\t\t}\n}\n\nsection:nth-of-type(odd) {\n\tbackground: $base;\n\tcolor: black;\n\n\th1 {\n\t\tcolor: $accent2;\n\t}\n}\n\nsection:nth-of-type(even) {\n\tpadding-top: 2em;\n\tpadding-bottom: 2em;\n\tbackground: svg(svg-polygon($base, \"0,0 100,100 200,0\"), \"0 0 200 100\") top / 1em auto repeat-x,\n\t svg(svg-polygon($base, \"0,100 100,0 200,100\"), \"0 0 200 100\") bottom / 1em auto repeat-x;\n\tbackground-color: $accent2;\n\n\th1 {\n\t\tcolor: $base;\n\t}\n\n\t&:last-of-type {\n\t\tbackground-image: svg(svg-polygon($base, \"0,0 100,100 200,0\"), \"0 0 200 100\"),\n\t\t svg(svg-polygon($accent1, \"0,100 100,0 200,100\"), \"0 0 200 100\");\n\t}\n}\n\n#features {\n\tul {\n\t\tpadding: 0;\n\t\tlist-style: none;\n\t}\n\n\t@media (min-width: 600px) {\n\t\tul {\n\t\t\t-webkit-columns: 2;\n\t\t\t-moz-columns: 2;\n\t\t\tcolumns: 2;\n\t\t}\n\t}\n\n\t\tli {\n\t\t\tposition: relative;\n\t\t\tbreak-inside: avoid;\n\t\t\t-webkit-column-break-inside: avoid;\n\t\t\tfont-size: 70%;\n\t\t\tmargin: 0 0 1em 2.5em;\n\t\t}\n\t\t\tli::before {\n\t\t\t\tcontent: \"✓\";\n\t\t\t\tposition: absolute;\n\t\t\t\ttop: .05em;\n\t\t\t\tright: 100%;\n\t\t\t\tmargin-right: .1em;\n\t\t\t\tfont-size: 320%;\n\t\t\t\tline-height: 1;\n\t\t\t\tcolor: $accent1;\n\t\t\t}\n\n\t\t\tli strong {\n\t\t\t\tdisplay: block;\n\t\t\t\tfont-size: 150%;\n\n\t\t\t\ta:not(:hover) {\n\t\t\t\t\ttext-decoration: none;\n\t\t\t\t}\n\t\t\t}\n}\n\n#examples {\n\toverflow: hidden;\n\n\tlabel,\n\ttextarea {\n\t\tdisplay: block;\n\t}\n\n\ttextarea {\n\n\t}\n\n\tlabel:first-of-type {\n\t\tfloat: right;\n\t\tmargin-top: -.6em;\n\t}\n\n\tlabel {\n\t\tmargin: 1em 0;\n\t}\n}\n\n#api {\n\tdt {\n\t\tfont-weight: bold;\n\t}\n\n\tdd + dt {\n\t\tmargin-top: 1em;\n\t}\n}\n\nfooter {\n\tbackground: $accent1 url(logo.svg) right / auto 100% no-repeat;\n\tbackground-origin: content-box;\n}\n\n.github-ribbon {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\ttransform: rotate(90deg) translateX(70.71067814%) rotate(-90deg) rotate(-45deg) translateY(-100%);\n\ttransform-origin: 0 0;\n\tpadding: .4em 3em;\n\tbackground: $accent2;\n\ttext-decoration: none;\n\tcolor: $base;\n\tbox-shadow: 0 .1em 0 .1em rgba(0,0,0,.15);\n\n\t&:hover {\n\t\tbackground: black;\n\t\tcolor: white;\n\t}\n}\n\n.social-media {\n\n\n\t@media (min-width: 1150px) {\n\t\t& {\n\t\t\tposition: absolute;\n\t\t\ttop: 1em;\n\t\t\tright: 1em;\n\t\t\twidth: -webkit-min-content;\n\t\t\twidth: -moz-min-content;\n\t\t\twidth: min-content;\n\t\t}\n\t}\n}\n\n#carbonads {\n position: absolute;\n top: 75vh;\n right: 1em;\n max-width: 130px;\n padding: 1em;\n border: 1px solid silver;\n font-size: 50%;\n line-height: 1.5;\n background: hsla(0,0%,100%,.9);\n}\n\n@media (max-width: 950px) {\n #carbonads {\n display: none;\n }\n}\n\n.carbon-text {\n display: block;\n text-decoration: none;\n}","/*\n * Cascading Graphics Sheets: Generate SVG data URIs in SCSS!\n * By Lea Verou — http://lea.verou.me\n * Do not use yet, API *will* change.\n */\n\n /* Helper functions */\n\n // Replace all instances of $search in $string with $replace\n @function str-replace($string, $search, $replace) {\n \t$length: str-length($search);\n \t$index: str-index($string, $search);\n \t$slice: $string;\n\n \t@while $index != null {\n \t $start: if($index > 1, str-slice($slice, 1, $index - 1), '');\n \t\t$slice: $start + $replace + str-slice($slice, $index + $length);\n\n \t\t$index: str-index($slice, $search);\n \t}\n\n \t@return $slice;\n }\n\n// Create an inline SVG data URI\n@function svg($content, $viewBox: \"0 0 100 100\") {\n\t$content: str-replace($content, '#', '%23'); // Firefox needs this\n\n\t@return url('data:image/svg+xml,#{$content}');\n}\n\n@function svg-polygon($fill, $points) {\n\t@return unquote('');\n}\n\n@function svg-path($fill, $d) {\n\t@return unquote('');\n}\n\n@function svg-rect($fill, $width: '100%', $height: '100%', $x: '0', $y: '0', $attr:'') {\n\t@return unquote('');\n}\n\n@function svg-square($fill, $width: '100%', $x: '0', $y: '0') {\n\t@return svg-rect($fill, $width, $width, $x, $y);\n}\n\n@function svg-circle($fill, $r: '50%', $cx: '50%', $cy: '50%') {\n\t@return unquote('');\n}\n\n@function svg-line($stroke, $x1: 0, $y1: 0, $x2: 100, $y2: 100, $width: '1pt') {\n\t@return unquote('');\n}\n\n@function svg-text($text, $y: 1.2em, $style:'', $x:0) {\n\t@return unquote('#{$text}');\n}"], 6 | "names": [], 7 | "file": "stretchy.css" 8 | } 9 | -------------------------------------------------------------------------------- /tests/fixtures/stretchy-with-sources.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"stretchy.min.js","sources":["stretchy.js"],"names":["$$","expr","con","Node","Window","slice","call","document","querySelectorAll","self","Element","prototype","matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector","_","Stretchy","selectors","base","split","join","filter","script","currentScript","pop","resize","element","resizes","cs","getComputedStyle","offset","value","placeholder","empty","type","nodeName","toLowerCase","style","height","boxSizing","offsetHeight","clientHeight","scrollHeight","width","offsetWidth","clientWidth","scrollLeft","Math","max","scrollWidth","option","createElement","textContent","options","selectedIndex","parentNode","insertBefore","nextSibling","appearance","property","test","removeChild","resizeAll","elements","forEach","active","init","getAttribute","body","readyState","addEventListener","listener","evt","target","MutationObserver","mutations","mutation","addedNodes","observe","childList","subtree"],"mappings":"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","sourcesContent":["/*\n * Stretchy: Form element autosizing, the way it should be.\n * by Lea Verou http://lea.verou.me\n * MIT license\n */\n(function() {\n\nif (!self.Element) {\n\treturn; // super old browser\n}\n\nif (!Element.prototype.matches) {\n\tElement.prototype.matches = Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || null;\n}\n\nif (!Element.prototype.matches) {\n\treturn;\n}\n\nfunction $$(expr, con) {\n\treturn expr instanceof Node || expr instanceof Window? [expr] :\n\t [].slice.call(typeof expr == \"string\"? (con || document).querySelectorAll(expr) : expr || []);\n}\n\nvar _ = self.Stretchy = {\n\tselectors: {\n\t\tbase: 'textarea, select:not([size]), input:not([type]), input[type=\"' + \"text url email tel\".split(\" \").join('\"], input[type=\"') + '\"]',\n\t\tfilter: \"*\"\n\t},\n\n\t// Script element this was included with, if any\n\tscript: document.currentScript || $$(\"script\").pop(),\n\n\t// Autosize one element. The core of Stretchy.\n\tresize: function(element) {\n\t\tif (!_.resizes(element)) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar cs = getComputedStyle(element);\n\t\tvar offset = 0;\n\n\t\tif (!element.value && element.placeholder) {\n\t\t\tvar empty = true;\n\t\t\telement.value = element.placeholder;\n\t\t}\n\n\t\tvar type = element.nodeName.toLowerCase();\n\n\t\tif (type == \"textarea\") {\n\t\t\telement.style.height = \"0\";\n\n\t\t\tif (cs.boxSizing == \"border-box\") {\n\t\t\t\toffset = element.offsetHeight;\n\t\t\t}\n\t\t\telse if (cs.boxSizing == \"content-box\") {\n\t\t\t\toffset = -element.clientHeight;\n\t\t\t}\n\n\t\t\telement.style.height = element.scrollHeight + offset + \"px\";\n\t\t}\n\t\telse if(type == \"input\") {\n\t\t\telement.style.width = \"0\";\n\n\t\t\tif (cs.boxSizing == \"border-box\") {\n\t\t\t\toffset = element.offsetWidth;\n\t\t\t}\n\t\t\telse if (cs.boxSizing == \"padding-box\") {\n\t\t\t\toffset = element.clientWidth;\n\t\t\t}\n\n\t\t\t// Safari misreports scrollWidth, so we will instead set scrollLeft to a\n\t\t\t// huge number, and read that back to see what it was clipped to\n\t\t\telement.scrollLeft = 1e+10;\n\n\t\t\tvar width = Math.max(element.scrollLeft + offset, element.scrollWidth - element.clientWidth);\n\n\t\t\telement.style.width = width + \"px\";\n\t\t}\n\t\telse if (type == \"select\") {\n\t\t\t// Need to use dummy element to measure :(\n\t\t\tvar option = document.createElement(\"_\");\n\t\t\toption.textContent = element.options[element.selectedIndex].textContent;\n\t\t\telement.parentNode.insertBefore(option, element.nextSibling);\n\n\t\t\t// The name of the appearance property, as it might be prefixed\n\t\t\tvar appearance;\n\n\t\t\tfor (var property in cs) {\n\t\t\t\tif (!/^(width|webkitLogicalWidth)$/.test(property)) {\n\t\t\t\t\t//console.log(property, option.offsetWidth, cs[property]);\n\t\t\t\t\toption.style[property] = cs[property];\n\n\t\t\t\t\tif (/appearance$/i.test(property)) {\n\t\t\t\t\t\tappearance = property;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toption.style.width = \"\";\n\n\t\t\tif (option.offsetWidth > 0) {\n\t\t\t\telement.style.width = option.offsetWidth + \"px\";\n\n\t\t\t\tif (!cs[appearance] || cs[appearance] !== \"none\") {\n\t\t\t\t\t// Account for arrow\n\t\t\t\t\telement.style.width = \"calc(\" + element.style.width + \" + 2em)\";\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toption.parentNode.removeChild(option);\n\t\t\toption = null;\n\t\t}\n\n\t\tif (empty) {\n\t\t\telement.value = \"\";\n\t\t}\n\t},\n\n\t// Autosize multiple elements\n\tresizeAll: function(elements) {\n\t\t$$(elements || _.selectors.base).forEach(function (element) {\n\t\t\t_.resize(element);\n\t\t});\n\t},\n\n\tactive: true,\n\n\t// Will stretchy do anything for this element?\n\tresizes: function(element) {\n\t\treturn element &&\n\t\t element.parentNode &&\n\t\t element.matches &&\n\t\t element.matches(_.selectors.base) &&\n\t\t element.matches(_.selectors.filter);\n\t},\n\n\tinit: function(){\n\t\t_.selectors.filter = _.script.getAttribute(\"data-filter\") ||\n\t\t ($$(\"[data-stretchy-filter]\").pop() || document.body).getAttribute(\"data-stretchy-filter\") || Stretchy.selectors.filter || \"*\";\n\n\t\t_.resizeAll();\n\t},\n\n\t$$: $$\n};\n\n// Autosize all elements once the DOM is loaded\n\n// DOM already loaded?\nif (document.readyState !== \"loading\") {\n\t_.init();\n}\nelse {\n\t// Wait for it\n\tdocument.addEventListener(\"DOMContentLoaded\", _.init);\n}\n\n// Listen for changes\nvar listener = function(evt) {\n\tif (_.active) {\n\t\t_.resize(evt.target);\n\t}\n};\n\ndocument.body.addEventListener(\"input\", listener);\n\n// Firefox fires a change event instead of an input event\ndocument.body.addEventListener(\"change\", listener);\n\n// Listen for new elements\nif (self.MutationObserver) {\n\t(new MutationObserver(function(mutations) {\n\t\tif (_.active) {\n\t\t\tmutations.forEach(function(mutation) {\n\t\t\t\tif (mutation.type == \"childList\") {\n\t\t\t\t\tStretchy.resizeAll(mutation.addedNodes);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t})).observe(document.body, {\n\t\tchildList: true,\n\t\tsubtree: true\n\t});\n}\n\n})();\n"]} -------------------------------------------------------------------------------- /tests/fixtures/stretchy.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "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", 4 | "sources": ["stretchy.scss","_svg.scss"], 5 | "names": [], 6 | "file": "stretchy.css" 7 | } 8 | -------------------------------------------------------------------------------- /tests/fixtures/stretchy.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"stretchy.min.js","sources":["stretchy.js"],"names":["$$","expr","con","Node","Window","slice","call","document","querySelectorAll","self","Element","prototype","matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector","_","Stretchy","selectors","base","split","join","filter","script","currentScript","pop","resize","element","resizes","cs","getComputedStyle","offset","value","placeholder","empty","type","nodeName","toLowerCase","style","height","boxSizing","offsetHeight","clientHeight","scrollHeight","width","offsetWidth","clientWidth","scrollLeft","Math","max","scrollWidth","option","createElement","textContent","options","selectedIndex","parentNode","insertBefore","nextSibling","appearance","property","test","removeChild","resizeAll","elements","forEach","active","init","getAttribute","body","readyState","addEventListener","listener","evt","target","MutationObserver","mutations","mutation","addedNodes","observe","childList","subtree"],"mappings":"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"} -------------------------------------------------------------------------------- /tests/index_test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * reverse.js 3 | * https://github.com/davidkevork/reverse 4 | * 5 | * Reverse engineering JavaScript and CSS sources from sourcemaps 6 | * 7 | * Copyright (c) Juga Paazmaya (https://paazmaya.fi) 8 | * Copyright (c) David Kevork (https://davidkevork.me) 9 | * Licensed under the MIT license 10 | */ 11 | 'use strict'; 12 | 13 | const tape = require('tape'); 14 | const shuji = require('../index'); 15 | 16 | tape('function is exported', (test) => { 17 | test.plan(1); 18 | 19 | test.equal(typeof shuji, 'function'); 20 | }); 21 | 22 | --------------------------------------------------------------------------------