├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmignore ├── .npmrc ├── .nvmrc ├── .pullapprove.yml ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bin └── cli.js ├── index.js ├── jest.config.js ├── package.json ├── renovate.json ├── script └── generateAlmostSketch.js └── test ├── _utils ├── dirContentsToObject.js └── jestSetup.js ├── config-file-path ├── __snapshots__ │ └── file.test.js.snap ├── custom.config.js ├── file.test.js └── index.html ├── config-file ├── __snapshots__ │ └── file.test.js.snap ├── file.test.js ├── html-sketchapp.config.js └── index.html ├── file ├── __snapshots__ │ └── file.test.js.snap ├── file.test.js └── index.html ├── nested-symbols ├── __snapshots__ │ └── nested-symbols.test.js.snap ├── index.html ├── nested-symbols.test.js └── unknown-symbol.html ├── serve-with-url ├── __snapshots__ │ └── serve-with-url.test.js.snap ├── serve-me │ ├── another-url │ │ └── index.html │ └── index.html └── serve-with-url.test.js ├── serve ├── __snapshots__ │ └── serve.test.js.snap ├── serve-me │ └── index.html └── serve.test.js ├── symbol-instance-middleware ├── __snapshots__ │ └── symbol-instance-middleware.test.js.snap ├── html-sketchapp.config.js ├── index.html ├── symbol-instance-middleware.test.js └── symbol-instance.middleware.js ├── symbol-layer-middleware ├── __snapshots__ │ └── symbol-layer-middleware.test.js.snap ├── html-sketchapp.config.js ├── index.html ├── symbol-layer-middleware.test.js └── symbol.layer.middleware.js ├── symbol-middleware ├── __snapshots__ │ └── symbol-middleware.test.js.snap ├── html-sketchapp.config.js ├── index.html ├── symbol-middleware.test.js └── symbol.middleware.js ├── url ├── __snapshots__ │ └── url.test.js.snap ├── index.html └── url.test.js └── viewports ├── __snapshots__ └── viewports.test.js.snap ├── index.html └── viewports.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.snap] 13 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "seek", 3 | "rules": { 4 | "no-console": "off", 5 | "no-process-exit": "off" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | .tmp/ 4 | 5 | package-lock.json 6 | yarn.lock 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* 2 | -------------------------------------------------------------------------------- /.pullapprove.yml: -------------------------------------------------------------------------------- 1 | # See https://www.pullapprove.com/docs/config/extends/ 2 | version: 3 3 | extends: https://raw.githubusercontent.com/seek-oss/pullapprove-config-seek/master/.pullapprove.yml 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "10" 5 | notifications: 6 | email: false 7 | before_script: 8 | - npm prune 9 | after_success: 10 | - npm run travis-deploy-once "npm run semantic-release" 11 | branches: 12 | except: 13 | - /^v\d+\.\d+\.\d+$/ 14 | git: 15 | depth: 5 16 | cache: 17 | directories: 18 | - $HOME/.npm 19 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 2 | 3 | After cloning the project, install the dependencies: 4 | 5 | ```bash 6 | $ npm install 7 | ``` 8 | 9 | Before starting your work, first ensure you're in the `master` branch and that you've pulled down the latest changes: 10 | 11 | ```bash 12 | $ git checkout master 13 | $ git pull 14 | ``` 15 | 16 | Next, create a new branch for your work, with an appropriate name for your change: 17 | 18 | ```bash 19 | $ git checkout -b add-my-cool-new-feature 20 | ``` 21 | 22 | To run the test suite locally: 23 | 24 | ```bash 25 | $ npm test 26 | ``` 27 | 28 | Note that the test suite needs to pass for your changes to be accepted, so it's worth running this locally during development and before committing. 29 | 30 | ### Committing 31 | 32 | Once you've made the desired changes and you're ready to commit, first stage your local changes: 33 | 34 | ```bash 35 | $ git add . 36 | ``` 37 | 38 | Before continuing, consider the scope of your changes according to [semantic versioning](http://semver.org), noting whether this is a breaking change, a feature release or a patch. 39 | 40 | New versions are published automatically from [Travis CI](https://travis-ci.org) using [semantic-release](https://github.com/semantic-release/semantic-release). In order to automatically increment version numbers correctly, commit messages must follow the [conventional commit message format](https://github.com/marionebl/commitlint/tree/master/%40commitlint/config-conventional). If your commit includes a breaking change, be sure to prefix your commit body with `BREAKING CHANGE: `. 41 | 42 | To make this process easier, we have a commit script (powered by [commitizen](https://github.com/commitizen/cz-cli)) to help guide you through the commit process: 43 | 44 | ```bash 45 | $ npm run commit 46 | ``` 47 | 48 | Once you've committed your work, push your changes to a branch of the same name on GitHub: 49 | 50 | ```bash 51 | $ git push --set-upstream origin add-my-cool-new-feature 52 | ``` 53 | 54 | Next, head over to this repo's GitHub page and create a new pull request from your branch. **Make sure your PR title matches your [conventional commit message](https://github.com/marionebl/commitlint/tree/master/%40commitlint/config-conventional).** 55 | 56 | In order for your pull request to be accepted, the [Travis CI](https://travis-ci.org) build needs to pass, and **your work needs to be reviewed by other contributors.** 57 | 58 | It's likely that you might need to make some changes for your work to be accepted, but don't take this personally! Ultimately, the aim is to make it feel like the codebase was written by a single person, but this takes a lot of work and constant review of each others' work. 59 | 60 | ### Merging 61 | 62 | If you have write access to this repo, whether this is your own work or the work of an outside collaborator, the next step is to merge the changes through the GitHub UI. Always make sure that the commit message matches the title of the PR (it may have been edited!) 63 | 64 | Once merged, thanks to semantic-release, the contents of the pull request will be automatically published! 65 | 66 | 🎨📦🚀 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 SEEK 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://img.shields.io/travis/seek-oss/html-sketchapp-cli/master.svg?style=flat-square)](http://travis-ci.org/seek-oss/html-sketchapp-cli) [![npm](https://img.shields.io/npm/v/html-sketchapp-cli.svg?style=flat-square)](https://www.npmjs.com/package/html-sketchapp-cli) [![David](https://img.shields.io/david/seek-oss/html-sketchapp-cli.svg?style=flat-square)](https://david-dm.org/seek-oss/html-sketchapp-cli) [![David](https://img.shields.io/david/dev/seek-oss/html-sketchapp-cli.svg?style=flat-square)](https://david-dm.org/seek-oss/html-sketchapp-cli?type=dev) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=flat-square)](http://commitizen.github.io/cz-cli/) 2 | 3 | # html-sketchapp-cli 4 | 5 | Quickly generate [Sketch libraries](https://www.sketchapp.com/docs/libraries/) from HTML documents and living style guides, powered by [html-sketchapp](https://github.com/brainly/html-sketchapp) and [Puppeteer](https://github.com/GoogleChrome/puppeteer). 6 | 7 | Add some simple markup to your page, for example: 8 | 9 | ```html 10 |
...
11 |
...
12 |
...
13 | ``` 14 | 15 | Then run the `html-sketchapp` command to generate JSON files in html-sketchapp's ["Almost Sketch"](https://github.com/brainly/html-sketchapp#how-does-it-work) format, ready to be [imported into Sketch](#importing-into-sketch). 16 | 17 | ```bash 18 | $ html-sketchapp --file sketch.html --out-dir dist/sketch 19 | ``` 20 | 21 | ## Install 22 | 23 | *Please note: html-sketchapp-cli requires [Node.js](https://nodejs.org/) and targets the latest ["Active LTS" version](https://github.com/nodejs/Release#release-schedule). Older versions of Node are unsupported.* 24 | 25 | If you're in a hurry and just want to try it out, you can install html-sketchapp-cli globally, along with html-sketchapp's Sketch plugin: 26 | 27 | ```bash 28 | $ npm install --global html-sketchapp-cli 29 | $ html-sketchapp install 30 | ``` 31 | 32 | However, when using html-sketchapp-cli in the context of a project, you should install it locally instead: 33 | 34 | ```bash 35 | $ npm install --save-dev html-sketchapp-cli 36 | ``` 37 | 38 | Then, add some scripts to your [package.json](https://docs.npmjs.com/files/package.json): 39 | 40 | ```json 41 | { 42 | "scripts": { 43 | "html-sketchapp-install": "html-sketchapp install", 44 | "html-sketchapp": "html-sketchapp [...args]" 45 | } 46 | } 47 | ``` 48 | 49 | Once these scripts have been added, the following commands can be run within your project: 50 | 51 | ```bash 52 | $ npm run html-sketchapp-install 53 | $ npm run html-sketchapp 54 | ``` 55 | 56 | ## Page Setup 57 | 58 | Before using this tool, you'll need to add some hooks to your page so that everything can be selected, extracted and named correctly. 59 | 60 | Annotate symbols with `data-sketch-symbol` attributes. Note that forward slashes will create nested menu items within Sketch. 61 | 62 | ```html 63 |
64 | ... 65 |
66 | ``` 67 | 68 | Annotate [nested symbols](https://www.sketchapp.com/docs/symbols/nested-symbols) with `data-sketch-symbol-instance` attributes, where the attribute values reference existing symbols defined elsewhere in the document. 69 | 70 | ```html 71 |
...
72 |
...
73 |
...
74 | 75 |
76 |
...
77 |
...
78 |
...
79 |
80 | ``` 81 | 82 | Annotate all text styles with `data-sketch-text` attributes. 83 | 84 | ```html 85 |
86 | ... 87 |
88 | ``` 89 | 90 | Annotate all colors with `data-sketch-color` attributes. Note that colors are unnamed in Sketch, so only the hex value needs to be provided. 91 | 92 | ```html 93 |
94 | ... 95 |
96 | ``` 97 | 98 | For a real world example, check out [SEEK Style Guide's sketch exports page](http://seek-oss.github.io/seek-style-guide/sketch-exports) and the corresponding [source code](https://github.com/seek-oss/seek-style-guide/blob/master/docs/src/components/SketchExports/SketchExports.js). 99 | 100 | ## CLI Usage 101 | 102 | ### Importing from a local file 103 | 104 | If your page is self-contained, you can import from a local HTML file. 105 | 106 | ```bash 107 | $ html-sketchapp --file sketch.html --out-dir dist 108 | ``` 109 | 110 | ### Importing from a local static web server 111 | 112 | If your page needs to be hosted on a static web server, you can provide a local directory to serve and a root relative URL to import from. 113 | 114 | ```bash 115 | $ html-sketchapp --serve docs --url /sketch --out-dir dist 116 | ``` 117 | 118 | ### Importing from existing web server 119 | 120 | If your page is hosted on an existing web server, you can provide an absolute URL. 121 | 122 | ```bash 123 | $ html-sketchapp --url http://localhost:3000 --out-dir dist 124 | ``` 125 | 126 | ### Viewport sizes and responsive design 127 | 128 | If you provide a set of one or more named viewports, every symbol and text style will be rendered for each screen size. 129 | 130 | ```bash 131 | $ html-sketchapp --viewports.Desktop 1024x768 --viewports.Mobile 320x568 --file sketch.html --out-dir dist 132 | ``` 133 | 134 | If multiple screen sizes are provided, the viewport name will be being appended to all symbol and text style names. For example, `Button/Primary` will be exported as `Button/Primary/Desktop` and `Button/Primary/Mobile`. 135 | 136 | Optionally, you can set the pixel density for a given viewport by adding an `@` followed by the desired scaling factor to the end of the viewport's resolution. For example, you can simulate a 1.5x and 2x display like so: 137 | 138 | ```bash 139 | $ html-sketchapp --viewports.HigherDensity 1024x768@1.5 --viewports.Retina 1024x768@2 --file sketch.html --out-dir dist 140 | ``` 141 | 142 | If no scaling factor is provided, a default of `1` will be used. 143 | 144 | ### Config file 145 | 146 | All options can be provided via an `html-sketchapp.config.js` file. 147 | 148 | ```js 149 | module.exports = { 150 | file: 'sketch.html', 151 | outDir: 'dist/sketch', 152 | viewports: { 153 | Desktop: '1024x768', 154 | Mobile: '320x568' 155 | }, 156 | puppeteerArgs: '--no-sandbox --disable-setuid-sandbox', 157 | puppeteerExecutablePath: 'google-chrome-unstable' 158 | }; 159 | ``` 160 | 161 | You can provide an alternate config file path with the `--config` option. 162 | 163 | ```bash 164 | $ html-sketchapp --config example.config.js 165 | ``` 166 | 167 | ### Importing into Sketch 168 | 169 | Once this command has successfully run, the following files will be generated in the output directory. 170 | 171 | - `document.asketch.json` 172 | - `page.asketch.json` 173 | 174 | These need to be imported into Sketch via html-sketchapp's corresponding Sketch plugin. To ease the install process, you can run the following command. 175 | 176 | ```bash 177 | $ html-sketchapp install 178 | ``` 179 | 180 | Then, open a new Sketch document and, from the menu, select `Plugins > From *Almost* Sketch to Sketch`. In the file picker, select both `document.asketch.json` and `page.asketch.json`, and click `Choose`. 181 | 182 | Congratulations! You should now have your symbols, text styles and document colors available within Sketch! 💎🎉 183 | 184 | ## Advanced Usage 185 | 186 | ### Debug mode 187 | 188 | If you need to see what Puppeteer is doing, you can provide the `--debug` flag which will do the following things: 189 | - Turn off headless mode 190 | - Bring the browser window to the front 191 | - Forward `console` calls to the terminal 192 | - Stop the browser from closing until you exit the CLI tool 193 | 194 | For example: 195 | 196 | ```bash 197 | $ html-sketchapp --url http://localhost:3000 --out-dir dist --debug 198 | ``` 199 | 200 | ### Puppeteer args 201 | 202 | If you need to provide command line arguments to the browser instance via [Puppeteer](https://github.com/GoogleChrome/puppeteer), you can provide the `puppeteer-args` option. 203 | 204 | Since Puppeteer uses [Chromium](https://www.chromium.org/Home) internally, you can refer to the [List of Chromium Command Line Switches](https://peter.sh/experiments/chromium-command-line-switches) for available options. 205 | 206 | For example, if you'd like to disable the browser sandbox: 207 | 208 | ```bash 209 | $ html-sketchapp --puppeteer-args="--no-sandbox --disable-setuid-sandbox" --file sketch.html --out-dir dist 210 | ``` 211 | 212 | *Note: Because Puppeteer args are prefixed with hyphens, you **must** use an equals sign and quotes when providing this option via the command line (as seen above).* 213 | 214 | ### Puppeteer `waitUntil` 215 | 216 | By default, Puppeteer is configured to consider the page loaded when there are no more than 2 network connections for at least 500ms (`networkidle2`). This is so that html-sketchapp-cli can handle development environments with long-lived connections. 217 | 218 | If the page you're requesting has 2 or fewer resources that stall for longer than 500ms and doesn't complete loading, you can switch back to `networkidle0` via the `puppeteer-wait-until` argument: 219 | 220 | ```bash 221 | $ html-sketchapp --puppeteer-wait-until networkidle0 --file sketch.html --out-dir dist 222 | ``` 223 | 224 | For the full list of available options for `waitUntil`, view the [Puppeteer `page.goto()` API documentation](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagegotourl-options). 225 | 226 | ### Chromium executable 227 | 228 | If you'd like to override the Chromium used by Puppeteer, you can provide a path to the executable with the `puppeteer-executable-path` option. 229 | 230 | ```bash 231 | $ html-sketchapp --puppeteer-executable-path google-chrome-unstable --file sketch.html --out-dir dist 232 | ``` 233 | 234 | ### Middleware 235 | 236 | If you need to call out to lower-level html-sketchapp APIs, you can provide middleware functions that allow you to modify the underlying Sketch classes as they're generated. 237 | 238 | It's recommended that you provide middleware via a [config file](#config-file) as inline functions, for example: 239 | 240 | ```js 241 | module.exports = { 242 | symbolLayerMiddleware: (args) => { ... } 243 | }; 244 | ``` 245 | 246 | Alternatively, you can also provide middleware as standalone JavaScript files, configured via the command line: 247 | 248 | ```bash 249 | $ html-sketchapp --symbol-layer-middleware symbol.layer.middleware.js 250 | ``` 251 | 252 | This assumes that your middleware is a JavaScript module that exports the function: 253 | 254 | ```js 255 | module.exports = (args) => { ... }; 256 | ``` 257 | 258 | However, in order to keep the documentation streamlined, all examples will use the config file notation. 259 | 260 | #### Symbol Layer Middleware 261 | 262 | This middleware is executed for every layer within a symbol. 263 | 264 | The typical use case for this is html-sketchapp's `layer.setResizingConstraint` API which allows you to configure how a layer should behave when a symbol is resized. 265 | 266 | ```js 267 | module.exports = { 268 | symbolLayerMiddleware: args => { ... } 269 | }; 270 | ``` 271 | 272 | The following arguments are passed into your middleware function: 273 | - layer: the html-sketchapp layer instance 274 | - SVG: The SVG class for type checking of layer 275 | - Text: The Text class for type checking of layer 276 | - Rectangle: The Rectangle class for type checking of layer 277 | - ShapeGroup: The ShapeGroup class for type checking of layer 278 | - RESIZING_CONSTRAINTS: Object containing constants for the `setResizingConstraint` API 279 | 280 | For example, when handling SVGs differently from other layers: 281 | 282 | ```js 283 | module.exports = { 284 | symbolLayerMiddleware: (args) => { 285 | const { layer, SVG, RESIZING_CONSTRAINTS } = args; 286 | 287 | layer.setResizingConstraint(RESIZING_CONSTRAINTS.LEFT, RESIZING_CONSTRAINTS.TOP); 288 | 289 | if(layer instanceof SVG) { 290 | layer.setResizingConstraint(RESIZING_CONSTRAINTS.TOP, RESIZING_CONSTRAINTS.LEFT, RESIZING_CONSTRAINTS.WIDTH, RESIZING_CONSTRAINTS.HEIGHT); 291 | } 292 | } 293 | }; 294 | 295 | ``` 296 | 297 | #### Symbol Middleware 298 | 299 | This middleware is executed for every symbol within a document. 300 | 301 | ```js 302 | module.exports = { 303 | symbolMiddleware: args => { ... } 304 | }; 305 | ``` 306 | 307 | The following arguments are passed into your middleware function: 308 | - symbol: The current symbol master 309 | - node: The source HTML node 310 | - suffix: The symbol name suffix (e.g. `/Desktop`) 311 | - RESIZING_CONSTRAINTS: Object containing constants for the `setResizingConstraint` API 312 | 313 | 314 | #### Symbol Instance Middleware 315 | 316 | This middleware is executed for every symbol instance within a document. 317 | 318 | ```js 319 | module.exports = { 320 | symbolInstanceMiddleware: args => { ... } 321 | }; 322 | ``` 323 | 324 | The following arguments are passed into your middleware function: 325 | - symbolInstance: The current symbol instance 326 | - symbolMaster: The symbol master that the symbol instance is referencing 327 | - node: The source HTML node 328 | - RESIZING_CONSTRAINTS: Object containing constants for the `setResizingConstraint` API 329 | 330 | ## Contributing 331 | 332 | Refer to [CONTRIBUTING.md](./CONTRIBUTING.md). 333 | 334 | ## License 335 | 336 | MIT. 337 | -------------------------------------------------------------------------------- /bin/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const urlJoin = require('url-join'); 4 | const findUp = require('find-up'); 5 | const { promisify } = require('es6-promisify'); 6 | const getPort = require('get-port'); 7 | const http = require('http'); 8 | const serveHandler = require('serve-handler'); 9 | const puppeteer = require('puppeteer'); 10 | const { rollup } = require('rollup'); 11 | const mkdirpAsync = promisify(require('mkdirp')); 12 | const writeFileAsync = promisify(require('fs').writeFile); 13 | const path = require('path'); 14 | 15 | const configPath = findUp.sync(['html-sketchapp.config.js']); 16 | const config = configPath ? require(configPath) : {}; 17 | 18 | const makeServer = async (relativePath, port) => { 19 | const server = http.createServer((request, response) => { 20 | return serveHandler(request, response, { 21 | public: relativePath 22 | }); 23 | }); 24 | 25 | await new Promise((resolve, reject) => { 26 | server.listen(port, err => err ? reject(err) : resolve()); 27 | }); 28 | 29 | return server; 30 | }; 31 | 32 | const resolveMiddleware = configValue => { 33 | return (typeof configValue === 'string') ? 34 | require(path.resolve(process.cwd(), configValue)) 35 | : configValue; 36 | }; 37 | 38 | require('yargs') 39 | .config(config) 40 | .config('config', 'Path to JavaScript config file', customConfigPath => require(customConfigPath)) 41 | .usage('Usage: $0 [options]') 42 | .command('$0', 'The default command', { 43 | 'serve': { 44 | alias: 's', 45 | describe: 'Directory to serve, relative to working directory' 46 | }, 47 | 'url': { 48 | alias: 'u', 49 | describe: 'URL to open. When using the "serve" option, URL should be root relative.', 50 | }, 51 | 'file': { 52 | alias: 'f', 53 | describe: 'File to open, relative to working directory', 54 | }, 55 | 'out-dir': { 56 | alias: 'o', 57 | describe: 'Output directory, relative to working directory', 58 | demandOption: true 59 | }, 60 | 'viewports': { 61 | alias: 'v', 62 | describe: 'Set of named viewport sizes for symbols, e.g. --viewports.Desktop=1024x768 --viewports.Mobile=320x568' 63 | }, 64 | 'debug': { 65 | alias: 'd', 66 | describe: 'Put into debug mode to see what the tool is doing' 67 | }, 68 | 'symbol-middleware': { 69 | describe: 'Path to symbol middleware to run when looping over sketch layers' 70 | }, 71 | 'puppeteer-args': { 72 | type: 'string', 73 | describe: 'Set of command line arguments to be provided to the Chromium instance via Puppeteer, e.g. --puppeteer-args="--no-sandbox --disable-setuid-sandbox"' 74 | }, 75 | 'puppeteer-executable-path': { 76 | type: 'string', 77 | describe: 'Path to a Chromium executable to use instead of the one downloaded by Puppeteer.' 78 | }, 79 | 'puppeteer-wait-until': { 80 | type: 'string', 81 | describe: 'The Puppeteer navigation event to use before considering the page loaded.', 82 | default: 'networkidle2', 83 | choices: ['load', 'domcontentloaded', 'networkidle0', 'networkidle2'] 84 | } 85 | }, async argv => { 86 | try { 87 | const port = argv.serve ? await getPort() : null; 88 | const server = argv.serve ? await makeServer(argv.serve, port) : null; 89 | 90 | try { 91 | const url = argv.file ? `file://${path.join(process.cwd(), argv.file)}` : argv.url; 92 | const symbolsUrl = argv.serve ? urlJoin(`http://localhost:${String(port)}`, argv.url || '/') : url; 93 | const debug = argv.debug; 94 | 95 | const symbolLayerMiddleware = resolveMiddleware(argv.symbolLayerMiddleware); 96 | const symbolMiddleware = resolveMiddleware(argv.symbolMiddleware); 97 | const symbolInstanceMiddleware = resolveMiddleware(argv.symbolInstanceMiddleware); 98 | 99 | const launchArgs = { 100 | args: argv.puppeteerArgs ? argv.puppeteerArgs.split(' ') : [], 101 | executablePath: argv.puppeteerExecutablePath, 102 | headless: !debug 103 | }; 104 | 105 | const browser = await puppeteer.launch(launchArgs); 106 | 107 | try { 108 | const page = await browser.newPage(); 109 | 110 | if (debug) { 111 | page.bringToFront(); 112 | page.on('console', msg => console.log('PAGE LOG:', msg.text())); 113 | } 114 | 115 | await page.goto(symbolsUrl, { waitUntil: argv.puppeteerWaitUntil }); 116 | 117 | const bundle = await rollup({ 118 | input: path.resolve(__dirname, '../script/generateAlmostSketch.js'), 119 | plugins: [ 120 | require('rollup-plugin-node-resolve')(), 121 | require('rollup-plugin-commonjs')() 122 | ] 123 | }); 124 | 125 | const { code } = await bundle.generate({ 126 | format: 'iife', 127 | name: 'generateAlmostSketch' 128 | }); 129 | 130 | await page.addScriptTag({ content: code }); 131 | 132 | await page.evaluate('generateAlmostSketch.setupSymbols({ name: "html-sketchapp symbols" })'); 133 | 134 | await page.evaluate('generateAlmostSketch.snapshotColorStyles()'); 135 | 136 | const viewports = argv.viewports || { Desktop: '1024x768' }; 137 | const hasViewports = Object.keys(viewports).length > 1; 138 | for (const viewportName in viewports) { 139 | if (viewports.hasOwnProperty(viewportName)) { 140 | const viewport = viewports[viewportName]; 141 | const [ size, scale ] = viewport.split('@'); 142 | const [ width, height ] = size.split('x').map(x => parseInt(x, 10)); 143 | const deviceScaleFactor = typeof scale === 'undefined' ? 1 : parseFloat(scale); 144 | await page.setViewport({ width, height, deviceScaleFactor }); 145 | await page.evaluate(`generateAlmostSketch.snapshotTextStyles({ suffix: "${hasViewports ? `/${viewportName}` : ''}" })`); 146 | await page.evaluate(`generateAlmostSketch.snapshotSymbols({ suffix: "${hasViewports ? `/${viewportName}` : ''}", symbolLayerMiddleware: ${symbolLayerMiddleware}, symbolMiddleware: ${symbolMiddleware}, symbolInstanceMiddleware: ${symbolInstanceMiddleware} })`); 147 | } 148 | } 149 | 150 | const asketchDocumentJSON = await page.evaluate('generateAlmostSketch.getDocumentJSON()'); 151 | const asketchPageJSON = await page.evaluate('generateAlmostSketch.getPageJSON()'); 152 | 153 | const outputPath = path.resolve(process.cwd(), argv.outDir); 154 | await mkdirpAsync(outputPath); 155 | 156 | const outputPagePath = path.join(outputPath, 'page.asketch.json'); 157 | const outputDocumentPath = path.join(outputPath, 'document.asketch.json'); 158 | 159 | await Promise.all([ 160 | writeFileAsync(outputPagePath, asketchPageJSON), 161 | writeFileAsync(outputDocumentPath, asketchDocumentJSON) 162 | ]); 163 | } finally { 164 | if (browser && typeof browser.close === 'function' && !debug) { 165 | browser.close(); 166 | } 167 | } 168 | } finally { 169 | if (server && typeof server.close === 'function') { 170 | server.close(); 171 | } 172 | } 173 | } catch (err) { 174 | console.error(err); 175 | process.exit(1); 176 | } 177 | }) 178 | .command('install', 'Install the html-sketchapp Sketch plugin', {}, async () => { 179 | const { version } = require('@brainly/html-sketchapp/package.json'); 180 | console.log(`Detected html-sketchapp v${version}`); 181 | 182 | const tmpDirPath = path.resolve(__dirname, '../', '.tmp'); 183 | const rimrafAsync = promisify(require('rimraf')); 184 | await rimrafAsync(tmpDirPath); 185 | await mkdirpAsync(tmpDirPath); 186 | 187 | const [ major, minor, patch ] = version.split('.'); 188 | const releaseUrl = `http://github.com/brainly/html-sketchapp/releases/download/v${version}/asketch2sketch-${major}-${minor}-${patch}.sketchplugin.zip`; 189 | console.log(`Downloading from ${releaseUrl}`); 190 | const axios = require('axios'); 191 | const { data } = await axios(releaseUrl, { responseType: 'arraybuffer' }); 192 | 193 | console.log(`Extracting to ${tmpDirPath}`); 194 | const decompress = require('decompress'); 195 | await decompress(data, tmpDirPath); 196 | 197 | const pluginPath = path.resolve(tmpDirPath, 'asketch2sketch.sketchplugin'); 198 | console.log(`Installing from ${pluginPath}`); 199 | const opn = require('opn'); 200 | opn(pluginPath, { wait: false }); 201 | }) 202 | .parse(); 203 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | throw new Error('Not yet implemented.'); 3 | }; 4 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | setupTestFrameworkScriptFile: path.resolve(__dirname, 'test/_utils/jestSetup.js'), 5 | testEnvironment: 'node' 6 | }; 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "html-sketchapp-cli", 3 | "version": "0.0.0-development", 4 | "description": "Quickly generate Sketch libraries from HTML documents and living style guides, powered by html-sketchapp", 5 | "main": "index.js", 6 | "engines": { 7 | "node": ">=7.6" 8 | }, 9 | "bin": { 10 | "html-sketchapp": "bin/cli.js" 11 | }, 12 | "scripts": { 13 | "lint": "eslint bin script test", 14 | "test": "npm run lint && jest", 15 | "commit": "git-cz", 16 | "commitmsg": "commitlint --edit --extends seek", 17 | "travis-deploy-once": "travis-deploy-once", 18 | "semantic-release": "semantic-release" 19 | }, 20 | "config": { 21 | "commitizen": { 22 | "path": "./node_modules/cz-conventional-changelog" 23 | } 24 | }, 25 | "release": { 26 | "success": false 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/seek-oss/html-sketchapp-cli.git" 31 | }, 32 | "author": "SEEK", 33 | "license": "MIT", 34 | "bugs": { 35 | "url": "https://github.com/seek-oss/html-sketchapp-cli/issues" 36 | }, 37 | "homepage": "https://github.com/seek-oss/html-sketchapp-cli#readme", 38 | "dependencies": { 39 | "@brainly/html-sketchapp": "^4.0.0", 40 | "axios": "^0.18.0", 41 | "decompress": "^4.2.0", 42 | "es6-promisify": "^6.0.0", 43 | "find-up": "^2.1.0", 44 | "get-port": "^3.2.0", 45 | "mkdirp": "^0.5.1", 46 | "opn": "^5.1.0", 47 | "puppeteer": "^1.0.0", 48 | "rimraf": "^2.6.2", 49 | "rollup": "^0.58.2", 50 | "rollup-plugin-commonjs": "^9.1.0", 51 | "rollup-plugin-node-resolve": "^3.3.0", 52 | "serve-handler": "^3.2.1", 53 | "url-join": "^4.0.0", 54 | "yargs": "^11.0.0" 55 | }, 56 | "devDependencies": { 57 | "@commitlint/cli": "^6.1.0", 58 | "child-process-promise": "^2.2.1", 59 | "commitizen": "^2.9.6", 60 | "commitlint-config-seek": "^1.0.0", 61 | "cz-conventional-changelog": "^2.1.0", 62 | "eslint": "^5.12.0", 63 | "eslint-config-seek": "^4.0.0", 64 | "husky": "^0.14.3", 65 | "jest": "^22.0.1", 66 | "semantic-release": "^15.1.3", 67 | "traverse": "^0.6.6", 68 | "travis-deploy-once": "^5.0.0" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "seek" 4 | ], 5 | "dependencies": { 6 | "pinVersions": false 7 | }, 8 | "packageRules": [ 9 | { 10 | "packageNames": ["@brainly/html-sketchapp"], 11 | "enabled": true 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /script/generateAlmostSketch.js: -------------------------------------------------------------------------------- 1 | import htmlSketchapp from '@brainly/html-sketchapp' 2 | import { RESIZING_CONSTRAINTS } from '@brainly/html-sketchapp/html2asketch/helpers/utils'; 3 | 4 | const { 5 | Page, 6 | Document, 7 | Text, 8 | nodeToSketchLayers, 9 | SymbolMaster, 10 | SVG, 11 | Rectangle, 12 | ShapeGroup 13 | } = htmlSketchapp; 14 | 15 | const getAllLayers = (rootNode, symbolMastersByName = {}, symbolInstanceMiddleware = {}) => { 16 | const rootNodeAndChildren = [rootNode, ...rootNode.querySelectorAll('*')]; 17 | 18 | const symbolInstanceChildren = new Set([ 19 | ...rootNode.querySelectorAll('[data-sketch-symbol-instance] *') 20 | ]); 21 | 22 | const layers = Array.from(rootNodeAndChildren).map(node => { 23 | if (node.dataset.sketchSymbolInstance) { 24 | const symbolName = node.dataset.sketchSymbolInstance; 25 | 26 | if (!(symbolName in symbolMastersByName)) { 27 | throw new Error(`Unknown symbol master: ${symbolName}`); 28 | } 29 | 30 | const symbolMaster = symbolMastersByName[symbolName]; 31 | 32 | const { left: x, top: y, width, height } = node.getBoundingClientRect(); 33 | const symbolInstance = symbolMaster.getSymbolInstance({ x, y, width, height }); 34 | 35 | symbolInstance.setName(symbolName); 36 | symbolInstanceMiddleware({symbolInstance, symbolMaster, node, RESIZING_CONSTRAINTS}); 37 | 38 | return [symbolInstance]; 39 | } else if (symbolInstanceChildren.has(node)) { 40 | // Anything nested under data-sketch-symbol-instance shouldn't be rendered, 41 | // otherwise it'll be included in the symbolInstance itself. 42 | return []; 43 | } 44 | 45 | return nodeToSketchLayers(node); 46 | }); 47 | 48 | return layers.reduce((prev, current) => prev.concat(current), []); 49 | }; 50 | 51 | const doc = new Document(); 52 | 53 | export function snapshotColorStyles() { 54 | Array.from(document.querySelectorAll('[data-sketch-color]')) 55 | .forEach(node => { 56 | const color = node.dataset.sketchColor; 57 | 58 | doc.addColor(color); 59 | }); 60 | } 61 | 62 | export function snapshotTextStyles({ suffix = '' }) { 63 | Array.from(document.querySelectorAll('[data-sketch-text]')) 64 | .forEach(node => { 65 | getAllLayers(node) 66 | .filter(layer => layer instanceof Text) 67 | .forEach(layer => { 68 | const name = node.dataset.sketchText; 69 | 70 | layer.setName(`${name}${suffix}`); 71 | doc.addTextStyle(layer); 72 | }); 73 | }); 74 | } 75 | 76 | export function getDocumentJSON() { 77 | return JSON.stringify(doc.toJSON()); 78 | } 79 | 80 | const page = new Page({ 81 | width: document.body.offsetWidth, 82 | height: document.body.offsetHeight 83 | }); 84 | 85 | export function setupSymbols({ name }) { 86 | page.setName(name); 87 | } 88 | 89 | export function snapshotSymbols({ suffix = '', symbolLayerMiddleware = () => {}, symbolMiddleware = () => {}, symbolInstanceMiddleware = () => {} },) { 90 | const nodes = Array.from(document.querySelectorAll('[data-sketch-symbol]')); 91 | 92 | const symbolMastersByName = nodes.reduce((obj, node) => { 93 | const name = node.dataset.sketchSymbol; 94 | const { left: x, top: y } = node.getBoundingClientRect(); 95 | 96 | const symbol = new SymbolMaster({ x, y }); 97 | symbol.setName(`${name}${suffix}`); 98 | symbolMiddleware({symbol, node, suffix, RESIZING_CONSTRAINTS}); 99 | obj[name] = symbol; 100 | 101 | return obj; 102 | }, {}); 103 | 104 | const symbols = nodes.map(node => { 105 | const name = node.dataset.sketchSymbol; 106 | const symbol = symbolMastersByName[name]; 107 | 108 | const layers = getAllLayers(node, symbolMastersByName, symbolInstanceMiddleware); 109 | 110 | layers 111 | .filter(layer => layer !== null) 112 | .forEach(layer => { 113 | symbolLayerMiddleware({layer, SVG, Text, ShapeGroup, Rectangle, RESIZING_CONSTRAINTS}); 114 | symbol.addLayer(layer); 115 | }); 116 | 117 | return symbol; 118 | }); 119 | 120 | symbols.forEach(obj => page.addLayer(obj)); 121 | } 122 | 123 | export function getPageJSON() { 124 | return JSON.stringify(page.toJSON()); 125 | } 126 | -------------------------------------------------------------------------------- /test/_utils/dirContentsToObject.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const path = require('path'); 3 | const readFileAsync = promisify(require('fs').readFile); 4 | const traverse = require('traverse'); 5 | 6 | const guidRegex = /[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}/; 7 | 8 | module.exports = async dir => { 9 | const document = await readFileAsync(path.join(dir, 'document.asketch.json')); 10 | const page = await readFileAsync(path.join(dir, 'page.asketch.json')); 11 | 12 | const output = { 13 | 'document.asketch.json': JSON.parse(document), 14 | 'document.page.json': JSON.parse(page) 15 | }; 16 | 17 | // Scrub out GUIDs or they'll fail the snapshot tests 18 | traverse(output).forEach(function() { 19 | if (guidRegex.test(this.node) ) { 20 | this.update('__GUID__'); 21 | } 22 | }); 23 | 24 | return output; 25 | }; 26 | -------------------------------------------------------------------------------- /test/_utils/jestSetup.js: -------------------------------------------------------------------------------- 1 | jest.setTimeout(20000); 2 | -------------------------------------------------------------------------------- /test/config-file-path/custom.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | file: 'index.html', 3 | outDir: 'dist', 4 | puppeteerArgs: '--no-sandbox --disable-setuid-sandbox' 5 | }; 6 | -------------------------------------------------------------------------------- /test/config-file-path/file.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | test('config-file-path', async () => { 12 | await exec('node ../../bin/cli --config custom.config.js', { cwd: __dirname }); 13 | 14 | const output = await dirContentsToObject(distPath); 15 | expect(output).toMatchSnapshot(); 16 | }); 17 | -------------------------------------------------------------------------------- /test/config-file-path/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
Symbol 1
23 |
Symbol 2
24 |
Symbol 3
25 | 26 |

Text 1

27 |

Text 2

28 |

Text 3

29 | 30 |
Color 1
31 |
Color 2
32 |
Color 3
33 | 34 | 35 | -------------------------------------------------------------------------------- /test/config-file/__snapshots__/file.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`config-file 1`] = ` 4 | Object { 5 | "document.asketch.json": Object { 6 | "_class": "document", 7 | "assets": Object { 8 | "_class": "assetCollection", 9 | "colors": Array [ 10 | Object { 11 | "_class": "color", 12 | "alpha": 1, 13 | "blue": 0, 14 | "green": 0, 15 | "red": 1, 16 | }, 17 | Object { 18 | "_class": "color", 19 | "alpha": 1, 20 | "blue": 0, 21 | "green": 1, 22 | "red": 0, 23 | }, 24 | Object { 25 | "_class": "color", 26 | "alpha": 1, 27 | "blue": 1, 28 | "green": 0, 29 | "red": 0, 30 | }, 31 | ], 32 | }, 33 | "currentPageIndex": 0, 34 | "do_objectID": "__GUID__", 35 | "enableLayerInteraction": true, 36 | "enableSliceInteraction": true, 37 | "foreignSymbols": Array [], 38 | "layerStyles": Object { 39 | "_class": "sharedStyleContainer", 40 | "objects": Array [], 41 | }, 42 | "layerSymbols": Object { 43 | "_class": "symbolContainer", 44 | "objects": Array [], 45 | }, 46 | "layerTextStyles": Object { 47 | "_class": "sharedTextStyleContainer", 48 | "objects": Array [ 49 | Object { 50 | "_class": "sharedStyle", 51 | "do_objectID": "__GUID__", 52 | "name": "Text 1", 53 | "style": Object { 54 | "color": "rgb(0, 0, 0)", 55 | "fontFamily": "Times New Roman", 56 | "fontSize": 40, 57 | "fontWeight": 700, 58 | "textAlign": "start", 59 | "textDecoration": "none", 60 | "textTransform": "none", 61 | }, 62 | }, 63 | Object { 64 | "_class": "sharedStyle", 65 | "do_objectID": "__GUID__", 66 | "name": "Text 2", 67 | "style": Object { 68 | "color": "rgb(0, 0, 0)", 69 | "fontFamily": "Times New Roman", 70 | "fontSize": 30, 71 | "fontWeight": 700, 72 | "textAlign": "start", 73 | "textDecoration": "none", 74 | "textTransform": "none", 75 | }, 76 | }, 77 | Object { 78 | "_class": "sharedStyle", 79 | "do_objectID": "__GUID__", 80 | "name": "Text 3", 81 | "style": Object { 82 | "color": "rgb(0, 0, 0)", 83 | "fontFamily": "Times New Roman", 84 | "fontSize": 20, 85 | "fontWeight": 700, 86 | "textAlign": "start", 87 | "textDecoration": "none", 88 | "textTransform": "none", 89 | }, 90 | }, 91 | ], 92 | }, 93 | "pages": Array [], 94 | }, 95 | "document.page.json": Object { 96 | "_class": "page", 97 | "clippingMaskMode": 0, 98 | "do_objectID": "__GUID__", 99 | "exportOptions": Object { 100 | "_class": "exportOptions", 101 | "exportFormats": Array [], 102 | "includedLayerIds": Array [], 103 | "layerOptions": 0, 104 | "shouldTrim": false, 105 | }, 106 | "frame": Object { 107 | "_class": "rect", 108 | "constrainProportions": false, 109 | "height": 352, 110 | "width": 784, 111 | "x": 0, 112 | "y": 0, 113 | }, 114 | "hasClickThrough": true, 115 | "hasClippingMask": false, 116 | "horizontalRulerData": Object { 117 | "_class": "rulerData", 118 | "base": 0, 119 | "guides": Array [], 120 | }, 121 | "includeInCloudUpload": true, 122 | "isFlippedHorizontal": false, 123 | "isFlippedVertical": false, 124 | "isLocked": false, 125 | "isVisible": true, 126 | "layerListExpandedType": 0, 127 | "layers": Array [ 128 | Object { 129 | "_class": "symbolMaster", 130 | "backgroundColor": Object { 131 | "_class": "color", 132 | "alpha": 1, 133 | "blue": 1, 134 | "green": 1, 135 | "red": 1, 136 | }, 137 | "changeIdentifier": 0, 138 | "clippingMaskMode": 0, 139 | "do_objectID": "__GUID__", 140 | "exportOptions": Object { 141 | "_class": "exportOptions", 142 | "exportFormats": Array [], 143 | "includedLayerIds": Array [], 144 | "layerOptions": 0, 145 | "shouldTrim": false, 146 | }, 147 | "frame": Object { 148 | "_class": "rect", 149 | "constrainProportions": false, 150 | "height": 38, 151 | "width": 998, 152 | "x": 8, 153 | "y": 10, 154 | }, 155 | "hasBackgroundColor": false, 156 | "hasClickThrough": true, 157 | "hasClippingMask": false, 158 | "horizontalRulerData": Object { 159 | "_class": "rulerData", 160 | "base": 0, 161 | "guides": Array [], 162 | }, 163 | "includeBackgroundColorInExport": true, 164 | "includeBackgroundColorInInstance": false, 165 | "includeInCloudUpload": true, 166 | "isFlippedHorizontal": false, 167 | "isFlippedVertical": false, 168 | "isLocked": false, 169 | "isVisible": true, 170 | "layerListExpandedType": 0, 171 | "layers": Array [ 172 | Object { 173 | "_class": "shapeGroup", 174 | "clippingMaskMode": 0, 175 | "do_objectID": "__GUID__", 176 | "exportOptions": Object { 177 | "_class": "exportOptions", 178 | "exportFormats": Array [], 179 | "includedLayerIds": Array [], 180 | "layerOptions": 0, 181 | "shouldTrim": false, 182 | }, 183 | "frame": Object { 184 | "_class": "rect", 185 | "constrainProportions": false, 186 | "height": 38, 187 | "width": 988, 188 | "x": 10, 189 | "y": 0, 190 | }, 191 | "hasClickThrough": false, 192 | "hasClippingMask": false, 193 | "isFlippedHorizontal": false, 194 | "isFlippedVertical": false, 195 | "isLocked": false, 196 | "isVisible": true, 197 | "layerListExpandedType": 0, 198 | "layers": Array [ 199 | Object { 200 | "_class": "rectangle", 201 | "booleanOperation": -1, 202 | "clippingMaskMode": 0, 203 | "do_objectID": "__GUID__", 204 | "edited": false, 205 | "exportOptions": Object { 206 | "_class": "exportOptions", 207 | "exportFormats": Array [], 208 | "includedLayerIds": Array [], 209 | "layerOptions": 0, 210 | "shouldTrim": false, 211 | }, 212 | "fixedRadius": 0, 213 | "frame": Object { 214 | "_class": "rect", 215 | "constrainProportions": false, 216 | "height": 38, 217 | "width": 988, 218 | "x": 0, 219 | "y": 0, 220 | }, 221 | "hasClippingMask": false, 222 | "hasConvertedToNewRoundCorners": true, 223 | "isFlippedHorizontal": false, 224 | "isFlippedVertical": false, 225 | "isLocked": false, 226 | "isVisible": true, 227 | "layerListExpandedType": 0, 228 | "layers": Array [], 229 | "name": "rectangle", 230 | "nameIsFixed": false, 231 | "path": Object { 232 | "_class": "path", 233 | "isClosed": true, 234 | "pointRadiusBehaviour": 1, 235 | "points": Array [ 236 | Object { 237 | "_class": "curvePoint", 238 | "cornerRadius": 0, 239 | "curveFrom": "{0, 0}", 240 | "curveMode": 1, 241 | "curveTo": "{0, 0}", 242 | "hasCurveFrom": false, 243 | "hasCurveTo": false, 244 | "point": "{0, 0}", 245 | }, 246 | Object { 247 | "_class": "curvePoint", 248 | "cornerRadius": 0, 249 | "curveFrom": "{1, 0}", 250 | "curveMode": 1, 251 | "curveTo": "{1, 0}", 252 | "hasCurveFrom": false, 253 | "hasCurveTo": false, 254 | "point": "{1, 0}", 255 | }, 256 | Object { 257 | "_class": "curvePoint", 258 | "cornerRadius": 0, 259 | "curveFrom": "{1, 1}", 260 | "curveMode": 1, 261 | "curveTo": "{1, 1}", 262 | "hasCurveFrom": false, 263 | "hasCurveTo": false, 264 | "point": "{1, 1}", 265 | }, 266 | Object { 267 | "_class": "curvePoint", 268 | "cornerRadius": 0, 269 | "curveFrom": "{0, 1}", 270 | "curveMode": 1, 271 | "curveTo": "{0, 1}", 272 | "hasCurveFrom": false, 273 | "hasCurveTo": false, 274 | "point": "{0, 1}", 275 | }, 276 | ], 277 | }, 278 | "resizingConstraint": 63, 279 | "resizingType": 0, 280 | "rotation": 0, 281 | "shouldBreakMaskChain": false, 282 | }, 283 | ], 284 | "name": "/html[1]/body[1]/div[1]/div[@class=\\"symbol red\\"]", 285 | "nameIsFixed": false, 286 | "resizingConstraint": 63, 287 | "resizingType": 0, 288 | "rotation": 0, 289 | "shouldBreakMaskChain": false, 290 | "style": Object { 291 | "_class": "style", 292 | "borders": Array [ 293 | Object { 294 | "_class": "border", 295 | "color": Object { 296 | "_class": "color", 297 | "alpha": 1, 298 | "blue": 0, 299 | "green": 0, 300 | "red": 0, 301 | }, 302 | "fillType": 0, 303 | "isEnabled": true, 304 | "position": 1, 305 | "thickness": 0, 306 | }, 307 | ], 308 | "contextSettings": Object { 309 | "_class": "graphicsContextSettings", 310 | "blendMode": 0, 311 | "opacity": "1", 312 | }, 313 | "endDecorationType": 0, 314 | "fills": Array [ 315 | Object { 316 | "_class": "fill", 317 | "color": Object { 318 | "_class": "color", 319 | "alpha": 1, 320 | "blue": 0.796078431372549, 321 | "green": 0.7529411764705882, 322 | "red": 1, 323 | }, 324 | "fillType": 0, 325 | "isEnabled": true, 326 | "noiseIndex": 0, 327 | "noiseIntensity": 0, 328 | "patternFillType": 1, 329 | "patternTileScale": 1, 330 | }, 331 | ], 332 | "innerShadows": Array [], 333 | "miterLimit": 10, 334 | "shadows": Array [], 335 | "startDecorationType": 0, 336 | }, 337 | "windingRule": 1, 338 | }, 339 | Object { 340 | "_class": "text", 341 | "automaticallyDrawOnUnderlyingPath": false, 342 | "clippingMaskMode": 0, 343 | "do_objectID": "__GUID__", 344 | "dontSynchroniseWithSymbol": false, 345 | "exportOptions": Object { 346 | "_class": "exportOptions", 347 | "exportFormats": Array [], 348 | "includedLayerIds": Array [], 349 | "layerOptions": 0, 350 | "shouldTrim": false, 351 | }, 352 | "frame": Object { 353 | "_class": "rect", 354 | "constrainProportions": false, 355 | "height": 17, 356 | "width": 61.78125, 357 | "x": 20, 358 | "y": 10, 359 | }, 360 | "hasClippingMask": false, 361 | "isFlippedHorizontal": false, 362 | "isFlippedVertical": false, 363 | "isLocked": false, 364 | "isVisible": true, 365 | "layerListExpandedType": 0, 366 | "lineSpacingBehaviour": 2, 367 | "name": "Symbol 1", 368 | "nameIsFixed": false, 369 | "resizingConstraint": 47, 370 | "resizingType": 0, 371 | "rotation": 0, 372 | "shouldBreakMaskChain": false, 373 | "style": Object { 374 | "color": "rgb(0, 0, 0)", 375 | "fontFamily": "Times New Roman", 376 | "fontSize": 16, 377 | "fontWeight": 400, 378 | "textAlign": "start", 379 | "textDecoration": "none", 380 | "textTransform": "none", 381 | }, 382 | "text": "Symbol 1", 383 | "textBehaviour": 0, 384 | }, 385 | ], 386 | "name": "Symbol 1", 387 | "nameIsFixed": false, 388 | "resizesContent": false, 389 | "resizingConstraint": 63, 390 | "resizingType": 0, 391 | "rotation": 0, 392 | "shouldBreakMaskChain": false, 393 | "style": Object { 394 | "_class": "style", 395 | "endDecorationType": 0, 396 | "miterLimit": 10, 397 | "startDecorationType": 0, 398 | }, 399 | "symbolID": "__GUID__", 400 | "verticalRulerData": Object { 401 | "_class": "rulerData", 402 | "base": 0, 403 | "guides": Array [], 404 | }, 405 | }, 406 | Object { 407 | "_class": "symbolMaster", 408 | "backgroundColor": Object { 409 | "_class": "color", 410 | "alpha": 1, 411 | "blue": 1, 412 | "green": 1, 413 | "red": 1, 414 | }, 415 | "changeIdentifier": 0, 416 | "clippingMaskMode": 0, 417 | "do_objectID": "__GUID__", 418 | "exportOptions": Object { 419 | "_class": "exportOptions", 420 | "exportFormats": Array [], 421 | "includedLayerIds": Array [], 422 | "layerOptions": 0, 423 | "shouldTrim": false, 424 | }, 425 | "frame": Object { 426 | "_class": "rect", 427 | "constrainProportions": false, 428 | "height": 38, 429 | "width": 998, 430 | "x": 8, 431 | "y": 58, 432 | }, 433 | "hasBackgroundColor": false, 434 | "hasClickThrough": true, 435 | "hasClippingMask": false, 436 | "horizontalRulerData": Object { 437 | "_class": "rulerData", 438 | "base": 0, 439 | "guides": Array [], 440 | }, 441 | "includeBackgroundColorInExport": true, 442 | "includeBackgroundColorInInstance": false, 443 | "includeInCloudUpload": true, 444 | "isFlippedHorizontal": false, 445 | "isFlippedVertical": false, 446 | "isLocked": false, 447 | "isVisible": true, 448 | "layerListExpandedType": 0, 449 | "layers": Array [ 450 | Object { 451 | "_class": "shapeGroup", 452 | "clippingMaskMode": 0, 453 | "do_objectID": "__GUID__", 454 | "exportOptions": Object { 455 | "_class": "exportOptions", 456 | "exportFormats": Array [], 457 | "includedLayerIds": Array [], 458 | "layerOptions": 0, 459 | "shouldTrim": false, 460 | }, 461 | "frame": Object { 462 | "_class": "rect", 463 | "constrainProportions": false, 464 | "height": 38, 465 | "width": 988, 466 | "x": 10, 467 | "y": 0, 468 | }, 469 | "hasClickThrough": false, 470 | "hasClippingMask": false, 471 | "isFlippedHorizontal": false, 472 | "isFlippedVertical": false, 473 | "isLocked": false, 474 | "isVisible": true, 475 | "layerListExpandedType": 0, 476 | "layers": Array [ 477 | Object { 478 | "_class": "rectangle", 479 | "booleanOperation": -1, 480 | "clippingMaskMode": 0, 481 | "do_objectID": "__GUID__", 482 | "edited": false, 483 | "exportOptions": Object { 484 | "_class": "exportOptions", 485 | "exportFormats": Array [], 486 | "includedLayerIds": Array [], 487 | "layerOptions": 0, 488 | "shouldTrim": false, 489 | }, 490 | "fixedRadius": 0, 491 | "frame": Object { 492 | "_class": "rect", 493 | "constrainProportions": false, 494 | "height": 38, 495 | "width": 988, 496 | "x": 0, 497 | "y": 0, 498 | }, 499 | "hasClippingMask": false, 500 | "hasConvertedToNewRoundCorners": true, 501 | "isFlippedHorizontal": false, 502 | "isFlippedVertical": false, 503 | "isLocked": false, 504 | "isVisible": true, 505 | "layerListExpandedType": 0, 506 | "layers": Array [], 507 | "name": "rectangle", 508 | "nameIsFixed": false, 509 | "path": Object { 510 | "_class": "path", 511 | "isClosed": true, 512 | "pointRadiusBehaviour": 1, 513 | "points": Array [ 514 | Object { 515 | "_class": "curvePoint", 516 | "cornerRadius": 0, 517 | "curveFrom": "{0, 0}", 518 | "curveMode": 1, 519 | "curveTo": "{0, 0}", 520 | "hasCurveFrom": false, 521 | "hasCurveTo": false, 522 | "point": "{0, 0}", 523 | }, 524 | Object { 525 | "_class": "curvePoint", 526 | "cornerRadius": 0, 527 | "curveFrom": "{1, 0}", 528 | "curveMode": 1, 529 | "curveTo": "{1, 0}", 530 | "hasCurveFrom": false, 531 | "hasCurveTo": false, 532 | "point": "{1, 0}", 533 | }, 534 | Object { 535 | "_class": "curvePoint", 536 | "cornerRadius": 0, 537 | "curveFrom": "{1, 1}", 538 | "curveMode": 1, 539 | "curveTo": "{1, 1}", 540 | "hasCurveFrom": false, 541 | "hasCurveTo": false, 542 | "point": "{1, 1}", 543 | }, 544 | Object { 545 | "_class": "curvePoint", 546 | "cornerRadius": 0, 547 | "curveFrom": "{0, 1}", 548 | "curveMode": 1, 549 | "curveTo": "{0, 1}", 550 | "hasCurveFrom": false, 551 | "hasCurveTo": false, 552 | "point": "{0, 1}", 553 | }, 554 | ], 555 | }, 556 | "resizingConstraint": 63, 557 | "resizingType": 0, 558 | "rotation": 0, 559 | "shouldBreakMaskChain": false, 560 | }, 561 | ], 562 | "name": "/html[1]/body[1]/div[2]/div[@class=\\"symbol green\\"]", 563 | "nameIsFixed": false, 564 | "resizingConstraint": 63, 565 | "resizingType": 0, 566 | "rotation": 0, 567 | "shouldBreakMaskChain": false, 568 | "style": Object { 569 | "_class": "style", 570 | "borders": Array [ 571 | Object { 572 | "_class": "border", 573 | "color": Object { 574 | "_class": "color", 575 | "alpha": 1, 576 | "blue": 0, 577 | "green": 0, 578 | "red": 0, 579 | }, 580 | "fillType": 0, 581 | "isEnabled": true, 582 | "position": 1, 583 | "thickness": 0, 584 | }, 585 | ], 586 | "contextSettings": Object { 587 | "_class": "graphicsContextSettings", 588 | "blendMode": 0, 589 | "opacity": "1", 590 | }, 591 | "endDecorationType": 0, 592 | "fills": Array [ 593 | Object { 594 | "_class": "fill", 595 | "color": Object { 596 | "_class": "color", 597 | "alpha": 1, 598 | "blue": 0.596078431372549, 599 | "green": 0.984313725490196, 600 | "red": 0.596078431372549, 601 | }, 602 | "fillType": 0, 603 | "isEnabled": true, 604 | "noiseIndex": 0, 605 | "noiseIntensity": 0, 606 | "patternFillType": 1, 607 | "patternTileScale": 1, 608 | }, 609 | ], 610 | "innerShadows": Array [], 611 | "miterLimit": 10, 612 | "shadows": Array [], 613 | "startDecorationType": 0, 614 | }, 615 | "windingRule": 1, 616 | }, 617 | Object { 618 | "_class": "text", 619 | "automaticallyDrawOnUnderlyingPath": false, 620 | "clippingMaskMode": 0, 621 | "do_objectID": "__GUID__", 622 | "dontSynchroniseWithSymbol": false, 623 | "exportOptions": Object { 624 | "_class": "exportOptions", 625 | "exportFormats": Array [], 626 | "includedLayerIds": Array [], 627 | "layerOptions": 0, 628 | "shouldTrim": false, 629 | }, 630 | "frame": Object { 631 | "_class": "rect", 632 | "constrainProportions": false, 633 | "height": 17, 634 | "width": 61.78125, 635 | "x": 20, 636 | "y": 10, 637 | }, 638 | "hasClippingMask": false, 639 | "isFlippedHorizontal": false, 640 | "isFlippedVertical": false, 641 | "isLocked": false, 642 | "isVisible": true, 643 | "layerListExpandedType": 0, 644 | "lineSpacingBehaviour": 2, 645 | "name": "Symbol 2", 646 | "nameIsFixed": false, 647 | "resizingConstraint": 47, 648 | "resizingType": 0, 649 | "rotation": 0, 650 | "shouldBreakMaskChain": false, 651 | "style": Object { 652 | "color": "rgb(0, 0, 0)", 653 | "fontFamily": "Times New Roman", 654 | "fontSize": 16, 655 | "fontWeight": 400, 656 | "textAlign": "start", 657 | "textDecoration": "none", 658 | "textTransform": "none", 659 | }, 660 | "text": "Symbol 2", 661 | "textBehaviour": 0, 662 | }, 663 | ], 664 | "name": "Symbol 2", 665 | "nameIsFixed": false, 666 | "resizesContent": false, 667 | "resizingConstraint": 63, 668 | "resizingType": 0, 669 | "rotation": 0, 670 | "shouldBreakMaskChain": false, 671 | "style": Object { 672 | "_class": "style", 673 | "endDecorationType": 0, 674 | "miterLimit": 10, 675 | "startDecorationType": 0, 676 | }, 677 | "symbolID": "__GUID__", 678 | "verticalRulerData": Object { 679 | "_class": "rulerData", 680 | "base": 0, 681 | "guides": Array [], 682 | }, 683 | }, 684 | Object { 685 | "_class": "symbolMaster", 686 | "backgroundColor": Object { 687 | "_class": "color", 688 | "alpha": 1, 689 | "blue": 1, 690 | "green": 1, 691 | "red": 1, 692 | }, 693 | "changeIdentifier": 0, 694 | "clippingMaskMode": 0, 695 | "do_objectID": "__GUID__", 696 | "exportOptions": Object { 697 | "_class": "exportOptions", 698 | "exportFormats": Array [], 699 | "includedLayerIds": Array [], 700 | "layerOptions": 0, 701 | "shouldTrim": false, 702 | }, 703 | "frame": Object { 704 | "_class": "rect", 705 | "constrainProportions": false, 706 | "height": 38, 707 | "width": 998, 708 | "x": 8, 709 | "y": 106, 710 | }, 711 | "hasBackgroundColor": false, 712 | "hasClickThrough": true, 713 | "hasClippingMask": false, 714 | "horizontalRulerData": Object { 715 | "_class": "rulerData", 716 | "base": 0, 717 | "guides": Array [], 718 | }, 719 | "includeBackgroundColorInExport": true, 720 | "includeBackgroundColorInInstance": false, 721 | "includeInCloudUpload": true, 722 | "isFlippedHorizontal": false, 723 | "isFlippedVertical": false, 724 | "isLocked": false, 725 | "isVisible": true, 726 | "layerListExpandedType": 0, 727 | "layers": Array [ 728 | Object { 729 | "_class": "shapeGroup", 730 | "clippingMaskMode": 0, 731 | "do_objectID": "__GUID__", 732 | "exportOptions": Object { 733 | "_class": "exportOptions", 734 | "exportFormats": Array [], 735 | "includedLayerIds": Array [], 736 | "layerOptions": 0, 737 | "shouldTrim": false, 738 | }, 739 | "frame": Object { 740 | "_class": "rect", 741 | "constrainProportions": false, 742 | "height": 38, 743 | "width": 988, 744 | "x": 10, 745 | "y": 0, 746 | }, 747 | "hasClickThrough": false, 748 | "hasClippingMask": false, 749 | "isFlippedHorizontal": false, 750 | "isFlippedVertical": false, 751 | "isLocked": false, 752 | "isVisible": true, 753 | "layerListExpandedType": 0, 754 | "layers": Array [ 755 | Object { 756 | "_class": "rectangle", 757 | "booleanOperation": -1, 758 | "clippingMaskMode": 0, 759 | "do_objectID": "__GUID__", 760 | "edited": false, 761 | "exportOptions": Object { 762 | "_class": "exportOptions", 763 | "exportFormats": Array [], 764 | "includedLayerIds": Array [], 765 | "layerOptions": 0, 766 | "shouldTrim": false, 767 | }, 768 | "fixedRadius": 0, 769 | "frame": Object { 770 | "_class": "rect", 771 | "constrainProportions": false, 772 | "height": 38, 773 | "width": 988, 774 | "x": 0, 775 | "y": 0, 776 | }, 777 | "hasClippingMask": false, 778 | "hasConvertedToNewRoundCorners": true, 779 | "isFlippedHorizontal": false, 780 | "isFlippedVertical": false, 781 | "isLocked": false, 782 | "isVisible": true, 783 | "layerListExpandedType": 0, 784 | "layers": Array [], 785 | "name": "rectangle", 786 | "nameIsFixed": false, 787 | "path": Object { 788 | "_class": "path", 789 | "isClosed": true, 790 | "pointRadiusBehaviour": 1, 791 | "points": Array [ 792 | Object { 793 | "_class": "curvePoint", 794 | "cornerRadius": 0, 795 | "curveFrom": "{0, 0}", 796 | "curveMode": 1, 797 | "curveTo": "{0, 0}", 798 | "hasCurveFrom": false, 799 | "hasCurveTo": false, 800 | "point": "{0, 0}", 801 | }, 802 | Object { 803 | "_class": "curvePoint", 804 | "cornerRadius": 0, 805 | "curveFrom": "{1, 0}", 806 | "curveMode": 1, 807 | "curveTo": "{1, 0}", 808 | "hasCurveFrom": false, 809 | "hasCurveTo": false, 810 | "point": "{1, 0}", 811 | }, 812 | Object { 813 | "_class": "curvePoint", 814 | "cornerRadius": 0, 815 | "curveFrom": "{1, 1}", 816 | "curveMode": 1, 817 | "curveTo": "{1, 1}", 818 | "hasCurveFrom": false, 819 | "hasCurveTo": false, 820 | "point": "{1, 1}", 821 | }, 822 | Object { 823 | "_class": "curvePoint", 824 | "cornerRadius": 0, 825 | "curveFrom": "{0, 1}", 826 | "curveMode": 1, 827 | "curveTo": "{0, 1}", 828 | "hasCurveFrom": false, 829 | "hasCurveTo": false, 830 | "point": "{0, 1}", 831 | }, 832 | ], 833 | }, 834 | "resizingConstraint": 63, 835 | "resizingType": 0, 836 | "rotation": 0, 837 | "shouldBreakMaskChain": false, 838 | }, 839 | ], 840 | "name": "/html[1]/body[1]/div[3]/div[@class=\\"symbol blue\\"]", 841 | "nameIsFixed": false, 842 | "resizingConstraint": 63, 843 | "resizingType": 0, 844 | "rotation": 0, 845 | "shouldBreakMaskChain": false, 846 | "style": Object { 847 | "_class": "style", 848 | "borders": Array [ 849 | Object { 850 | "_class": "border", 851 | "color": Object { 852 | "_class": "color", 853 | "alpha": 1, 854 | "blue": 0, 855 | "green": 0, 856 | "red": 0, 857 | }, 858 | "fillType": 0, 859 | "isEnabled": true, 860 | "position": 1, 861 | "thickness": 0, 862 | }, 863 | ], 864 | "contextSettings": Object { 865 | "_class": "graphicsContextSettings", 866 | "blendMode": 0, 867 | "opacity": "1", 868 | }, 869 | "endDecorationType": 0, 870 | "fills": Array [ 871 | Object { 872 | "_class": "fill", 873 | "color": Object { 874 | "_class": "color", 875 | "alpha": 1, 876 | "blue": 1, 877 | "green": 1, 878 | "red": 0, 879 | }, 880 | "fillType": 0, 881 | "isEnabled": true, 882 | "noiseIndex": 0, 883 | "noiseIntensity": 0, 884 | "patternFillType": 1, 885 | "patternTileScale": 1, 886 | }, 887 | ], 888 | "innerShadows": Array [], 889 | "miterLimit": 10, 890 | "shadows": Array [], 891 | "startDecorationType": 0, 892 | }, 893 | "windingRule": 1, 894 | }, 895 | Object { 896 | "_class": "text", 897 | "automaticallyDrawOnUnderlyingPath": false, 898 | "clippingMaskMode": 0, 899 | "do_objectID": "__GUID__", 900 | "dontSynchroniseWithSymbol": false, 901 | "exportOptions": Object { 902 | "_class": "exportOptions", 903 | "exportFormats": Array [], 904 | "includedLayerIds": Array [], 905 | "layerOptions": 0, 906 | "shouldTrim": false, 907 | }, 908 | "frame": Object { 909 | "_class": "rect", 910 | "constrainProportions": false, 911 | "height": 17, 912 | "width": 61.78125, 913 | "x": 20, 914 | "y": 10, 915 | }, 916 | "hasClippingMask": false, 917 | "isFlippedHorizontal": false, 918 | "isFlippedVertical": false, 919 | "isLocked": false, 920 | "isVisible": true, 921 | "layerListExpandedType": 0, 922 | "lineSpacingBehaviour": 2, 923 | "name": "Symbol 3", 924 | "nameIsFixed": false, 925 | "resizingConstraint": 47, 926 | "resizingType": 0, 927 | "rotation": 0, 928 | "shouldBreakMaskChain": false, 929 | "style": Object { 930 | "color": "rgb(0, 0, 0)", 931 | "fontFamily": "Times New Roman", 932 | "fontSize": 16, 933 | "fontWeight": 400, 934 | "textAlign": "start", 935 | "textDecoration": "none", 936 | "textTransform": "none", 937 | }, 938 | "text": "Symbol 3", 939 | "textBehaviour": 0, 940 | }, 941 | ], 942 | "name": "Symbol 3", 943 | "nameIsFixed": false, 944 | "resizesContent": false, 945 | "resizingConstraint": 63, 946 | "resizingType": 0, 947 | "rotation": 0, 948 | "shouldBreakMaskChain": false, 949 | "style": Object { 950 | "_class": "style", 951 | "endDecorationType": 0, 952 | "miterLimit": 10, 953 | "startDecorationType": 0, 954 | }, 955 | "symbolID": "__GUID__", 956 | "verticalRulerData": Object { 957 | "_class": "rulerData", 958 | "base": 0, 959 | "guides": Array [], 960 | }, 961 | }, 962 | ], 963 | "name": "html-sketchapp symbols", 964 | "nameIsFixed": false, 965 | "resizingConstraint": 63, 966 | "resizingType": 0, 967 | "rotation": 0, 968 | "shouldBreakMaskChain": false, 969 | "style": Object { 970 | "_class": "style", 971 | "endDecorationType": 0, 972 | "miterLimit": 10, 973 | "startDecorationType": 0, 974 | }, 975 | "verticalRulerData": Object { 976 | "_class": "rulerData", 977 | "base": 0, 978 | "guides": Array [], 979 | }, 980 | }, 981 | } 982 | `; 983 | -------------------------------------------------------------------------------- /test/config-file/file.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | test('config-file', async () => { 12 | await exec('node ../../bin/cli', { cwd: __dirname }); 13 | 14 | const output = await dirContentsToObject(distPath); 15 | expect(output).toMatchSnapshot(); 16 | }); 17 | -------------------------------------------------------------------------------- /test/config-file/html-sketchapp.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | file: 'index.html', 3 | outDir: 'dist', 4 | puppeteerArgs: '--no-sandbox --disable-setuid-sandbox' 5 | }; 6 | -------------------------------------------------------------------------------- /test/config-file/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
Symbol 1
23 |
Symbol 2
24 |
Symbol 3
25 | 26 |

Text 1

27 |

Text 2

28 |

Text 3

29 | 30 |
Color 1
31 |
Color 2
32 |
Color 3
33 | 34 | 35 | -------------------------------------------------------------------------------- /test/file/__snapshots__/file.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`file 1`] = ` 4 | Object { 5 | "document.asketch.json": Object { 6 | "_class": "document", 7 | "assets": Object { 8 | "_class": "assetCollection", 9 | "colors": Array [ 10 | Object { 11 | "_class": "color", 12 | "alpha": 1, 13 | "blue": 0, 14 | "green": 0, 15 | "red": 1, 16 | }, 17 | Object { 18 | "_class": "color", 19 | "alpha": 1, 20 | "blue": 0, 21 | "green": 1, 22 | "red": 0, 23 | }, 24 | Object { 25 | "_class": "color", 26 | "alpha": 1, 27 | "blue": 1, 28 | "green": 0, 29 | "red": 0, 30 | }, 31 | ], 32 | }, 33 | "currentPageIndex": 0, 34 | "do_objectID": "__GUID__", 35 | "enableLayerInteraction": true, 36 | "enableSliceInteraction": true, 37 | "foreignSymbols": Array [], 38 | "layerStyles": Object { 39 | "_class": "sharedStyleContainer", 40 | "objects": Array [], 41 | }, 42 | "layerSymbols": Object { 43 | "_class": "symbolContainer", 44 | "objects": Array [], 45 | }, 46 | "layerTextStyles": Object { 47 | "_class": "sharedTextStyleContainer", 48 | "objects": Array [ 49 | Object { 50 | "_class": "sharedStyle", 51 | "do_objectID": "__GUID__", 52 | "name": "Text 1", 53 | "style": Object { 54 | "color": "rgb(0, 0, 0)", 55 | "fontFamily": "Times New Roman", 56 | "fontSize": 40, 57 | "fontWeight": 700, 58 | "textAlign": "start", 59 | "textDecoration": "none", 60 | "textTransform": "none", 61 | }, 62 | }, 63 | Object { 64 | "_class": "sharedStyle", 65 | "do_objectID": "__GUID__", 66 | "name": "Text 2", 67 | "style": Object { 68 | "color": "rgb(0, 0, 0)", 69 | "fontFamily": "Times New Roman", 70 | "fontSize": 30, 71 | "fontWeight": 700, 72 | "textAlign": "start", 73 | "textDecoration": "none", 74 | "textTransform": "none", 75 | }, 76 | }, 77 | Object { 78 | "_class": "sharedStyle", 79 | "do_objectID": "__GUID__", 80 | "name": "Text 3", 81 | "style": Object { 82 | "color": "rgb(0, 0, 0)", 83 | "fontFamily": "Times New Roman", 84 | "fontSize": 20, 85 | "fontWeight": 700, 86 | "textAlign": "start", 87 | "textDecoration": "none", 88 | "textTransform": "none", 89 | }, 90 | }, 91 | ], 92 | }, 93 | "pages": Array [], 94 | }, 95 | "document.page.json": Object { 96 | "_class": "page", 97 | "clippingMaskMode": 0, 98 | "do_objectID": "__GUID__", 99 | "exportOptions": Object { 100 | "_class": "exportOptions", 101 | "exportFormats": Array [], 102 | "includedLayerIds": Array [], 103 | "layerOptions": 0, 104 | "shouldTrim": false, 105 | }, 106 | "frame": Object { 107 | "_class": "rect", 108 | "constrainProportions": false, 109 | "height": 352, 110 | "width": 784, 111 | "x": 0, 112 | "y": 0, 113 | }, 114 | "hasClickThrough": true, 115 | "hasClippingMask": false, 116 | "horizontalRulerData": Object { 117 | "_class": "rulerData", 118 | "base": 0, 119 | "guides": Array [], 120 | }, 121 | "includeInCloudUpload": true, 122 | "isFlippedHorizontal": false, 123 | "isFlippedVertical": false, 124 | "isLocked": false, 125 | "isVisible": true, 126 | "layerListExpandedType": 0, 127 | "layers": Array [ 128 | Object { 129 | "_class": "symbolMaster", 130 | "backgroundColor": Object { 131 | "_class": "color", 132 | "alpha": 1, 133 | "blue": 1, 134 | "green": 1, 135 | "red": 1, 136 | }, 137 | "changeIdentifier": 0, 138 | "clippingMaskMode": 0, 139 | "do_objectID": "__GUID__", 140 | "exportOptions": Object { 141 | "_class": "exportOptions", 142 | "exportFormats": Array [], 143 | "includedLayerIds": Array [], 144 | "layerOptions": 0, 145 | "shouldTrim": false, 146 | }, 147 | "frame": Object { 148 | "_class": "rect", 149 | "constrainProportions": false, 150 | "height": 38, 151 | "width": 998, 152 | "x": 8, 153 | "y": 10, 154 | }, 155 | "hasBackgroundColor": false, 156 | "hasClickThrough": true, 157 | "hasClippingMask": false, 158 | "horizontalRulerData": Object { 159 | "_class": "rulerData", 160 | "base": 0, 161 | "guides": Array [], 162 | }, 163 | "includeBackgroundColorInExport": true, 164 | "includeBackgroundColorInInstance": false, 165 | "includeInCloudUpload": true, 166 | "isFlippedHorizontal": false, 167 | "isFlippedVertical": false, 168 | "isLocked": false, 169 | "isVisible": true, 170 | "layerListExpandedType": 0, 171 | "layers": Array [ 172 | Object { 173 | "_class": "shapeGroup", 174 | "clippingMaskMode": 0, 175 | "do_objectID": "__GUID__", 176 | "exportOptions": Object { 177 | "_class": "exportOptions", 178 | "exportFormats": Array [], 179 | "includedLayerIds": Array [], 180 | "layerOptions": 0, 181 | "shouldTrim": false, 182 | }, 183 | "frame": Object { 184 | "_class": "rect", 185 | "constrainProportions": false, 186 | "height": 38, 187 | "width": 988, 188 | "x": 10, 189 | "y": 0, 190 | }, 191 | "hasClickThrough": false, 192 | "hasClippingMask": false, 193 | "isFlippedHorizontal": false, 194 | "isFlippedVertical": false, 195 | "isLocked": false, 196 | "isVisible": true, 197 | "layerListExpandedType": 0, 198 | "layers": Array [ 199 | Object { 200 | "_class": "rectangle", 201 | "booleanOperation": -1, 202 | "clippingMaskMode": 0, 203 | "do_objectID": "__GUID__", 204 | "edited": false, 205 | "exportOptions": Object { 206 | "_class": "exportOptions", 207 | "exportFormats": Array [], 208 | "includedLayerIds": Array [], 209 | "layerOptions": 0, 210 | "shouldTrim": false, 211 | }, 212 | "fixedRadius": 0, 213 | "frame": Object { 214 | "_class": "rect", 215 | "constrainProportions": false, 216 | "height": 38, 217 | "width": 988, 218 | "x": 0, 219 | "y": 0, 220 | }, 221 | "hasClippingMask": false, 222 | "hasConvertedToNewRoundCorners": true, 223 | "isFlippedHorizontal": false, 224 | "isFlippedVertical": false, 225 | "isLocked": false, 226 | "isVisible": true, 227 | "layerListExpandedType": 0, 228 | "layers": Array [], 229 | "name": "rectangle", 230 | "nameIsFixed": false, 231 | "path": Object { 232 | "_class": "path", 233 | "isClosed": true, 234 | "pointRadiusBehaviour": 1, 235 | "points": Array [ 236 | Object { 237 | "_class": "curvePoint", 238 | "cornerRadius": 0, 239 | "curveFrom": "{0, 0}", 240 | "curveMode": 1, 241 | "curveTo": "{0, 0}", 242 | "hasCurveFrom": false, 243 | "hasCurveTo": false, 244 | "point": "{0, 0}", 245 | }, 246 | Object { 247 | "_class": "curvePoint", 248 | "cornerRadius": 0, 249 | "curveFrom": "{1, 0}", 250 | "curveMode": 1, 251 | "curveTo": "{1, 0}", 252 | "hasCurveFrom": false, 253 | "hasCurveTo": false, 254 | "point": "{1, 0}", 255 | }, 256 | Object { 257 | "_class": "curvePoint", 258 | "cornerRadius": 0, 259 | "curveFrom": "{1, 1}", 260 | "curveMode": 1, 261 | "curveTo": "{1, 1}", 262 | "hasCurveFrom": false, 263 | "hasCurveTo": false, 264 | "point": "{1, 1}", 265 | }, 266 | Object { 267 | "_class": "curvePoint", 268 | "cornerRadius": 0, 269 | "curveFrom": "{0, 1}", 270 | "curveMode": 1, 271 | "curveTo": "{0, 1}", 272 | "hasCurveFrom": false, 273 | "hasCurveTo": false, 274 | "point": "{0, 1}", 275 | }, 276 | ], 277 | }, 278 | "resizingConstraint": 63, 279 | "resizingType": 0, 280 | "rotation": 0, 281 | "shouldBreakMaskChain": false, 282 | }, 283 | ], 284 | "name": "/html[1]/body[1]/div[1]/div[@class=\\"symbol red\\"]", 285 | "nameIsFixed": false, 286 | "resizingConstraint": 63, 287 | "resizingType": 0, 288 | "rotation": 0, 289 | "shouldBreakMaskChain": false, 290 | "style": Object { 291 | "_class": "style", 292 | "borders": Array [ 293 | Object { 294 | "_class": "border", 295 | "color": Object { 296 | "_class": "color", 297 | "alpha": 1, 298 | "blue": 0, 299 | "green": 0, 300 | "red": 0, 301 | }, 302 | "fillType": 0, 303 | "isEnabled": true, 304 | "position": 1, 305 | "thickness": 0, 306 | }, 307 | ], 308 | "contextSettings": Object { 309 | "_class": "graphicsContextSettings", 310 | "blendMode": 0, 311 | "opacity": "1", 312 | }, 313 | "endDecorationType": 0, 314 | "fills": Array [ 315 | Object { 316 | "_class": "fill", 317 | "color": Object { 318 | "_class": "color", 319 | "alpha": 1, 320 | "blue": 0.796078431372549, 321 | "green": 0.7529411764705882, 322 | "red": 1, 323 | }, 324 | "fillType": 0, 325 | "isEnabled": true, 326 | "noiseIndex": 0, 327 | "noiseIntensity": 0, 328 | "patternFillType": 1, 329 | "patternTileScale": 1, 330 | }, 331 | ], 332 | "innerShadows": Array [], 333 | "miterLimit": 10, 334 | "shadows": Array [], 335 | "startDecorationType": 0, 336 | }, 337 | "windingRule": 1, 338 | }, 339 | Object { 340 | "_class": "text", 341 | "automaticallyDrawOnUnderlyingPath": false, 342 | "clippingMaskMode": 0, 343 | "do_objectID": "__GUID__", 344 | "dontSynchroniseWithSymbol": false, 345 | "exportOptions": Object { 346 | "_class": "exportOptions", 347 | "exportFormats": Array [], 348 | "includedLayerIds": Array [], 349 | "layerOptions": 0, 350 | "shouldTrim": false, 351 | }, 352 | "frame": Object { 353 | "_class": "rect", 354 | "constrainProportions": false, 355 | "height": 17, 356 | "width": 61.78125, 357 | "x": 20, 358 | "y": 10, 359 | }, 360 | "hasClippingMask": false, 361 | "isFlippedHorizontal": false, 362 | "isFlippedVertical": false, 363 | "isLocked": false, 364 | "isVisible": true, 365 | "layerListExpandedType": 0, 366 | "lineSpacingBehaviour": 2, 367 | "name": "Symbol 1", 368 | "nameIsFixed": false, 369 | "resizingConstraint": 47, 370 | "resizingType": 0, 371 | "rotation": 0, 372 | "shouldBreakMaskChain": false, 373 | "style": Object { 374 | "color": "rgb(0, 0, 0)", 375 | "fontFamily": "Times New Roman", 376 | "fontSize": 16, 377 | "fontWeight": 400, 378 | "textAlign": "start", 379 | "textDecoration": "none", 380 | "textTransform": "none", 381 | }, 382 | "text": "Symbol 1", 383 | "textBehaviour": 0, 384 | }, 385 | ], 386 | "name": "Symbol 1", 387 | "nameIsFixed": false, 388 | "resizesContent": false, 389 | "resizingConstraint": 63, 390 | "resizingType": 0, 391 | "rotation": 0, 392 | "shouldBreakMaskChain": false, 393 | "style": Object { 394 | "_class": "style", 395 | "endDecorationType": 0, 396 | "miterLimit": 10, 397 | "startDecorationType": 0, 398 | }, 399 | "symbolID": "__GUID__", 400 | "verticalRulerData": Object { 401 | "_class": "rulerData", 402 | "base": 0, 403 | "guides": Array [], 404 | }, 405 | }, 406 | Object { 407 | "_class": "symbolMaster", 408 | "backgroundColor": Object { 409 | "_class": "color", 410 | "alpha": 1, 411 | "blue": 1, 412 | "green": 1, 413 | "red": 1, 414 | }, 415 | "changeIdentifier": 0, 416 | "clippingMaskMode": 0, 417 | "do_objectID": "__GUID__", 418 | "exportOptions": Object { 419 | "_class": "exportOptions", 420 | "exportFormats": Array [], 421 | "includedLayerIds": Array [], 422 | "layerOptions": 0, 423 | "shouldTrim": false, 424 | }, 425 | "frame": Object { 426 | "_class": "rect", 427 | "constrainProportions": false, 428 | "height": 38, 429 | "width": 998, 430 | "x": 8, 431 | "y": 58, 432 | }, 433 | "hasBackgroundColor": false, 434 | "hasClickThrough": true, 435 | "hasClippingMask": false, 436 | "horizontalRulerData": Object { 437 | "_class": "rulerData", 438 | "base": 0, 439 | "guides": Array [], 440 | }, 441 | "includeBackgroundColorInExport": true, 442 | "includeBackgroundColorInInstance": false, 443 | "includeInCloudUpload": true, 444 | "isFlippedHorizontal": false, 445 | "isFlippedVertical": false, 446 | "isLocked": false, 447 | "isVisible": true, 448 | "layerListExpandedType": 0, 449 | "layers": Array [ 450 | Object { 451 | "_class": "shapeGroup", 452 | "clippingMaskMode": 0, 453 | "do_objectID": "__GUID__", 454 | "exportOptions": Object { 455 | "_class": "exportOptions", 456 | "exportFormats": Array [], 457 | "includedLayerIds": Array [], 458 | "layerOptions": 0, 459 | "shouldTrim": false, 460 | }, 461 | "frame": Object { 462 | "_class": "rect", 463 | "constrainProportions": false, 464 | "height": 38, 465 | "width": 988, 466 | "x": 10, 467 | "y": 0, 468 | }, 469 | "hasClickThrough": false, 470 | "hasClippingMask": false, 471 | "isFlippedHorizontal": false, 472 | "isFlippedVertical": false, 473 | "isLocked": false, 474 | "isVisible": true, 475 | "layerListExpandedType": 0, 476 | "layers": Array [ 477 | Object { 478 | "_class": "rectangle", 479 | "booleanOperation": -1, 480 | "clippingMaskMode": 0, 481 | "do_objectID": "__GUID__", 482 | "edited": false, 483 | "exportOptions": Object { 484 | "_class": "exportOptions", 485 | "exportFormats": Array [], 486 | "includedLayerIds": Array [], 487 | "layerOptions": 0, 488 | "shouldTrim": false, 489 | }, 490 | "fixedRadius": 0, 491 | "frame": Object { 492 | "_class": "rect", 493 | "constrainProportions": false, 494 | "height": 38, 495 | "width": 988, 496 | "x": 0, 497 | "y": 0, 498 | }, 499 | "hasClippingMask": false, 500 | "hasConvertedToNewRoundCorners": true, 501 | "isFlippedHorizontal": false, 502 | "isFlippedVertical": false, 503 | "isLocked": false, 504 | "isVisible": true, 505 | "layerListExpandedType": 0, 506 | "layers": Array [], 507 | "name": "rectangle", 508 | "nameIsFixed": false, 509 | "path": Object { 510 | "_class": "path", 511 | "isClosed": true, 512 | "pointRadiusBehaviour": 1, 513 | "points": Array [ 514 | Object { 515 | "_class": "curvePoint", 516 | "cornerRadius": 0, 517 | "curveFrom": "{0, 0}", 518 | "curveMode": 1, 519 | "curveTo": "{0, 0}", 520 | "hasCurveFrom": false, 521 | "hasCurveTo": false, 522 | "point": "{0, 0}", 523 | }, 524 | Object { 525 | "_class": "curvePoint", 526 | "cornerRadius": 0, 527 | "curveFrom": "{1, 0}", 528 | "curveMode": 1, 529 | "curveTo": "{1, 0}", 530 | "hasCurveFrom": false, 531 | "hasCurveTo": false, 532 | "point": "{1, 0}", 533 | }, 534 | Object { 535 | "_class": "curvePoint", 536 | "cornerRadius": 0, 537 | "curveFrom": "{1, 1}", 538 | "curveMode": 1, 539 | "curveTo": "{1, 1}", 540 | "hasCurveFrom": false, 541 | "hasCurveTo": false, 542 | "point": "{1, 1}", 543 | }, 544 | Object { 545 | "_class": "curvePoint", 546 | "cornerRadius": 0, 547 | "curveFrom": "{0, 1}", 548 | "curveMode": 1, 549 | "curveTo": "{0, 1}", 550 | "hasCurveFrom": false, 551 | "hasCurveTo": false, 552 | "point": "{0, 1}", 553 | }, 554 | ], 555 | }, 556 | "resizingConstraint": 63, 557 | "resizingType": 0, 558 | "rotation": 0, 559 | "shouldBreakMaskChain": false, 560 | }, 561 | ], 562 | "name": "/html[1]/body[1]/div[2]/div[@class=\\"symbol green\\"]", 563 | "nameIsFixed": false, 564 | "resizingConstraint": 63, 565 | "resizingType": 0, 566 | "rotation": 0, 567 | "shouldBreakMaskChain": false, 568 | "style": Object { 569 | "_class": "style", 570 | "borders": Array [ 571 | Object { 572 | "_class": "border", 573 | "color": Object { 574 | "_class": "color", 575 | "alpha": 1, 576 | "blue": 0, 577 | "green": 0, 578 | "red": 0, 579 | }, 580 | "fillType": 0, 581 | "isEnabled": true, 582 | "position": 1, 583 | "thickness": 0, 584 | }, 585 | ], 586 | "contextSettings": Object { 587 | "_class": "graphicsContextSettings", 588 | "blendMode": 0, 589 | "opacity": "1", 590 | }, 591 | "endDecorationType": 0, 592 | "fills": Array [ 593 | Object { 594 | "_class": "fill", 595 | "color": Object { 596 | "_class": "color", 597 | "alpha": 1, 598 | "blue": 0.596078431372549, 599 | "green": 0.984313725490196, 600 | "red": 0.596078431372549, 601 | }, 602 | "fillType": 0, 603 | "isEnabled": true, 604 | "noiseIndex": 0, 605 | "noiseIntensity": 0, 606 | "patternFillType": 1, 607 | "patternTileScale": 1, 608 | }, 609 | ], 610 | "innerShadows": Array [], 611 | "miterLimit": 10, 612 | "shadows": Array [], 613 | "startDecorationType": 0, 614 | }, 615 | "windingRule": 1, 616 | }, 617 | Object { 618 | "_class": "text", 619 | "automaticallyDrawOnUnderlyingPath": false, 620 | "clippingMaskMode": 0, 621 | "do_objectID": "__GUID__", 622 | "dontSynchroniseWithSymbol": false, 623 | "exportOptions": Object { 624 | "_class": "exportOptions", 625 | "exportFormats": Array [], 626 | "includedLayerIds": Array [], 627 | "layerOptions": 0, 628 | "shouldTrim": false, 629 | }, 630 | "frame": Object { 631 | "_class": "rect", 632 | "constrainProportions": false, 633 | "height": 17, 634 | "width": 61.78125, 635 | "x": 20, 636 | "y": 10, 637 | }, 638 | "hasClippingMask": false, 639 | "isFlippedHorizontal": false, 640 | "isFlippedVertical": false, 641 | "isLocked": false, 642 | "isVisible": true, 643 | "layerListExpandedType": 0, 644 | "lineSpacingBehaviour": 2, 645 | "name": "Symbol 2", 646 | "nameIsFixed": false, 647 | "resizingConstraint": 47, 648 | "resizingType": 0, 649 | "rotation": 0, 650 | "shouldBreakMaskChain": false, 651 | "style": Object { 652 | "color": "rgb(0, 0, 0)", 653 | "fontFamily": "Times New Roman", 654 | "fontSize": 16, 655 | "fontWeight": 400, 656 | "textAlign": "start", 657 | "textDecoration": "none", 658 | "textTransform": "none", 659 | }, 660 | "text": "Symbol 2", 661 | "textBehaviour": 0, 662 | }, 663 | ], 664 | "name": "Symbol 2", 665 | "nameIsFixed": false, 666 | "resizesContent": false, 667 | "resizingConstraint": 63, 668 | "resizingType": 0, 669 | "rotation": 0, 670 | "shouldBreakMaskChain": false, 671 | "style": Object { 672 | "_class": "style", 673 | "endDecorationType": 0, 674 | "miterLimit": 10, 675 | "startDecorationType": 0, 676 | }, 677 | "symbolID": "__GUID__", 678 | "verticalRulerData": Object { 679 | "_class": "rulerData", 680 | "base": 0, 681 | "guides": Array [], 682 | }, 683 | }, 684 | Object { 685 | "_class": "symbolMaster", 686 | "backgroundColor": Object { 687 | "_class": "color", 688 | "alpha": 1, 689 | "blue": 1, 690 | "green": 1, 691 | "red": 1, 692 | }, 693 | "changeIdentifier": 0, 694 | "clippingMaskMode": 0, 695 | "do_objectID": "__GUID__", 696 | "exportOptions": Object { 697 | "_class": "exportOptions", 698 | "exportFormats": Array [], 699 | "includedLayerIds": Array [], 700 | "layerOptions": 0, 701 | "shouldTrim": false, 702 | }, 703 | "frame": Object { 704 | "_class": "rect", 705 | "constrainProportions": false, 706 | "height": 38, 707 | "width": 998, 708 | "x": 8, 709 | "y": 106, 710 | }, 711 | "hasBackgroundColor": false, 712 | "hasClickThrough": true, 713 | "hasClippingMask": false, 714 | "horizontalRulerData": Object { 715 | "_class": "rulerData", 716 | "base": 0, 717 | "guides": Array [], 718 | }, 719 | "includeBackgroundColorInExport": true, 720 | "includeBackgroundColorInInstance": false, 721 | "includeInCloudUpload": true, 722 | "isFlippedHorizontal": false, 723 | "isFlippedVertical": false, 724 | "isLocked": false, 725 | "isVisible": true, 726 | "layerListExpandedType": 0, 727 | "layers": Array [ 728 | Object { 729 | "_class": "shapeGroup", 730 | "clippingMaskMode": 0, 731 | "do_objectID": "__GUID__", 732 | "exportOptions": Object { 733 | "_class": "exportOptions", 734 | "exportFormats": Array [], 735 | "includedLayerIds": Array [], 736 | "layerOptions": 0, 737 | "shouldTrim": false, 738 | }, 739 | "frame": Object { 740 | "_class": "rect", 741 | "constrainProportions": false, 742 | "height": 38, 743 | "width": 988, 744 | "x": 10, 745 | "y": 0, 746 | }, 747 | "hasClickThrough": false, 748 | "hasClippingMask": false, 749 | "isFlippedHorizontal": false, 750 | "isFlippedVertical": false, 751 | "isLocked": false, 752 | "isVisible": true, 753 | "layerListExpandedType": 0, 754 | "layers": Array [ 755 | Object { 756 | "_class": "rectangle", 757 | "booleanOperation": -1, 758 | "clippingMaskMode": 0, 759 | "do_objectID": "__GUID__", 760 | "edited": false, 761 | "exportOptions": Object { 762 | "_class": "exportOptions", 763 | "exportFormats": Array [], 764 | "includedLayerIds": Array [], 765 | "layerOptions": 0, 766 | "shouldTrim": false, 767 | }, 768 | "fixedRadius": 0, 769 | "frame": Object { 770 | "_class": "rect", 771 | "constrainProportions": false, 772 | "height": 38, 773 | "width": 988, 774 | "x": 0, 775 | "y": 0, 776 | }, 777 | "hasClippingMask": false, 778 | "hasConvertedToNewRoundCorners": true, 779 | "isFlippedHorizontal": false, 780 | "isFlippedVertical": false, 781 | "isLocked": false, 782 | "isVisible": true, 783 | "layerListExpandedType": 0, 784 | "layers": Array [], 785 | "name": "rectangle", 786 | "nameIsFixed": false, 787 | "path": Object { 788 | "_class": "path", 789 | "isClosed": true, 790 | "pointRadiusBehaviour": 1, 791 | "points": Array [ 792 | Object { 793 | "_class": "curvePoint", 794 | "cornerRadius": 0, 795 | "curveFrom": "{0, 0}", 796 | "curveMode": 1, 797 | "curveTo": "{0, 0}", 798 | "hasCurveFrom": false, 799 | "hasCurveTo": false, 800 | "point": "{0, 0}", 801 | }, 802 | Object { 803 | "_class": "curvePoint", 804 | "cornerRadius": 0, 805 | "curveFrom": "{1, 0}", 806 | "curveMode": 1, 807 | "curveTo": "{1, 0}", 808 | "hasCurveFrom": false, 809 | "hasCurveTo": false, 810 | "point": "{1, 0}", 811 | }, 812 | Object { 813 | "_class": "curvePoint", 814 | "cornerRadius": 0, 815 | "curveFrom": "{1, 1}", 816 | "curveMode": 1, 817 | "curveTo": "{1, 1}", 818 | "hasCurveFrom": false, 819 | "hasCurveTo": false, 820 | "point": "{1, 1}", 821 | }, 822 | Object { 823 | "_class": "curvePoint", 824 | "cornerRadius": 0, 825 | "curveFrom": "{0, 1}", 826 | "curveMode": 1, 827 | "curveTo": "{0, 1}", 828 | "hasCurveFrom": false, 829 | "hasCurveTo": false, 830 | "point": "{0, 1}", 831 | }, 832 | ], 833 | }, 834 | "resizingConstraint": 63, 835 | "resizingType": 0, 836 | "rotation": 0, 837 | "shouldBreakMaskChain": false, 838 | }, 839 | ], 840 | "name": "/html[1]/body[1]/div[3]/div[@class=\\"symbol blue\\"]", 841 | "nameIsFixed": false, 842 | "resizingConstraint": 63, 843 | "resizingType": 0, 844 | "rotation": 0, 845 | "shouldBreakMaskChain": false, 846 | "style": Object { 847 | "_class": "style", 848 | "borders": Array [ 849 | Object { 850 | "_class": "border", 851 | "color": Object { 852 | "_class": "color", 853 | "alpha": 1, 854 | "blue": 0, 855 | "green": 0, 856 | "red": 0, 857 | }, 858 | "fillType": 0, 859 | "isEnabled": true, 860 | "position": 1, 861 | "thickness": 0, 862 | }, 863 | ], 864 | "contextSettings": Object { 865 | "_class": "graphicsContextSettings", 866 | "blendMode": 0, 867 | "opacity": "1", 868 | }, 869 | "endDecorationType": 0, 870 | "fills": Array [ 871 | Object { 872 | "_class": "fill", 873 | "color": Object { 874 | "_class": "color", 875 | "alpha": 1, 876 | "blue": 1, 877 | "green": 1, 878 | "red": 0, 879 | }, 880 | "fillType": 0, 881 | "isEnabled": true, 882 | "noiseIndex": 0, 883 | "noiseIntensity": 0, 884 | "patternFillType": 1, 885 | "patternTileScale": 1, 886 | }, 887 | ], 888 | "innerShadows": Array [], 889 | "miterLimit": 10, 890 | "shadows": Array [], 891 | "startDecorationType": 0, 892 | }, 893 | "windingRule": 1, 894 | }, 895 | Object { 896 | "_class": "text", 897 | "automaticallyDrawOnUnderlyingPath": false, 898 | "clippingMaskMode": 0, 899 | "do_objectID": "__GUID__", 900 | "dontSynchroniseWithSymbol": false, 901 | "exportOptions": Object { 902 | "_class": "exportOptions", 903 | "exportFormats": Array [], 904 | "includedLayerIds": Array [], 905 | "layerOptions": 0, 906 | "shouldTrim": false, 907 | }, 908 | "frame": Object { 909 | "_class": "rect", 910 | "constrainProportions": false, 911 | "height": 17, 912 | "width": 61.78125, 913 | "x": 20, 914 | "y": 10, 915 | }, 916 | "hasClippingMask": false, 917 | "isFlippedHorizontal": false, 918 | "isFlippedVertical": false, 919 | "isLocked": false, 920 | "isVisible": true, 921 | "layerListExpandedType": 0, 922 | "lineSpacingBehaviour": 2, 923 | "name": "Symbol 3", 924 | "nameIsFixed": false, 925 | "resizingConstraint": 47, 926 | "resizingType": 0, 927 | "rotation": 0, 928 | "shouldBreakMaskChain": false, 929 | "style": Object { 930 | "color": "rgb(0, 0, 0)", 931 | "fontFamily": "Times New Roman", 932 | "fontSize": 16, 933 | "fontWeight": 400, 934 | "textAlign": "start", 935 | "textDecoration": "none", 936 | "textTransform": "none", 937 | }, 938 | "text": "Symbol 3", 939 | "textBehaviour": 0, 940 | }, 941 | ], 942 | "name": "Symbol 3", 943 | "nameIsFixed": false, 944 | "resizesContent": false, 945 | "resizingConstraint": 63, 946 | "resizingType": 0, 947 | "rotation": 0, 948 | "shouldBreakMaskChain": false, 949 | "style": Object { 950 | "_class": "style", 951 | "endDecorationType": 0, 952 | "miterLimit": 10, 953 | "startDecorationType": 0, 954 | }, 955 | "symbolID": "__GUID__", 956 | "verticalRulerData": Object { 957 | "_class": "rulerData", 958 | "base": 0, 959 | "guides": Array [], 960 | }, 961 | }, 962 | ], 963 | "name": "html-sketchapp symbols", 964 | "nameIsFixed": false, 965 | "resizingConstraint": 63, 966 | "resizingType": 0, 967 | "rotation": 0, 968 | "shouldBreakMaskChain": false, 969 | "style": Object { 970 | "_class": "style", 971 | "endDecorationType": 0, 972 | "miterLimit": 10, 973 | "startDecorationType": 0, 974 | }, 975 | "verticalRulerData": Object { 976 | "_class": "rulerData", 977 | "base": 0, 978 | "guides": Array [], 979 | }, 980 | }, 981 | } 982 | `; 983 | -------------------------------------------------------------------------------- /test/file/file.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | test('file', async () => { 12 | await exec('node ../../bin/cli --puppeteer-args="--no-sandbox --disable-setuid-sandbox" --out-dir dist --file index.html', { cwd: __dirname }); 13 | 14 | const output = await dirContentsToObject(distPath); 15 | expect(output).toMatchSnapshot(); 16 | }); 17 | -------------------------------------------------------------------------------- /test/file/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
Symbol 1
23 |
Symbol 2
24 |
Symbol 3
25 | 26 |

Text 1

27 |

Text 2

28 |

Text 3

29 | 30 |
Color 1
31 |
Color 2
32 |
Color 3
33 | 34 | 35 | -------------------------------------------------------------------------------- /test/nested-symbols/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 |
A
16 |
B
17 | 18 |
19 |
20 |
A
21 |
B
22 |
23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /test/nested-symbols/nested-symbols.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | test('fails when referencing unknown Symbol', (done) => { 12 | exec( 13 | [ 14 | 'node ../../bin/cli', 15 | '--puppeteer-args="--no-sandbox --disable-setuid-sandbox"', 16 | '--out-dir dist', 17 | '--file unknown-symbol.html' 18 | ].join(' '), 19 | { cwd: __dirname } 20 | ).catch(err => { 21 | expect(err.stderr).toMatch('Unknown symbol master: Some Symbol'); 22 | done(); 23 | }); 24 | }); 25 | 26 | test('generates symbolInstance nodes', async () => { 27 | await exec( 28 | [ 29 | 'node ../../bin/cli', 30 | '--puppeteer-args="--no-sandbox --disable-setuid-sandbox"', 31 | '--out-dir dist', 32 | '--file index.html', 33 | '--viewports.Desktop 1024x768', 34 | '--viewports.Mobile 320x568' 35 | ].join(' '), 36 | { cwd: __dirname } 37 | ); 38 | 39 | const output = await dirContentsToObject(distPath); 40 | expect(output).toMatchSnapshot(); 41 | }); 42 | -------------------------------------------------------------------------------- /test/nested-symbols/unknown-symbol.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 |
A
7 |
8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /test/serve-with-url/serve-me/another-url/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
Symbol 1
23 |
Symbol 2
24 |
Symbol 3
25 | 26 |

Text 1

27 |

Text 2

28 |

Text 3

29 | 30 |
Color 1
31 |
Color 2
32 |
Color 3
33 | 34 | 35 | -------------------------------------------------------------------------------- /test/serve-with-url/serve-me/index.html: -------------------------------------------------------------------------------- 1 | Nothing to see here. 2 | -------------------------------------------------------------------------------- /test/serve-with-url/serve-with-url.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | test('serve-with-url', async () => { 12 | await exec('node ../../bin/cli --puppeteer-args="--no-sandbox --disable-setuid-sandbox" --out-dir dist --serve serve-me --url /another-url', { cwd: __dirname }); 13 | 14 | const output = await dirContentsToObject(distPath); 15 | expect(output).toMatchSnapshot(); 16 | }); 17 | -------------------------------------------------------------------------------- /test/serve/__snapshots__/serve.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`serve 1`] = ` 4 | Object { 5 | "document.asketch.json": Object { 6 | "_class": "document", 7 | "assets": Object { 8 | "_class": "assetCollection", 9 | "colors": Array [ 10 | Object { 11 | "_class": "color", 12 | "alpha": 1, 13 | "blue": 0, 14 | "green": 0, 15 | "red": 1, 16 | }, 17 | Object { 18 | "_class": "color", 19 | "alpha": 1, 20 | "blue": 0, 21 | "green": 1, 22 | "red": 0, 23 | }, 24 | Object { 25 | "_class": "color", 26 | "alpha": 1, 27 | "blue": 1, 28 | "green": 0, 29 | "red": 0, 30 | }, 31 | ], 32 | }, 33 | "currentPageIndex": 0, 34 | "do_objectID": "__GUID__", 35 | "enableLayerInteraction": true, 36 | "enableSliceInteraction": true, 37 | "foreignSymbols": Array [], 38 | "layerStyles": Object { 39 | "_class": "sharedStyleContainer", 40 | "objects": Array [], 41 | }, 42 | "layerSymbols": Object { 43 | "_class": "symbolContainer", 44 | "objects": Array [], 45 | }, 46 | "layerTextStyles": Object { 47 | "_class": "sharedTextStyleContainer", 48 | "objects": Array [ 49 | Object { 50 | "_class": "sharedStyle", 51 | "do_objectID": "__GUID__", 52 | "name": "Text 1", 53 | "style": Object { 54 | "color": "rgb(0, 0, 0)", 55 | "fontFamily": "Times New Roman", 56 | "fontSize": 40, 57 | "fontWeight": 700, 58 | "textAlign": "start", 59 | "textDecoration": "none", 60 | "textTransform": "none", 61 | }, 62 | }, 63 | Object { 64 | "_class": "sharedStyle", 65 | "do_objectID": "__GUID__", 66 | "name": "Text 2", 67 | "style": Object { 68 | "color": "rgb(0, 0, 0)", 69 | "fontFamily": "Times New Roman", 70 | "fontSize": 30, 71 | "fontWeight": 700, 72 | "textAlign": "start", 73 | "textDecoration": "none", 74 | "textTransform": "none", 75 | }, 76 | }, 77 | Object { 78 | "_class": "sharedStyle", 79 | "do_objectID": "__GUID__", 80 | "name": "Text 3", 81 | "style": Object { 82 | "color": "rgb(0, 0, 0)", 83 | "fontFamily": "Times New Roman", 84 | "fontSize": 20, 85 | "fontWeight": 700, 86 | "textAlign": "start", 87 | "textDecoration": "none", 88 | "textTransform": "none", 89 | }, 90 | }, 91 | ], 92 | }, 93 | "pages": Array [], 94 | }, 95 | "document.page.json": Object { 96 | "_class": "page", 97 | "clippingMaskMode": 0, 98 | "do_objectID": "__GUID__", 99 | "exportOptions": Object { 100 | "_class": "exportOptions", 101 | "exportFormats": Array [], 102 | "includedLayerIds": Array [], 103 | "layerOptions": 0, 104 | "shouldTrim": false, 105 | }, 106 | "frame": Object { 107 | "_class": "rect", 108 | "constrainProportions": false, 109 | "height": 352, 110 | "width": 784, 111 | "x": 0, 112 | "y": 0, 113 | }, 114 | "hasClickThrough": true, 115 | "hasClippingMask": false, 116 | "horizontalRulerData": Object { 117 | "_class": "rulerData", 118 | "base": 0, 119 | "guides": Array [], 120 | }, 121 | "includeInCloudUpload": true, 122 | "isFlippedHorizontal": false, 123 | "isFlippedVertical": false, 124 | "isLocked": false, 125 | "isVisible": true, 126 | "layerListExpandedType": 0, 127 | "layers": Array [ 128 | Object { 129 | "_class": "symbolMaster", 130 | "backgroundColor": Object { 131 | "_class": "color", 132 | "alpha": 1, 133 | "blue": 1, 134 | "green": 1, 135 | "red": 1, 136 | }, 137 | "changeIdentifier": 0, 138 | "clippingMaskMode": 0, 139 | "do_objectID": "__GUID__", 140 | "exportOptions": Object { 141 | "_class": "exportOptions", 142 | "exportFormats": Array [], 143 | "includedLayerIds": Array [], 144 | "layerOptions": 0, 145 | "shouldTrim": false, 146 | }, 147 | "frame": Object { 148 | "_class": "rect", 149 | "constrainProportions": false, 150 | "height": 38, 151 | "width": 998, 152 | "x": 8, 153 | "y": 10, 154 | }, 155 | "hasBackgroundColor": false, 156 | "hasClickThrough": true, 157 | "hasClippingMask": false, 158 | "horizontalRulerData": Object { 159 | "_class": "rulerData", 160 | "base": 0, 161 | "guides": Array [], 162 | }, 163 | "includeBackgroundColorInExport": true, 164 | "includeBackgroundColorInInstance": false, 165 | "includeInCloudUpload": true, 166 | "isFlippedHorizontal": false, 167 | "isFlippedVertical": false, 168 | "isLocked": false, 169 | "isVisible": true, 170 | "layerListExpandedType": 0, 171 | "layers": Array [ 172 | Object { 173 | "_class": "shapeGroup", 174 | "clippingMaskMode": 0, 175 | "do_objectID": "__GUID__", 176 | "exportOptions": Object { 177 | "_class": "exportOptions", 178 | "exportFormats": Array [], 179 | "includedLayerIds": Array [], 180 | "layerOptions": 0, 181 | "shouldTrim": false, 182 | }, 183 | "frame": Object { 184 | "_class": "rect", 185 | "constrainProportions": false, 186 | "height": 38, 187 | "width": 988, 188 | "x": 10, 189 | "y": 0, 190 | }, 191 | "hasClickThrough": false, 192 | "hasClippingMask": false, 193 | "isFlippedHorizontal": false, 194 | "isFlippedVertical": false, 195 | "isLocked": false, 196 | "isVisible": true, 197 | "layerListExpandedType": 0, 198 | "layers": Array [ 199 | Object { 200 | "_class": "rectangle", 201 | "booleanOperation": -1, 202 | "clippingMaskMode": 0, 203 | "do_objectID": "__GUID__", 204 | "edited": false, 205 | "exportOptions": Object { 206 | "_class": "exportOptions", 207 | "exportFormats": Array [], 208 | "includedLayerIds": Array [], 209 | "layerOptions": 0, 210 | "shouldTrim": false, 211 | }, 212 | "fixedRadius": 0, 213 | "frame": Object { 214 | "_class": "rect", 215 | "constrainProportions": false, 216 | "height": 38, 217 | "width": 988, 218 | "x": 0, 219 | "y": 0, 220 | }, 221 | "hasClippingMask": false, 222 | "hasConvertedToNewRoundCorners": true, 223 | "isFlippedHorizontal": false, 224 | "isFlippedVertical": false, 225 | "isLocked": false, 226 | "isVisible": true, 227 | "layerListExpandedType": 0, 228 | "layers": Array [], 229 | "name": "rectangle", 230 | "nameIsFixed": false, 231 | "path": Object { 232 | "_class": "path", 233 | "isClosed": true, 234 | "pointRadiusBehaviour": 1, 235 | "points": Array [ 236 | Object { 237 | "_class": "curvePoint", 238 | "cornerRadius": 0, 239 | "curveFrom": "{0, 0}", 240 | "curveMode": 1, 241 | "curveTo": "{0, 0}", 242 | "hasCurveFrom": false, 243 | "hasCurveTo": false, 244 | "point": "{0, 0}", 245 | }, 246 | Object { 247 | "_class": "curvePoint", 248 | "cornerRadius": 0, 249 | "curveFrom": "{1, 0}", 250 | "curveMode": 1, 251 | "curveTo": "{1, 0}", 252 | "hasCurveFrom": false, 253 | "hasCurveTo": false, 254 | "point": "{1, 0}", 255 | }, 256 | Object { 257 | "_class": "curvePoint", 258 | "cornerRadius": 0, 259 | "curveFrom": "{1, 1}", 260 | "curveMode": 1, 261 | "curveTo": "{1, 1}", 262 | "hasCurveFrom": false, 263 | "hasCurveTo": false, 264 | "point": "{1, 1}", 265 | }, 266 | Object { 267 | "_class": "curvePoint", 268 | "cornerRadius": 0, 269 | "curveFrom": "{0, 1}", 270 | "curveMode": 1, 271 | "curveTo": "{0, 1}", 272 | "hasCurveFrom": false, 273 | "hasCurveTo": false, 274 | "point": "{0, 1}", 275 | }, 276 | ], 277 | }, 278 | "resizingConstraint": 63, 279 | "resizingType": 0, 280 | "rotation": 0, 281 | "shouldBreakMaskChain": false, 282 | }, 283 | ], 284 | "name": "/html[1]/body[1]/div[1]/div[@class=\\"symbol red\\"]", 285 | "nameIsFixed": false, 286 | "resizingConstraint": 63, 287 | "resizingType": 0, 288 | "rotation": 0, 289 | "shouldBreakMaskChain": false, 290 | "style": Object { 291 | "_class": "style", 292 | "borders": Array [ 293 | Object { 294 | "_class": "border", 295 | "color": Object { 296 | "_class": "color", 297 | "alpha": 1, 298 | "blue": 0, 299 | "green": 0, 300 | "red": 0, 301 | }, 302 | "fillType": 0, 303 | "isEnabled": true, 304 | "position": 1, 305 | "thickness": 0, 306 | }, 307 | ], 308 | "contextSettings": Object { 309 | "_class": "graphicsContextSettings", 310 | "blendMode": 0, 311 | "opacity": "1", 312 | }, 313 | "endDecorationType": 0, 314 | "fills": Array [ 315 | Object { 316 | "_class": "fill", 317 | "color": Object { 318 | "_class": "color", 319 | "alpha": 1, 320 | "blue": 0.796078431372549, 321 | "green": 0.7529411764705882, 322 | "red": 1, 323 | }, 324 | "fillType": 0, 325 | "isEnabled": true, 326 | "noiseIndex": 0, 327 | "noiseIntensity": 0, 328 | "patternFillType": 1, 329 | "patternTileScale": 1, 330 | }, 331 | ], 332 | "innerShadows": Array [], 333 | "miterLimit": 10, 334 | "shadows": Array [], 335 | "startDecorationType": 0, 336 | }, 337 | "windingRule": 1, 338 | }, 339 | Object { 340 | "_class": "text", 341 | "automaticallyDrawOnUnderlyingPath": false, 342 | "clippingMaskMode": 0, 343 | "do_objectID": "__GUID__", 344 | "dontSynchroniseWithSymbol": false, 345 | "exportOptions": Object { 346 | "_class": "exportOptions", 347 | "exportFormats": Array [], 348 | "includedLayerIds": Array [], 349 | "layerOptions": 0, 350 | "shouldTrim": false, 351 | }, 352 | "frame": Object { 353 | "_class": "rect", 354 | "constrainProportions": false, 355 | "height": 17, 356 | "width": 61.78125, 357 | "x": 20, 358 | "y": 10, 359 | }, 360 | "hasClippingMask": false, 361 | "isFlippedHorizontal": false, 362 | "isFlippedVertical": false, 363 | "isLocked": false, 364 | "isVisible": true, 365 | "layerListExpandedType": 0, 366 | "lineSpacingBehaviour": 2, 367 | "name": "Symbol 1", 368 | "nameIsFixed": false, 369 | "resizingConstraint": 47, 370 | "resizingType": 0, 371 | "rotation": 0, 372 | "shouldBreakMaskChain": false, 373 | "style": Object { 374 | "color": "rgb(0, 0, 0)", 375 | "fontFamily": "Times New Roman", 376 | "fontSize": 16, 377 | "fontWeight": 400, 378 | "textAlign": "start", 379 | "textDecoration": "none", 380 | "textTransform": "none", 381 | }, 382 | "text": "Symbol 1", 383 | "textBehaviour": 0, 384 | }, 385 | ], 386 | "name": "Symbol 1", 387 | "nameIsFixed": false, 388 | "resizesContent": false, 389 | "resizingConstraint": 63, 390 | "resizingType": 0, 391 | "rotation": 0, 392 | "shouldBreakMaskChain": false, 393 | "style": Object { 394 | "_class": "style", 395 | "endDecorationType": 0, 396 | "miterLimit": 10, 397 | "startDecorationType": 0, 398 | }, 399 | "symbolID": "__GUID__", 400 | "verticalRulerData": Object { 401 | "_class": "rulerData", 402 | "base": 0, 403 | "guides": Array [], 404 | }, 405 | }, 406 | Object { 407 | "_class": "symbolMaster", 408 | "backgroundColor": Object { 409 | "_class": "color", 410 | "alpha": 1, 411 | "blue": 1, 412 | "green": 1, 413 | "red": 1, 414 | }, 415 | "changeIdentifier": 0, 416 | "clippingMaskMode": 0, 417 | "do_objectID": "__GUID__", 418 | "exportOptions": Object { 419 | "_class": "exportOptions", 420 | "exportFormats": Array [], 421 | "includedLayerIds": Array [], 422 | "layerOptions": 0, 423 | "shouldTrim": false, 424 | }, 425 | "frame": Object { 426 | "_class": "rect", 427 | "constrainProportions": false, 428 | "height": 38, 429 | "width": 998, 430 | "x": 8, 431 | "y": 58, 432 | }, 433 | "hasBackgroundColor": false, 434 | "hasClickThrough": true, 435 | "hasClippingMask": false, 436 | "horizontalRulerData": Object { 437 | "_class": "rulerData", 438 | "base": 0, 439 | "guides": Array [], 440 | }, 441 | "includeBackgroundColorInExport": true, 442 | "includeBackgroundColorInInstance": false, 443 | "includeInCloudUpload": true, 444 | "isFlippedHorizontal": false, 445 | "isFlippedVertical": false, 446 | "isLocked": false, 447 | "isVisible": true, 448 | "layerListExpandedType": 0, 449 | "layers": Array [ 450 | Object { 451 | "_class": "shapeGroup", 452 | "clippingMaskMode": 0, 453 | "do_objectID": "__GUID__", 454 | "exportOptions": Object { 455 | "_class": "exportOptions", 456 | "exportFormats": Array [], 457 | "includedLayerIds": Array [], 458 | "layerOptions": 0, 459 | "shouldTrim": false, 460 | }, 461 | "frame": Object { 462 | "_class": "rect", 463 | "constrainProportions": false, 464 | "height": 38, 465 | "width": 988, 466 | "x": 10, 467 | "y": 0, 468 | }, 469 | "hasClickThrough": false, 470 | "hasClippingMask": false, 471 | "isFlippedHorizontal": false, 472 | "isFlippedVertical": false, 473 | "isLocked": false, 474 | "isVisible": true, 475 | "layerListExpandedType": 0, 476 | "layers": Array [ 477 | Object { 478 | "_class": "rectangle", 479 | "booleanOperation": -1, 480 | "clippingMaskMode": 0, 481 | "do_objectID": "__GUID__", 482 | "edited": false, 483 | "exportOptions": Object { 484 | "_class": "exportOptions", 485 | "exportFormats": Array [], 486 | "includedLayerIds": Array [], 487 | "layerOptions": 0, 488 | "shouldTrim": false, 489 | }, 490 | "fixedRadius": 0, 491 | "frame": Object { 492 | "_class": "rect", 493 | "constrainProportions": false, 494 | "height": 38, 495 | "width": 988, 496 | "x": 0, 497 | "y": 0, 498 | }, 499 | "hasClippingMask": false, 500 | "hasConvertedToNewRoundCorners": true, 501 | "isFlippedHorizontal": false, 502 | "isFlippedVertical": false, 503 | "isLocked": false, 504 | "isVisible": true, 505 | "layerListExpandedType": 0, 506 | "layers": Array [], 507 | "name": "rectangle", 508 | "nameIsFixed": false, 509 | "path": Object { 510 | "_class": "path", 511 | "isClosed": true, 512 | "pointRadiusBehaviour": 1, 513 | "points": Array [ 514 | Object { 515 | "_class": "curvePoint", 516 | "cornerRadius": 0, 517 | "curveFrom": "{0, 0}", 518 | "curveMode": 1, 519 | "curveTo": "{0, 0}", 520 | "hasCurveFrom": false, 521 | "hasCurveTo": false, 522 | "point": "{0, 0}", 523 | }, 524 | Object { 525 | "_class": "curvePoint", 526 | "cornerRadius": 0, 527 | "curveFrom": "{1, 0}", 528 | "curveMode": 1, 529 | "curveTo": "{1, 0}", 530 | "hasCurveFrom": false, 531 | "hasCurveTo": false, 532 | "point": "{1, 0}", 533 | }, 534 | Object { 535 | "_class": "curvePoint", 536 | "cornerRadius": 0, 537 | "curveFrom": "{1, 1}", 538 | "curveMode": 1, 539 | "curveTo": "{1, 1}", 540 | "hasCurveFrom": false, 541 | "hasCurveTo": false, 542 | "point": "{1, 1}", 543 | }, 544 | Object { 545 | "_class": "curvePoint", 546 | "cornerRadius": 0, 547 | "curveFrom": "{0, 1}", 548 | "curveMode": 1, 549 | "curveTo": "{0, 1}", 550 | "hasCurveFrom": false, 551 | "hasCurveTo": false, 552 | "point": "{0, 1}", 553 | }, 554 | ], 555 | }, 556 | "resizingConstraint": 63, 557 | "resizingType": 0, 558 | "rotation": 0, 559 | "shouldBreakMaskChain": false, 560 | }, 561 | ], 562 | "name": "/html[1]/body[1]/div[2]/div[@class=\\"symbol green\\"]", 563 | "nameIsFixed": false, 564 | "resizingConstraint": 63, 565 | "resizingType": 0, 566 | "rotation": 0, 567 | "shouldBreakMaskChain": false, 568 | "style": Object { 569 | "_class": "style", 570 | "borders": Array [ 571 | Object { 572 | "_class": "border", 573 | "color": Object { 574 | "_class": "color", 575 | "alpha": 1, 576 | "blue": 0, 577 | "green": 0, 578 | "red": 0, 579 | }, 580 | "fillType": 0, 581 | "isEnabled": true, 582 | "position": 1, 583 | "thickness": 0, 584 | }, 585 | ], 586 | "contextSettings": Object { 587 | "_class": "graphicsContextSettings", 588 | "blendMode": 0, 589 | "opacity": "1", 590 | }, 591 | "endDecorationType": 0, 592 | "fills": Array [ 593 | Object { 594 | "_class": "fill", 595 | "color": Object { 596 | "_class": "color", 597 | "alpha": 1, 598 | "blue": 0.596078431372549, 599 | "green": 0.984313725490196, 600 | "red": 0.596078431372549, 601 | }, 602 | "fillType": 0, 603 | "isEnabled": true, 604 | "noiseIndex": 0, 605 | "noiseIntensity": 0, 606 | "patternFillType": 1, 607 | "patternTileScale": 1, 608 | }, 609 | ], 610 | "innerShadows": Array [], 611 | "miterLimit": 10, 612 | "shadows": Array [], 613 | "startDecorationType": 0, 614 | }, 615 | "windingRule": 1, 616 | }, 617 | Object { 618 | "_class": "text", 619 | "automaticallyDrawOnUnderlyingPath": false, 620 | "clippingMaskMode": 0, 621 | "do_objectID": "__GUID__", 622 | "dontSynchroniseWithSymbol": false, 623 | "exportOptions": Object { 624 | "_class": "exportOptions", 625 | "exportFormats": Array [], 626 | "includedLayerIds": Array [], 627 | "layerOptions": 0, 628 | "shouldTrim": false, 629 | }, 630 | "frame": Object { 631 | "_class": "rect", 632 | "constrainProportions": false, 633 | "height": 17, 634 | "width": 61.78125, 635 | "x": 20, 636 | "y": 10, 637 | }, 638 | "hasClippingMask": false, 639 | "isFlippedHorizontal": false, 640 | "isFlippedVertical": false, 641 | "isLocked": false, 642 | "isVisible": true, 643 | "layerListExpandedType": 0, 644 | "lineSpacingBehaviour": 2, 645 | "name": "Symbol 2", 646 | "nameIsFixed": false, 647 | "resizingConstraint": 47, 648 | "resizingType": 0, 649 | "rotation": 0, 650 | "shouldBreakMaskChain": false, 651 | "style": Object { 652 | "color": "rgb(0, 0, 0)", 653 | "fontFamily": "Times New Roman", 654 | "fontSize": 16, 655 | "fontWeight": 400, 656 | "textAlign": "start", 657 | "textDecoration": "none", 658 | "textTransform": "none", 659 | }, 660 | "text": "Symbol 2", 661 | "textBehaviour": 0, 662 | }, 663 | ], 664 | "name": "Symbol 2", 665 | "nameIsFixed": false, 666 | "resizesContent": false, 667 | "resizingConstraint": 63, 668 | "resizingType": 0, 669 | "rotation": 0, 670 | "shouldBreakMaskChain": false, 671 | "style": Object { 672 | "_class": "style", 673 | "endDecorationType": 0, 674 | "miterLimit": 10, 675 | "startDecorationType": 0, 676 | }, 677 | "symbolID": "__GUID__", 678 | "verticalRulerData": Object { 679 | "_class": "rulerData", 680 | "base": 0, 681 | "guides": Array [], 682 | }, 683 | }, 684 | Object { 685 | "_class": "symbolMaster", 686 | "backgroundColor": Object { 687 | "_class": "color", 688 | "alpha": 1, 689 | "blue": 1, 690 | "green": 1, 691 | "red": 1, 692 | }, 693 | "changeIdentifier": 0, 694 | "clippingMaskMode": 0, 695 | "do_objectID": "__GUID__", 696 | "exportOptions": Object { 697 | "_class": "exportOptions", 698 | "exportFormats": Array [], 699 | "includedLayerIds": Array [], 700 | "layerOptions": 0, 701 | "shouldTrim": false, 702 | }, 703 | "frame": Object { 704 | "_class": "rect", 705 | "constrainProportions": false, 706 | "height": 38, 707 | "width": 998, 708 | "x": 8, 709 | "y": 106, 710 | }, 711 | "hasBackgroundColor": false, 712 | "hasClickThrough": true, 713 | "hasClippingMask": false, 714 | "horizontalRulerData": Object { 715 | "_class": "rulerData", 716 | "base": 0, 717 | "guides": Array [], 718 | }, 719 | "includeBackgroundColorInExport": true, 720 | "includeBackgroundColorInInstance": false, 721 | "includeInCloudUpload": true, 722 | "isFlippedHorizontal": false, 723 | "isFlippedVertical": false, 724 | "isLocked": false, 725 | "isVisible": true, 726 | "layerListExpandedType": 0, 727 | "layers": Array [ 728 | Object { 729 | "_class": "shapeGroup", 730 | "clippingMaskMode": 0, 731 | "do_objectID": "__GUID__", 732 | "exportOptions": Object { 733 | "_class": "exportOptions", 734 | "exportFormats": Array [], 735 | "includedLayerIds": Array [], 736 | "layerOptions": 0, 737 | "shouldTrim": false, 738 | }, 739 | "frame": Object { 740 | "_class": "rect", 741 | "constrainProportions": false, 742 | "height": 38, 743 | "width": 988, 744 | "x": 10, 745 | "y": 0, 746 | }, 747 | "hasClickThrough": false, 748 | "hasClippingMask": false, 749 | "isFlippedHorizontal": false, 750 | "isFlippedVertical": false, 751 | "isLocked": false, 752 | "isVisible": true, 753 | "layerListExpandedType": 0, 754 | "layers": Array [ 755 | Object { 756 | "_class": "rectangle", 757 | "booleanOperation": -1, 758 | "clippingMaskMode": 0, 759 | "do_objectID": "__GUID__", 760 | "edited": false, 761 | "exportOptions": Object { 762 | "_class": "exportOptions", 763 | "exportFormats": Array [], 764 | "includedLayerIds": Array [], 765 | "layerOptions": 0, 766 | "shouldTrim": false, 767 | }, 768 | "fixedRadius": 0, 769 | "frame": Object { 770 | "_class": "rect", 771 | "constrainProportions": false, 772 | "height": 38, 773 | "width": 988, 774 | "x": 0, 775 | "y": 0, 776 | }, 777 | "hasClippingMask": false, 778 | "hasConvertedToNewRoundCorners": true, 779 | "isFlippedHorizontal": false, 780 | "isFlippedVertical": false, 781 | "isLocked": false, 782 | "isVisible": true, 783 | "layerListExpandedType": 0, 784 | "layers": Array [], 785 | "name": "rectangle", 786 | "nameIsFixed": false, 787 | "path": Object { 788 | "_class": "path", 789 | "isClosed": true, 790 | "pointRadiusBehaviour": 1, 791 | "points": Array [ 792 | Object { 793 | "_class": "curvePoint", 794 | "cornerRadius": 0, 795 | "curveFrom": "{0, 0}", 796 | "curveMode": 1, 797 | "curveTo": "{0, 0}", 798 | "hasCurveFrom": false, 799 | "hasCurveTo": false, 800 | "point": "{0, 0}", 801 | }, 802 | Object { 803 | "_class": "curvePoint", 804 | "cornerRadius": 0, 805 | "curveFrom": "{1, 0}", 806 | "curveMode": 1, 807 | "curveTo": "{1, 0}", 808 | "hasCurveFrom": false, 809 | "hasCurveTo": false, 810 | "point": "{1, 0}", 811 | }, 812 | Object { 813 | "_class": "curvePoint", 814 | "cornerRadius": 0, 815 | "curveFrom": "{1, 1}", 816 | "curveMode": 1, 817 | "curveTo": "{1, 1}", 818 | "hasCurveFrom": false, 819 | "hasCurveTo": false, 820 | "point": "{1, 1}", 821 | }, 822 | Object { 823 | "_class": "curvePoint", 824 | "cornerRadius": 0, 825 | "curveFrom": "{0, 1}", 826 | "curveMode": 1, 827 | "curveTo": "{0, 1}", 828 | "hasCurveFrom": false, 829 | "hasCurveTo": false, 830 | "point": "{0, 1}", 831 | }, 832 | ], 833 | }, 834 | "resizingConstraint": 63, 835 | "resizingType": 0, 836 | "rotation": 0, 837 | "shouldBreakMaskChain": false, 838 | }, 839 | ], 840 | "name": "/html[1]/body[1]/div[3]/div[@class=\\"symbol blue\\"]", 841 | "nameIsFixed": false, 842 | "resizingConstraint": 63, 843 | "resizingType": 0, 844 | "rotation": 0, 845 | "shouldBreakMaskChain": false, 846 | "style": Object { 847 | "_class": "style", 848 | "borders": Array [ 849 | Object { 850 | "_class": "border", 851 | "color": Object { 852 | "_class": "color", 853 | "alpha": 1, 854 | "blue": 0, 855 | "green": 0, 856 | "red": 0, 857 | }, 858 | "fillType": 0, 859 | "isEnabled": true, 860 | "position": 1, 861 | "thickness": 0, 862 | }, 863 | ], 864 | "contextSettings": Object { 865 | "_class": "graphicsContextSettings", 866 | "blendMode": 0, 867 | "opacity": "1", 868 | }, 869 | "endDecorationType": 0, 870 | "fills": Array [ 871 | Object { 872 | "_class": "fill", 873 | "color": Object { 874 | "_class": "color", 875 | "alpha": 1, 876 | "blue": 1, 877 | "green": 1, 878 | "red": 0, 879 | }, 880 | "fillType": 0, 881 | "isEnabled": true, 882 | "noiseIndex": 0, 883 | "noiseIntensity": 0, 884 | "patternFillType": 1, 885 | "patternTileScale": 1, 886 | }, 887 | ], 888 | "innerShadows": Array [], 889 | "miterLimit": 10, 890 | "shadows": Array [], 891 | "startDecorationType": 0, 892 | }, 893 | "windingRule": 1, 894 | }, 895 | Object { 896 | "_class": "text", 897 | "automaticallyDrawOnUnderlyingPath": false, 898 | "clippingMaskMode": 0, 899 | "do_objectID": "__GUID__", 900 | "dontSynchroniseWithSymbol": false, 901 | "exportOptions": Object { 902 | "_class": "exportOptions", 903 | "exportFormats": Array [], 904 | "includedLayerIds": Array [], 905 | "layerOptions": 0, 906 | "shouldTrim": false, 907 | }, 908 | "frame": Object { 909 | "_class": "rect", 910 | "constrainProportions": false, 911 | "height": 17, 912 | "width": 61.78125, 913 | "x": 20, 914 | "y": 10, 915 | }, 916 | "hasClippingMask": false, 917 | "isFlippedHorizontal": false, 918 | "isFlippedVertical": false, 919 | "isLocked": false, 920 | "isVisible": true, 921 | "layerListExpandedType": 0, 922 | "lineSpacingBehaviour": 2, 923 | "name": "Symbol 3", 924 | "nameIsFixed": false, 925 | "resizingConstraint": 47, 926 | "resizingType": 0, 927 | "rotation": 0, 928 | "shouldBreakMaskChain": false, 929 | "style": Object { 930 | "color": "rgb(0, 0, 0)", 931 | "fontFamily": "Times New Roman", 932 | "fontSize": 16, 933 | "fontWeight": 400, 934 | "textAlign": "start", 935 | "textDecoration": "none", 936 | "textTransform": "none", 937 | }, 938 | "text": "Symbol 3", 939 | "textBehaviour": 0, 940 | }, 941 | ], 942 | "name": "Symbol 3", 943 | "nameIsFixed": false, 944 | "resizesContent": false, 945 | "resizingConstraint": 63, 946 | "resizingType": 0, 947 | "rotation": 0, 948 | "shouldBreakMaskChain": false, 949 | "style": Object { 950 | "_class": "style", 951 | "endDecorationType": 0, 952 | "miterLimit": 10, 953 | "startDecorationType": 0, 954 | }, 955 | "symbolID": "__GUID__", 956 | "verticalRulerData": Object { 957 | "_class": "rulerData", 958 | "base": 0, 959 | "guides": Array [], 960 | }, 961 | }, 962 | ], 963 | "name": "html-sketchapp symbols", 964 | "nameIsFixed": false, 965 | "resizingConstraint": 63, 966 | "resizingType": 0, 967 | "rotation": 0, 968 | "shouldBreakMaskChain": false, 969 | "style": Object { 970 | "_class": "style", 971 | "endDecorationType": 0, 972 | "miterLimit": 10, 973 | "startDecorationType": 0, 974 | }, 975 | "verticalRulerData": Object { 976 | "_class": "rulerData", 977 | "base": 0, 978 | "guides": Array [], 979 | }, 980 | }, 981 | } 982 | `; 983 | -------------------------------------------------------------------------------- /test/serve/serve-me/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
Symbol 1
23 |
Symbol 2
24 |
Symbol 3
25 | 26 |

Text 1

27 |

Text 2

28 |

Text 3

29 | 30 |
Color 1
31 |
Color 2
32 |
Color 3
33 | 34 | 35 | -------------------------------------------------------------------------------- /test/serve/serve.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | test('serve', async () => { 12 | await exec('node ../../bin/cli --puppeteer-args="--no-sandbox --disable-setuid-sandbox" --out-dir dist --serve serve-me', { cwd: __dirname }); 13 | 14 | const output = await dirContentsToObject(distPath); 15 | expect(output).toMatchSnapshot(); 16 | }); 17 | -------------------------------------------------------------------------------- /test/symbol-instance-middleware/html-sketchapp.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | file: 'index.html', 3 | outDir: 'dist', 4 | puppeteerArgs: '--no-sandbox --disable-setuid-sandbox', 5 | symbolInstanceMiddleware: (args) => { 6 | const { symbolInstance, RESIZING_CONSTRAINTS, node } = args; 7 | 8 | symbolInstance.setName(`from-inline-function-${node.dataset.sketchSymbolInstance}`); 9 | symbolInstance.setResizingConstraint(RESIZING_CONSTRAINTS.LEFT, RESIZING_CONSTRAINTS.TOP); 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /test/symbol-instance-middleware/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
Reply
7 |
Retweet
8 |
Like
9 | 10 |
11 |
Reply
12 |
Retweet
13 |
Like
14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /test/symbol-instance-middleware/symbol-instance-middleware.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | describe('symbol-instance-middleware sets style for symbolInstance when middleware function is defined', () => { 12 | test('inline in config file', async () => { 13 | await exec('node ../../bin/cli', { cwd: __dirname }); 14 | 15 | const output = await dirContentsToObject(distPath); 16 | expect(output).toMatchSnapshot(); 17 | }); 18 | 19 | test('in separate config file', async () => { 20 | await exec('node ../../bin/cli --puppeteer-args="--no-sandbox --disable-setuid-sandbox" --out-dir dist --file index.html --symbol-instance-middleware symbol-instance.middleware.js', { cwd: __dirname }); 21 | 22 | const output = await dirContentsToObject(distPath); 23 | expect(output).toMatchSnapshot(); 24 | }); 25 | }) 26 | -------------------------------------------------------------------------------- /test/symbol-instance-middleware/symbol-instance.middleware.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ symbolInstance, node, RESIZING_CONSTRAINTS}) => { 2 | symbolInstance.setName(`from-config-file-${node.dataset.sketchSymbolInstance}`); 3 | symbolInstance.setResizingConstraint(RESIZING_CONSTRAINTS.LEFT, RESIZING_CONSTRAINTS.TOP); 4 | }; 5 | -------------------------------------------------------------------------------- /test/symbol-layer-middleware/html-sketchapp.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | file: 'index.html', 3 | outDir: 'dist', 4 | puppeteerArgs: '--no-sandbox --disable-setuid-sandbox', 5 | symbolLayerMiddleware: (args) => { 6 | const { layer, RESIZING_CONSTRAINTS } = args; 7 | 8 | layer.setResizingConstraint(RESIZING_CONSTRAINTS.LEFT, RESIZING_CONSTRAINTS.TOP); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /test/symbol-layer-middleware/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
Symbol 1
23 |
Symbol 2
24 |
Symbol 3
25 | 26 |

Text 1

27 |

Text 2

28 |

Text 3

29 | 30 |
Color 1
31 |
Color 2
32 |
Color 3
33 | 34 | 35 | -------------------------------------------------------------------------------- /test/symbol-layer-middleware/symbol-layer-middleware.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | describe('symbol-layer-middleware', () => { 12 | test('function', async () => { 13 | await exec('node ../../bin/cli', { cwd: __dirname }); 14 | 15 | const output = await dirContentsToObject(distPath); 16 | expect(output).toMatchSnapshot(); 17 | }); 18 | 19 | test('string', async () => { 20 | await exec('node ../../bin/cli --puppeteer-args="--no-sandbox --disable-setuid-sandbox" --out-dir dist --file index.html --symbol-layer-middleware symbol.layer.middleware.js', { cwd: __dirname }); 21 | 22 | const output = await dirContentsToObject(distPath); 23 | expect(output).toMatchSnapshot(); 24 | }); 25 | }) 26 | -------------------------------------------------------------------------------- /test/symbol-layer-middleware/symbol.layer.middleware.js: -------------------------------------------------------------------------------- 1 | module.exports = (args) => { 2 | const { layer, RESIZING_CONSTRAINTS } = args; 3 | 4 | layer.setResizingConstraint(RESIZING_CONSTRAINTS.LEFT, RESIZING_CONSTRAINTS.TOP); 5 | }; 6 | -------------------------------------------------------------------------------- /test/symbol-middleware/html-sketchapp.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | file: 'index.html', 3 | outDir: 'dist', 4 | puppeteerArgs: '--no-sandbox --disable-setuid-sandbox', 5 | symbolMiddleware: ({ symbol, node, suffix }) => { 6 | symbol.setId(`from-inline-function-${node.dataset.sketchSymbol}${suffix}`); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /test/symbol-middleware/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
Symbol 1
23 |
Symbol 2
24 |
Symbol 3
25 | 26 |

Text 1

27 |

Text 2

28 |

Text 3

29 | 30 |
Color 1
31 |
Color 2
32 |
Color 3
33 | 34 | 35 | -------------------------------------------------------------------------------- /test/symbol-middleware/symbol-middleware.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | describe('symbol-middleware sets symbolId for symbol when middleware function is defined', () => { 12 | test('inline in config file', async () => { 13 | await exec('node ../../bin/cli', { cwd: __dirname }); 14 | 15 | const output = await dirContentsToObject(distPath); 16 | expect(output).toMatchSnapshot(); 17 | }); 18 | 19 | test('in separate config file', async () => { 20 | await exec('node ../../bin/cli --puppeteer-args="--no-sandbox --disable-setuid-sandbox" --out-dir dist --file index.html --symbol-middleware symbol.middleware.js', { cwd: __dirname }); 21 | 22 | const output = await dirContentsToObject(distPath); 23 | expect(output).toMatchSnapshot(); 24 | }); 25 | }) 26 | -------------------------------------------------------------------------------- /test/symbol-middleware/symbol.middleware.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ symbol, node, suffix }) => { 2 | symbol.setId(`from-config-file-${node.dataset.sketchSymbol}${suffix}`); 3 | }; 4 | -------------------------------------------------------------------------------- /test/url/__snapshots__/url.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`url 1`] = ` 4 | Object { 5 | "document.asketch.json": Object { 6 | "_class": "document", 7 | "assets": Object { 8 | "_class": "assetCollection", 9 | "colors": Array [ 10 | Object { 11 | "_class": "color", 12 | "alpha": 1, 13 | "blue": 0, 14 | "green": 0, 15 | "red": 1, 16 | }, 17 | Object { 18 | "_class": "color", 19 | "alpha": 1, 20 | "blue": 0, 21 | "green": 1, 22 | "red": 0, 23 | }, 24 | Object { 25 | "_class": "color", 26 | "alpha": 1, 27 | "blue": 1, 28 | "green": 0, 29 | "red": 0, 30 | }, 31 | ], 32 | }, 33 | "currentPageIndex": 0, 34 | "do_objectID": "__GUID__", 35 | "enableLayerInteraction": true, 36 | "enableSliceInteraction": true, 37 | "foreignSymbols": Array [], 38 | "layerStyles": Object { 39 | "_class": "sharedStyleContainer", 40 | "objects": Array [], 41 | }, 42 | "layerSymbols": Object { 43 | "_class": "symbolContainer", 44 | "objects": Array [], 45 | }, 46 | "layerTextStyles": Object { 47 | "_class": "sharedTextStyleContainer", 48 | "objects": Array [ 49 | Object { 50 | "_class": "sharedStyle", 51 | "do_objectID": "__GUID__", 52 | "name": "Text 1", 53 | "style": Object { 54 | "color": "rgb(0, 0, 0)", 55 | "fontFamily": "Times New Roman", 56 | "fontSize": 40, 57 | "fontWeight": 700, 58 | "textAlign": "start", 59 | "textDecoration": "none", 60 | "textTransform": "none", 61 | }, 62 | }, 63 | Object { 64 | "_class": "sharedStyle", 65 | "do_objectID": "__GUID__", 66 | "name": "Text 2", 67 | "style": Object { 68 | "color": "rgb(0, 0, 0)", 69 | "fontFamily": "Times New Roman", 70 | "fontSize": 30, 71 | "fontWeight": 700, 72 | "textAlign": "start", 73 | "textDecoration": "none", 74 | "textTransform": "none", 75 | }, 76 | }, 77 | Object { 78 | "_class": "sharedStyle", 79 | "do_objectID": "__GUID__", 80 | "name": "Text 3", 81 | "style": Object { 82 | "color": "rgb(0, 0, 0)", 83 | "fontFamily": "Times New Roman", 84 | "fontSize": 20, 85 | "fontWeight": 700, 86 | "textAlign": "start", 87 | "textDecoration": "none", 88 | "textTransform": "none", 89 | }, 90 | }, 91 | ], 92 | }, 93 | "pages": Array [], 94 | }, 95 | "document.page.json": Object { 96 | "_class": "page", 97 | "clippingMaskMode": 0, 98 | "do_objectID": "__GUID__", 99 | "exportOptions": Object { 100 | "_class": "exportOptions", 101 | "exportFormats": Array [], 102 | "includedLayerIds": Array [], 103 | "layerOptions": 0, 104 | "shouldTrim": false, 105 | }, 106 | "frame": Object { 107 | "_class": "rect", 108 | "constrainProportions": false, 109 | "height": 352, 110 | "width": 784, 111 | "x": 0, 112 | "y": 0, 113 | }, 114 | "hasClickThrough": true, 115 | "hasClippingMask": false, 116 | "horizontalRulerData": Object { 117 | "_class": "rulerData", 118 | "base": 0, 119 | "guides": Array [], 120 | }, 121 | "includeInCloudUpload": true, 122 | "isFlippedHorizontal": false, 123 | "isFlippedVertical": false, 124 | "isLocked": false, 125 | "isVisible": true, 126 | "layerListExpandedType": 0, 127 | "layers": Array [ 128 | Object { 129 | "_class": "symbolMaster", 130 | "backgroundColor": Object { 131 | "_class": "color", 132 | "alpha": 1, 133 | "blue": 1, 134 | "green": 1, 135 | "red": 1, 136 | }, 137 | "changeIdentifier": 0, 138 | "clippingMaskMode": 0, 139 | "do_objectID": "__GUID__", 140 | "exportOptions": Object { 141 | "_class": "exportOptions", 142 | "exportFormats": Array [], 143 | "includedLayerIds": Array [], 144 | "layerOptions": 0, 145 | "shouldTrim": false, 146 | }, 147 | "frame": Object { 148 | "_class": "rect", 149 | "constrainProportions": false, 150 | "height": 38, 151 | "width": 998, 152 | "x": 8, 153 | "y": 10, 154 | }, 155 | "hasBackgroundColor": false, 156 | "hasClickThrough": true, 157 | "hasClippingMask": false, 158 | "horizontalRulerData": Object { 159 | "_class": "rulerData", 160 | "base": 0, 161 | "guides": Array [], 162 | }, 163 | "includeBackgroundColorInExport": true, 164 | "includeBackgroundColorInInstance": false, 165 | "includeInCloudUpload": true, 166 | "isFlippedHorizontal": false, 167 | "isFlippedVertical": false, 168 | "isLocked": false, 169 | "isVisible": true, 170 | "layerListExpandedType": 0, 171 | "layers": Array [ 172 | Object { 173 | "_class": "shapeGroup", 174 | "clippingMaskMode": 0, 175 | "do_objectID": "__GUID__", 176 | "exportOptions": Object { 177 | "_class": "exportOptions", 178 | "exportFormats": Array [], 179 | "includedLayerIds": Array [], 180 | "layerOptions": 0, 181 | "shouldTrim": false, 182 | }, 183 | "frame": Object { 184 | "_class": "rect", 185 | "constrainProportions": false, 186 | "height": 38, 187 | "width": 988, 188 | "x": 10, 189 | "y": 0, 190 | }, 191 | "hasClickThrough": false, 192 | "hasClippingMask": false, 193 | "isFlippedHorizontal": false, 194 | "isFlippedVertical": false, 195 | "isLocked": false, 196 | "isVisible": true, 197 | "layerListExpandedType": 0, 198 | "layers": Array [ 199 | Object { 200 | "_class": "rectangle", 201 | "booleanOperation": -1, 202 | "clippingMaskMode": 0, 203 | "do_objectID": "__GUID__", 204 | "edited": false, 205 | "exportOptions": Object { 206 | "_class": "exportOptions", 207 | "exportFormats": Array [], 208 | "includedLayerIds": Array [], 209 | "layerOptions": 0, 210 | "shouldTrim": false, 211 | }, 212 | "fixedRadius": 0, 213 | "frame": Object { 214 | "_class": "rect", 215 | "constrainProportions": false, 216 | "height": 38, 217 | "width": 988, 218 | "x": 0, 219 | "y": 0, 220 | }, 221 | "hasClippingMask": false, 222 | "hasConvertedToNewRoundCorners": true, 223 | "isFlippedHorizontal": false, 224 | "isFlippedVertical": false, 225 | "isLocked": false, 226 | "isVisible": true, 227 | "layerListExpandedType": 0, 228 | "layers": Array [], 229 | "name": "rectangle", 230 | "nameIsFixed": false, 231 | "path": Object { 232 | "_class": "path", 233 | "isClosed": true, 234 | "pointRadiusBehaviour": 1, 235 | "points": Array [ 236 | Object { 237 | "_class": "curvePoint", 238 | "cornerRadius": 0, 239 | "curveFrom": "{0, 0}", 240 | "curveMode": 1, 241 | "curveTo": "{0, 0}", 242 | "hasCurveFrom": false, 243 | "hasCurveTo": false, 244 | "point": "{0, 0}", 245 | }, 246 | Object { 247 | "_class": "curvePoint", 248 | "cornerRadius": 0, 249 | "curveFrom": "{1, 0}", 250 | "curveMode": 1, 251 | "curveTo": "{1, 0}", 252 | "hasCurveFrom": false, 253 | "hasCurveTo": false, 254 | "point": "{1, 0}", 255 | }, 256 | Object { 257 | "_class": "curvePoint", 258 | "cornerRadius": 0, 259 | "curveFrom": "{1, 1}", 260 | "curveMode": 1, 261 | "curveTo": "{1, 1}", 262 | "hasCurveFrom": false, 263 | "hasCurveTo": false, 264 | "point": "{1, 1}", 265 | }, 266 | Object { 267 | "_class": "curvePoint", 268 | "cornerRadius": 0, 269 | "curveFrom": "{0, 1}", 270 | "curveMode": 1, 271 | "curveTo": "{0, 1}", 272 | "hasCurveFrom": false, 273 | "hasCurveTo": false, 274 | "point": "{0, 1}", 275 | }, 276 | ], 277 | }, 278 | "resizingConstraint": 63, 279 | "resizingType": 0, 280 | "rotation": 0, 281 | "shouldBreakMaskChain": false, 282 | }, 283 | ], 284 | "name": "/html[1]/body[1]/div[1]/div[@class=\\"symbol red\\"]", 285 | "nameIsFixed": false, 286 | "resizingConstraint": 63, 287 | "resizingType": 0, 288 | "rotation": 0, 289 | "shouldBreakMaskChain": false, 290 | "style": Object { 291 | "_class": "style", 292 | "borders": Array [ 293 | Object { 294 | "_class": "border", 295 | "color": Object { 296 | "_class": "color", 297 | "alpha": 1, 298 | "blue": 0, 299 | "green": 0, 300 | "red": 0, 301 | }, 302 | "fillType": 0, 303 | "isEnabled": true, 304 | "position": 1, 305 | "thickness": 0, 306 | }, 307 | ], 308 | "contextSettings": Object { 309 | "_class": "graphicsContextSettings", 310 | "blendMode": 0, 311 | "opacity": "1", 312 | }, 313 | "endDecorationType": 0, 314 | "fills": Array [ 315 | Object { 316 | "_class": "fill", 317 | "color": Object { 318 | "_class": "color", 319 | "alpha": 1, 320 | "blue": 0.796078431372549, 321 | "green": 0.7529411764705882, 322 | "red": 1, 323 | }, 324 | "fillType": 0, 325 | "isEnabled": true, 326 | "noiseIndex": 0, 327 | "noiseIntensity": 0, 328 | "patternFillType": 1, 329 | "patternTileScale": 1, 330 | }, 331 | ], 332 | "innerShadows": Array [], 333 | "miterLimit": 10, 334 | "shadows": Array [], 335 | "startDecorationType": 0, 336 | }, 337 | "windingRule": 1, 338 | }, 339 | Object { 340 | "_class": "text", 341 | "automaticallyDrawOnUnderlyingPath": false, 342 | "clippingMaskMode": 0, 343 | "do_objectID": "__GUID__", 344 | "dontSynchroniseWithSymbol": false, 345 | "exportOptions": Object { 346 | "_class": "exportOptions", 347 | "exportFormats": Array [], 348 | "includedLayerIds": Array [], 349 | "layerOptions": 0, 350 | "shouldTrim": false, 351 | }, 352 | "frame": Object { 353 | "_class": "rect", 354 | "constrainProportions": false, 355 | "height": 17, 356 | "width": 61.78125, 357 | "x": 20, 358 | "y": 10, 359 | }, 360 | "hasClippingMask": false, 361 | "isFlippedHorizontal": false, 362 | "isFlippedVertical": false, 363 | "isLocked": false, 364 | "isVisible": true, 365 | "layerListExpandedType": 0, 366 | "lineSpacingBehaviour": 2, 367 | "name": "Symbol 1", 368 | "nameIsFixed": false, 369 | "resizingConstraint": 47, 370 | "resizingType": 0, 371 | "rotation": 0, 372 | "shouldBreakMaskChain": false, 373 | "style": Object { 374 | "color": "rgb(0, 0, 0)", 375 | "fontFamily": "Times New Roman", 376 | "fontSize": 16, 377 | "fontWeight": 400, 378 | "textAlign": "start", 379 | "textDecoration": "none", 380 | "textTransform": "none", 381 | }, 382 | "text": "Symbol 1", 383 | "textBehaviour": 0, 384 | }, 385 | ], 386 | "name": "Symbol 1", 387 | "nameIsFixed": false, 388 | "resizesContent": false, 389 | "resizingConstraint": 63, 390 | "resizingType": 0, 391 | "rotation": 0, 392 | "shouldBreakMaskChain": false, 393 | "style": Object { 394 | "_class": "style", 395 | "endDecorationType": 0, 396 | "miterLimit": 10, 397 | "startDecorationType": 0, 398 | }, 399 | "symbolID": "__GUID__", 400 | "verticalRulerData": Object { 401 | "_class": "rulerData", 402 | "base": 0, 403 | "guides": Array [], 404 | }, 405 | }, 406 | Object { 407 | "_class": "symbolMaster", 408 | "backgroundColor": Object { 409 | "_class": "color", 410 | "alpha": 1, 411 | "blue": 1, 412 | "green": 1, 413 | "red": 1, 414 | }, 415 | "changeIdentifier": 0, 416 | "clippingMaskMode": 0, 417 | "do_objectID": "__GUID__", 418 | "exportOptions": Object { 419 | "_class": "exportOptions", 420 | "exportFormats": Array [], 421 | "includedLayerIds": Array [], 422 | "layerOptions": 0, 423 | "shouldTrim": false, 424 | }, 425 | "frame": Object { 426 | "_class": "rect", 427 | "constrainProportions": false, 428 | "height": 38, 429 | "width": 998, 430 | "x": 8, 431 | "y": 58, 432 | }, 433 | "hasBackgroundColor": false, 434 | "hasClickThrough": true, 435 | "hasClippingMask": false, 436 | "horizontalRulerData": Object { 437 | "_class": "rulerData", 438 | "base": 0, 439 | "guides": Array [], 440 | }, 441 | "includeBackgroundColorInExport": true, 442 | "includeBackgroundColorInInstance": false, 443 | "includeInCloudUpload": true, 444 | "isFlippedHorizontal": false, 445 | "isFlippedVertical": false, 446 | "isLocked": false, 447 | "isVisible": true, 448 | "layerListExpandedType": 0, 449 | "layers": Array [ 450 | Object { 451 | "_class": "shapeGroup", 452 | "clippingMaskMode": 0, 453 | "do_objectID": "__GUID__", 454 | "exportOptions": Object { 455 | "_class": "exportOptions", 456 | "exportFormats": Array [], 457 | "includedLayerIds": Array [], 458 | "layerOptions": 0, 459 | "shouldTrim": false, 460 | }, 461 | "frame": Object { 462 | "_class": "rect", 463 | "constrainProportions": false, 464 | "height": 38, 465 | "width": 988, 466 | "x": 10, 467 | "y": 0, 468 | }, 469 | "hasClickThrough": false, 470 | "hasClippingMask": false, 471 | "isFlippedHorizontal": false, 472 | "isFlippedVertical": false, 473 | "isLocked": false, 474 | "isVisible": true, 475 | "layerListExpandedType": 0, 476 | "layers": Array [ 477 | Object { 478 | "_class": "rectangle", 479 | "booleanOperation": -1, 480 | "clippingMaskMode": 0, 481 | "do_objectID": "__GUID__", 482 | "edited": false, 483 | "exportOptions": Object { 484 | "_class": "exportOptions", 485 | "exportFormats": Array [], 486 | "includedLayerIds": Array [], 487 | "layerOptions": 0, 488 | "shouldTrim": false, 489 | }, 490 | "fixedRadius": 0, 491 | "frame": Object { 492 | "_class": "rect", 493 | "constrainProportions": false, 494 | "height": 38, 495 | "width": 988, 496 | "x": 0, 497 | "y": 0, 498 | }, 499 | "hasClippingMask": false, 500 | "hasConvertedToNewRoundCorners": true, 501 | "isFlippedHorizontal": false, 502 | "isFlippedVertical": false, 503 | "isLocked": false, 504 | "isVisible": true, 505 | "layerListExpandedType": 0, 506 | "layers": Array [], 507 | "name": "rectangle", 508 | "nameIsFixed": false, 509 | "path": Object { 510 | "_class": "path", 511 | "isClosed": true, 512 | "pointRadiusBehaviour": 1, 513 | "points": Array [ 514 | Object { 515 | "_class": "curvePoint", 516 | "cornerRadius": 0, 517 | "curveFrom": "{0, 0}", 518 | "curveMode": 1, 519 | "curveTo": "{0, 0}", 520 | "hasCurveFrom": false, 521 | "hasCurveTo": false, 522 | "point": "{0, 0}", 523 | }, 524 | Object { 525 | "_class": "curvePoint", 526 | "cornerRadius": 0, 527 | "curveFrom": "{1, 0}", 528 | "curveMode": 1, 529 | "curveTo": "{1, 0}", 530 | "hasCurveFrom": false, 531 | "hasCurveTo": false, 532 | "point": "{1, 0}", 533 | }, 534 | Object { 535 | "_class": "curvePoint", 536 | "cornerRadius": 0, 537 | "curveFrom": "{1, 1}", 538 | "curveMode": 1, 539 | "curveTo": "{1, 1}", 540 | "hasCurveFrom": false, 541 | "hasCurveTo": false, 542 | "point": "{1, 1}", 543 | }, 544 | Object { 545 | "_class": "curvePoint", 546 | "cornerRadius": 0, 547 | "curveFrom": "{0, 1}", 548 | "curveMode": 1, 549 | "curveTo": "{0, 1}", 550 | "hasCurveFrom": false, 551 | "hasCurveTo": false, 552 | "point": "{0, 1}", 553 | }, 554 | ], 555 | }, 556 | "resizingConstraint": 63, 557 | "resizingType": 0, 558 | "rotation": 0, 559 | "shouldBreakMaskChain": false, 560 | }, 561 | ], 562 | "name": "/html[1]/body[1]/div[2]/div[@class=\\"symbol green\\"]", 563 | "nameIsFixed": false, 564 | "resizingConstraint": 63, 565 | "resizingType": 0, 566 | "rotation": 0, 567 | "shouldBreakMaskChain": false, 568 | "style": Object { 569 | "_class": "style", 570 | "borders": Array [ 571 | Object { 572 | "_class": "border", 573 | "color": Object { 574 | "_class": "color", 575 | "alpha": 1, 576 | "blue": 0, 577 | "green": 0, 578 | "red": 0, 579 | }, 580 | "fillType": 0, 581 | "isEnabled": true, 582 | "position": 1, 583 | "thickness": 0, 584 | }, 585 | ], 586 | "contextSettings": Object { 587 | "_class": "graphicsContextSettings", 588 | "blendMode": 0, 589 | "opacity": "1", 590 | }, 591 | "endDecorationType": 0, 592 | "fills": Array [ 593 | Object { 594 | "_class": "fill", 595 | "color": Object { 596 | "_class": "color", 597 | "alpha": 1, 598 | "blue": 0.596078431372549, 599 | "green": 0.984313725490196, 600 | "red": 0.596078431372549, 601 | }, 602 | "fillType": 0, 603 | "isEnabled": true, 604 | "noiseIndex": 0, 605 | "noiseIntensity": 0, 606 | "patternFillType": 1, 607 | "patternTileScale": 1, 608 | }, 609 | ], 610 | "innerShadows": Array [], 611 | "miterLimit": 10, 612 | "shadows": Array [], 613 | "startDecorationType": 0, 614 | }, 615 | "windingRule": 1, 616 | }, 617 | Object { 618 | "_class": "text", 619 | "automaticallyDrawOnUnderlyingPath": false, 620 | "clippingMaskMode": 0, 621 | "do_objectID": "__GUID__", 622 | "dontSynchroniseWithSymbol": false, 623 | "exportOptions": Object { 624 | "_class": "exportOptions", 625 | "exportFormats": Array [], 626 | "includedLayerIds": Array [], 627 | "layerOptions": 0, 628 | "shouldTrim": false, 629 | }, 630 | "frame": Object { 631 | "_class": "rect", 632 | "constrainProportions": false, 633 | "height": 17, 634 | "width": 61.78125, 635 | "x": 20, 636 | "y": 10, 637 | }, 638 | "hasClippingMask": false, 639 | "isFlippedHorizontal": false, 640 | "isFlippedVertical": false, 641 | "isLocked": false, 642 | "isVisible": true, 643 | "layerListExpandedType": 0, 644 | "lineSpacingBehaviour": 2, 645 | "name": "Symbol 2", 646 | "nameIsFixed": false, 647 | "resizingConstraint": 47, 648 | "resizingType": 0, 649 | "rotation": 0, 650 | "shouldBreakMaskChain": false, 651 | "style": Object { 652 | "color": "rgb(0, 0, 0)", 653 | "fontFamily": "Times New Roman", 654 | "fontSize": 16, 655 | "fontWeight": 400, 656 | "textAlign": "start", 657 | "textDecoration": "none", 658 | "textTransform": "none", 659 | }, 660 | "text": "Symbol 2", 661 | "textBehaviour": 0, 662 | }, 663 | ], 664 | "name": "Symbol 2", 665 | "nameIsFixed": false, 666 | "resizesContent": false, 667 | "resizingConstraint": 63, 668 | "resizingType": 0, 669 | "rotation": 0, 670 | "shouldBreakMaskChain": false, 671 | "style": Object { 672 | "_class": "style", 673 | "endDecorationType": 0, 674 | "miterLimit": 10, 675 | "startDecorationType": 0, 676 | }, 677 | "symbolID": "__GUID__", 678 | "verticalRulerData": Object { 679 | "_class": "rulerData", 680 | "base": 0, 681 | "guides": Array [], 682 | }, 683 | }, 684 | Object { 685 | "_class": "symbolMaster", 686 | "backgroundColor": Object { 687 | "_class": "color", 688 | "alpha": 1, 689 | "blue": 1, 690 | "green": 1, 691 | "red": 1, 692 | }, 693 | "changeIdentifier": 0, 694 | "clippingMaskMode": 0, 695 | "do_objectID": "__GUID__", 696 | "exportOptions": Object { 697 | "_class": "exportOptions", 698 | "exportFormats": Array [], 699 | "includedLayerIds": Array [], 700 | "layerOptions": 0, 701 | "shouldTrim": false, 702 | }, 703 | "frame": Object { 704 | "_class": "rect", 705 | "constrainProportions": false, 706 | "height": 38, 707 | "width": 998, 708 | "x": 8, 709 | "y": 106, 710 | }, 711 | "hasBackgroundColor": false, 712 | "hasClickThrough": true, 713 | "hasClippingMask": false, 714 | "horizontalRulerData": Object { 715 | "_class": "rulerData", 716 | "base": 0, 717 | "guides": Array [], 718 | }, 719 | "includeBackgroundColorInExport": true, 720 | "includeBackgroundColorInInstance": false, 721 | "includeInCloudUpload": true, 722 | "isFlippedHorizontal": false, 723 | "isFlippedVertical": false, 724 | "isLocked": false, 725 | "isVisible": true, 726 | "layerListExpandedType": 0, 727 | "layers": Array [ 728 | Object { 729 | "_class": "shapeGroup", 730 | "clippingMaskMode": 0, 731 | "do_objectID": "__GUID__", 732 | "exportOptions": Object { 733 | "_class": "exportOptions", 734 | "exportFormats": Array [], 735 | "includedLayerIds": Array [], 736 | "layerOptions": 0, 737 | "shouldTrim": false, 738 | }, 739 | "frame": Object { 740 | "_class": "rect", 741 | "constrainProportions": false, 742 | "height": 38, 743 | "width": 988, 744 | "x": 10, 745 | "y": 0, 746 | }, 747 | "hasClickThrough": false, 748 | "hasClippingMask": false, 749 | "isFlippedHorizontal": false, 750 | "isFlippedVertical": false, 751 | "isLocked": false, 752 | "isVisible": true, 753 | "layerListExpandedType": 0, 754 | "layers": Array [ 755 | Object { 756 | "_class": "rectangle", 757 | "booleanOperation": -1, 758 | "clippingMaskMode": 0, 759 | "do_objectID": "__GUID__", 760 | "edited": false, 761 | "exportOptions": Object { 762 | "_class": "exportOptions", 763 | "exportFormats": Array [], 764 | "includedLayerIds": Array [], 765 | "layerOptions": 0, 766 | "shouldTrim": false, 767 | }, 768 | "fixedRadius": 0, 769 | "frame": Object { 770 | "_class": "rect", 771 | "constrainProportions": false, 772 | "height": 38, 773 | "width": 988, 774 | "x": 0, 775 | "y": 0, 776 | }, 777 | "hasClippingMask": false, 778 | "hasConvertedToNewRoundCorners": true, 779 | "isFlippedHorizontal": false, 780 | "isFlippedVertical": false, 781 | "isLocked": false, 782 | "isVisible": true, 783 | "layerListExpandedType": 0, 784 | "layers": Array [], 785 | "name": "rectangle", 786 | "nameIsFixed": false, 787 | "path": Object { 788 | "_class": "path", 789 | "isClosed": true, 790 | "pointRadiusBehaviour": 1, 791 | "points": Array [ 792 | Object { 793 | "_class": "curvePoint", 794 | "cornerRadius": 0, 795 | "curveFrom": "{0, 0}", 796 | "curveMode": 1, 797 | "curveTo": "{0, 0}", 798 | "hasCurveFrom": false, 799 | "hasCurveTo": false, 800 | "point": "{0, 0}", 801 | }, 802 | Object { 803 | "_class": "curvePoint", 804 | "cornerRadius": 0, 805 | "curveFrom": "{1, 0}", 806 | "curveMode": 1, 807 | "curveTo": "{1, 0}", 808 | "hasCurveFrom": false, 809 | "hasCurveTo": false, 810 | "point": "{1, 0}", 811 | }, 812 | Object { 813 | "_class": "curvePoint", 814 | "cornerRadius": 0, 815 | "curveFrom": "{1, 1}", 816 | "curveMode": 1, 817 | "curveTo": "{1, 1}", 818 | "hasCurveFrom": false, 819 | "hasCurveTo": false, 820 | "point": "{1, 1}", 821 | }, 822 | Object { 823 | "_class": "curvePoint", 824 | "cornerRadius": 0, 825 | "curveFrom": "{0, 1}", 826 | "curveMode": 1, 827 | "curveTo": "{0, 1}", 828 | "hasCurveFrom": false, 829 | "hasCurveTo": false, 830 | "point": "{0, 1}", 831 | }, 832 | ], 833 | }, 834 | "resizingConstraint": 63, 835 | "resizingType": 0, 836 | "rotation": 0, 837 | "shouldBreakMaskChain": false, 838 | }, 839 | ], 840 | "name": "/html[1]/body[1]/div[3]/div[@class=\\"symbol blue\\"]", 841 | "nameIsFixed": false, 842 | "resizingConstraint": 63, 843 | "resizingType": 0, 844 | "rotation": 0, 845 | "shouldBreakMaskChain": false, 846 | "style": Object { 847 | "_class": "style", 848 | "borders": Array [ 849 | Object { 850 | "_class": "border", 851 | "color": Object { 852 | "_class": "color", 853 | "alpha": 1, 854 | "blue": 0, 855 | "green": 0, 856 | "red": 0, 857 | }, 858 | "fillType": 0, 859 | "isEnabled": true, 860 | "position": 1, 861 | "thickness": 0, 862 | }, 863 | ], 864 | "contextSettings": Object { 865 | "_class": "graphicsContextSettings", 866 | "blendMode": 0, 867 | "opacity": "1", 868 | }, 869 | "endDecorationType": 0, 870 | "fills": Array [ 871 | Object { 872 | "_class": "fill", 873 | "color": Object { 874 | "_class": "color", 875 | "alpha": 1, 876 | "blue": 1, 877 | "green": 1, 878 | "red": 0, 879 | }, 880 | "fillType": 0, 881 | "isEnabled": true, 882 | "noiseIndex": 0, 883 | "noiseIntensity": 0, 884 | "patternFillType": 1, 885 | "patternTileScale": 1, 886 | }, 887 | ], 888 | "innerShadows": Array [], 889 | "miterLimit": 10, 890 | "shadows": Array [], 891 | "startDecorationType": 0, 892 | }, 893 | "windingRule": 1, 894 | }, 895 | Object { 896 | "_class": "text", 897 | "automaticallyDrawOnUnderlyingPath": false, 898 | "clippingMaskMode": 0, 899 | "do_objectID": "__GUID__", 900 | "dontSynchroniseWithSymbol": false, 901 | "exportOptions": Object { 902 | "_class": "exportOptions", 903 | "exportFormats": Array [], 904 | "includedLayerIds": Array [], 905 | "layerOptions": 0, 906 | "shouldTrim": false, 907 | }, 908 | "frame": Object { 909 | "_class": "rect", 910 | "constrainProportions": false, 911 | "height": 17, 912 | "width": 61.78125, 913 | "x": 20, 914 | "y": 10, 915 | }, 916 | "hasClippingMask": false, 917 | "isFlippedHorizontal": false, 918 | "isFlippedVertical": false, 919 | "isLocked": false, 920 | "isVisible": true, 921 | "layerListExpandedType": 0, 922 | "lineSpacingBehaviour": 2, 923 | "name": "Symbol 3", 924 | "nameIsFixed": false, 925 | "resizingConstraint": 47, 926 | "resizingType": 0, 927 | "rotation": 0, 928 | "shouldBreakMaskChain": false, 929 | "style": Object { 930 | "color": "rgb(0, 0, 0)", 931 | "fontFamily": "Times New Roman", 932 | "fontSize": 16, 933 | "fontWeight": 400, 934 | "textAlign": "start", 935 | "textDecoration": "none", 936 | "textTransform": "none", 937 | }, 938 | "text": "Symbol 3", 939 | "textBehaviour": 0, 940 | }, 941 | ], 942 | "name": "Symbol 3", 943 | "nameIsFixed": false, 944 | "resizesContent": false, 945 | "resizingConstraint": 63, 946 | "resizingType": 0, 947 | "rotation": 0, 948 | "shouldBreakMaskChain": false, 949 | "style": Object { 950 | "_class": "style", 951 | "endDecorationType": 0, 952 | "miterLimit": 10, 953 | "startDecorationType": 0, 954 | }, 955 | "symbolID": "__GUID__", 956 | "verticalRulerData": Object { 957 | "_class": "rulerData", 958 | "base": 0, 959 | "guides": Array [], 960 | }, 961 | }, 962 | ], 963 | "name": "html-sketchapp symbols", 964 | "nameIsFixed": false, 965 | "resizingConstraint": 63, 966 | "resizingType": 0, 967 | "rotation": 0, 968 | "shouldBreakMaskChain": false, 969 | "style": Object { 970 | "_class": "style", 971 | "endDecorationType": 0, 972 | "miterLimit": 10, 973 | "startDecorationType": 0, 974 | }, 975 | "verticalRulerData": Object { 976 | "_class": "rulerData", 977 | "base": 0, 978 | "guides": Array [], 979 | }, 980 | }, 981 | } 982 | `; 983 | -------------------------------------------------------------------------------- /test/url/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 |
Symbol 1
23 |
Symbol 2
24 |
Symbol 3
25 | 26 |

Text 1

27 |

Text 2

28 |

Text 3

29 | 30 |
Color 1
31 |
Color 2
32 |
Color 3
33 | 34 | 35 | -------------------------------------------------------------------------------- /test/url/url.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | test('url', async () => { 12 | const url = `file://${path.join(__dirname, 'index.html')}`; 13 | 14 | await exec(`node ../../bin/cli --puppeteer-args="--no-sandbox --disable-setuid-sandbox" --out-dir dist --url ${url}`, { cwd: __dirname }); 15 | 16 | const output = await dirContentsToObject(distPath); 17 | expect(output).toMatchSnapshot(); 18 | }); 19 | -------------------------------------------------------------------------------- /test/viewports/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 33 | 34 | 35 |
Symbol 1
36 |
Symbol 2
37 |
Symbol 3
38 |
Symbol 4
39 | 40 |

Text 1

41 |

Text 2

42 |

Text 3

43 | 44 | 45 | -------------------------------------------------------------------------------- /test/viewports/viewports.test.js: -------------------------------------------------------------------------------- 1 | const { promisify } = require('es6-promisify'); 2 | const rimrafAsync = promisify(require('rimraf')); 3 | const path = require('path'); 4 | const { exec } = require('child-process-promise'); 5 | const dirContentsToObject = require('../_utils/dirContentsToObject'); 6 | 7 | const distPath = path.join(__dirname, 'dist'); 8 | 9 | beforeEach(() => rimrafAsync(distPath)); 10 | 11 | test('viewports', async () => { 12 | await exec([ 13 | 'node ../../bin/cli', 14 | '--puppeteer-args="--no-sandbox --disable-setuid-sandbox"', 15 | '--out-dir dist', 16 | '--file index.html', 17 | '--viewports.Desktop 1024x768', 18 | '--viewports.Mobile 320x568', 19 | '--viewports.Retina 1024x768@2', 20 | ].join(' '), { cwd: __dirname }); 21 | 22 | const output = await dirContentsToObject(distPath); 23 | expect(output).toMatchSnapshot(); 24 | }); 25 | --------------------------------------------------------------------------------