mirror of
https://github.com/beautifier/js-beautify.git
synced 2024-11-23 12:49:40 +00:00
Merge branch 'master' into add-tests
This commit is contained in:
commit
1e99b57827
@ -8,10 +8,10 @@ ratings:
|
||||
- "**.js"
|
||||
- "**.py"
|
||||
exclude_paths:
|
||||
- test/resources/**
|
||||
- webpack.config.js
|
||||
- "**/resources/**"
|
||||
- js/test/**
|
||||
- test/data/**
|
||||
- web/lib/**
|
||||
- js/lib/beautify.js
|
||||
- js/lib/beautify-css.js
|
||||
- js/lib/beautify-html.js
|
||||
- tools/template/*
|
||||
- "**/generated/*"
|
||||
|
@ -6,8 +6,7 @@ node_modules/**
|
||||
python/**
|
||||
target/**
|
||||
tools/**
|
||||
test/resources/underscore-min.js
|
||||
test/resources/underscore.js
|
||||
test/resources/*
|
||||
web/lib/**
|
||||
build/**
|
||||
|
||||
|
@ -4,8 +4,10 @@
|
||||
"eqeqeq": true,
|
||||
"noarg": true,
|
||||
"nocomma": true,
|
||||
"node": true,
|
||||
"nonbsp": true,
|
||||
"nonew": true,
|
||||
"strict": true,
|
||||
"unused": true,
|
||||
"esversion": 3
|
||||
}
|
||||
|
120
CHANGELOG.md
120
CHANGELOG.md
@ -1,42 +1,112 @@
|
||||
# Changelog
|
||||
## v1.8.0-rc2
|
||||
## v1.8.6
|
||||
|
||||
### Description
|
||||
Beautifier has moved to https://beautifier.io
|
||||
|
||||
### Closed Issues
|
||||
* JS beautify break the angular compile ([#1544](https://github.com/beautify-web/js-beautify/issues/1544))
|
||||
* base64 string is broken with v1.8.4 ([#1535](https://github.com/beautify-web/js-beautify/issues/1535))
|
||||
* Bookmarklet becomes totally useless ([#1408](https://github.com/beautify-web/js-beautify/issues/1408))
|
||||
* HTTPS ([#1399](https://github.com/beautify-web/js-beautify/issues/1399))
|
||||
* Beautify breaks when js starts with space followed by multi-line comment ([#789](https://github.com/beautify-web/js-beautify/issues/789))
|
||||
|
||||
|
||||
## v1.8.4
|
||||
|
||||
### Description
|
||||
Broader adoption of 1.8.x revealed a few more high priority fixes
|
||||
|
||||
|
||||
### Closed Issues
|
||||
* Multiple newlines added between empty textarea and "unformatted" inline elements ([#1534](https://github.com/beautify-web/js-beautify/issues/1534))
|
||||
* unindent_chained_methods broken ([#1533](https://github.com/beautify-web/js-beautify/issues/1533))
|
||||
|
||||
|
||||
## v1.8.3
|
||||
|
||||
### Description
|
||||
|
||||
|
||||
### Closed Issues
|
||||
* Missing Bower Assets ([#1521](https://github.com/beautify-web/js-beautify/issues/1521))
|
||||
* Javascript ternary breaked with `await` ([#1519](https://github.com/beautify-web/js-beautify/issues/1519))
|
||||
* Object property indented after `await` ([#1517](https://github.com/beautify-web/js-beautify/issues/1517))
|
||||
* Handlebars formatting problems ([#870](https://github.com/beautify-web/js-beautify/issues/870))
|
||||
* beautify.js doesn't have indent_level option ([#724](https://github.com/beautify-web/js-beautify/issues/724))
|
||||
|
||||
|
||||
## v1.8.1
|
||||
|
||||
### Description
|
||||
|
||||
|
||||
### Closed Issues
|
||||
* Why npm is a dependency? ([#1516](https://github.com/beautify-web/js-beautify/issues/1516))
|
||||
* indent_inner_html not working in v1.8.0 ([#1514](https://github.com/beautify-web/js-beautify/issues/1514))
|
||||
|
||||
|
||||
## v1.8.0
|
||||
|
||||
### Description
|
||||
Massive set of fixes and improvements.
|
||||
|
||||
Thanks to contributors: @cheerypick, @swan46, @MacKLess, @Elrendio, @madman-bob, @amanda-bot, @Hirse
|
||||
Thanks to contributors: @cheerypick, @swan46, @MacKLess, @Elrendio, @madman-bob, @amanda-bot, @Hirse, @aeschli, and many more.
|
||||
|
||||
Special thanks to @astronomersiva and @garretwilson for finding key bugs in the RC releases,
|
||||
and to @MacKLess for driving down the open bug count with tons of regression tests.
|
||||
|
||||
Highlights:
|
||||
|
||||
* CSS: `newline_between_rules` support for nested rules - CSS/SASS/SCSS/LESS (@MacKLess)
|
||||
* CSS: @import support in CSS (@MacKLess)
|
||||
* HTML: inline element support (@madman-bob)
|
||||
* HTML: `wrap_attributes` setting `align-multiple` (@cheerypick)
|
||||
* HTML: optional close tags do not over indent - li, tr, etc.
|
||||
* HTML: Improved line wrapping in HTML - still not fully correct
|
||||
* HTML: 10x performance improvement in HTML beautifier
|
||||
* JS: ES6 BigInt support (@thejoshwolfe)
|
||||
* JS: ES6 Dynamic import support
|
||||
* CSS: :hover for @extend formatting (@MacKLess)
|
||||
* HTML: Incorrect line wrapping issue (@andreyvolokitin)
|
||||
* JS: Javascript ++ Operator Indentation (@Elrendio)
|
||||
* JS: Better packer handling in Python (@swan46)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### Closed Issues
|
||||
* list items of nested lists get indented backwards ([#1501](https://github.com/beautify-web/js-beautify/issues/1501))
|
||||
* Make beautifier auto-convert options with dashes into underscores ([#1497](https://github.com/beautify-web/js-beautify/issues/1497))
|
||||
* ReferenceError: token is not defined ([#1496](https://github.com/beautify-web/js-beautify/issues/1496))
|
||||
* Publish v1.8.0 ([#1495](https://github.com/beautify-web/js-beautify/issues/1495))
|
||||
* still probem #1439 / #1337 ([#1491](https://github.com/beautify-web/js-beautify/issues/1491))
|
||||
* Duplicating HTML Code Nested In PHP ([#1483](https://github.com/beautify-web/js-beautify/issues/1483))
|
||||
* Handlebars - `if` tags are broken when using helper with `textarea` ([#1482](https://github.com/beautify-web/js-beautify/issues/1482))
|
||||
* TypeError: Cannot read property '1' of null ([#1481](https://github.com/beautify-web/js-beautify/issues/1481))
|
||||
* Space in Self Closing Tag Issue ([#1478](https://github.com/beautify-web/js-beautify/issues/1478))
|
||||
* Weird Formatting in VSCode ([#1475](https://github.com/beautify-web/js-beautify/issues/1475))
|
||||
* Indent with tab issue on website ([#1470](https://github.com/beautify-web/js-beautify/issues/1470))
|
||||
* Contents of hbs tags are converted to lowercase ([#1464](https://github.com/beautify-web/js-beautify/issues/1464))
|
||||
* HTML tags are indented wrongly when attributes are present ([#1462](https://github.com/beautify-web/js-beautify/issues/1462))
|
||||
* hbs tags are stripped when there is a comment below or inline ([#1461](https://github.com/beautify-web/js-beautify/issues/1461))
|
||||
* Spaces added to handlebars with '=' ([#1460](https://github.com/beautify-web/js-beautify/issues/1460))
|
||||
* jsbeautifier.org don't works ([#1445](https://github.com/beautify-web/js-beautify/issues/1445))
|
||||
* Commenting code and then beautifying removes line breaks ([#1440](https://github.com/beautify-web/js-beautify/issues/1440))
|
||||
* Less: Where is my space? ([#1411](https://github.com/beautify-web/js-beautify/issues/1411))
|
||||
* No newline after @import ([#1406](https://github.com/beautify-web/js-beautify/issues/1406))
|
||||
* "html.format.wrapAttributes": "force-aligned" adds empty line on long attributes ([#1403](https://github.com/beautify-web/js-beautify/issues/1403))
|
||||
* HTML: wrap_line_length is handled incorrectly ([#1401](https://github.com/beautify-web/js-beautify/issues/1401))
|
||||
* js-beautify is breaking code by adding space after import ([#1393](https://github.com/beautify-web/js-beautify/issues/1393))
|
||||
* JS-Beautify should format XML tags inside HTML files ([#1383](https://github.com/beautify-web/js-beautify/issues/1383))
|
||||
* python unpacker can not handle if radix given as [] and not as a number ([#1381](https://github.com/beautify-web/js-beautify/issues/1381))
|
||||
* unindent_chained_methods breaks indentation for if statements without brackets ([#1378](https://github.com/beautify-web/js-beautify/issues/1378))
|
||||
* function parameters merged into single line when starting with ! or [ ([#1374](https://github.com/beautify-web/js-beautify/issues/1374))
|
||||
* CSS selector issue (header > div[class~="div-all"]) in SCSS file ([#1373](https://github.com/beautify-web/js-beautify/issues/1373))
|
||||
* Add "Create Issue for Unexpected Output" button to website ([#1371](https://github.com/beautify-web/js-beautify/issues/1371))
|
||||
* Add combobox to control type of beautification ([#1370](https://github.com/beautify-web/js-beautify/issues/1370))
|
||||
* Add Options textbox to website for debugging ([#1369](https://github.com/beautify-web/js-beautify/issues/1369))
|
||||
* Python version fails to properly beautify packed code ([#1367](https://github.com/beautify-web/js-beautify/issues/1367))
|
||||
* How to keep comments on their own lines after formating ([#1348](https://github.com/beautify-web/js-beautify/issues/1348))
|
||||
* Beautification of Multiline PHP ([#1346](https://github.com/beautify-web/js-beautify/issues/1346))
|
||||
* Beautification of PHP with echo short tags ([#1339](https://github.com/beautify-web/js-beautify/issues/1339))
|
||||
* URGENT: @extend with :hover, :focus and so on... ([#1331](https://github.com/beautify-web/js-beautify/issues/1331))
|
||||
* JSBeautify options for programmatic use? ([#1327](https://github.com/beautify-web/js-beautify/issues/1327))
|
||||
* js-beautify: fix handling for --eol and --outfile ([#1315](https://github.com/beautify-web/js-beautify/pull/1315))
|
||||
* Note that `gsort` is GNU sort ([#1314](https://github.com/beautify-web/js-beautify/issues/1314))
|
||||
* `pip` doesn't use same version as `/usr/bin/env python` ([#1312](https://github.com/beautify-web/js-beautify/issues/1312))
|
||||
* Wrap and align html attributes when line reaches wrap-line-length ([#1285](https://github.com/beautify-web/js-beautify/issues/1285))
|
||||
* Javascript ++ Operator get wrong indent ([#1283](https://github.com/beautify-web/js-beautify/issues/1283))
|
||||
* Create beta channel for releases ([#1255](https://github.com/beautify-web/js-beautify/issues/1255))
|
||||
* await import(...) ([#1228](https://github.com/beautify-web/js-beautify/issues/1228))
|
||||
* The result of "Format document" is weird of certain HTML content. ([#1223](https://github.com/beautify-web/js-beautify/issues/1223))
|
||||
* (next_tag || "").match is not a function ([#1202](https://github.com/beautify-web/js-beautify/issues/1202))
|
||||
* `force-expand-multiline` doesn't work as expected ([#1186](https://github.com/beautify-web/js-beautify/issues/1186))
|
||||
* HTML text content formatted incorrectly ([#1184](https://github.com/beautify-web/js-beautify/issues/1184))
|
||||
* Nested span tags not indenting properly ([#1167](https://github.com/beautify-web/js-beautify/issues/1167))
|
||||
* SCSS Comment Issue ([#1165](https://github.com/beautify-web/js-beautify/issues/1165))
|
||||
* Less function parameters are wrapped unexpected ([#1156](https://github.com/beautify-web/js-beautify/issues/1156))
|
||||
* TypeError: Cannot read property 'replace' of undefined ([#1120](https://github.com/beautify-web/js-beautify/issues/1120))
|
||||
* HTML formatting wraps ending block tag for no reason with nested inline elements ([#1041](https://github.com/beautify-web/js-beautify/issues/1041))
|
||||
* not correctly joining lines for HTML ([#1033](https://github.com/beautify-web/js-beautify/issues/1033))
|
||||
|
||||
|
||||
## v1.7.5
|
||||
|
46
CODE_OF_CONDUCT.md
Normal file
46
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at team@beautifier.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
@ -9,12 +9,12 @@ Fixes and enhancements are totally welcome. We prefer you to file an issue befo
|
||||
|
||||
### 0. Prereqisites for development
|
||||
|
||||
* bash
|
||||
* bash
|
||||
* make
|
||||
* nodejs - v10.x (with npm)
|
||||
* python - v2.7.x or v3.x (with pip)
|
||||
|
||||
If you encounter issues and cannot build, come chat on gitter.im. We're happy to help.
|
||||
If you encounter issues and cannot build, come chat on gitter.im. We're happy to help.
|
||||
|
||||
### 1. Build and Test Locally
|
||||
This repository holds two mostly identical implementations of the beautifiers: a JavaScript implementation and a Python implementation.
|
||||
@ -62,7 +62,7 @@ Files related to the JavaScript implementations of the beautifiers.
|
||||
Files related to the Python implementations of the beautifiers.
|
||||
|
||||
## `web`
|
||||
Files related to http://jsbeautifier.org/.
|
||||
Files related to https://beautifier.io/.
|
||||
|
||||
## `test`
|
||||
Test data files and support files used to generate implementation-specific test files.
|
||||
@ -73,8 +73,11 @@ Test data files and support files used to generate implementation-specific test
|
||||
## Master
|
||||
We use the `master` branch as the primary development branch.
|
||||
|
||||
## Milestone Release Tags
|
||||
Each release is has a tag created for it when it is released. The latest release is linked from the `README.md`.
|
||||
## Release
|
||||
We use the `release` branch to hold releases, including built files for bower and the website.
|
||||
|
||||
# Tags
|
||||
Each release is has a tag created for it in the `release` branch when it is published. The latest release is linked from the `README.md`.
|
||||
|
||||
## Attic
|
||||
This project has been around for a while. While some parts have improved significantly over time, others fell
|
||||
@ -119,6 +122,7 @@ This is script will:
|
||||
|
||||
* Update README.md with correct cdn links
|
||||
* Update CHANGLOG.md with the milestone description and a list of closed issues
|
||||
* Commit the built files to the `release` branch
|
||||
* Publish the python version to PyPI
|
||||
* Publish the javascript version to npm
|
||||
* Merge the changes and publish them on the gh-pages branch
|
||||
|
14
Makefile
14
Makefile
@ -32,14 +32,14 @@ py: generate-tests $(BUILD_DIR)/python
|
||||
@echo Testing python beautify functionality...
|
||||
$(SCRIPT_DIR)/python-dev python python/js-beautify-test.py || exit 1
|
||||
|
||||
jstest: depends js package
|
||||
jstest: depends js build/*.tgz
|
||||
@echo Testing javascript implementation...
|
||||
@$(NODE) js/test/node-beautify-tests.js || exit 1
|
||||
@$(NODE) js/test/amd-beautify-tests.js || exit 1
|
||||
@$(NODE) --version && \
|
||||
./js/test/shell-test.sh
|
||||
|
||||
pytest: depends py package
|
||||
pytest: depends py python/dist/*
|
||||
@echo Testing python implementation...
|
||||
@cd python && \
|
||||
$(PYTHON) --version && \
|
||||
@ -50,12 +50,16 @@ package: js py build/*.tgz python/dist/*
|
||||
|
||||
perf:
|
||||
@echo ----------------------------------------
|
||||
@echo Testing beautify performance...
|
||||
@echo Testing node js beautify performance...
|
||||
$(NODE) js/test/node-beautify-perf-tests.js || exit 1
|
||||
@echo Testing node css beautify performance...
|
||||
$(NODE) js/test/node-beautify-css-perf-tests.js || exit 1
|
||||
@echo Testing html-beautify performance...
|
||||
$(NODE) js/test/node-beautify-html-perf-tests.js || exit 1
|
||||
@echo Testing python beautify performance...
|
||||
@echo Testing python js beautify performance...
|
||||
$(SCRIPT_DIR)/python-dev python python/test-perf-jsbeautifier.py || exit 1
|
||||
@echo Testing python css beautify performance...
|
||||
$(SCRIPT_DIR)/python-dev python python/test-perf-cssbeautifier.py || exit 1
|
||||
@echo ----------------------------------------
|
||||
|
||||
generate-tests: $(BUILD_DIR)/generate
|
||||
@ -67,7 +71,7 @@ beautify:
|
||||
#######################################################
|
||||
|
||||
# javascript bundle generation
|
||||
js/lib/*.js: $(BUILD_DIR)/node $(BUILD_DIR)/generate $(wildcard js/src/**/*) js/index.js tools/template/* webpack.config.js
|
||||
js/lib/*.js: $(BUILD_DIR)/node $(BUILD_DIR)/generate $(wildcard js/src/**/*) $(wildcard web/*.js) js/index.js tools/template/* webpack.config.js
|
||||
$(SCRIPT_DIR)/build.sh js
|
||||
|
||||
|
||||
|
33
README.md
33
README.md
@ -15,10 +15,10 @@
|
||||
|
||||
This little beautifier will reformat and re-indent bookmarklets, ugly
|
||||
JavaScript, unpack scripts packed by Dean Edward’s popular packer,
|
||||
as well as deobfuscate scripts processed by
|
||||
[javascriptobfuscator.com](http://javascriptobfuscator.com/).
|
||||
as well as partly deobfuscate scripts processed by the npm package
|
||||
[javascript-obfuscator](https://github.com/javascript-obfuscator/javascript-obfuscator).
|
||||
|
||||
Open [jsbeautifier.org](http://jsbeautifier.org/) to try it out. Options are available via the UI.
|
||||
Open [beautifier.io](https://beautifier.io/) to try it out. Options are available via the UI.
|
||||
|
||||
# Contributors Needed
|
||||
I'm putting this front and center above because existing owners have very limited time to work on this project currently.
|
||||
@ -62,17 +62,17 @@ JS Beautifier is hosted on two CDN services: [cdnjs](https://cdnjs.com/libraries
|
||||
|
||||
To pull the latest version from one of these services include one set of the script tags below in your document:
|
||||
```html
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.0-rc4/beautify.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.0-rc4/beautify-css.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.0-rc4/beautify-html.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.6/beautify.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.6/beautify-css.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.6/beautify-html.js"></script>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.0-rc4/beautify.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.0-rc4/beautify-css.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.0-rc4/beautify-html.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.6/beautify.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.6/beautify-css.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.8.6/beautify-html.min.js"></script>
|
||||
|
||||
<script src="https://cdn.rawgit.com/beautify-web/js-beautify/gh-pages/js/lib/beautify.js"></script>
|
||||
<script src="https://cdn.rawgit.com/beautify-web/js-beautify/gh-pages/js/lib/beautify-css.js"></script>
|
||||
<script src="https://cdn.rawgit.com/beautify-web/js-beautify/gh-pages/js/lib/beautify-html.js"></script>
|
||||
<script src="https://cdn.rawgit.com/beautify-web/js-beautify/v1.8.6/js/lib/beautify.js"></script>
|
||||
<script src="https://cdn.rawgit.com/beautify-web/js-beautify/v1.8.6/js/lib/beautify-css.js"></script>
|
||||
<script src="https://cdn.rawgit.com/beautify-web/js-beautify/v1.8.6/js/lib/beautify-html.js"></script>
|
||||
```
|
||||
|
||||
Older versions are available by changing the version number.
|
||||
@ -92,7 +92,7 @@ $ pip install jsbeautifier
|
||||
You can beautify javascript using JS Beautifier in your web browser, or on the command-line using node.js or python.
|
||||
|
||||
## Web Browser
|
||||
Open [jsbeautifier.org](http://jsbeautifier.org/). Options are available via the UI.
|
||||
Open [beautifier.io](https://beautifier.io/). Options are available via the UI.
|
||||
|
||||
## Web Libary
|
||||
The script tags above expose three functions: `js_beautify`, `css_beautify`, and `html_beautify`.
|
||||
@ -180,6 +180,7 @@ Beautifier Options:
|
||||
-E, --space-in-empty-paren Add a single space inside empty paren, ie. f( )
|
||||
-j, --jslint-happy Enable jslint-stricter mode
|
||||
-a, --space-after-anon-function Add a space before an anonymous function's parens, ie. function ()
|
||||
--space-after-named-function Add a space before a named function's parens, i.e. function example ()
|
||||
-b, --brace-style [collapse|expand|end-expand|none][,preserve-inline] [collapse,preserve-inline]
|
||||
-u, --unindent-chained-methods Don't indent chained method calls
|
||||
-B, --break-chained-methods Break chained method calls across subsequent lines
|
||||
@ -365,13 +366,13 @@ You are free to use this in any way you want, in case you find this useful or wo
|
||||
|
||||
# Credits
|
||||
|
||||
* Created by Einar Lielmanis, <einar@jsbeautifier.org>
|
||||
* Created by Einar Lielmanis, <einar@beautifier.io>
|
||||
* Python version flourished by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
* Command-line for node.js by Daniel Stockman <daniel.stockman@gmail.com>
|
||||
* Maintained and expanded by Liam Newman <bitwiseman@gmail.com>
|
||||
* Maintained and expanded by Liam Newman <bitwiseman@beautifier.io>
|
||||
|
||||
Thanks also to Jason Diamond, Patrick Hof, Nochum Sossonko, Andreas Schneider, Dave
|
||||
Vasilevsky, Vital Batmanov, Ron Baldwin, Gabriel Harrison, Chris J. Shull,
|
||||
Mathias Bynens, Vittorio Gambaletta and others.
|
||||
|
||||
(README.md: js-beautify@1.8.0-rc4)
|
||||
(README.md: js-beautify@1.8.6)
|
||||
|
457
index.html
457
index.html
@ -25,254 +25,255 @@
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
-->
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" /><meta http-equiv="Content-type" content="text/html;charset=utf-8" />
|
||||
<!-- if you feel an urge to move this to bootstrap or something, you're most welcome -->
|
||||
<title>Online JavaScript beautifier</title>
|
||||
<link rel="icon" href="web/favicon.png" type="image/png">
|
||||
<link rel="stylesheet" href="web/lib/codemirror/lib/codemirror.css">
|
||||
|
||||
<script src="web/lib/codemirror/lib/codemirror.js"></script>
|
||||
<script src="web/lib/codemirror/mode/javascript/javascript.js"></script>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=utf-8" />
|
||||
<!-- if you feel an urge to move this to bootstrap or something, you're most welcome -->
|
||||
<title>Online JavaScript beautifier</title>
|
||||
<link rel="icon" href="web/favicon.png" type="image/png">
|
||||
<link rel="stylesheet" href="web/lib/codemirror/lib/codemirror.css">
|
||||
|
||||
<link rel="stylesheet" href="web/common-style.css"></style>
|
||||
<script src="web/lib/codemirror/lib/codemirror.js"></script>
|
||||
<script src="web/lib/codemirror/mode/javascript/javascript.js"></script>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
|
||||
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.2.0/js.cookie.min.js"
|
||||
integrity="sha256-9Nt2r+tJnSd2A2CRUvnjgsD+ES1ExvjbjBNqidm9doI="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.min.js"
|
||||
integrity="sha256-0SGl1PJNDyJwcV5T+weg2zpEMrh7xvlwO4oXgvZCeZk="
|
||||
crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="web/common-style.css">
|
||||
|
||||
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=default&flags=gated"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.2.0/js.cookie.min.js" integrity="sha256-9Nt2r+tJnSd2A2CRUvnjgsD+ES1ExvjbjBNqidm9doI=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.min.js" integrity="sha256-0SGl1PJNDyJwcV5T+weg2zpEMrh7xvlwO4oXgvZCeZk=" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="js/lib/unpackers/javascriptobfuscator_unpacker.js"></script>
|
||||
<script src="js/lib/unpackers/urlencode_unpacker.js"></script>
|
||||
<script src="js/lib/unpackers/p_a_c_k_e_r_unpacker.js"></script>
|
||||
<script src="js/lib/unpackers/myobfuscate_unpacker.js"></script>
|
||||
<script src="web/common-function.js"></script>
|
||||
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=default&flags=gated"></script>
|
||||
|
||||
<script src="js/lib/unpackers/javascriptobfuscator_unpacker.js"></script>
|
||||
<script src="js/lib/unpackers/urlencode_unpacker.js"></script>
|
||||
<script src="js/lib/unpackers/p_a_c_k_e_r_unpacker.js"></script>
|
||||
<script src="js/lib/unpackers/myobfuscate_unpacker.js"></script>
|
||||
<script src="web/common-function.js"></script>
|
||||
</head>
|
||||
|
||||
<h1>Online JavaScript Beautifier <span id="version-number"></span></h1>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="about">
|
||||
<p>
|
||||
<a class="self" href="./">Beautify, unpack or deobfuscate JavaScript and HTML, make JSON/JSONP readable, etc.</a>
|
||||
</p>
|
||||
<p>
|
||||
All of the source code is completely free and open, available on <a href="https://github.com/beautify-web/js-beautify">GitHub</a> under MIT licence,
|
||||
<br>and we have a command-line version, python library and a <a href="https://npmjs.org/package/js-beautify">node package</a> as well.
|
||||
</p>
|
||||
</div>
|
||||
<div id="about">
|
||||
<p>
|
||||
<a class="self" href="./">Beautify, unpack or deobfuscate JavaScript and HTML, make JSON/JSONP readable, etc.</a>
|
||||
</p>
|
||||
<p>
|
||||
All of the source code is completely free and open, available on <a href="https://github.com/beautify-web/js-beautify">GitHub</a> under MIT licence,
|
||||
<br>and we have a command-line version, python library and a <a href="https://npmjs.org/package/js-beautify">node package</a> as well.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<table id="options">
|
||||
<tr>
|
||||
<td>
|
||||
<select name="tabsize" id="tabsize">
|
||||
<option value="1">Indent with a tab character</option>
|
||||
<option value="2">Indent with 2 spaces</option>
|
||||
<option value="3">Indent with 3 spaces</option>
|
||||
<option value="4">Indent with 4 spaces</option>
|
||||
<option value="8">Indent with 8 spaces</option>
|
||||
</select>
|
||||
<br>
|
||||
|
||||
<select name="max-preserve-newlines" id="max-preserve-newlines">
|
||||
<option value="-1">Remove all extra newlines</option>
|
||||
<option value="1">Allow 1 newline between tokens</option>
|
||||
<option value="2">Allow 2 newlines between tokens</option>
|
||||
<option value="5">Allow 5 newlines between tokens</option>
|
||||
<option value="10">Allow 10 newlines between tokens</option>
|
||||
<option value="0">Allow unlimited newlines between tokens</option>
|
||||
</select>
|
||||
<br>
|
||||
|
||||
<select name="wrap-line-length" id="wrap-line-length">
|
||||
<option value="0">Do not wrap lines</option>
|
||||
<option value="40">Wrap lines near 40 characters</option>
|
||||
<option value="70">Wrap lines near 70 characters</option>
|
||||
<option value="80">Wrap lines near 80 characters</option>
|
||||
<option value="110">Wrap lines near 110 characters</option>
|
||||
<option value="120">Wrap lines near 120 characters</option>
|
||||
<option value="160">Wrap lines near 160 characters</option>
|
||||
</select>
|
||||
<br>
|
||||
|
||||
<select id="brace-style">
|
||||
<option value="collapse">Braces with control statement</option>
|
||||
<option value="expand">Braces on own line</option>
|
||||
<option value="end-expand">End braces on own line</option>
|
||||
<option value="none">Attempt to keep braces where they are</option>
|
||||
</select>
|
||||
|
||||
<p style="margin:6px 0 0 0">HTML <style>, <script> formatting:</p>
|
||||
<select id="indent-scripts">
|
||||
<option value="keep">Keep indent level of the tag</option>
|
||||
<option value="normal">Add one indent level</option>
|
||||
<option value="separate">Separate indentation</option>
|
||||
</select>
|
||||
|
||||
<p style="margin:6px 0 0 0">Additional Settings (JSON):</p>
|
||||
<textarea id="additional-options" rows="5" cols="32">{}</textarea>
|
||||
|
||||
<p id ="additional-options-error" hidden style="margin:6px 0 0 0; color:red ">Could Not Parse JSON!</p>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<input class="checkbox" type="checkbox" id="end-with-newline">
|
||||
<label for="end-with-newline">End script and style with newline?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="e4x">
|
||||
<label for="e4x">Support e4x/jsx syntax</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="comma-first">
|
||||
<label for="comma-first">Use comma-first list style?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="detect-packers">
|
||||
<label for="detect-packers">Detect packers and obfuscators?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="brace-preserve-inline">
|
||||
<label for="brace-preserve-inline">Preserve inline braces/code blocks?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="keep-array-indentation">
|
||||
<label for="keep-array-indentation">Keep array indentation?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="break-chained-methods">
|
||||
<label for="break-chained-methods">Break lines on chained methods?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="space-before-conditional">
|
||||
<label for="space-before-conditional">Space before conditional: "if(x)" / "if (x)"</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="unescape-strings">
|
||||
<label for="unescape-strings">Unescape printable chars encoded as \xNN or \uNNNN?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="jslint-happy">
|
||||
<label for="jslint-happy">Use JSLint-happy formatting tweaks?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="indent-inner-html">
|
||||
<label for="indent-inner-html">Indent <head> and <body> sections?</label>
|
||||
<br><a href="?without-codemirror" class="turn-off-codemirror">Use a simple textarea for code input?</a>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div style="line-height: 0">
|
||||
<select name="language" id="language">
|
||||
<option value="auto">Auto Detect</option>
|
||||
<option value="css">CSS</option>
|
||||
<option value="html">HTML</option>
|
||||
<option value="js">JavaScript</option>
|
||||
<table id="options">
|
||||
<tr>
|
||||
<td>
|
||||
<select name="tabsize" id="tabsize">
|
||||
<option value="1">Indent with a tab character</option>
|
||||
<option value="2">Indent with 2 spaces</option>
|
||||
<option value="3">Indent with 3 spaces</option>
|
||||
<option value="4">Indent with 4 spaces</option>
|
||||
<option value="8">Indent with 8 spaces</option>
|
||||
</select>
|
||||
<button class="submit"><strong>Beautify JavaScript or HTML</strong> <em>(ctrl-enter)</em>
|
||||
</button>
|
||||
<textarea id="source" rows="30" cols="160"></textarea>
|
||||
<button class="submit"><strong>Beautify JavaScript or HTML</strong> <em>(ctrl-enter)</em>
|
||||
</button>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<p style="margin:6px 0 0 0">Your Selected Options (JSON):</p>
|
||||
<div style="line-height: 0">
|
||||
<textarea readonly id="options-selected" rows="10" cols="40"></textarea>
|
||||
</div>
|
||||
<select name="max-preserve-newlines" id="max-preserve-newlines">
|
||||
<option value="-1">Remove all extra newlines</option>
|
||||
<option value="1">Allow 1 newline between tokens</option>
|
||||
<option value="2">Allow 2 newlines between tokens</option>
|
||||
<option value="5">Allow 5 newlines between tokens</option>
|
||||
<option value="10">Allow 10 newlines between tokens</option>
|
||||
<option value="0">Allow unlimited newlines between tokens</option>
|
||||
</select>
|
||||
<br>
|
||||
|
||||
<p id="open-issue" hidden>Not pretty enough for you?
|
||||
<select name="wrap-line-length" id="wrap-line-length">
|
||||
<option value="0">Do not wrap lines</option>
|
||||
<option value="40">Wrap lines near 40 characters</option>
|
||||
<option value="70">Wrap lines near 70 characters</option>
|
||||
<option value="80">Wrap lines near 80 characters</option>
|
||||
<option value="110">Wrap lines near 110 characters</option>
|
||||
<option value="120">Wrap lines near 120 characters</option>
|
||||
<option value="160">Wrap lines near 160 characters</option>
|
||||
</select>
|
||||
<br>
|
||||
|
||||
<select id="brace-style">
|
||||
<option value="collapse">Braces with control statement</option>
|
||||
<option value="expand">Braces on own line</option>
|
||||
<option value="end-expand">End braces on own line</option>
|
||||
<option value="none">Attempt to keep braces where they are</option>
|
||||
</select>
|
||||
|
||||
<p style="margin:6px 0 0 0">HTML <style>, <script> formatting:</p>
|
||||
<select id="indent-scripts">
|
||||
<option value="keep">Keep indent level of the tag</option>
|
||||
<option value="normal">Add one indent level</option>
|
||||
<option value="separate">Separate indentation</option>
|
||||
</select>
|
||||
|
||||
<p style="margin:6px 0 0 0">Additional Settings (JSON):</p>
|
||||
<textarea id="additional-options" rows="5" cols="32">{}</textarea>
|
||||
|
||||
<p id="additional-options-error" hidden style="margin:6px 0 0 0; color:red ">Could Not Parse JSON!</p>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<input class="checkbox" type="checkbox" id="end-with-newline">
|
||||
<label for="end-with-newline">End script and style with newline?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="e4x">
|
||||
<label for="e4x">Support e4x/jsx syntax</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="comma-first">
|
||||
<label for="comma-first">Use comma-first list style?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="detect-packers">
|
||||
<label for="detect-packers">Detect packers and obfuscators?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="brace-preserve-inline">
|
||||
<label for="brace-preserve-inline">Preserve inline braces/code blocks?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="keep-array-indentation">
|
||||
<label for="keep-array-indentation">Keep array indentation?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="break-chained-methods">
|
||||
<label for="break-chained-methods">Break lines on chained methods?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="space-before-conditional">
|
||||
<label for="space-before-conditional">Space before conditional: "if(x)" / "if (x)"</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="unescape-strings">
|
||||
<label for="unescape-strings">Unescape printable chars encoded as \xNN or \uNNNN?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="jslint-happy">
|
||||
<label for="jslint-happy">Use JSLint-happy formatting tweaks?</label>
|
||||
<br>
|
||||
<input class="checkbox" type="checkbox" id="indent-inner-html">
|
||||
<label for="indent-inner-html">Indent <head> and <body> sections?</label>
|
||||
<br><a href="?without-codemirror" class="turn-off-codemirror">Use a simple textarea for code input?</a>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div style="line-height: 0">
|
||||
<select name="language" id="language">
|
||||
<option value="auto">Auto Detect</option>
|
||||
<option value="css">CSS</option>
|
||||
<option value="html">HTML</option>
|
||||
<option value="js">JavaScript</option>
|
||||
</select>
|
||||
<button class="submit"><strong>Beautify JavaScript or HTML</strong> <em>(ctrl-enter)</em>
|
||||
</button>
|
||||
<textarea id="source" rows="30" cols="160"></textarea>
|
||||
<button class="submit"><strong>Beautify JavaScript or HTML</strong> <em>(ctrl-enter)</em>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p style="margin:6px 0 0 0">Your Selected Options (JSON):</p>
|
||||
<div style="line-height: 0">
|
||||
<textarea readonly id="options-selected" rows="10" cols="40"></textarea>
|
||||
</div>
|
||||
|
||||
<p id="open-issue" hidden>Not pretty enough for you?
|
||||
<button type="button" onclick="submitIssue()" name="issue-button">Report an issue</button>
|
||||
</p>
|
||||
|
||||
<div class="blurb">
|
||||
|
||||
<h2>Browser extensions and other uses</h2>
|
||||
<div class="col-6">
|
||||
<ul class="uses">
|
||||
|
||||
<li>A
|
||||
<a href="javascript:(function(){s=document.getElementsByTagName('SCRIPT');tx='';sr=[];for(i=0;i<s.length;i++){with(s.item(i)){t=text;if(t){tx+=t;}else{sr.push(src)};}};with(window.open()){document.write('<textarea id="t">'+(sr.join("\n"))+"\n\n-----\n\n"+tx+'</textarea><script src="https://beautifier.io/js/lib/beautify.js"></script><script>with(document.getElementById("t")){value=js_beautify(value);with(style){width="99%";height="99%";borderStyle="none";}};</script>');document.close();}})();">
|
||||
<strong>bookmarklet</strong></a>
|
||||
(drag it to your bookmarks) by Ichiro Hiroshi to see all scripts used on the page,</li>
|
||||
|
||||
<li><strong>Chrome</strong>, in case the built-in CSS and javascript formatting isn't enough for you:<br>
|
||||
— <a href="https://chrome.google.com/webstore/detail/cfmcghennfbpmhemnnfjhkdmnbidpanb">Quick source viewer</a> by Tomi Mickelsson (<a href="https://github.com/tomimick/chrome-ext-view-src">github</a>, <a href="http://tomicloud.com/2012/07/viewsrc-chrome-ext">blog</a>),<br>
|
||||
— <a href="https://chrome.google.com/webstore/detail/javascript-and-css-code-b/iiglodndmmefofehaibmaignglbpdald">Javascript and CSS Code beautifier</a> by c7sky,<br>
|
||||
— <a href="https://chrome.google.com/webstore/detail/jsbeautify-for-google-chr/kkioiolcacgoihiiekambdciinadbpfk">jsbeautify-for-chrome</a> by Tom Rix (<a href="https://github.com/rixth/jsbeautify-for-chrome">github</a>),<br>
|
||||
— <a href="https://chrome.google.com/webstore/detail/piekbefgpgdecckjcpffhnacjflfoddg">Pretty Beautiful JavaScript</a> by Will McSweeney<br>
|
||||
— <a href="https://chrome.google.com/webstore/detail/stackoverflow-code-beauti/pljeafjjkkbacckkollfejkciddacmeb">Stackoverflow Code Beautify</a> by Making Odd Edit Studios (<a href="https://github.com/MakingOddEdit/CodeBeautify">github</a>).
|
||||
</li>
|
||||
<li><strong>Firefox</strong>: <a href="https://addons.mozilla.org/en-US/firefox/addon/javascript-deminifier/">Javascript deminifier</a> by Ben Murphy, to be
|
||||
used together with the firebug (<a href="https://github.com/benmmurphy/jsdeminifier_xpi/">github</a>),</li>
|
||||
<li><strong>Safari</strong>: <a href="http://spadin.github.com/js-beautify-safari-extension">Safari extension</a> by Sandro Padin,</li>
|
||||
<li><strong>Opera</strong>: <a href="https://addons.opera.com/addons/extensions/details/readable-javascript/">Readable JavaScript</a>
|
||||
(<a href="https://github.com/Dither/readable-javascript">github</a>) by Dither,</li>
|
||||
<li><strong>Opera</strong>: <a href="https://addons.opera.com/addons/extensions/details/source/">Source</a> extension by Deathamns,</li>
|
||||
<li><strong>Sublime Text 2/3:</strong> <a href="https://github.com/akalongman/sublimetext-codeformatter">CodeFormatter</a>, a python plugin by Avtandil Kikabidze, supports HTML, CSS, JS and a bunch of other languages,</li>
|
||||
<li><strong>Sublime Text 2/3:</strong> <a href="https://github.com/victorporof/Sublime-HTMLPrettify">HTMLPrettify</a>, a javascript plugin by Victor Porof,</li>
|
||||
<li><strong>Sublime Text 2:</strong> <a href="https://github.com/jdc0589/JsFormat">JsFormat</a>, a javascript formatting plugin for this nice editor by Davis
|
||||
Clark,</li>
|
||||
<li><strong>vim:</strong> <a href="https://github.com/michalliu/sourcebeautify.vim">sourcebeautify.vim</a>, a plugin by michalliu (requires node.js, V8, SpiderMonkey
|
||||
or cscript js engine),</li>
|
||||
<li><strong>vim:</strong> <a href="https://github.com/maksimr/vim-jsbeautify">vim-jsbeautify</a>, a plugin by Maksim Ryzhikov (node.js or V8 required),</li>
|
||||
|
||||
<li><strong>Emacs:</strong> <a href="https://github.com/yasuyk/web-beautify">Web-beautify</a> formatting package by Yasuyuki Oka,</li>
|
||||
<li><strong>Komodo IDE:</strong> <a href="http://komodoide.com/packages/addons/beautify-js/">Beautify-js</a> addon by Bob de Haas (<a href="https://github.com/babobski/Beautify-js">github</a>),</li>
|
||||
<li><strong>C#:</strong> ghost6991 <a href="https://github.com/ghost6991/Jsbeautifier">ported the javascript formatter to C#</a>,</li>
|
||||
<li><strong>Go:</strong> ditashi has <a href="https://github.com/ditashi/jsbeautifier-go">ported the javascript formatter to golang</a>,</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<ul class="uses">
|
||||
<li><a href="https://marketplace.visualstudio.com/items/HookyQR.beautify">Beautify plugin</a> (<a href="https://github.com/HookyQR/VSCodeBeautify">github</a>) by HookyQR for the <a href="https://code.visualstudio.com/">Visual Studio Code</a> IDE</a>,</li>
|
||||
<li><a href="http://fiddler2.com/">Fiddler</a> proxy: <a href="http://fiddler2.com/Fiddler2/extensions.asp">JavaScript Formatter addon</a>,</li>
|
||||
<li><a href="https://github.com/nagaozen/gedit-tunnings/">gEdit tips</a> by Fabio Nagao,</li>
|
||||
<li><a href="http://akelpad.sourceforge.net/forum/viewtopic.php?p=11246#11246">Akelpad extension</a> by Infocatcher,</li>
|
||||
<li>Beautifier in <a href="http://sethmason.com/2011/04/28/jsbeautify-in-emacs.html">Emacs</a> write-up by Seth Mason,</li>
|
||||
<li><a href="http://c9.io">Cloud9</a>, a lovely IDE running in a browser, working in the node/cloud, uses jsbeautifier (<a href="https://github.com/ajaxorg/cloud9">github</a>),</li>
|
||||
<li><a href="https://www.comment-devenir-un-hacker.com/app.html">Devenir Hacker App</a>, a non-free JavaScript packer for Mac,</li>
|
||||
<li><a href="http://www.restconsole.com/">REST Console</a>, a request debugging tool for Chrome, beautifies JSON responses (<a href="https://github.com/codeinchaos/rest-console">github</a>),</li>
|
||||
<li><a href="http://mitmproxy.org/">mitmproxy</a>, a nifty SSL-capable HTTP proxy, provides pretty javascript responses (<a href="https://github.com/cortesi/mitmproxy">github</a>).</li>
|
||||
<li><a href="http://www.wakanda.org/">wakanda</a>, a neat IDE for web and mobile applications has a <a href="http://forum.wakanda.org/showthread.php?1483-3-new-extensions-JSLint-Beautifier-and-Snippet">Beautifier extension</a>
|
||||
(<a href="https://github.com/Wakanda/wakanda-extensions/tree/master/Beautifier">github</a>).</li>
|
||||
<li><a href="http://portswigger.net/burp/">Burp Suite</a> now has a <a href="https://github.com/irsdl/BurpSuiteJSBeautifier/">beautfier extension</a>,
|
||||
thanks to Soroush Dalili,</li>
|
||||
<li><a href="http://plugins.netbeans.org/plugin/43263/jsbeautify">Netbeans jsbeautify</a> plugin by Drew Hamlett
|
||||
(<a href="https://github.com/drewhjava/netbeans-jsbeautify">github</a>).</li>
|
||||
<li><a href="https://github.com/drewhjava/brackets-beautify">brackets-beautify-extension</a> for <a href="http://brackets.io">Adobe Brackets</a> by Drew
|
||||
Hamlett (<a href="https://github.com/drewhjava/brackets-beautify">github</a>),</li>
|
||||
<li><a href="http://codecaddy.net/">codecaddy.net</a>, a collection of webdev-related tools, assembled by Darik Hall,</li>
|
||||
<li><a href="http://www.editey.com/">editey.com</a>, an interesting and free Google-Drive oriented editor uses this beautifier,</li>
|
||||
<li><a href="https://github.com/vkadam/grunt-jsbeautifier">a beautifier plugin for Grunt</a> by Vishal Kadam,</li>
|
||||
<li><a href="http://www.uvviewsoft.com/synwrite/">SynWrite</a> editor has a JsFormat plugin (<a href="https://sourceforge.net/projects/synwrite-addons/files/PyPlugins/Alexey.JsFormat/">rar</a>, <a href="http://synwrite.sourceforge.net/forums/viewtopic.php?f=19&t=865">readme</a>),</li>
|
||||
<li><a href="http://liveditor.com/">LIVEditor</a>, a live-editing HTML/CSS/JS IDE (commercial, Windows-only) uses the library,</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>Doing anything interesting? Write us to <b>team@beautifier.io</b> so we can add your project to the list.</p>
|
||||
|
||||
<p class="contributor-sep">Written by <a href="https://github.com/einars">Einar Lielmanis</a>, maintained and evolved by <a href="https://github.com/bitwiseman/">Liam Newman</a>.</p>
|
||||
<p>We use the wonderful <a href="http://codemirror.net">CodeMirror</a> syntax highlighting editor, written by Marijn Haverbeke.
|
||||
</p>
|
||||
<p class="contributors">Made with a great help of Jason Diamond, Patrick Hof, Nochum Sossonko, Andreas Schneider,
|
||||
<br>Dave Vasilevsky,
|
||||
<a href="https://moikrug.ru/vital">Vital Batmanov</a>, Ron Baldwin, Gabriel Harrison,
|
||||
<a href="http://shullian.com">Chris J. Shull</a>,
|
||||
<a href="http://mathiasbynens.be/">Mathias Bynens</a>,
|
||||
<br>
|
||||
<a href="https://www.vittgam.net/">Vittorio Gambaletta</a>,
|
||||
<a href="https://github.com/esseks">Stefano Sanfilippo</a> and
|
||||
<a href="https://github.com/evocateur">Daniel Stockman</a>.
|
||||
</p>
|
||||
|
||||
<div class="blurb">
|
||||
<p style="text-align:right">
|
||||
<a href="#" style="color: #ccc; border-bottom: 1px dashed #ccc; text-decoration: none;" onclick="run_tests(); return false;">Run the tests</a>
|
||||
</p>
|
||||
|
||||
<h2>Browser extensions and other uses</h2>
|
||||
<div class="col-6">
|
||||
<ul class="uses">
|
||||
|
||||
<li>A <a href="javascript:(function(){s=document.getElementsByTagName('SCRIPT');tx='';sr=[];for(i=0;i<s.length;i++){with(s.item(i)){t=text;if(t){tx+=t;}else{sr.push(src)};}};with(window.open()){document.write('<textarea id="t">'+(sr.join("\n"))+"\n\n-----\n\n"+tx+'</textarea><script src="http://jsbeautifier.org/beautify.js"></script><script>with(document.getElementById("t")){value=js_beautify(value);with(style){width="99%";height="99%";borderStyle="none";}};</script>');document.close();}})();"><strong>bookmarklet</strong></a> (drag
|
||||
it to your bookmarks) by Ichiro Hiroshi to see all scripts used on the page,</li>
|
||||
|
||||
<li><strong>Chrome</strong>, in case the built-in CSS and javascript formatting isn't enough for you:<br>
|
||||
— <a href="https://chrome.google.com/webstore/detail/cfmcghennfbpmhemnnfjhkdmnbidpanb">Quick source viewer</a> by Tomi Mickelsson (<a href="https://github.com/tomimick/chrome-ext-view-src">github</a>, <a href="http://tomicloud.com/2012/07/viewsrc-chrome-ext">blog</a>),<br>
|
||||
— <a href="https://chrome.google.com/webstore/detail/javascript-and-css-code-b/iiglodndmmefofehaibmaignglbpdald">Javascript and CSS Code beautifier</a> by c7sky,<br>
|
||||
— <a href="https://chrome.google.com/webstore/detail/jsbeautify-for-google-chr/kkioiolcacgoihiiekambdciinadbpfk">jsbeautify-for-chrome</a> by Tom Rix (<a href="https://github.com/rixth/jsbeautify-for-chrome">github</a>),<br>
|
||||
— <a href="https://chrome.google.com/webstore/detail/piekbefgpgdecckjcpffhnacjflfoddg">Pretty Beautiful JavaScript</a> by Will McSweeney<br>
|
||||
— <a href="https://chrome.google.com/webstore/detail/stackoverflow-code-beauti/pljeafjjkkbacckkollfejkciddacmeb">Stackoverflow Code Beautify</a> by Making Odd Edit Studios (<a href="https://github.com/MakingOddEdit/CodeBeautify">github</a>).
|
||||
</li>
|
||||
<li><strong>Firefox</strong>: <a href="https://addons.mozilla.org/en-US/firefox/addon/javascript-deminifier/">Javascript deminifier</a> by Ben Murphy, to be
|
||||
used together with the firebug (<a href="https://github.com/benmmurphy/jsdeminifier_xpi/">github</a>),</li>
|
||||
<li><strong>Safari</strong>: <a href="http://spadin.github.com/js-beautify-safari-extension">Safari extension</a> by Sandro Padin,</li>
|
||||
<li><strong>Opera</strong>: <a href="https://addons.opera.com/addons/extensions/details/readable-javascript/">Readable JavaScript</a>
|
||||
(<a href="https://github.com/Dither/readable-javascript">github</a>) by Dither,</li>
|
||||
<li><strong>Opera</strong>: <a href="https://addons.opera.com/addons/extensions/details/source/">Source</a> extension by Deathamns,</li>
|
||||
<li><strong>Sublime Text 2/3:</strong> <a href="https://github.com/akalongman/sublimetext-codeformatter">CodeFormatter</a>, a python plugin by Avtandil Kikabidze, supports HTML, CSS, JS and a bunch of other languages,</li>
|
||||
<li><strong>Sublime Text 2/3:</strong> <a href="https://github.com/victorporof/Sublime-HTMLPrettify">HTMLPrettify</a>, a javascript plugin by Victor Porof,</li>
|
||||
<li><strong>Sublime Text 2:</strong> <a href="https://github.com/jdc0589/JsFormat">JsFormat</a>, a javascript formatting plugin for this nice editor by Davis
|
||||
Clark,</li>
|
||||
<li><strong>vim:</strong> <a href="https://github.com/michalliu/sourcebeautify.vim">sourcebeautify.vim</a>, a plugin by michalliu (requires node.js, V8, SpiderMonkey
|
||||
or cscript js engine),</li>
|
||||
<li><strong>vim:</strong> <a href="https://github.com/maksimr/vim-jsbeautify">vim-jsbeautify</a>, a plugin by Maksim Ryzhikov (node.js or V8 required),</li>
|
||||
|
||||
<li><strong>Emacs:</strong> <a href="https://github.com/yasuyk/web-beautify">Web-beautify</a> formatting package by Yasuyuki Oka,</li>
|
||||
<li><strong>Komodo IDE:</strong> <a href="http://komodoide.com/packages/addons/beautify-js/">Beautify-js</a> addon by Bob de Haas (<a href="https://github.com/babobski/Beautify-js">github</a>),</li>
|
||||
<li><strong>C#:</strong> ghost6991 <a href="https://github.com/ghost6991/Jsbeautifier">ported the javascript formatter to C#</a>,
|
||||
<li><strong>Go:</strong> ditashi has <a href="https://github.com/ditashi/jsbeautifier-go">ported the javascript formatter to golang</a>,
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<ul class="uses">
|
||||
<li><a href="https://marketplace.visualstudio.com/items/HookyQR.beautify">Beautify plugin</a> (<a href="https://github.com/HookyQR/VSCodeBeautify">github</a>) by HookyQR for the <a href="https://code.visualstudio.com/">Visual Studio Code</a> IDE</a>,
|
||||
<li><a href="http://fiddler2.com/">Fiddler</a> proxy: <a href="http://fiddler2.com/Fiddler2/extensions.asp">JavaScript Formatter addon</a>,
|
||||
<li><a href="https://github.com/nagaozen/gedit-tunnings/">gEdit tips</a> by Fabio Nagao,</li>
|
||||
<li><a href="http://akelpad.sourceforge.net/forum/viewtopic.php?p=11246#11246">Akelpad extension</a> by Infocatcher,</li>
|
||||
<li>Beautifier in <a href="http://sethmason.com/2011/04/28/jsbeautify-in-emacs.html">Emacs</a> write-up by Seth Mason,</li>
|
||||
<li><a href="http://c9.io">Cloud9</a>, a lovely IDE running in a browser, working in the node/cloud, uses jsbeautifier (<a href="https://github.com/ajaxorg/cloud9">github</a>),</li>
|
||||
<li><a href="https://www.comment-devenir-un-hacker.com/app.html">Devenir Hacker App</a>, a non-free JavaScript packer for Mac,</li>
|
||||
<li><a href="http://www.restconsole.com/">REST Console</a>, a request debugging tool for Chrome, beautifies JSON responses (<a href="https://github.com/codeinchaos/rest-console">github</a>),</li>
|
||||
<li><a href="http://mitmproxy.org/">mitmproxy</a>, a nifty SSL-capable HTTP proxy, provides pretty javascript responses (<a href="https://github.com/cortesi/mitmproxy">github</a>).</li>
|
||||
<li><a href="http://www.wakanda.org/">wakanda</a>, a neat IDE for web and mobile applications has a <a href="http://forum.wakanda.org/showthread.php?1483-3-new-extensions-JSLint-Beautifier-and-Snippet">Beautifier extension</a>
|
||||
(<a href="https://github.com/Wakanda/wakanda-extensions/tree/master/Beautifier">github</a>).</li>
|
||||
<li><a href="http://portswigger.net/burp/">Burp Suite</a> now has a <a href="https://github.com/irsdl/BurpSuiteJSBeautifier/">beautfier extension</a>,
|
||||
thanks to Soroush Dalili,</li>
|
||||
<li><a href="http://plugins.netbeans.org/plugin/43263/jsbeautify">Netbeans jsbeautify</a> plugin by Drew Hamlett
|
||||
(<a href="https://github.com/drewhjava/netbeans-jsbeautify">github</a>).</li>
|
||||
<li><a href="https://github.com/drewhjava/brackets-beautify">brackets-beautify-extension</a> for <a href="http://brackets.io">Adobe Brackets</a> by Drew
|
||||
Hamlett (<a href="https://github.com/drewhjava/brackets-beautify">github</a>),</li>
|
||||
<li><a href="http://codecaddy.net/">codecaddy.net</a>, a collection of webdev-related tools, assembled by Darik Hall,
|
||||
<li><a href="http://www.editey.com/">editey.com</a>, an interesting and free Google-Drive oriented editor uses this beautifier,
|
||||
<li><a href="https://github.com/vkadam/grunt-jsbeautifier">a beautifier plugin for Grunt</a> by Vishal Kadam,
|
||||
<li><a href="http://www.uvviewsoft.com/synwrite/">SynWrite</a> editor has a JsFormat plugin (<a href="https://sourceforge.net/projects/synwrite-addons/files/PyPlugins/Alexey.JsFormat/">rar</a>, <a href="http://synwrite.sourceforge.net/forums/viewtopic.php?f=19&t=865">readme</a>),
|
||||
<li><a href="http://liveditor.com/">LIVEditor</a>, a live-editing HTML/CSS/JS IDE (commercial, Windows-only) uses the library,
|
||||
</ul>
|
||||
</div>
|
||||
<p>Doing anything interesting? Write us to <b>team@jsbeautifier.org</b> so we can add your project to the list.</p>
|
||||
|
||||
<p class="contributor-sep">Written by <a href="https://github.com/einars">Einar Lielmanis</a>, maintained and evolved by <a href="https://github.com/bitwiseman/">Liam Newman</a>.</p>
|
||||
<p>We use the wonderful <a href="http://codemirror.net">CodeMirror</a> syntax highlighting editor, written by Marijn Haverbeke.
|
||||
</p>
|
||||
<p class="contributors">Made with a great help of Jason Diamond, Patrick Hof, Nochum Sossonko, Andreas Schneider,
|
||||
<br>Dave Vasilevsky,
|
||||
<a href="https://moikrug.ru/vital">Vital Batmanov</a>, Ron Baldwin, Gabriel Harrison,
|
||||
<a href="http://shullian.com">Chris J. Shull</a>,
|
||||
<a href="http://mathiasbynens.be/">Mathias Bynens</a>,
|
||||
<br>
|
||||
<a href="https://www.vittgam.net/">Vittorio Gambaletta</a>,
|
||||
<a href="https://github.com/esseks">Stefano Sanfilippo</a> and
|
||||
<a href="https://github.com/evocateur">Daniel Stockman</a>.
|
||||
</p>
|
||||
|
||||
<p style="text-align:right">
|
||||
<a href="#" style="color: #ccc; border-bottom: 1px dashed #ccc; text-decoration: none;" onclick="run_tests(); return false;">Run the tests</a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div id="testresults"></div>
|
||||
<script src="web/onload.js"></script>
|
||||
<script src="web/google-analytics.js"></script>
|
||||
</div>
|
||||
<div id="testresults"></div>
|
||||
<script src="web/onload.js">
|
||||
</script>
|
||||
<script src="web/google-analytics.js">
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
@ -1,3 +1,5 @@
|
||||
/*jshint node:true */
|
||||
/* globals define */
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
@ -25,6 +27,8 @@
|
||||
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
The following batches are equivalent:
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
Written by Daniel Stockman (daniel.stockman@gmail.com)
|
||||
|
||||
*/
|
||||
/*jshint strict:false */
|
||||
|
||||
var debug = process.env.DEBUG_JSBEAUTIFY || process.env.JSBEAUTIFY_DEBUG ? function() {
|
||||
console.error.apply(console, arguments);
|
||||
@ -77,13 +78,14 @@ var path = require('path'),
|
||||
"space_in_empty_paren": Boolean,
|
||||
"jslint_happy": Boolean,
|
||||
"space_after_anon_function": Boolean,
|
||||
"space_after_named_function": Boolean,
|
||||
"brace_style": "brace_style", //See above for validation
|
||||
"unindent_chained_methods": Boolean,
|
||||
"break_chained_methods": Boolean,
|
||||
"keep_array_indentation": Boolean,
|
||||
"unescape_strings": Boolean,
|
||||
"wrap_line_length": Number,
|
||||
"wrap_attributes": ["auto", "force", "force-aligned"],
|
||||
"wrap_attributes": ["auto", "force", "force-aligned", "force-expand-multiline", "aligned-multiple"],
|
||||
"wrap_attributes_indent_size": Number,
|
||||
"e4x": Boolean,
|
||||
"end_with_newline": Boolean,
|
||||
@ -353,6 +355,7 @@ function usage(err) {
|
||||
msg.push(' -E, --space-in-empty-paren Add a single space inside empty paren, ie. f( )');
|
||||
msg.push(' -j, --jslint-happy Enable jslint-stricter mode');
|
||||
msg.push(' -a, --space-after-anon-function Add a space before an anonymous function\'s parens, ie. function ()');
|
||||
msg.push(' --space_after_named_function Add a space before a named function\'s parens, ie. function example ()');
|
||||
msg.push(' -b, --brace-style [collapse|expand|end-expand|none][,preserve-inline] [collapse,preserve-inline]');
|
||||
msg.push(' -u, --unindent-chained-methods Don\'t indent chained method calls');
|
||||
msg.push(' -B, --break-chained-methods Break chained method calls across subsequent lines');
|
||||
|
@ -1,60 +1,61 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function Directives(start_block_pattern, end_block_pattern) {
|
||||
start_block_pattern = typeof start_block_pattern === 'string' ? start_block_pattern : start_block_pattern.source;
|
||||
end_block_pattern = typeof end_block_pattern === 'string' ? end_block_pattern : end_block_pattern.source;
|
||||
this._directives_block_pattern = new RegExp(start_block_pattern + / beautify( \w+[:]\w+)+ /.source + end_block_pattern, 'g');
|
||||
this._directive_pattern = / (\w+)[:](\w+)/g;
|
||||
this.__directives_block_pattern = new RegExp(start_block_pattern + / beautify( \w+[:]\w+)+ /.source + end_block_pattern, 'g');
|
||||
this.__directive_pattern = / (\w+)[:](\w+)/g;
|
||||
|
||||
this._directives_end_ignore_pattern = new RegExp('(?:[\\s\\S]*?)((?:' + start_block_pattern + /\sbeautify\signore:end\s/.source + end_block_pattern + ')|$)', 'g');
|
||||
this.__directives_end_ignore_pattern = new RegExp('(?:[\\s\\S]*?)((?:' + start_block_pattern + /\sbeautify\signore:end\s/.source + end_block_pattern + ')|$)', 'g');
|
||||
}
|
||||
|
||||
Directives.prototype.get_directives = function(text) {
|
||||
if (!text.match(this._directives_block_pattern)) {
|
||||
if (!text.match(this.__directives_block_pattern)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var directives = {};
|
||||
this._directive_pattern.lastIndex = 0;
|
||||
var directive_match = this._directive_pattern.exec(text);
|
||||
this.__directive_pattern.lastIndex = 0;
|
||||
var directive_match = this.__directive_pattern.exec(text);
|
||||
|
||||
while (directive_match) {
|
||||
directives[directive_match[1]] = directive_match[2];
|
||||
directive_match = this._directive_pattern.exec(text);
|
||||
directive_match = this.__directive_pattern.exec(text);
|
||||
}
|
||||
|
||||
return directives;
|
||||
};
|
||||
|
||||
Directives.prototype.readIgnored = function(input) {
|
||||
return input.read(this._directives_end_ignore_pattern);
|
||||
return input.read(this.__directives_end_ignore_pattern);
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
@ -26,31 +26,33 @@
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function InputScanner(input_string) {
|
||||
this._input = input_string || '';
|
||||
this._input_length = this._input.length;
|
||||
this._position = 0;
|
||||
this.__input = input_string || '';
|
||||
this.__input_length = this.__input.length;
|
||||
this.__position = 0;
|
||||
}
|
||||
|
||||
InputScanner.prototype.restart = function() {
|
||||
this._position = 0;
|
||||
this.__position = 0;
|
||||
};
|
||||
|
||||
InputScanner.prototype.back = function() {
|
||||
if (this._position > 0) {
|
||||
this._position -= 1;
|
||||
if (this.__position > 0) {
|
||||
this.__position -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
InputScanner.prototype.hasNext = function() {
|
||||
return this._position < this._input_length;
|
||||
return this.__position < this.__input_length;
|
||||
};
|
||||
|
||||
InputScanner.prototype.next = function() {
|
||||
var val = null;
|
||||
if (this.hasNext()) {
|
||||
val = this._input.charAt(this._position);
|
||||
this._position += 1;
|
||||
val = this.__input.charAt(this.__position);
|
||||
this.__position += 1;
|
||||
}
|
||||
return val;
|
||||
};
|
||||
@ -58,20 +60,20 @@ InputScanner.prototype.next = function() {
|
||||
InputScanner.prototype.peek = function(index) {
|
||||
var val = null;
|
||||
index = index || 0;
|
||||
index += this._position;
|
||||
if (index >= 0 && index < this._input_length) {
|
||||
val = this._input.charAt(index);
|
||||
index += this.__position;
|
||||
if (index >= 0 && index < this.__input_length) {
|
||||
val = this.__input.charAt(index);
|
||||
}
|
||||
return val;
|
||||
};
|
||||
|
||||
InputScanner.prototype.test = function(pattern, index) {
|
||||
index = index || 0;
|
||||
index += this._position;
|
||||
index += this.__position;
|
||||
pattern.lastIndex = index;
|
||||
|
||||
if (index >= 0 && index < this._input_length) {
|
||||
var pattern_match = pattern.exec(this._input);
|
||||
if (index >= 0 && index < this.__input_length) {
|
||||
var pattern_match = pattern.exec(this.__input);
|
||||
return pattern_match && pattern_match.index === index;
|
||||
} else {
|
||||
return false;
|
||||
@ -85,10 +87,10 @@ InputScanner.prototype.testChar = function(pattern, index) {
|
||||
};
|
||||
|
||||
InputScanner.prototype.match = function(pattern) {
|
||||
pattern.lastIndex = this._position;
|
||||
var pattern_match = pattern.exec(this._input);
|
||||
if (pattern_match && pattern_match.index === this._position) {
|
||||
this._position += pattern_match[0].length;
|
||||
pattern.lastIndex = this.__position;
|
||||
var pattern_match = pattern.exec(this.__input);
|
||||
if (pattern_match && pattern_match.index === this.__position) {
|
||||
this.__position += pattern_match[0].length;
|
||||
} else {
|
||||
pattern_match = null;
|
||||
}
|
||||
@ -106,9 +108,9 @@ InputScanner.prototype.read = function(pattern) {
|
||||
|
||||
InputScanner.prototype.readUntil = function(pattern, include_match) {
|
||||
var val = '';
|
||||
var match_index = this._position;
|
||||
pattern.lastIndex = this._position;
|
||||
var pattern_match = pattern.exec(this._input);
|
||||
var match_index = this.__position;
|
||||
pattern.lastIndex = this.__position;
|
||||
var pattern_match = pattern.exec(this.__input);
|
||||
if (pattern_match) {
|
||||
if (include_match) {
|
||||
match_index = pattern_match.index + pattern_match[0].length;
|
||||
@ -116,11 +118,11 @@ InputScanner.prototype.readUntil = function(pattern, include_match) {
|
||||
match_index = pattern_match.index;
|
||||
}
|
||||
} else {
|
||||
match_index = this._input_length;
|
||||
match_index = this.__input_length;
|
||||
}
|
||||
|
||||
val = this._input.substring(this._position, match_index);
|
||||
this._position = match_index;
|
||||
val = this.__input.substring(this.__position, match_index);
|
||||
this.__position = match_index;
|
||||
return val;
|
||||
};
|
||||
|
||||
@ -130,15 +132,15 @@ InputScanner.prototype.readUntilAfter = function(pattern) {
|
||||
|
||||
/* css beautifier legacy helpers */
|
||||
InputScanner.prototype.peekUntilAfter = function(pattern) {
|
||||
var start = this._position;
|
||||
var start = this.__position;
|
||||
var val = this.readUntilAfter(pattern);
|
||||
this._position = start;
|
||||
this.__position = start;
|
||||
return val;
|
||||
};
|
||||
|
||||
InputScanner.prototype.lookBack = function(testVal) {
|
||||
var start = this._position - 1;
|
||||
return start >= testVal.length && this._input.substring(start - testVal.length, start)
|
||||
var start = this.__position - 1;
|
||||
return start >= testVal.length && this.__input.substring(start - testVal.length, start)
|
||||
.toLowerCase() === testVal;
|
||||
};
|
||||
|
||||
|
@ -1,38 +1,150 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function Options(options, merge_child_field) {
|
||||
options = _mergeOpts(options, merge_child_field);
|
||||
this.raw_options = _normalizeOpts(options);
|
||||
|
||||
// Support passing the source text back with no change
|
||||
this.disabled = this._get_boolean('disabled');
|
||||
|
||||
this.eol = this._get_characters('eol', 'auto');
|
||||
this.end_with_newline = this._get_boolean('end_with_newline');
|
||||
this.indent_size = this._get_number('indent_size', 4);
|
||||
this.indent_char = this._get_characters('indent_char', ' ');
|
||||
this.indent_level = this._get_number('indent_level');
|
||||
|
||||
this.preserve_newlines = this._get_boolean('preserve_newlines', true);
|
||||
this.max_preserve_newlines = this._get_number('max_preserve_newlines', 32786);
|
||||
if (!this.preserve_newlines) {
|
||||
this.max_preserve_newlines = 0;
|
||||
}
|
||||
|
||||
this.indent_with_tabs = this._get_boolean('indent_with_tabs');
|
||||
if (this.indent_with_tabs) {
|
||||
this.indent_char = '\t';
|
||||
this.indent_size = 1;
|
||||
}
|
||||
|
||||
// Backwards compat with 1.3.x
|
||||
this.wrap_line_length = this._get_number('wrap_line_length', this._get_number('max_char'));
|
||||
|
||||
}
|
||||
|
||||
Options.prototype._get_array = function(name, default_value) {
|
||||
var option_value = this.raw_options[name];
|
||||
var result = default_value || [];
|
||||
if (typeof option_value === 'object') {
|
||||
if (option_value !== null && typeof option_value.concat === 'function') {
|
||||
result = option_value.concat();
|
||||
}
|
||||
} else if (typeof option_value === 'string') {
|
||||
result = option_value.split(/[^a-zA-Z0-9_\/\-]+/);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
Options.prototype._get_boolean = function(name, default_value) {
|
||||
var option_value = this.raw_options[name];
|
||||
var result = option_value === undefined ? !!default_value : !!option_value;
|
||||
return result;
|
||||
};
|
||||
|
||||
Options.prototype._get_characters = function(name, default_value) {
|
||||
var option_value = this.raw_options[name];
|
||||
var result = default_value || '';
|
||||
if (typeof option_value === 'string') {
|
||||
result = option_value.replace(/\\r/, '\r').replace(/\\n/, '\n').replace(/\\t/, '\t');
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
Options.prototype._get_number = function(name, default_value) {
|
||||
var option_value = this.raw_options[name];
|
||||
default_value = parseInt(default_value, 10);
|
||||
if (isNaN(default_value)) {
|
||||
default_value = 0;
|
||||
}
|
||||
var result = parseInt(option_value, 10);
|
||||
if (isNaN(result)) {
|
||||
result = default_value;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
Options.prototype._get_selection = function(name, selection_list, default_value) {
|
||||
var result = this._get_selection_list(name, selection_list, default_value);
|
||||
if (result.length !== 1) {
|
||||
throw new Error(
|
||||
"Invalid Option Value: The option '" + name + "' can only be one of the following values:\n" +
|
||||
selection_list + "\nYou passed in: '" + this.raw_options[name] + "'");
|
||||
}
|
||||
|
||||
return result[0];
|
||||
};
|
||||
|
||||
|
||||
Options.prototype._get_selection_list = function(name, selection_list, default_value) {
|
||||
if (!selection_list || selection_list.length === 0) {
|
||||
throw new Error("Selection list cannot be empty.");
|
||||
}
|
||||
|
||||
default_value = default_value || [selection_list[0]];
|
||||
if (!this._is_valid_selection(default_value, selection_list)) {
|
||||
throw new Error("Invalid Default Value!");
|
||||
}
|
||||
|
||||
var result = this._get_array(name, default_value);
|
||||
if (!this._is_valid_selection(result, selection_list)) {
|
||||
throw new Error(
|
||||
"Invalid Option Value: The option '" + name + "' can contain only the following values:\n" +
|
||||
selection_list + "\nYou passed in: '" + this.raw_options[name] + "'");
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Options.prototype._is_valid_selection = function(result, selection_list) {
|
||||
return result.length && selection_list.length &&
|
||||
!result.some(function(item) { return selection_list.indexOf(item) === -1; });
|
||||
};
|
||||
|
||||
|
||||
// merges child options up with the parent options object
|
||||
// Example: obj = {a: 1, b: {a: 2}}
|
||||
// mergeOpts(obj, 'b')
|
||||
//
|
||||
// Returns: {a: 2, b: {a: 2}}
|
||||
function mergeOpts(allOptions, childFieldName) {
|
||||
function _mergeOpts(allOptions, childFieldName) {
|
||||
var finalOpts = {};
|
||||
allOptions = allOptions || {};
|
||||
var name;
|
||||
|
||||
for (name in allOptions) {
|
||||
@ -42,7 +154,7 @@ function mergeOpts(allOptions, childFieldName) {
|
||||
}
|
||||
|
||||
//merge in the per type settings for the childFieldName
|
||||
if (childFieldName in allOptions) {
|
||||
if (childFieldName && allOptions[childFieldName]) {
|
||||
for (name in allOptions[childFieldName]) {
|
||||
finalOpts[name] = allOptions[childFieldName][name];
|
||||
}
|
||||
@ -50,4 +162,17 @@ function mergeOpts(allOptions, childFieldName) {
|
||||
return finalOpts;
|
||||
}
|
||||
|
||||
module.exports.mergeOpts = mergeOpts;
|
||||
function _normalizeOpts(options) {
|
||||
var convertedOpts = {};
|
||||
var key;
|
||||
|
||||
for (key in options) {
|
||||
var newKey = key.replace(/-/g, "_");
|
||||
convertedOpts[newKey] = options[key];
|
||||
}
|
||||
return convertedOpts;
|
||||
}
|
||||
|
||||
module.exports.Options = Options;
|
||||
module.exports.normalizeOpts = _normalizeOpts;
|
||||
module.exports.mergeOpts = _mergeOpts;
|
@ -1,4 +1,4 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
@ -26,123 +26,193 @@
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
function OutputLine(parent) {
|
||||
this._parent = parent;
|
||||
this._character_count = 0;
|
||||
// use indent_count as a marker for this._lines that have preserved indentation
|
||||
this._indent_count = -1;
|
||||
'use strict';
|
||||
|
||||
this._items = [];
|
||||
function OutputLine(parent) {
|
||||
this.__parent = parent;
|
||||
this.__character_count = 0;
|
||||
// use indent_count as a marker for this.__lines that have preserved indentation
|
||||
this.__indent_count = -1;
|
||||
this.__alignment_count = 0;
|
||||
|
||||
this.__items = [];
|
||||
}
|
||||
|
||||
OutputLine.prototype.set_indent = function(level) {
|
||||
this._character_count = this._parent.baseIndentLength + level * this._parent.indent_length;
|
||||
this._indent_count = level;
|
||||
OutputLine.prototype.item = function(index) {
|
||||
if (index < 0) {
|
||||
return this.__items[this.__items.length + index];
|
||||
} else {
|
||||
return this.__items[index];
|
||||
}
|
||||
};
|
||||
|
||||
OutputLine.prototype.has_match = function(pattern) {
|
||||
for (var lastCheckedOutput = this.__items.length - 1; lastCheckedOutput >= 0; lastCheckedOutput--) {
|
||||
if (this.__items[lastCheckedOutput].match(pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
OutputLine.prototype.set_indent = function(indent, alignment) {
|
||||
this.__indent_count = indent || 0;
|
||||
this.__alignment_count = alignment || 0;
|
||||
this.__character_count = this.__parent.baseIndentLength + this.__alignment_count + this.__indent_count * this.__parent.indent_length;
|
||||
};
|
||||
|
||||
OutputLine.prototype.get_character_count = function() {
|
||||
return this._character_count;
|
||||
return this.__character_count;
|
||||
};
|
||||
|
||||
OutputLine.prototype.is_empty = function() {
|
||||
return this._items.length === 0;
|
||||
return this.__items.length === 0;
|
||||
};
|
||||
|
||||
OutputLine.prototype.last = function() {
|
||||
if (!this.is_empty()) {
|
||||
return this._items[this._items.length - 1];
|
||||
return this.__items[this.__items.length - 1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
OutputLine.prototype.push = function(item) {
|
||||
this._items.push(item);
|
||||
this._character_count += item.length;
|
||||
this.__items.push(item);
|
||||
this.__character_count += item.length;
|
||||
};
|
||||
|
||||
OutputLine.prototype.push_raw = function(item) {
|
||||
this.push(item);
|
||||
var last_newline_index = item.lastIndexOf('\n');
|
||||
if (last_newline_index !== -1) {
|
||||
this.__character_count = item.length - last_newline_index;
|
||||
}
|
||||
};
|
||||
|
||||
OutputLine.prototype.pop = function() {
|
||||
var item = null;
|
||||
if (!this.is_empty()) {
|
||||
item = this._items.pop();
|
||||
this._character_count -= item.length;
|
||||
item = this.__items.pop();
|
||||
this.__character_count -= item.length;
|
||||
}
|
||||
return item;
|
||||
};
|
||||
|
||||
OutputLine.prototype.remove_indent = function() {
|
||||
if (this._indent_count > 0) {
|
||||
this._indent_count -= 1;
|
||||
this._character_count -= this._parent.indent_length;
|
||||
if (this.__indent_count > 0) {
|
||||
this.__indent_count -= 1;
|
||||
this.__character_count -= this.__parent.indent_length;
|
||||
}
|
||||
};
|
||||
|
||||
OutputLine.prototype.trim = function() {
|
||||
while (this.last() === ' ') {
|
||||
this._items.pop();
|
||||
this._character_count -= 1;
|
||||
this.__items.pop();
|
||||
this.__character_count -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
OutputLine.prototype.toString = function() {
|
||||
var result = '';
|
||||
if (!this.is_empty()) {
|
||||
if (this._indent_count >= 0) {
|
||||
result = this._parent.indent_cache[this._indent_count];
|
||||
if (this.__indent_count >= 0) {
|
||||
result = this.__parent.get_indent_string(this.__indent_count);
|
||||
}
|
||||
result += this._items.join('');
|
||||
if (this.__alignment_count >= 0) {
|
||||
result += this.__parent.get_alignment_string(this.__alignment_count);
|
||||
}
|
||||
result += this.__items.join('');
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
function IndentCache(base_string, level_string) {
|
||||
this.__cache = [base_string];
|
||||
this.__level_string = level_string;
|
||||
}
|
||||
|
||||
function Output(indent_string, baseIndentString) {
|
||||
IndentCache.prototype.__ensure_cache = function(level) {
|
||||
while (level >= this.__cache.length) {
|
||||
this.__cache.push(this.__cache[this.__cache.length - 1] + this.__level_string);
|
||||
}
|
||||
};
|
||||
|
||||
IndentCache.prototype.get_level_string = function(level) {
|
||||
this.__ensure_cache(level);
|
||||
return this.__cache[level];
|
||||
};
|
||||
|
||||
|
||||
function Output(options, baseIndentString) {
|
||||
var indent_string = options.indent_char;
|
||||
if (options.indent_size > 1) {
|
||||
indent_string = new Array(options.indent_size + 1).join(options.indent_char);
|
||||
}
|
||||
|
||||
// Set to null to continue support for auto detection of base indent level.
|
||||
baseIndentString = baseIndentString || '';
|
||||
this.indent_cache = [baseIndentString];
|
||||
if (options.indent_level > 0) {
|
||||
baseIndentString = new Array(options.indent_level + 1).join(indent_string);
|
||||
}
|
||||
|
||||
this.__indent_cache = new IndentCache(baseIndentString, indent_string);
|
||||
this.__alignment_cache = new IndentCache('', ' ');
|
||||
this.baseIndentLength = baseIndentString.length;
|
||||
this.indent_length = indent_string.length;
|
||||
this.raw = false;
|
||||
this._end_with_newline = options.end_with_newline;
|
||||
|
||||
this._lines = [];
|
||||
this.baseIndentString = baseIndentString;
|
||||
this.indent_string = indent_string;
|
||||
this.__lines = [];
|
||||
this.previous_line = null;
|
||||
this.current_line = null;
|
||||
this.space_before_token = false;
|
||||
// initialize
|
||||
this.add_outputline();
|
||||
this.__add_outputline();
|
||||
}
|
||||
|
||||
Output.prototype.add_outputline = function() {
|
||||
Output.prototype.__add_outputline = function() {
|
||||
this.previous_line = this.current_line;
|
||||
this.current_line = new OutputLine(this);
|
||||
this._lines.push(this.current_line);
|
||||
this.__lines.push(this.current_line);
|
||||
};
|
||||
|
||||
Output.prototype.get_line_number = function() {
|
||||
return this._lines.length;
|
||||
return this.__lines.length;
|
||||
};
|
||||
|
||||
Output.prototype.get_indent_string = function(level) {
|
||||
return this.__indent_cache.get_level_string(level);
|
||||
};
|
||||
|
||||
Output.prototype.get_alignment_string = function(level) {
|
||||
return this.__alignment_cache.get_level_string(level);
|
||||
};
|
||||
|
||||
Output.prototype.is_empty = function() {
|
||||
return !this.previous_line && this.current_line.is_empty();
|
||||
};
|
||||
|
||||
// Using object instead of string to allow for later expansion of info about each line
|
||||
Output.prototype.add_new_line = function(force_newline) {
|
||||
if (this.get_line_number() === 1 && this.just_added_newline()) {
|
||||
return false; // no newline on start of file
|
||||
// never newline at the start of file
|
||||
// otherwise, newline only if we didn't just add one or we're forced
|
||||
if (this.is_empty() ||
|
||||
(!force_newline && this.just_added_newline())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (force_newline || !this.just_added_newline()) {
|
||||
if (!this.raw) {
|
||||
this.add_outputline();
|
||||
}
|
||||
return true;
|
||||
// if raw output is enabled, don't print additional newlines,
|
||||
// but still return True as though you had
|
||||
if (!this.raw) {
|
||||
this.__add_outputline();
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
Output.prototype.get_code = function(end_with_newline, eol) {
|
||||
var sweet_code = this._lines.join('\n').replace(/[\r\n\t ]+$/, '');
|
||||
Output.prototype.get_code = function(eol) {
|
||||
var sweet_code = this.__lines.join('\n').replace(/[\r\n\t ]+$/, '');
|
||||
|
||||
if (end_with_newline) {
|
||||
if (this._end_with_newline) {
|
||||
sweet_code += '\n';
|
||||
}
|
||||
|
||||
@ -153,26 +223,25 @@ Output.prototype.get_code = function(end_with_newline, eol) {
|
||||
return sweet_code;
|
||||
};
|
||||
|
||||
Output.prototype.set_indent = function(level) {
|
||||
// Never indent your first output indent at the start of the file
|
||||
if (this._lines.length > 1) {
|
||||
while (level >= this.indent_cache.length) {
|
||||
this.indent_cache.push(this.indent_cache[this.indent_cache.length - 1] + this.indent_string);
|
||||
}
|
||||
Output.prototype.set_indent = function(indent, alignment) {
|
||||
indent = indent || 0;
|
||||
alignment = alignment || 0;
|
||||
|
||||
this.current_line.set_indent(level);
|
||||
// Never indent your first output indent at the start of the file
|
||||
if (this.__lines.length > 1) {
|
||||
this.current_line.set_indent(indent, alignment);
|
||||
return true;
|
||||
}
|
||||
this.current_line.set_indent(0);
|
||||
this.current_line.set_indent();
|
||||
return false;
|
||||
};
|
||||
|
||||
Output.prototype.add_raw_token = function(token) {
|
||||
for (var x = 0; x < token.newlines; x++) {
|
||||
this.add_outputline();
|
||||
this.__add_outputline();
|
||||
}
|
||||
this.current_line.push(token.whitespace_before);
|
||||
this.current_line.push(token.text);
|
||||
this.current_line.push_raw(token.text);
|
||||
this.space_before_token = false;
|
||||
};
|
||||
|
||||
@ -189,9 +258,9 @@ Output.prototype.add_space_before_token = function() {
|
||||
};
|
||||
|
||||
Output.prototype.remove_indent = function(index) {
|
||||
var output_length = this._lines.length;
|
||||
var output_length = this.__lines.length;
|
||||
while (index < output_length) {
|
||||
this._lines[index].remove_indent();
|
||||
this.__lines[index].remove_indent();
|
||||
index++;
|
||||
}
|
||||
};
|
||||
@ -201,14 +270,15 @@ Output.prototype.trim = function(eat_newlines) {
|
||||
|
||||
this.current_line.trim(this.indent_string, this.baseIndentString);
|
||||
|
||||
while (eat_newlines && this._lines.length > 1 &&
|
||||
while (eat_newlines && this.__lines.length > 1 &&
|
||||
this.current_line.is_empty()) {
|
||||
this._lines.pop();
|
||||
this.current_line = this._lines[this._lines.length - 1];
|
||||
this.__lines.pop();
|
||||
this.current_line = this.__lines[this.__lines.length - 1];
|
||||
this.current_line.trim();
|
||||
}
|
||||
|
||||
this.previous_line = this._lines.length > 1 ? this._lines[this._lines.length - 2] : null;
|
||||
this.previous_line = this.__lines.length > 1 ?
|
||||
this.__lines[this.__lines.length - 2] : null;
|
||||
};
|
||||
|
||||
Output.prototype.just_added_newline = function() {
|
||||
@ -216,16 +286,24 @@ Output.prototype.just_added_newline = function() {
|
||||
};
|
||||
|
||||
Output.prototype.just_added_blankline = function() {
|
||||
if (this.just_added_newline()) {
|
||||
if (this._lines.length === 1) {
|
||||
return true; // start of the file and newline = blank
|
||||
}
|
||||
|
||||
var line = this._lines[this._lines.length - 2];
|
||||
return line.is_empty();
|
||||
}
|
||||
return false;
|
||||
return this.is_empty() ||
|
||||
(this.current_line.is_empty() && this.previous_line.is_empty());
|
||||
};
|
||||
|
||||
Output.prototype.ensure_empty_line_above = function(starts_with, ends_with) {
|
||||
var index = this.__lines.length - 2;
|
||||
while (index >= 0) {
|
||||
var potentialEmptyLine = this.__lines[index];
|
||||
if (potentialEmptyLine.is_empty()) {
|
||||
break;
|
||||
} else if (potentialEmptyLine.item(0).indexOf(starts_with) !== 0 &&
|
||||
potentialEmptyLine.item(-1) !== ends_with) {
|
||||
this.__lines.splice(index + 1, 0, new OutputLine(this));
|
||||
this.previous_line = this.__lines[this.__lines.length - 2];
|
||||
break;
|
||||
}
|
||||
index--;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.Output = Output;
|
@ -1,4 +1,4 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
@ -26,6 +26,8 @@
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function Token(type, text, newlines, whitespace_before) {
|
||||
this.type = type;
|
||||
this.text = text;
|
||||
@ -41,7 +43,10 @@ function Token(type, text, newlines, whitespace_before) {
|
||||
this.newlines = newlines || 0;
|
||||
this.whitespace_before = whitespace_before || '';
|
||||
this.parent = null;
|
||||
this.next = null;
|
||||
this.previous = null;
|
||||
this.opened = null;
|
||||
this.closed = null;
|
||||
this.directives = null;
|
||||
}
|
||||
|
||||
|
@ -1,31 +1,33 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var InputScanner = require('../core/inputscanner').InputScanner;
|
||||
var Token = require('../core/token').Token;
|
||||
var TokenStream = require('../core/tokenstream').TokenStream;
|
||||
@ -36,33 +38,34 @@ var TOKEN = {
|
||||
EOF: 'TK_EOF'
|
||||
};
|
||||
|
||||
var Tokenizer = function(input_string) { // jshint unused:false
|
||||
var Tokenizer = function(input_string, options) {
|
||||
this._input = new InputScanner(input_string);
|
||||
this._tokens = null;
|
||||
this._newline_count = 0;
|
||||
this._whitespace_before_token = '';
|
||||
this._options = options || {};
|
||||
this.__tokens = null;
|
||||
this.__newline_count = 0;
|
||||
this.__whitespace_before_token = '';
|
||||
|
||||
this._whitespace_pattern = /[\n\r\u2028\u2029\t ]+/g;
|
||||
this._newline_pattern = /([\t ]*)(\r\n|[\n\r\u2028\u2029])?/g;
|
||||
this._whitespace_pattern = /[\n\r\t ]+/g;
|
||||
this._newline_pattern = /([^\n\r]*)(\r\n|[\n\r])?/g;
|
||||
};
|
||||
|
||||
Tokenizer.prototype.tokenize = function() {
|
||||
this._input.restart();
|
||||
this._tokens = new TokenStream();
|
||||
this.__tokens = new TokenStream();
|
||||
|
||||
this.reset();
|
||||
this._reset();
|
||||
|
||||
var current;
|
||||
var last = new Token(TOKEN.START, '');
|
||||
var previous = new Token(TOKEN.START, '');
|
||||
var open_token = null;
|
||||
var open_stack = [];
|
||||
var comments = new TokenStream();
|
||||
|
||||
while (last.type !== TOKEN.EOF) {
|
||||
current = this.get_next_token(last);
|
||||
while (this.is_comment(current)) {
|
||||
while (previous.type !== TOKEN.EOF) {
|
||||
current = this._get_next_token(previous, open_token);
|
||||
while (this._is_comment(current)) {
|
||||
comments.add(current);
|
||||
current = this.get_next_token(last);
|
||||
current = this._get_next_token(previous, open_token);
|
||||
}
|
||||
|
||||
if (!comments.isEmpty()) {
|
||||
@ -70,71 +73,76 @@ Tokenizer.prototype.tokenize = function() {
|
||||
comments = new TokenStream();
|
||||
}
|
||||
|
||||
if (this.is_opening(current)) {
|
||||
current.parent = last;
|
||||
current.parent = open_token;
|
||||
|
||||
if (this._is_opening(current)) {
|
||||
open_stack.push(open_token);
|
||||
open_token = current;
|
||||
} else if (open_token && this.is_closing(current, open_token)) {
|
||||
current.parent = open_token.parent;
|
||||
} else if (open_token && this._is_closing(current, open_token)) {
|
||||
current.opened = open_token;
|
||||
|
||||
open_token.closed = current;
|
||||
open_token = open_stack.pop();
|
||||
current.parent = open_token;
|
||||
}
|
||||
|
||||
this._tokens.add(current);
|
||||
last = current;
|
||||
current.previous = previous;
|
||||
previous.next = current;
|
||||
|
||||
this.__tokens.add(current);
|
||||
previous = current;
|
||||
}
|
||||
|
||||
return this._tokens;
|
||||
return this.__tokens;
|
||||
};
|
||||
|
||||
|
||||
Tokenizer.prototype.reset = function() {};
|
||||
Tokenizer.prototype._is_first_token = function() {
|
||||
return this.__tokens.isEmpty();
|
||||
};
|
||||
|
||||
Tokenizer.prototype.get_next_token = function(last_token) { // jshint unused:false
|
||||
this.readWhitespace();
|
||||
Tokenizer.prototype._reset = function() {};
|
||||
|
||||
Tokenizer.prototype._get_next_token = function(previous_token, open_token) { // jshint unused:false
|
||||
this._readWhitespace();
|
||||
var resulting_string = this._input.read(/.+/g);
|
||||
if (resulting_string) {
|
||||
return this.create_token(TOKEN.RAW, resulting_string);
|
||||
return this._create_token(TOKEN.RAW, resulting_string);
|
||||
} else {
|
||||
return this.create_token(TOKEN.EOF, '');
|
||||
return this._create_token(TOKEN.EOF, '');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Tokenizer.prototype.is_comment = function(current_token) { // jshint unused:false
|
||||
Tokenizer.prototype._is_comment = function(current_token) { // jshint unused:false
|
||||
return false;
|
||||
};
|
||||
|
||||
Tokenizer.prototype.is_opening = function(current_token) { // jshint unused:false
|
||||
Tokenizer.prototype._is_opening = function(current_token) { // jshint unused:false
|
||||
return false;
|
||||
};
|
||||
|
||||
Tokenizer.prototype.is_closing = function(current_token, open_token) { // jshint unused:false
|
||||
Tokenizer.prototype._is_closing = function(current_token, open_token) { // jshint unused:false
|
||||
return false;
|
||||
};
|
||||
|
||||
Tokenizer.prototype.create_token = function(type, text) {
|
||||
var token = new Token(type, text, this._newline_count, this._whitespace_before_token);
|
||||
this._newline_count = 0;
|
||||
this._whitespace_before_token = '';
|
||||
Tokenizer.prototype._create_token = function(type, text) {
|
||||
var token = new Token(type, text, this.__newline_count, this.__whitespace_before_token);
|
||||
this.__newline_count = 0;
|
||||
this.__whitespace_before_token = '';
|
||||
return token;
|
||||
};
|
||||
|
||||
Tokenizer.prototype.readWhitespace = function() {
|
||||
Tokenizer.prototype._readWhitespace = function() {
|
||||
var resulting_string = this._input.read(this._whitespace_pattern);
|
||||
if (resulting_string !== '') {
|
||||
if (resulting_string === ' ') {
|
||||
this._whitespace_before_token = resulting_string;
|
||||
} else {
|
||||
this._newline_pattern.lastIndex = 0;
|
||||
var nextMatch = this._newline_pattern.exec(resulting_string);
|
||||
while (nextMatch[2]) {
|
||||
this._newline_count += 1;
|
||||
nextMatch = this._newline_pattern.exec(resulting_string);
|
||||
}
|
||||
this._whitespace_before_token = nextMatch[1];
|
||||
if (resulting_string === ' ') {
|
||||
this.__whitespace_before_token = resulting_string;
|
||||
} else if (resulting_string !== '') {
|
||||
this._newline_pattern.lastIndex = 0;
|
||||
var nextMatch = this._newline_pattern.exec(resulting_string);
|
||||
while (nextMatch[2]) {
|
||||
this.__newline_count += 1;
|
||||
nextMatch = this._newline_pattern.exec(resulting_string);
|
||||
}
|
||||
this.__whitespace_before_token = nextMatch[1];
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,56 +1,58 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function TokenStream(parent_token) {
|
||||
// private
|
||||
this._tokens = [];
|
||||
this._tokens_length = this._tokens.length;
|
||||
this._position = 0;
|
||||
this._parent_token = parent_token;
|
||||
this.__tokens = [];
|
||||
this.__tokens_length = this.__tokens.length;
|
||||
this.__position = 0;
|
||||
this.__parent_token = parent_token;
|
||||
}
|
||||
|
||||
TokenStream.prototype.restart = function() {
|
||||
this._position = 0;
|
||||
this.__position = 0;
|
||||
};
|
||||
|
||||
TokenStream.prototype.isEmpty = function() {
|
||||
return this._tokens_length === 0;
|
||||
return this.__tokens_length === 0;
|
||||
};
|
||||
|
||||
TokenStream.prototype.hasNext = function() {
|
||||
return this._position < this._tokens_length;
|
||||
return this.__position < this.__tokens_length;
|
||||
};
|
||||
|
||||
TokenStream.prototype.next = function() {
|
||||
var val = null;
|
||||
if (this.hasNext()) {
|
||||
val = this._tokens[this._position];
|
||||
this._position += 1;
|
||||
val = this.__tokens[this.__position];
|
||||
this.__position += 1;
|
||||
}
|
||||
return val;
|
||||
};
|
||||
@ -58,19 +60,19 @@ TokenStream.prototype.next = function() {
|
||||
TokenStream.prototype.peek = function(index) {
|
||||
var val = null;
|
||||
index = index || 0;
|
||||
index += this._position;
|
||||
if (index >= 0 && index < this._tokens_length) {
|
||||
val = this._tokens[index];
|
||||
index += this.__position;
|
||||
if (index >= 0 && index < this.__tokens_length) {
|
||||
val = this.__tokens[index];
|
||||
}
|
||||
return val;
|
||||
};
|
||||
|
||||
TokenStream.prototype.add = function(token) {
|
||||
if (this._parent_token) {
|
||||
token.parent = this._parent_token;
|
||||
if (this.__parent_token) {
|
||||
token.parent = this.__parent_token;
|
||||
}
|
||||
this._tokens.push(token);
|
||||
this._tokens_length += 1;
|
||||
this.__tokens.push(token);
|
||||
this.__tokens_length += 1;
|
||||
};
|
||||
|
||||
module.exports.TokenStream = TokenStream;
|
@ -1,4 +1,4 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
@ -26,409 +26,28 @@
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
var mergeOpts = require('../core/options').mergeOpts;
|
||||
var acorn = require('../core/acorn');
|
||||
'use strict';
|
||||
|
||||
var Options = require('./options').Options;
|
||||
var Output = require('../core/output').Output;
|
||||
var InputScanner = require('../core/inputscanner').InputScanner;
|
||||
|
||||
var lineBreak = acorn.lineBreak;
|
||||
var allLineBreaks = acorn.allLineBreaks;
|
||||
var lineBreak = /\r\n|[\r\n]/;
|
||||
var allLineBreaks = /\r\n|[\r\n]/g;
|
||||
|
||||
// tokenizer
|
||||
var whitespaceChar = /\s/;
|
||||
var whitespacePattern = /(?:\s|\n)+/g;
|
||||
var block_comment_pattern = /\/\*(?:[\s\S]*?)((?:\*\/)|$)/g;
|
||||
var comment_pattern = /\/\/(?:[^\n\r\u2028\u2029]*)/g;
|
||||
|
||||
function Beautifier(source_text, options) {
|
||||
source_text = source_text || '';
|
||||
options = options || {};
|
||||
|
||||
this._source_text = source_text || '';
|
||||
// Allow the setting of language/file-type specific options
|
||||
// with inheritance of overall settings
|
||||
options = mergeOpts(options, 'css');
|
||||
|
||||
var indentSize = options.indent_size ? parseInt(options.indent_size, 10) : 4;
|
||||
var indentCharacter = options.indent_char || ' ';
|
||||
var preserve_newlines = (options.preserve_newlines === undefined) ? false : options.preserve_newlines;
|
||||
var selectorSeparatorNewline = (options.selector_separator_newline === undefined) ? true : options.selector_separator_newline;
|
||||
var end_with_newline = (options.end_with_newline === undefined) ? false : options.end_with_newline;
|
||||
var newline_between_rules = (options.newline_between_rules === undefined) ? true : options.newline_between_rules;
|
||||
var space_around_combinator = (options.space_around_combinator === undefined) ? false : options.space_around_combinator;
|
||||
space_around_combinator = space_around_combinator || ((options.space_around_selector_separator === undefined) ? false : options.space_around_selector_separator);
|
||||
var eol = options.eol ? options.eol : 'auto';
|
||||
|
||||
if (options.indent_with_tabs) {
|
||||
indentCharacter = '\t';
|
||||
indentSize = 1;
|
||||
}
|
||||
|
||||
if (eol === 'auto') {
|
||||
eol = '\n';
|
||||
if (source_text && lineBreak.test(source_text || '')) {
|
||||
eol = source_text.match(lineBreak)[0];
|
||||
}
|
||||
}
|
||||
|
||||
eol = eol.replace(/\\r/, '\r').replace(/\\n/, '\n');
|
||||
|
||||
// HACK: newline parsing inconsistent. This brute force normalizes the input.
|
||||
source_text = source_text.replace(allLineBreaks, '\n');
|
||||
|
||||
// tokenizer
|
||||
var whitespaceChar = /\s/;
|
||||
var whitespacePattern = /(?:\s|\n)+/g;
|
||||
var block_comment_pattern = /\/\*(?:[\s\S]*?)((?:\*\/)|$)/g;
|
||||
var comment_pattern = /\/\/(?:[^\n\r\u2028\u2029]*)/g;
|
||||
|
||||
var ch;
|
||||
var parenLevel = 0;
|
||||
var input;
|
||||
|
||||
function eatString(endChars) {
|
||||
var result = '';
|
||||
ch = input.next();
|
||||
while (ch) {
|
||||
result += ch;
|
||||
if (ch === "\\") {
|
||||
result += input.next();
|
||||
} else if (endChars.indexOf(ch) !== -1 || ch === "\n") {
|
||||
break;
|
||||
}
|
||||
ch = input.next();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Skips any white space in the source text from the current position.
|
||||
// When allowAtLeastOneNewLine is true, will output new lines for each
|
||||
// newline character found; if the user has preserve_newlines off, only
|
||||
// the first newline will be output
|
||||
function eatWhitespace(allowAtLeastOneNewLine) {
|
||||
var result = whitespaceChar.test(input.peek());
|
||||
var isFirstNewLine = true;
|
||||
|
||||
while (whitespaceChar.test(input.peek())) {
|
||||
ch = input.next();
|
||||
if (allowAtLeastOneNewLine && ch === '\n') {
|
||||
if (preserve_newlines || isFirstNewLine) {
|
||||
isFirstNewLine = false;
|
||||
output.add_new_line(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Nested pseudo-class if we are insideRule
|
||||
// and the next special character found opens
|
||||
// a new block
|
||||
function foundNestedPseudoClass() {
|
||||
var openParen = 0;
|
||||
var i = 1;
|
||||
var ch = input.peek(i);
|
||||
while (ch) {
|
||||
if (ch === "{") {
|
||||
return true;
|
||||
} else if (ch === '(') {
|
||||
// pseudoclasses can contain ()
|
||||
openParen += 1;
|
||||
} else if (ch === ')') {
|
||||
if (openParen === 0) {
|
||||
return false;
|
||||
}
|
||||
openParen -= 1;
|
||||
} else if (ch === ";" || ch === "}") {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
ch = input.peek(i);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// printer
|
||||
var baseIndentString = '';
|
||||
var preindent_index = 0;
|
||||
if (source_text && source_text.length) {
|
||||
while ((source_text.charAt(preindent_index) === ' ' ||
|
||||
source_text.charAt(preindent_index) === '\t')) {
|
||||
preindent_index += 1;
|
||||
}
|
||||
baseIndentString = source_text.substring(0, preindent_index);
|
||||
source_text = source_text.substring(preindent_index);
|
||||
}
|
||||
|
||||
|
||||
var singleIndent = new Array(indentSize + 1).join(indentCharacter);
|
||||
var indentLevel;
|
||||
var nestedLevel;
|
||||
var output;
|
||||
|
||||
function print_string(output_string) {
|
||||
if (output.just_added_newline()) {
|
||||
output.set_indent(indentLevel);
|
||||
}
|
||||
output.add_token(output_string);
|
||||
}
|
||||
|
||||
function preserveSingleSpace(isAfterSpace) {
|
||||
if (isAfterSpace) {
|
||||
output.space_before_token = true;
|
||||
}
|
||||
}
|
||||
|
||||
function indent() {
|
||||
indentLevel++;
|
||||
}
|
||||
|
||||
function outdent() {
|
||||
if (indentLevel > 0) {
|
||||
indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
/*_____________________--------------------_____________________*/
|
||||
|
||||
this.beautify = function() {
|
||||
// reset
|
||||
output = new Output(singleIndent, baseIndentString);
|
||||
input = new InputScanner(source_text);
|
||||
indentLevel = 0;
|
||||
nestedLevel = 0;
|
||||
|
||||
ch = null;
|
||||
parenLevel = 0;
|
||||
|
||||
var insideRule = false;
|
||||
// This is the value side of a property value pair (blue in the following ex)
|
||||
// label { content: blue }
|
||||
var insidePropertyValue = false;
|
||||
var enteringConditionalGroup = false;
|
||||
var insideAtExtend = false;
|
||||
|
||||
while (true) {
|
||||
var whitespace = input.read(whitespacePattern);
|
||||
var isAfterSpace = whitespace !== '';
|
||||
ch = input.next();
|
||||
|
||||
if (!ch) {
|
||||
break;
|
||||
} else if (ch === '/' && input.peek() === '*') {
|
||||
// /* css comment */
|
||||
// Always start block comments on a new line.
|
||||
// This handles scenarios where a block comment immediately
|
||||
// follows a property definition on the same line or where
|
||||
// minified code is being beautified.
|
||||
output.add_new_line();
|
||||
input.back();
|
||||
print_string(input.read(block_comment_pattern));
|
||||
|
||||
// Ensures any new lines following the comment are preserved
|
||||
eatWhitespace(true);
|
||||
|
||||
// Block comments are followed by a new line so they don't
|
||||
// share a line with other properties
|
||||
output.add_new_line();
|
||||
} else if (ch === '/' && input.peek() === '/') {
|
||||
// // single line comment
|
||||
// Preserves the space before a comment
|
||||
// on the same line as a rule
|
||||
output.space_before_token = true;
|
||||
input.back();
|
||||
print_string(input.read(comment_pattern));
|
||||
|
||||
// Ensures any new lines following the comment are preserved
|
||||
eatWhitespace(true);
|
||||
} else if (ch === '@') {
|
||||
preserveSingleSpace(isAfterSpace);
|
||||
|
||||
// deal with less propery mixins @{...}
|
||||
if (input.peek() === '{') {
|
||||
print_string(ch + eatString('}'));
|
||||
} else {
|
||||
print_string(ch);
|
||||
|
||||
// strip trailing space, if present, for hash property checks
|
||||
var variableOrRule = input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g);
|
||||
|
||||
if (variableOrRule.match(/[ :]$/)) {
|
||||
// we have a variable or pseudo-class, add it and insert one space before continuing
|
||||
variableOrRule = eatString(": ").replace(/\s$/, '');
|
||||
print_string(variableOrRule);
|
||||
output.space_before_token = true;
|
||||
}
|
||||
|
||||
variableOrRule = variableOrRule.replace(/\s$/, '');
|
||||
|
||||
if (variableOrRule === 'extend') {
|
||||
insideAtExtend = true;
|
||||
}
|
||||
|
||||
// might be a nesting at-rule
|
||||
if (variableOrRule in this.NESTED_AT_RULE) {
|
||||
nestedLevel += 1;
|
||||
if (variableOrRule in this.CONDITIONAL_GROUP_RULE) {
|
||||
enteringConditionalGroup = true;
|
||||
}
|
||||
// might be less variable
|
||||
} else if (!insideRule && parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
|
||||
insidePropertyValue = true;
|
||||
}
|
||||
}
|
||||
} else if (ch === '#' && input.peek() === '{') {
|
||||
preserveSingleSpace(isAfterSpace);
|
||||
print_string(ch + eatString('}'));
|
||||
} else if (ch === '{') {
|
||||
if (input.match(/[\t\n ]*}/g)) {
|
||||
output.space_before_token = true;
|
||||
print_string("{}");
|
||||
|
||||
eatWhitespace(true);
|
||||
output.add_new_line();
|
||||
|
||||
if (newline_between_rules && indentLevel === 0 && !output.just_added_blankline()) {
|
||||
output.add_new_line(true);
|
||||
}
|
||||
} else {
|
||||
indent();
|
||||
output.space_before_token = true;
|
||||
print_string(ch);
|
||||
eatWhitespace(true);
|
||||
output.add_new_line();
|
||||
|
||||
// when entering conditional groups, only rulesets are allowed
|
||||
if (enteringConditionalGroup) {
|
||||
enteringConditionalGroup = false;
|
||||
insideRule = (indentLevel > nestedLevel);
|
||||
} else {
|
||||
// otherwise, declarations are also allowed
|
||||
insideRule = (indentLevel >= nestedLevel);
|
||||
}
|
||||
}
|
||||
} else if (ch === '}') {
|
||||
outdent();
|
||||
output.add_new_line();
|
||||
print_string(ch);
|
||||
insideRule = false;
|
||||
insidePropertyValue = false;
|
||||
if (nestedLevel) {
|
||||
nestedLevel--;
|
||||
}
|
||||
|
||||
eatWhitespace(true);
|
||||
output.add_new_line();
|
||||
|
||||
if (newline_between_rules && indentLevel === 0 && !output.just_added_blankline()) {
|
||||
output.add_new_line(true);
|
||||
}
|
||||
} else if (ch === ":") {
|
||||
if ((insideRule || enteringConditionalGroup) &&
|
||||
!(input.lookBack("&") || foundNestedPseudoClass()) &&
|
||||
!input.lookBack("(") && !insideAtExtend) {
|
||||
// 'property: value' delimiter
|
||||
// which could be in a conditional group query
|
||||
print_string(':');
|
||||
if (!insidePropertyValue) {
|
||||
insidePropertyValue = true;
|
||||
output.space_before_token = true;
|
||||
}
|
||||
} else {
|
||||
// sass/less parent reference don't use a space
|
||||
// sass nested pseudo-class don't use a space
|
||||
|
||||
// preserve space before pseudoclasses/pseudoelements, as it means "in any child"
|
||||
if (input.lookBack(" ")) {
|
||||
output.space_before_token = true;
|
||||
}
|
||||
if (input.peek() === ":") {
|
||||
// pseudo-element
|
||||
ch = input.next();
|
||||
print_string("::");
|
||||
} else {
|
||||
// pseudo-class
|
||||
print_string(':');
|
||||
}
|
||||
}
|
||||
} else if (ch === '"' || ch === '\'') {
|
||||
preserveSingleSpace(isAfterSpace);
|
||||
print_string(ch + eatString(ch));
|
||||
} else if (ch === ';') {
|
||||
insidePropertyValue = false;
|
||||
insideAtExtend = false;
|
||||
print_string(ch);
|
||||
eatWhitespace(true);
|
||||
|
||||
// This maintains single line comments on the same
|
||||
// line. Block comments are also affected, but
|
||||
// a new line is always output before one inside
|
||||
// that section
|
||||
if (input.peek() !== '/') {
|
||||
output.add_new_line();
|
||||
}
|
||||
} else if (ch === '(') { // may be a url
|
||||
if (input.lookBack("url")) {
|
||||
print_string(ch);
|
||||
eatWhitespace();
|
||||
ch = input.next();
|
||||
if (ch) {
|
||||
if (ch !== ')' && ch !== '"' && ch !== '\'') {
|
||||
print_string(ch + eatString(')'));
|
||||
} else {
|
||||
input.back();
|
||||
parenLevel++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parenLevel++;
|
||||
preserveSingleSpace(isAfterSpace);
|
||||
print_string(ch);
|
||||
eatWhitespace();
|
||||
}
|
||||
} else if (ch === ')') {
|
||||
print_string(ch);
|
||||
parenLevel--;
|
||||
} else if (ch === ',') {
|
||||
print_string(ch);
|
||||
eatWhitespace(true);
|
||||
if (selectorSeparatorNewline && !insidePropertyValue && parenLevel < 1) {
|
||||
output.add_new_line();
|
||||
} else {
|
||||
output.space_before_token = true;
|
||||
}
|
||||
} else if ((ch === '>' || ch === '+' || ch === '~') &&
|
||||
!insidePropertyValue && parenLevel < 1) {
|
||||
//handle combinator spacing
|
||||
if (space_around_combinator) {
|
||||
output.space_before_token = true;
|
||||
print_string(ch);
|
||||
output.space_before_token = true;
|
||||
} else {
|
||||
print_string(ch);
|
||||
eatWhitespace();
|
||||
// squash extra whitespace
|
||||
if (ch && whitespaceChar.test(ch)) {
|
||||
ch = '';
|
||||
}
|
||||
}
|
||||
} else if (ch === ']') {
|
||||
print_string(ch);
|
||||
} else if (ch === '[') {
|
||||
preserveSingleSpace(isAfterSpace);
|
||||
print_string(ch);
|
||||
} else if (ch === '=') { // no whitespace before or after
|
||||
eatWhitespace();
|
||||
print_string('=');
|
||||
if (whitespaceChar.test(ch)) {
|
||||
ch = '';
|
||||
}
|
||||
} else if (ch === '!') { // !important
|
||||
print_string(' ');
|
||||
print_string(ch);
|
||||
} else {
|
||||
preserveSingleSpace(isAfterSpace);
|
||||
print_string(ch);
|
||||
}
|
||||
}
|
||||
|
||||
var sweetCode = output.get_code(end_with_newline, eol);
|
||||
|
||||
return sweetCode;
|
||||
};
|
||||
this._options = new Options(options);
|
||||
this._ch = null;
|
||||
this._input = null;
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
|
||||
this.NESTED_AT_RULE = {
|
||||
@ -445,6 +64,375 @@ function Beautifier(source_text, options) {
|
||||
"@supports": true,
|
||||
"@document": true
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Beautifier.prototype.eatString = function(endChars) {
|
||||
var result = '';
|
||||
this._ch = this._input.next();
|
||||
while (this._ch) {
|
||||
result += this._ch;
|
||||
if (this._ch === "\\") {
|
||||
result += this._input.next();
|
||||
} else if (endChars.indexOf(this._ch) !== -1 || this._ch === "\n") {
|
||||
break;
|
||||
}
|
||||
this._ch = this._input.next();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Skips any white space in the source text from the current position.
|
||||
// When allowAtLeastOneNewLine is true, will output new lines for each
|
||||
// newline character found; if the user has preserve_newlines off, only
|
||||
// the first newline will be output
|
||||
Beautifier.prototype.eatWhitespace = function(allowAtLeastOneNewLine) {
|
||||
var result = whitespaceChar.test(this._input.peek());
|
||||
var isFirstNewLine = true;
|
||||
|
||||
while (whitespaceChar.test(this._input.peek())) {
|
||||
this._ch = this._input.next();
|
||||
if (allowAtLeastOneNewLine && this._ch === '\n') {
|
||||
if (this._options.preserve_newlines || isFirstNewLine) {
|
||||
isFirstNewLine = false;
|
||||
this._output.add_new_line(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Nested pseudo-class if we are insideRule
|
||||
// and the next special character found opens
|
||||
// a new block
|
||||
Beautifier.prototype.foundNestedPseudoClass = function() {
|
||||
var openParen = 0;
|
||||
var i = 1;
|
||||
var ch = this._input.peek(i);
|
||||
while (ch) {
|
||||
if (ch === "{") {
|
||||
return true;
|
||||
} else if (ch === '(') {
|
||||
// pseudoclasses can contain ()
|
||||
openParen += 1;
|
||||
} else if (ch === ')') {
|
||||
if (openParen === 0) {
|
||||
return false;
|
||||
}
|
||||
openParen -= 1;
|
||||
} else if (ch === ";" || ch === "}") {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
ch = this._input.peek(i);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Beautifier.prototype.print_string = function(output_string) {
|
||||
if (this._output.just_added_newline()) {
|
||||
this._output.set_indent(this._indentLevel);
|
||||
}
|
||||
this._output.add_token(output_string);
|
||||
};
|
||||
|
||||
Beautifier.prototype.preserveSingleSpace = function(isAfterSpace) {
|
||||
if (isAfterSpace) {
|
||||
this._output.space_before_token = true;
|
||||
}
|
||||
};
|
||||
|
||||
Beautifier.prototype.indent = function() {
|
||||
this._indentLevel++;
|
||||
};
|
||||
|
||||
Beautifier.prototype.outdent = function() {
|
||||
if (this._indentLevel > 0) {
|
||||
this._indentLevel--;
|
||||
}
|
||||
};
|
||||
|
||||
/*_____________________--------------------_____________________*/
|
||||
|
||||
Beautifier.prototype.beautify = function() {
|
||||
if (this._options.disabled) {
|
||||
return this._source_text;
|
||||
}
|
||||
|
||||
var source_text = this._source_text;
|
||||
var eol = this._options.eol;
|
||||
if (eol === 'auto') {
|
||||
eol = '\n';
|
||||
if (source_text && lineBreak.test(source_text || '')) {
|
||||
eol = source_text.match(lineBreak)[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// HACK: newline parsing inconsistent. This brute force normalizes the this._input.
|
||||
source_text = source_text.replace(allLineBreaks, '\n');
|
||||
|
||||
// reset
|
||||
var baseIndentString = source_text.match(/^[\t ]*/)[0];
|
||||
|
||||
this._output = new Output(this._options, baseIndentString);
|
||||
this._input = new InputScanner(source_text);
|
||||
this._indentLevel = 0;
|
||||
this._nestedLevel = 0;
|
||||
|
||||
this._ch = null;
|
||||
var parenLevel = 0;
|
||||
|
||||
var insideRule = false;
|
||||
// This is the value side of a property value pair (blue in the following ex)
|
||||
// label { content: blue }
|
||||
var insidePropertyValue = false;
|
||||
var enteringConditionalGroup = false;
|
||||
var insideAtExtend = false;
|
||||
var insideAtImport = false;
|
||||
var topCharacter = this._ch;
|
||||
|
||||
while (true) {
|
||||
var whitespace = this._input.read(whitespacePattern);
|
||||
var isAfterSpace = whitespace !== '';
|
||||
var previous_ch = topCharacter;
|
||||
this._ch = this._input.next();
|
||||
topCharacter = this._ch;
|
||||
|
||||
if (!this._ch) {
|
||||
break;
|
||||
} else if (this._ch === '/' && this._input.peek() === '*') {
|
||||
// /* css comment */
|
||||
// Always start block comments on a new line.
|
||||
// This handles scenarios where a block comment immediately
|
||||
// follows a property definition on the same line or where
|
||||
// minified code is being beautified.
|
||||
this._output.add_new_line();
|
||||
this._input.back();
|
||||
this.print_string(this._input.read(block_comment_pattern));
|
||||
|
||||
// Ensures any new lines following the comment are preserved
|
||||
this.eatWhitespace(true);
|
||||
|
||||
// Block comments are followed by a new line so they don't
|
||||
// share a line with other properties
|
||||
this._output.add_new_line();
|
||||
} else if (this._ch === '/' && this._input.peek() === '/') {
|
||||
// // single line comment
|
||||
// Preserves the space before a comment
|
||||
// on the same line as a rule
|
||||
this._output.space_before_token = true;
|
||||
this._input.back();
|
||||
this.print_string(this._input.read(comment_pattern));
|
||||
|
||||
// Ensures any new lines following the comment are preserved
|
||||
this.eatWhitespace(true);
|
||||
} else if (this._ch === '@') {
|
||||
this.preserveSingleSpace(isAfterSpace);
|
||||
|
||||
// deal with less propery mixins @{...}
|
||||
if (this._input.peek() === '{') {
|
||||
this.print_string(this._ch + this.eatString('}'));
|
||||
} else {
|
||||
this.print_string(this._ch);
|
||||
|
||||
// strip trailing space, if present, for hash property checks
|
||||
var variableOrRule = this._input.peekUntilAfter(/[: ,;{}()[\]\/='"]/g);
|
||||
|
||||
if (variableOrRule.match(/[ :]$/)) {
|
||||
// we have a variable or pseudo-class, add it and insert one space before continuing
|
||||
variableOrRule = this.eatString(": ").replace(/\s$/, '');
|
||||
this.print_string(variableOrRule);
|
||||
this._output.space_before_token = true;
|
||||
}
|
||||
|
||||
variableOrRule = variableOrRule.replace(/\s$/, '');
|
||||
|
||||
if (variableOrRule === 'extend') {
|
||||
insideAtExtend = true;
|
||||
} else if (variableOrRule === 'import') {
|
||||
insideAtImport = true;
|
||||
}
|
||||
|
||||
// might be a nesting at-rule
|
||||
if (variableOrRule in this.NESTED_AT_RULE) {
|
||||
this._nestedLevel += 1;
|
||||
if (variableOrRule in this.CONDITIONAL_GROUP_RULE) {
|
||||
enteringConditionalGroup = true;
|
||||
}
|
||||
// might be less variable
|
||||
} else if (!insideRule && parenLevel === 0 && variableOrRule.indexOf(':') !== -1) {
|
||||
insidePropertyValue = true;
|
||||
this.indent();
|
||||
}
|
||||
}
|
||||
} else if (this._ch === '#' && this._input.peek() === '{') {
|
||||
this.preserveSingleSpace(isAfterSpace);
|
||||
this.print_string(this._ch + this.eatString('}'));
|
||||
} else if (this._ch === '{') {
|
||||
if (insidePropertyValue) {
|
||||
insidePropertyValue = false;
|
||||
this.outdent();
|
||||
}
|
||||
this.indent();
|
||||
this._output.space_before_token = true;
|
||||
this.print_string(this._ch);
|
||||
|
||||
// when entering conditional groups, only rulesets are allowed
|
||||
if (enteringConditionalGroup) {
|
||||
enteringConditionalGroup = false;
|
||||
insideRule = (this._indentLevel > this._nestedLevel);
|
||||
} else {
|
||||
// otherwise, declarations are also allowed
|
||||
insideRule = (this._indentLevel >= this._nestedLevel);
|
||||
}
|
||||
if (this._options.newline_between_rules && insideRule) {
|
||||
if (this._output.previous_line && this._output.previous_line.item(-1) !== '{') {
|
||||
this._output.ensure_empty_line_above('/', ',');
|
||||
}
|
||||
}
|
||||
this.eatWhitespace(true);
|
||||
this._output.add_new_line();
|
||||
} else if (this._ch === '}') {
|
||||
this.outdent();
|
||||
this._output.add_new_line();
|
||||
if (previous_ch === '{') {
|
||||
this._output.trim(true);
|
||||
}
|
||||
insideAtImport = false;
|
||||
insideAtExtend = false;
|
||||
if (insidePropertyValue) {
|
||||
this.outdent();
|
||||
insidePropertyValue = false;
|
||||
}
|
||||
this.print_string(this._ch);
|
||||
insideRule = false;
|
||||
if (this._nestedLevel) {
|
||||
this._nestedLevel--;
|
||||
}
|
||||
|
||||
this.eatWhitespace(true);
|
||||
this._output.add_new_line();
|
||||
|
||||
if (this._options.newline_between_rules && !this._output.just_added_blankline()) {
|
||||
if (this._input.peek() !== '}') {
|
||||
this._output.add_new_line(true);
|
||||
}
|
||||
}
|
||||
} else if (this._ch === ":") {
|
||||
if ((insideRule || enteringConditionalGroup) && !(this._input.lookBack("&") || this.foundNestedPseudoClass()) && !this._input.lookBack("(") && !insideAtExtend) {
|
||||
// 'property: value' delimiter
|
||||
// which could be in a conditional group query
|
||||
this.print_string(':');
|
||||
if (!insidePropertyValue) {
|
||||
insidePropertyValue = true;
|
||||
this._output.space_before_token = true;
|
||||
this.eatWhitespace(true);
|
||||
this.indent();
|
||||
}
|
||||
} else {
|
||||
// sass/less parent reference don't use a space
|
||||
// sass nested pseudo-class don't use a space
|
||||
|
||||
// preserve space before pseudoclasses/pseudoelements, as it means "in any child"
|
||||
if (this._input.lookBack(" ")) {
|
||||
this._output.space_before_token = true;
|
||||
}
|
||||
if (this._input.peek() === ":") {
|
||||
// pseudo-element
|
||||
this._ch = this._input.next();
|
||||
this.print_string("::");
|
||||
} else {
|
||||
// pseudo-class
|
||||
this.print_string(':');
|
||||
}
|
||||
}
|
||||
} else if (this._ch === '"' || this._ch === '\'') {
|
||||
this.preserveSingleSpace(isAfterSpace);
|
||||
this.print_string(this._ch + this.eatString(this._ch));
|
||||
this.eatWhitespace(true);
|
||||
} else if (this._ch === ';') {
|
||||
if (insidePropertyValue) {
|
||||
this.outdent();
|
||||
insidePropertyValue = false;
|
||||
}
|
||||
insideAtExtend = false;
|
||||
insideAtImport = false;
|
||||
this.print_string(this._ch);
|
||||
this.eatWhitespace(true);
|
||||
|
||||
// This maintains single line comments on the same
|
||||
// line. Block comments are also affected, but
|
||||
// a new line is always output before one inside
|
||||
// that section
|
||||
if (this._input.peek() !== '/') {
|
||||
this._output.add_new_line();
|
||||
}
|
||||
} else if (this._ch === '(') { // may be a url
|
||||
if (this._input.lookBack("url")) {
|
||||
this.print_string(this._ch);
|
||||
this.eatWhitespace();
|
||||
this._ch = this._input.next();
|
||||
if (this._ch === ')' || this._ch === '"' || this._ch === '\'') {
|
||||
this._input.back();
|
||||
parenLevel++;
|
||||
} else if (this._ch) {
|
||||
this.print_string(this._ch + this.eatString(')'));
|
||||
}
|
||||
} else {
|
||||
parenLevel++;
|
||||
this.preserveSingleSpace(isAfterSpace);
|
||||
this.print_string(this._ch);
|
||||
this.eatWhitespace();
|
||||
}
|
||||
} else if (this._ch === ')') {
|
||||
this.print_string(this._ch);
|
||||
parenLevel--;
|
||||
} else if (this._ch === ',') {
|
||||
this.print_string(this._ch);
|
||||
this.eatWhitespace(true);
|
||||
if (this._options.selector_separator_newline && !insidePropertyValue && parenLevel < 1 && !insideAtImport) {
|
||||
this._output.add_new_line();
|
||||
} else {
|
||||
this._output.space_before_token = true;
|
||||
}
|
||||
} else if ((this._ch === '>' || this._ch === '+' || this._ch === '~') && !insidePropertyValue && parenLevel < 1) {
|
||||
//handle combinator spacing
|
||||
if (this._options.space_around_combinator) {
|
||||
this._output.space_before_token = true;
|
||||
this.print_string(this._ch);
|
||||
this._output.space_before_token = true;
|
||||
} else {
|
||||
this.print_string(this._ch);
|
||||
this.eatWhitespace();
|
||||
// squash extra whitespace
|
||||
if (this._ch && whitespaceChar.test(this._ch)) {
|
||||
this._ch = '';
|
||||
}
|
||||
}
|
||||
} else if (this._ch === ']') {
|
||||
this.print_string(this._ch);
|
||||
} else if (this._ch === '[') {
|
||||
this.preserveSingleSpace(isAfterSpace);
|
||||
this.print_string(this._ch);
|
||||
} else if (this._ch === '=') { // no whitespace before or after
|
||||
this.eatWhitespace();
|
||||
this.print_string('=');
|
||||
if (whitespaceChar.test(this._ch)) {
|
||||
this._ch = '';
|
||||
}
|
||||
} else if (this._ch === '!') { // !important
|
||||
this.print_string(' ');
|
||||
this.print_string(this._ch);
|
||||
} else {
|
||||
this.preserveSingleSpace(isAfterSpace);
|
||||
this.print_string(this._ch);
|
||||
}
|
||||
}
|
||||
|
||||
var sweetCode = this._output.get_code(eol);
|
||||
|
||||
return sweetCode;
|
||||
};
|
||||
|
||||
module.exports.Beautifier = Beautifier;
|
@ -1,31 +1,33 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var Beautifier = require('./beautifier').Beautifier;
|
||||
|
||||
function css_beautify(source_text, options) {
|
||||
|
46
js/src/css/options.js
Normal file
46
js/src/css/options.js
Normal file
@ -0,0 +1,46 @@
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var BaseOptions = require('../core/options').Options;
|
||||
|
||||
function Options(options) {
|
||||
BaseOptions.call(this, options, 'css');
|
||||
|
||||
this.selector_separator_newline = this._get_boolean('selector_separator_newline', true);
|
||||
this.newline_between_rules = this._get_boolean('newline_between_rules', true);
|
||||
var space_around_selector_separator = this._get_boolean('space_around_selector_separator');
|
||||
this.space_around_combinator = this._get_boolean('space_around_combinator') || space_around_selector_separator;
|
||||
|
||||
}
|
||||
Options.prototype = new BaseOptions();
|
||||
|
||||
|
||||
|
||||
module.exports.Options = Options;
|
@ -1,4 +1,4 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
@ -24,4 +24,6 @@
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
*/
|
||||
|
||||
'use strict';
|
File diff suppressed because it is too large
Load Diff
@ -1,31 +1,33 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var Beautifier = require('./beautifier').Beautifier;
|
||||
|
||||
function style_html(html_source, options, js_beautify, css_beautify) {
|
||||
|
82
js/src/html/options.js
Normal file
82
js/src/html/options.js
Normal file
@ -0,0 +1,82 @@
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var BaseOptions = require('../core/options').Options;
|
||||
|
||||
function Options(options) {
|
||||
BaseOptions.call(this, options, 'html');
|
||||
|
||||
this.indent_inner_html = this._get_boolean('indent_inner_html');
|
||||
this.indent_body_inner_html = this._get_boolean('indent_body_inner_html', true);
|
||||
this.indent_head_inner_html = this._get_boolean('indent_head_inner_html', true);
|
||||
|
||||
this.indent_handlebars = this._get_boolean('indent_handlebars', true);
|
||||
this.wrap_attributes = this._get_selection('wrap_attributes',
|
||||
['auto', 'force', 'force-aligned', 'force-expand-multiline', 'aligned-multiple']);
|
||||
this.wrap_attributes_indent_size = this._get_number('wrap_attributes_indent_size', this.indent_size);
|
||||
this.extra_liners = this._get_array('extra_liners', ['head', 'body', '/html']);
|
||||
|
||||
this.inline = this._get_array('inline', [
|
||||
// https://www.w3.org/TR/html5/dom.html#phrasing-content
|
||||
'a', 'abbr', 'area', 'audio', 'b', 'bdi', 'bdo', 'br', 'button', 'canvas', 'cite',
|
||||
'code', 'data', 'datalist', 'del', 'dfn', 'em', 'embed', 'i', 'iframe', 'img',
|
||||
'input', 'ins', 'kbd', 'keygen', 'label', 'map', 'mark', 'math', 'meter', 'noscript',
|
||||
'object', 'output', 'progress', 'q', 'ruby', 's', 'samp', /* 'script', */ 'select', 'small',
|
||||
'span', 'strong', 'sub', 'sup', 'svg', 'template', 'textarea', 'time', 'u', 'var',
|
||||
'video', 'wbr', 'text',
|
||||
// prexisting - not sure of full effect of removing, leaving in
|
||||
'acronym', 'address', 'big', 'dt', 'ins', 'strike', 'tt'
|
||||
]);
|
||||
this.void_elements = this._get_array('void_elements', [
|
||||
// HTLM void elements - aka self-closing tags - aka singletons
|
||||
// https://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
|
||||
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen',
|
||||
'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr',
|
||||
// NOTE: Optional tags are too complex for a simple list
|
||||
// they are hard coded in _do_optional_end_element
|
||||
|
||||
// Doctype and xml elements
|
||||
'!doctype', '?xml',
|
||||
// ?php and ?= tags
|
||||
'?php', '?=',
|
||||
// other tags that were in this list, keeping just in case
|
||||
'basefont', 'isindex'
|
||||
]);
|
||||
this.unformatted = this._get_array('unformatted', []);
|
||||
this.content_unformatted = this._get_array('content_unformatted', [
|
||||
'pre', 'textarea'
|
||||
]);
|
||||
this.indent_scripts = this._get_selection('indent_scripts', ['normal', 'keep', 'separate']);
|
||||
}
|
||||
Options.prototype = new BaseOptions();
|
||||
|
||||
|
||||
|
||||
module.exports.Options = Options;
|
@ -1,4 +1,4 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
@ -24,4 +24,265 @@
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var BaseTokenizer = require('../core/tokenizer').Tokenizer;
|
||||
var BASETOKEN = require('../core/tokenizer').TOKEN;
|
||||
var Directives = require('../core/directives').Directives;
|
||||
|
||||
var TOKEN = {
|
||||
TAG_OPEN: 'TK_TAG_OPEN',
|
||||
TAG_CLOSE: 'TK_TAG_CLOSE',
|
||||
ATTRIBUTE: 'TK_ATTRIBUTE',
|
||||
EQUALS: 'TK_EQUALS',
|
||||
VALUE: 'TK_VALUE',
|
||||
COMMENT: 'TK_COMMENT',
|
||||
TEXT: 'TK_TEXT',
|
||||
UNKNOWN: 'TK_UNKNOWN',
|
||||
START: BASETOKEN.START,
|
||||
RAW: BASETOKEN.RAW,
|
||||
EOF: BASETOKEN.EOF
|
||||
};
|
||||
|
||||
var directives_core = new Directives(/<\!--/, /-->/);
|
||||
|
||||
var Tokenizer = function(input_string, options) {
|
||||
BaseTokenizer.call(this, input_string, options);
|
||||
this._current_tag_name = '';
|
||||
|
||||
// Words end at whitespace or when a tag starts
|
||||
// if we are indenting handlebars, they are considered tags
|
||||
this._word_pattern = this._options.indent_handlebars ? /[\n\r\t <]|{{/g : /[\n\r\t <]/g;
|
||||
};
|
||||
Tokenizer.prototype = new BaseTokenizer();
|
||||
|
||||
Tokenizer.prototype._is_comment = function(current_token) { // jshint unused:false
|
||||
return false; //current_token.type === TOKEN.COMMENT || current_token.type === TOKEN.UNKNOWN;
|
||||
};
|
||||
|
||||
Tokenizer.prototype._is_opening = function(current_token) {
|
||||
return current_token.type === TOKEN.TAG_OPEN;
|
||||
};
|
||||
|
||||
Tokenizer.prototype._is_closing = function(current_token, open_token) {
|
||||
return current_token.type === TOKEN.TAG_CLOSE &&
|
||||
(open_token && (
|
||||
((current_token.text === '>' || current_token.text === '/>') && open_token.text[0] === '<') ||
|
||||
(current_token.text === '}}' && open_token.text[0] === '{' && open_token.text[1] === '{')));
|
||||
};
|
||||
|
||||
Tokenizer.prototype._reset = function() {
|
||||
this._current_tag_name = '';
|
||||
};
|
||||
|
||||
Tokenizer.prototype._get_next_token = function(previous_token, open_token) { // jshint unused:false
|
||||
this._readWhitespace();
|
||||
var token = null;
|
||||
var c = this._input.peek();
|
||||
|
||||
if (c === null) {
|
||||
return this._create_token(TOKEN.EOF, '');
|
||||
}
|
||||
|
||||
token = token || this._read_attribute(c, previous_token, open_token);
|
||||
token = token || this._read_raw_content(previous_token, open_token);
|
||||
token = token || this._read_comment(c);
|
||||
token = token || this._read_open(c, open_token);
|
||||
token = token || this._read_close(c, open_token);
|
||||
token = token || this._read_content_word();
|
||||
token = token || this._create_token(TOKEN.UNKNOWN, this._input.next());
|
||||
|
||||
return token;
|
||||
};
|
||||
|
||||
Tokenizer.prototype._read_comment = function(c) { // jshint unused:false
|
||||
var token = null;
|
||||
if (c === '<' || c === '{') {
|
||||
var peek1 = this._input.peek(1);
|
||||
var peek2 = this._input.peek(2);
|
||||
if ((c === '<' && (peek1 === '!' || peek1 === '?' || peek1 === '%')) ||
|
||||
this._options.indent_handlebars && c === '{' && peek1 === '{' && peek2 === '!') {
|
||||
//if we're in a comment, do something special
|
||||
// We treat all comments as literals, even more than preformatted tags
|
||||
// we just look for the appropriate close tag
|
||||
|
||||
// this is will have very poor perf, but will work for now.
|
||||
var comment = '',
|
||||
delimiter = '>',
|
||||
matched = false;
|
||||
|
||||
var input_char = this._input.next();
|
||||
|
||||
while (input_char) {
|
||||
comment += input_char;
|
||||
|
||||
// only need to check for the delimiter if the last chars match
|
||||
if (comment.charAt(comment.length - 1) === delimiter.charAt(delimiter.length - 1) &&
|
||||
comment.indexOf(delimiter) !== -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// only need to search for custom delimiter for the first few characters
|
||||
if (!matched) {
|
||||
matched = comment.length > 10;
|
||||
if (comment.indexOf('<![if') === 0) { //peek for <![if conditional comment
|
||||
delimiter = '<![endif]>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<![cdata[') === 0) { //if it's a <[cdata[ comment...
|
||||
delimiter = ']]>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<![') === 0) { // some other ![ comment? ...
|
||||
delimiter = ']>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<!--') === 0) { // <!-- comment ...
|
||||
delimiter = '-->';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('{{!--') === 0) { // {{!-- handlebars comment
|
||||
delimiter = '--}}';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('{{!') === 0) { // {{! handlebars comment
|
||||
if (comment.length === 5 && comment.indexOf('{{!--') === -1) {
|
||||
delimiter = '}}';
|
||||
matched = true;
|
||||
}
|
||||
} else if (comment.indexOf('<?') === 0) { // {{! handlebars comment
|
||||
delimiter = '?>';
|
||||
matched = true;
|
||||
} else if (comment.indexOf('<%') === 0) { // {{! handlebars comment
|
||||
delimiter = '%>';
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
|
||||
input_char = this._input.next();
|
||||
}
|
||||
|
||||
var directives = directives_core.get_directives(comment);
|
||||
if (directives && directives.ignore === 'start') {
|
||||
comment += directives_core.readIgnored(this._input);
|
||||
}
|
||||
token = this._create_token(TOKEN.COMMENT, comment);
|
||||
token.directives = directives;
|
||||
}
|
||||
}
|
||||
|
||||
return token;
|
||||
};
|
||||
|
||||
Tokenizer.prototype._read_open = function(c, open_token) {
|
||||
var resulting_string = null;
|
||||
var token = null;
|
||||
if (!open_token) {
|
||||
if (c === '<') {
|
||||
resulting_string = this._input.read(/<(?:[^\n\r\t >{][^\n\r\t >{/]*)?/g);
|
||||
token = this._create_token(TOKEN.TAG_OPEN, resulting_string);
|
||||
} else if (this._options.indent_handlebars && c === '{' && this._input.peek(1) === '{') {
|
||||
resulting_string = this._input.readUntil(/[\n\r\t }]/g);
|
||||
token = this._create_token(TOKEN.TAG_OPEN, resulting_string);
|
||||
}
|
||||
}
|
||||
return token;
|
||||
};
|
||||
|
||||
Tokenizer.prototype._read_close = function(c, open_token) {
|
||||
var resulting_string = null;
|
||||
var token = null;
|
||||
if (open_token) {
|
||||
if (open_token.text[0] === '<' && (c === '>' || (c === '/' && this._input.peek(1) === '>'))) {
|
||||
resulting_string = this._input.next();
|
||||
if (c === '/') { // for close tag "/>"
|
||||
resulting_string += this._input.next();
|
||||
}
|
||||
token = this._create_token(TOKEN.TAG_CLOSE, resulting_string);
|
||||
} else if (open_token.text[0] === '{' && c === '}' && this._input.peek(1) === '}') {
|
||||
this._input.next();
|
||||
this._input.next();
|
||||
token = this._create_token(TOKEN.TAG_CLOSE, '}}');
|
||||
}
|
||||
}
|
||||
|
||||
return token;
|
||||
};
|
||||
|
||||
Tokenizer.prototype._read_attribute = function(c, previous_token, open_token) {
|
||||
var token = null;
|
||||
var resulting_string = '';
|
||||
if (open_token && open_token.text[0] === '<') {
|
||||
|
||||
if (c === '=') {
|
||||
token = this._create_token(TOKEN.EQUALS, this._input.next());
|
||||
} else if (c === '"' || c === "'") {
|
||||
var content = this._input.next();
|
||||
var input_string = '';
|
||||
var string_pattern = new RegExp(c + '|{{', 'g');
|
||||
while (this._input.hasNext()) {
|
||||
input_string = this._input.readUntilAfter(string_pattern);
|
||||
content += input_string;
|
||||
if (input_string[input_string.length - 1] === '"' || input_string[input_string.length - 1] === "'") {
|
||||
break;
|
||||
} else if (this._input.hasNext()) {
|
||||
content += this._input.readUntilAfter(/}}/g);
|
||||
}
|
||||
}
|
||||
|
||||
token = this._create_token(TOKEN.VALUE, content);
|
||||
} else {
|
||||
if (c === '{' && this._input.peek(1) === '{') {
|
||||
resulting_string = this._input.readUntilAfter(/}}/g);
|
||||
} else {
|
||||
resulting_string = this._input.readUntil(/[\n\r\t =\/>]/g);
|
||||
}
|
||||
|
||||
if (resulting_string) {
|
||||
if (previous_token.type === TOKEN.EQUALS) {
|
||||
token = this._create_token(TOKEN.VALUE, resulting_string);
|
||||
} else {
|
||||
token = this._create_token(TOKEN.ATTRIBUTE, resulting_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return token;
|
||||
};
|
||||
|
||||
Tokenizer.prototype._is_content_unformatted = function(tag_name) {
|
||||
// void_elements have no content and so cannot have unformatted content
|
||||
// script and style tags should always be read as unformatted content
|
||||
// finally content_unformatted and unformatted element contents are unformatted
|
||||
return this._options.void_elements.indexOf(tag_name) === -1 &&
|
||||
(tag_name === 'script' || tag_name === 'style' ||
|
||||
this._options.content_unformatted.indexOf(tag_name) !== -1 ||
|
||||
this._options.unformatted.indexOf(tag_name) !== -1);
|
||||
};
|
||||
|
||||
|
||||
Tokenizer.prototype._read_raw_content = function(previous_token, open_token) { // jshint unused:false
|
||||
var resulting_string = '';
|
||||
if (open_token && open_token.text[0] === '{') {
|
||||
resulting_string = this._input.readUntil(/}}/g);
|
||||
} else if (previous_token.type === TOKEN.TAG_CLOSE && (previous_token.opened.text[0] === '<')) {
|
||||
var tag_name = previous_token.opened.text.substr(1).toLowerCase();
|
||||
if (this._is_content_unformatted(tag_name)) {
|
||||
resulting_string = this._input.readUntil(new RegExp('</' + tag_name + '[\\n\\r\\t ]*?>', 'ig'));
|
||||
}
|
||||
}
|
||||
|
||||
if (resulting_string) {
|
||||
return this._create_token(TOKEN.TEXT, resulting_string);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Tokenizer.prototype._read_content_word = function() {
|
||||
// if we get here and we see handlebars treat them as plain text
|
||||
var resulting_string = this._input.readUntil(this._word_pattern);
|
||||
if (resulting_string) {
|
||||
return this._create_token(TOKEN.TEXT, resulting_string);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.Tokenizer = Tokenizer;
|
||||
module.exports.TOKEN = TOKEN;
|
@ -1,4 +1,4 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
@ -26,6 +26,8 @@
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var js_beautify = require('./javascript/index');
|
||||
var css_beautify = require('./css/index');
|
||||
var html_beautify = require('./html/index');
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* jshint curly: false */
|
||||
// This section of code is taken from acorn.
|
||||
/* jshint node: true, curly: false */
|
||||
// Parts of this section of code is taken from acorn.
|
||||
//
|
||||
// Acorn was written by Marijn Haverbeke and released under an MIT
|
||||
// license. The Unicode regexps (for identifiers and whitespace) were
|
||||
@ -12,25 +12,37 @@
|
||||
|
||||
// ## Character categories
|
||||
|
||||
|
||||
'use strict';
|
||||
|
||||
// acorn used char codes to squeeze the last bit of performance out
|
||||
// Beautifier is okay without that, so we're using regex
|
||||
// permit $ (36) and @ (64). @ is used in ES7 decorators.
|
||||
// 65 through 91 are uppercase letters.
|
||||
// permit _ (95).
|
||||
// 97 through 123 are lowercase letters.
|
||||
var baseASCIIidentifierStartChars = "\x24\x40\x41-\x5a\x5f\x61-\x7a";
|
||||
|
||||
// inside an identifier @ is not allowed but 0-9 are.
|
||||
var baseASCIIidentifierChars = "\x24\x30-\x39\x41-\x5a\x5f\x61-\x7a";
|
||||
|
||||
// Big ugly regular expressions that match characters in the
|
||||
// whitespace, identifier, and identifier-start categories. These
|
||||
// are only applied when a character is found to actually have a
|
||||
// code point above 128.
|
||||
|
||||
var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; // jshint ignore:line
|
||||
var baseASCIIidentifierStartChars = "\x24\x40\x41-\x5a\x5f\x61-\x7a";
|
||||
var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
|
||||
var baseASCIIidentifierChars = "\x24\x30-\x39\x41-\x5a\x5f\x61-\x7a";
|
||||
var nonASCIIidentifierChars = "\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f";
|
||||
//var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
|
||||
//var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
|
||||
|
||||
var identifierStart = new RegExp("[" + baseASCIIidentifierStartChars + nonASCIIidentifierStartChars + "]");
|
||||
var identifierChars = new RegExp("[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
|
||||
var identifierStart = "[" + baseASCIIidentifierStartChars + nonASCIIidentifierStartChars + "]";
|
||||
var identifierChars = "[" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]*";
|
||||
|
||||
exports.identifier = new RegExp("[" + baseASCIIidentifierStartChars + nonASCIIidentifierStartChars + "][" + baseASCIIidentifierChars + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]*", 'g');
|
||||
exports.identifier = new RegExp(identifierStart + identifierChars, 'g');
|
||||
|
||||
|
||||
var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/; // jshint ignore:line
|
||||
|
||||
// Whether a single character denotes a newline.
|
||||
|
||||
exports.newline = /[\n\r\u2028\u2029]/;
|
||||
@ -41,31 +53,4 @@ exports.newline = /[\n\r\u2028\u2029]/;
|
||||
// in javascript, these two differ
|
||||
// in python they are the same, different methods are called on them
|
||||
exports.lineBreak = new RegExp('\r\n|' + exports.newline.source);
|
||||
exports.allLineBreaks = new RegExp(exports.lineBreak.source, 'g');
|
||||
|
||||
|
||||
// Test whether a given character code starts an identifier.
|
||||
|
||||
exports.isIdentifierStart = function(code) {
|
||||
// // permit $ (36) and @ (64). @ is used in ES7 decorators.
|
||||
// if (code < 65) return code === 36 || code === 64;
|
||||
// // 65 through 91 are uppercase letters.
|
||||
// if (code < 91) return true;
|
||||
// // permit _ (95).
|
||||
// if (code < 97) return code === 95;
|
||||
// // 97 through 123 are lowercase letters.
|
||||
// if (code < 123) return true;
|
||||
return identifierStart.test(String.fromCharCode(code));
|
||||
};
|
||||
|
||||
// Test whether a given character is part of an identifier.
|
||||
|
||||
exports.isIdentifierChar = function(code) {
|
||||
// if (code < 48) return code === 36;
|
||||
// if (code < 58) return true;
|
||||
// if (code < 65) return false;
|
||||
// if (code < 91) return true;
|
||||
// if (code < 97) return code === 95;
|
||||
// if (code < 123) return true;
|
||||
return identifierChars.test(String.fromCharCode(code));
|
||||
};
|
||||
exports.allLineBreaks = new RegExp(exports.lineBreak.source, 'g');
|
File diff suppressed because it is too large
Load Diff
@ -1,31 +1,33 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var Beautifier = require('./beautifier').Beautifier;
|
||||
|
||||
function js_beautify(js_source_text, options) {
|
||||
|
93
js/src/javascript/options.js
Normal file
93
js/src/javascript/options.js
Normal file
@ -0,0 +1,93 @@
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var BaseOptions = require('../core/options').Options;
|
||||
|
||||
var validPositionValues = ['before-newline', 'after-newline', 'preserve-newline'];
|
||||
|
||||
function Options(options) {
|
||||
BaseOptions.call(this, options, 'js');
|
||||
|
||||
// compatibility, re
|
||||
var raw_brace_style = this.raw_options.brace_style || null;
|
||||
if (raw_brace_style === "expand-strict") { //graceful handling of deprecated option
|
||||
this.raw_options.brace_style = "expand";
|
||||
} else if (raw_brace_style === "collapse-preserve-inline") { //graceful handling of deprecated option
|
||||
this.raw_options.brace_style = "collapse,preserve-inline";
|
||||
} else if (this.raw_options.braces_on_own_line !== undefined) { //graceful handling of deprecated option
|
||||
this.raw_options.brace_style = this.raw_options.braces_on_own_line ? "expand" : "collapse";
|
||||
// } else if (!raw_brace_style) { //Nothing exists to set it
|
||||
// raw_brace_style = "collapse";
|
||||
}
|
||||
|
||||
//preserve-inline in delimited string will trigger brace_preserve_inline, everything
|
||||
//else is considered a brace_style and the last one only will have an effect
|
||||
|
||||
var brace_style_split = this._get_selection_list('brace_style', ['collapse', 'expand', 'end-expand', 'none', 'preserve-inline']);
|
||||
|
||||
this.brace_preserve_inline = false; //Defaults in case one or other was not specified in meta-option
|
||||
this.brace_style = "collapse";
|
||||
|
||||
for (var bs = 0; bs < brace_style_split.length; bs++) {
|
||||
if (brace_style_split[bs] === "preserve-inline") {
|
||||
this.brace_preserve_inline = true;
|
||||
} else {
|
||||
this.brace_style = brace_style_split[bs];
|
||||
}
|
||||
}
|
||||
|
||||
this.unindent_chained_methods = this._get_boolean('unindent_chained_methods');
|
||||
this.break_chained_methods = this._get_boolean('break_chained_methods');
|
||||
this.space_in_paren = this._get_boolean('space_in_paren');
|
||||
this.space_in_empty_paren = this._get_boolean('space_in_empty_paren');
|
||||
this.jslint_happy = this._get_boolean('jslint_happy');
|
||||
this.space_after_anon_function = this._get_boolean('space_after_anon_function');
|
||||
this.space_after_named_function = this._get_boolean('space_after_named_function');
|
||||
this.keep_array_indentation = this._get_boolean('keep_array_indentation');
|
||||
this.space_before_conditional = this._get_boolean('space_before_conditional', true);
|
||||
this.unescape_strings = this._get_boolean('unescape_strings');
|
||||
this.e4x = this._get_boolean('e4x');
|
||||
this.comma_first = this._get_boolean('comma_first');
|
||||
this.operator_position = this._get_selection('operator_position', validPositionValues);
|
||||
|
||||
// For testing of beautify preserve:start directive
|
||||
this.test_output_raw = this._get_boolean('test_output_raw');
|
||||
|
||||
// force this._options.space_after_anon_function to true if this._options.jslint_happy
|
||||
if (this.jslint_happy) {
|
||||
this.space_after_anon_function = true;
|
||||
}
|
||||
|
||||
}
|
||||
Options.prototype = new BaseOptions();
|
||||
|
||||
|
||||
|
||||
module.exports.Options = Options;
|
@ -1,36 +1,38 @@
|
||||
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/*jshint node:true */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var InputScanner = require('../core/inputscanner').InputScanner;
|
||||
var BaseTokenizer = require('../core/tokenizer').Tokenizer;
|
||||
var BASETOKEN = require('../core/tokenizer').TOKEN;
|
||||
var acorn = require('../core/acorn');
|
||||
var Directives = require('../core/directives').Directives;
|
||||
var acorn = require('./acorn');
|
||||
|
||||
function in_array(what, arr) {
|
||||
return arr.indexOf(what) !== -1;
|
||||
@ -101,23 +103,23 @@ var template_pattern = /(?:(?:<\?php|<\?=)[\s\S]*?\?>)|(?:<%[\s\S]*?%>)/g;
|
||||
|
||||
var in_html_comment;
|
||||
|
||||
var Tokenizer = function(input_string, opts) {
|
||||
BaseTokenizer.call(this, input_string);
|
||||
this._opts = opts;
|
||||
this.positionable_operators = positionable_operators;
|
||||
this.line_starters = line_starters;
|
||||
var Tokenizer = function(input_string, options) {
|
||||
BaseTokenizer.call(this, input_string, options);
|
||||
|
||||
this._whitespace_pattern = /[\n\r\u2028\u2029\t\u000B\u00A0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff ]+/g;
|
||||
this._newline_pattern = /([^\n\r\u2028\u2029]*)(\r\n|[\n\r\u2028\u2029])?/g;
|
||||
};
|
||||
Tokenizer.prototype = new BaseTokenizer();
|
||||
|
||||
Tokenizer.prototype.is_comment = function(current_token) {
|
||||
Tokenizer.prototype._is_comment = function(current_token) {
|
||||
return current_token.type === TOKEN.COMMENT || current_token.type === TOKEN.BLOCK_COMMENT || current_token.type === TOKEN.UNKNOWN;
|
||||
};
|
||||
|
||||
Tokenizer.prototype.is_opening = function(current_token) {
|
||||
Tokenizer.prototype._is_opening = function(current_token) {
|
||||
return current_token.type === TOKEN.START_BLOCK || current_token.type === TOKEN.START_EXPR;
|
||||
};
|
||||
|
||||
Tokenizer.prototype.is_closing = function(current_token, open_token) {
|
||||
Tokenizer.prototype._is_closing = function(current_token, open_token) {
|
||||
return (current_token.type === TOKEN.END_BLOCK || current_token.type === TOKEN.END_EXPR) &&
|
||||
(open_token && (
|
||||
(current_token.text === ']' && open_token.text === '[') ||
|
||||
@ -125,68 +127,68 @@ Tokenizer.prototype.is_closing = function(current_token, open_token) {
|
||||
(current_token.text === '}' && open_token.text === '{')));
|
||||
};
|
||||
|
||||
Tokenizer.prototype.reset = function() {
|
||||
Tokenizer.prototype._reset = function() {
|
||||
in_html_comment = false;
|
||||
};
|
||||
|
||||
Tokenizer.prototype.get_next_token = function(last_token) {
|
||||
this.readWhitespace();
|
||||
Tokenizer.prototype._get_next_token = function(previous_token, open_token) { // jshint unused:false
|
||||
this._readWhitespace();
|
||||
var token = null;
|
||||
var c = this._input.peek();
|
||||
|
||||
token = token || this._read_singles(c);
|
||||
token = token || this._read_word(last_token);
|
||||
token = token || this._read_word(previous_token);
|
||||
token = token || this._read_comment(c);
|
||||
token = token || this._read_string(c);
|
||||
token = token || this._read_regexp(c, last_token);
|
||||
token = token || this._read_xml(c, last_token);
|
||||
token = token || this._read_regexp(c, previous_token);
|
||||
token = token || this._read_xml(c, previous_token);
|
||||
token = token || this._read_non_javascript(c);
|
||||
token = token || this._read_punctuation();
|
||||
token = token || this.create_token(TOKEN.UNKNOWN, this._input.next());
|
||||
token = token || this._create_token(TOKEN.UNKNOWN, this._input.next());
|
||||
|
||||
return token;
|
||||
};
|
||||
|
||||
Tokenizer.prototype._read_word = function(last_token) {
|
||||
Tokenizer.prototype._read_word = function(previous_token) {
|
||||
var resulting_string;
|
||||
resulting_string = this._input.read(acorn.identifier);
|
||||
if (resulting_string !== '') {
|
||||
if (!(last_token.type === TOKEN.DOT ||
|
||||
(last_token.type === TOKEN.RESERVED && (last_token.text === 'set' || last_token.text === 'get'))) &&
|
||||
if (!(previous_token.type === TOKEN.DOT ||
|
||||
(previous_token.type === TOKEN.RESERVED && (previous_token.text === 'set' || previous_token.text === 'get'))) &&
|
||||
reserved_word_pattern.test(resulting_string)) {
|
||||
if (resulting_string === 'in' || resulting_string === 'of') { // hack for 'in' and 'of' operators
|
||||
return this.create_token(TOKEN.OPERATOR, resulting_string);
|
||||
return this._create_token(TOKEN.OPERATOR, resulting_string);
|
||||
}
|
||||
return this.create_token(TOKEN.RESERVED, resulting_string);
|
||||
return this._create_token(TOKEN.RESERVED, resulting_string);
|
||||
}
|
||||
|
||||
return this.create_token(TOKEN.WORD, resulting_string);
|
||||
return this._create_token(TOKEN.WORD, resulting_string);
|
||||
}
|
||||
|
||||
resulting_string = this._input.read(number_pattern);
|
||||
if (resulting_string !== '') {
|
||||
return this.create_token(TOKEN.WORD, resulting_string);
|
||||
return this._create_token(TOKEN.WORD, resulting_string);
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype._read_singles = function(c) {
|
||||
var token = null;
|
||||
if (c === null) {
|
||||
token = this.create_token(TOKEN.EOF, '');
|
||||
token = this._create_token(TOKEN.EOF, '');
|
||||
} else if (c === '(' || c === '[') {
|
||||
token = this.create_token(TOKEN.START_EXPR, c);
|
||||
token = this._create_token(TOKEN.START_EXPR, c);
|
||||
} else if (c === ')' || c === ']') {
|
||||
token = this.create_token(TOKEN.END_EXPR, c);
|
||||
token = this._create_token(TOKEN.END_EXPR, c);
|
||||
} else if (c === '{') {
|
||||
token = this.create_token(TOKEN.START_BLOCK, c);
|
||||
token = this._create_token(TOKEN.START_BLOCK, c);
|
||||
} else if (c === '}') {
|
||||
token = this.create_token(TOKEN.END_BLOCK, c);
|
||||
token = this._create_token(TOKEN.END_BLOCK, c);
|
||||
} else if (c === ';') {
|
||||
token = this.create_token(TOKEN.SEMICOLON, c);
|
||||
token = this._create_token(TOKEN.SEMICOLON, c);
|
||||
} else if (c === '.' && dot_pattern.test(this._input.peek(1))) {
|
||||
token = this.create_token(TOKEN.DOT, c);
|
||||
token = this._create_token(TOKEN.DOT, c);
|
||||
} else if (c === ',') {
|
||||
token = this.create_token(TOKEN.COMMA, c);
|
||||
token = this._create_token(TOKEN.COMMA, c);
|
||||
}
|
||||
|
||||
if (token) {
|
||||
@ -200,9 +202,9 @@ Tokenizer.prototype._read_punctuation = function() {
|
||||
|
||||
if (resulting_string !== '') {
|
||||
if (resulting_string === '=') {
|
||||
return this.create_token(TOKEN.EQUALS, resulting_string);
|
||||
return this._create_token(TOKEN.EQUALS, resulting_string);
|
||||
} else {
|
||||
return this.create_token(TOKEN.OPERATOR, resulting_string);
|
||||
return this._create_token(TOKEN.OPERATOR, resulting_string);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -213,14 +215,14 @@ Tokenizer.prototype._read_non_javascript = function(c) {
|
||||
if (c === '#') {
|
||||
c = this._input.next();
|
||||
|
||||
if (this._tokens.isEmpty() && this._input.peek() === '!') {
|
||||
if (this._is_first_token() && this._input.peek() === '!') {
|
||||
// shebang
|
||||
resulting_string = c;
|
||||
while (this._input.hasNext() && c !== '\n') {
|
||||
c = this._input.next();
|
||||
resulting_string += c;
|
||||
}
|
||||
return this.create_token(TOKEN.UNKNOWN, resulting_string.trim() + '\n');
|
||||
return this._create_token(TOKEN.UNKNOWN, resulting_string.trim() + '\n');
|
||||
}
|
||||
|
||||
// Spidermonkey-specific sharp variables for circular references. Considered obsolete.
|
||||
@ -241,7 +243,7 @@ Tokenizer.prototype._read_non_javascript = function(c) {
|
||||
this._input.next();
|
||||
this._input.next();
|
||||
}
|
||||
return this.create_token(TOKEN.WORD, sharp);
|
||||
return this._create_token(TOKEN.WORD, sharp);
|
||||
}
|
||||
|
||||
this._input.back();
|
||||
@ -251,7 +253,7 @@ Tokenizer.prototype._read_non_javascript = function(c) {
|
||||
resulting_string = this._input.read(template_pattern);
|
||||
if (resulting_string) {
|
||||
resulting_string = resulting_string.replace(acorn.allLineBreaks, '\n');
|
||||
return this.create_token(TOKEN.STRING, resulting_string);
|
||||
return this._create_token(TOKEN.STRING, resulting_string);
|
||||
}
|
||||
} else if (this._input.match(/<\!--/g)) {
|
||||
c = '<!--';
|
||||
@ -259,11 +261,11 @@ Tokenizer.prototype._read_non_javascript = function(c) {
|
||||
c += this._input.next();
|
||||
}
|
||||
in_html_comment = true;
|
||||
return this.create_token(TOKEN.COMMENT, c);
|
||||
return this._create_token(TOKEN.COMMENT, c);
|
||||
}
|
||||
} else if (c === '-' && in_html_comment && this._input.match(/-->/g)) {
|
||||
in_html_comment = false;
|
||||
return this.create_token(TOKEN.COMMENT, '-->');
|
||||
return this._create_token(TOKEN.COMMENT, '-->');
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -281,12 +283,12 @@ Tokenizer.prototype._read_comment = function(c) {
|
||||
comment += directives_core.readIgnored(this._input);
|
||||
}
|
||||
comment = comment.replace(acorn.allLineBreaks, '\n');
|
||||
token = this.create_token(TOKEN.BLOCK_COMMENT, comment);
|
||||
token = this._create_token(TOKEN.BLOCK_COMMENT, comment);
|
||||
token.directives = directives;
|
||||
} else if (this._input.peek(1) === '/') {
|
||||
// peek for comment // ...
|
||||
comment = this._input.read(comment_pattern);
|
||||
token = this.create_token(TOKEN.COMMENT, comment);
|
||||
token = this._create_token(TOKEN.COMMENT, comment);
|
||||
}
|
||||
}
|
||||
return token;
|
||||
@ -303,32 +305,32 @@ Tokenizer.prototype._read_string = function(c) {
|
||||
resulting_string += this._read_string_recursive(c);
|
||||
}
|
||||
|
||||
if (this.has_char_escapes && this._opts.unescape_strings) {
|
||||
if (this.has_char_escapes && this._options.unescape_strings) {
|
||||
resulting_string = unescape_string(resulting_string);
|
||||
}
|
||||
if (this._input.peek() === c) {
|
||||
resulting_string += this._input.next();
|
||||
}
|
||||
|
||||
return this.create_token(TOKEN.STRING, resulting_string);
|
||||
return this._create_token(TOKEN.STRING, resulting_string);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Tokenizer.prototype._allow_regexp_or_xml = function(last_token) {
|
||||
Tokenizer.prototype._allow_regexp_or_xml = function(previous_token) {
|
||||
// regex and xml can only appear in specific locations during parsing
|
||||
return (last_token.type === TOKEN.RESERVED && in_array(last_token.text, ['return', 'case', 'throw', 'else', 'do', 'typeof', 'yield'])) ||
|
||||
(last_token.type === TOKEN.END_EXPR && last_token.text === ')' &&
|
||||
last_token.parent && last_token.parent.type === TOKEN.RESERVED && in_array(last_token.parent.text, ['if', 'while', 'for'])) ||
|
||||
(in_array(last_token.type, [TOKEN.COMMENT, TOKEN.START_EXPR, TOKEN.START_BLOCK, TOKEN.START,
|
||||
return (previous_token.type === TOKEN.RESERVED && in_array(previous_token.text, ['return', 'case', 'throw', 'else', 'do', 'typeof', 'yield'])) ||
|
||||
(previous_token.type === TOKEN.END_EXPR && previous_token.text === ')' &&
|
||||
previous_token.opened.previous.type === TOKEN.RESERVED && in_array(previous_token.opened.previous.text, ['if', 'while', 'for'])) ||
|
||||
(in_array(previous_token.type, [TOKEN.COMMENT, TOKEN.START_EXPR, TOKEN.START_BLOCK, TOKEN.START,
|
||||
TOKEN.END_BLOCK, TOKEN.OPERATOR, TOKEN.EQUALS, TOKEN.EOF, TOKEN.SEMICOLON, TOKEN.COMMA
|
||||
]));
|
||||
};
|
||||
|
||||
Tokenizer.prototype._read_regexp = function(c, last_token) {
|
||||
Tokenizer.prototype._read_regexp = function(c, previous_token) {
|
||||
|
||||
if (c === '/' && this._allow_regexp_or_xml(last_token)) {
|
||||
if (c === '/' && this._allow_regexp_or_xml(previous_token)) {
|
||||
// handle regexp
|
||||
//
|
||||
var resulting_string = this._input.next();
|
||||
@ -359,7 +361,7 @@ Tokenizer.prototype._read_regexp = function(c, last_token) {
|
||||
// Only [gim] are valid, but if the user puts in garbage, do what we can to take it.
|
||||
resulting_string += this._input.read(acorn.identifier);
|
||||
}
|
||||
return this.create_token(TOKEN.STRING, resulting_string);
|
||||
return this._create_token(TOKEN.STRING, resulting_string);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@ -368,9 +370,9 @@ Tokenizer.prototype._read_regexp = function(c, last_token) {
|
||||
var startXmlRegExp = /<()([-a-zA-Z:0-9_.]+|{[\s\S]+?}|!\[CDATA\[[\s\S]*?\]\])(\s+{[\s\S]+?}|\s+[-a-zA-Z:0-9_.]+|\s+[-a-zA-Z:0-9_.]+\s*=\s*('[^']*'|"[^"]*"|{[\s\S]+?}))*\s*(\/?)\s*>/g;
|
||||
var xmlRegExp = /[\s\S]*?<(\/?)([-a-zA-Z:0-9_.]+|{[\s\S]+?}|!\[CDATA\[[\s\S]*?\]\])(\s+{[\s\S]+?}|\s+[-a-zA-Z:0-9_.]+|\s+[-a-zA-Z:0-9_.]+\s*=\s*('[^']*'|"[^"]*"|{[\s\S]+?}))*\s*(\/?)\s*>/g;
|
||||
|
||||
Tokenizer.prototype._read_xml = function(c, last_token) {
|
||||
Tokenizer.prototype._read_xml = function(c, previous_token) {
|
||||
|
||||
if (this._opts.e4x && c === "<" && this._input.test(startXmlRegExp) && this._allow_regexp_or_xml(last_token)) {
|
||||
if (this._options.e4x && c === "<" && this._input.test(startXmlRegExp) && this._allow_regexp_or_xml(previous_token)) {
|
||||
// handle e4x xml literals
|
||||
//
|
||||
var xmlStr = '';
|
||||
@ -403,7 +405,7 @@ Tokenizer.prototype._read_xml = function(c, last_token) {
|
||||
xmlStr += this._input.match(/[\s\S]*/g)[0];
|
||||
}
|
||||
xmlStr = xmlStr.replace(acorn.allLineBreaks, '\n');
|
||||
return this.create_token(TOKEN.STRING, xmlStr);
|
||||
return this._create_token(TOKEN.STRING, xmlStr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -526,7 +528,7 @@ Tokenizer.prototype._read_string_recursive = function(delimiter, allow_unescaped
|
||||
return resulting_string;
|
||||
};
|
||||
|
||||
|
||||
|
||||
module.exports.Tokenizer = Tokenizer;
|
||||
module.exports.TOKEN = TOKEN;
|
||||
module.exports.TOKEN = TOKEN;
|
||||
module.exports.positionable_operators = positionable_operators.slice();
|
||||
module.exports.line_starters = line_starters.slice();
|
@ -1,6 +1,33 @@
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
//
|
||||
// simple unpacker/deobfuscator for scripts messed up with javascriptobfuscator.com
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
// written by Einar Lielmanis <einar@beautifier.io>
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
@ -10,6 +37,8 @@
|
||||
//
|
||||
//
|
||||
|
||||
/*jshint strict:false */
|
||||
|
||||
var JavascriptObfuscator = {
|
||||
detect: function(str) {
|
||||
return /^var _0x[a-f0-9]+ ?\= ?\[/.test(str);
|
||||
|
@ -1,3 +1,30 @@
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
//
|
||||
// simple unpacker/deobfuscator for scripts messed up with myobfuscate.com
|
||||
// You really don't want to obfuscate your scripts there: they're tracking
|
||||
@ -16,7 +43,7 @@
|
||||
|
||||
*/
|
||||
//
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
// written by Einar Lielmanis <einar@beautifier.io>
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
@ -26,6 +53,8 @@
|
||||
//
|
||||
//
|
||||
|
||||
/*jshint strict:false */
|
||||
|
||||
var MyObfuscate = {
|
||||
detect: function(str) {
|
||||
if (/^var _?[0O1lI]{3}\=('|\[).*\)\)\);/.test(str)) {
|
||||
|
@ -1,6 +1,32 @@
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
//
|
||||
// Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
//
|
||||
// Coincidentally, it can defeat a couple of other eval-based compressors.
|
||||
//
|
||||
@ -12,6 +38,8 @@
|
||||
//
|
||||
//
|
||||
|
||||
/*jshint strict:false */
|
||||
|
||||
var P_A_C_K_E_R = {
|
||||
detect: function(str) {
|
||||
return (P_A_C_K_E_R.get_chunks(str).length > 0);
|
||||
|
@ -1,8 +1,36 @@
|
||||
/*global unescape */
|
||||
/*jshint curly: false, scripturl: true */
|
||||
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
//
|
||||
// trivial bookmarklet/escaped script detector for the javascript beautifier
|
||||
// written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
// written by Einar Lielmanis <einar@beautifier.io>
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
@ -12,6 +40,9 @@
|
||||
//
|
||||
//
|
||||
|
||||
/*jshint strict:false */
|
||||
|
||||
|
||||
var isNode = (typeof module !== 'undefined' && module.exports);
|
||||
if (isNode) {
|
||||
var SanityTest = require(__dirname + '/../../test/sanitytest');
|
||||
|
@ -1,5 +1,7 @@
|
||||
/*jshint node:true */
|
||||
|
||||
'use strict';
|
||||
|
||||
var requirejs = require('requirejs'),
|
||||
SanityTest = require('./sanitytest'),
|
||||
Urlencoded = require('../lib/unpackers/urlencode_unpacker'),
|
||||
|
@ -1,3 +1,6 @@
|
||||
/*jshint mocha:true */
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var InputScanner = require('../../src/core/inputscanner').InputScanner;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
45
js/test/node-beautify-css-perf-tests.js
Normal file
45
js/test/node-beautify-css-perf-tests.js
Normal file
@ -0,0 +1,45 @@
|
||||
/*global js_beautify: true */
|
||||
/*jshint node:true */
|
||||
/*jshint unused:false */
|
||||
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs'),
|
||||
SanityTest = require('./sanitytest'),
|
||||
Benchmark = require('benchmark'),
|
||||
Urlencoded = require('../lib/unpackers/urlencode_unpacker'),
|
||||
beautifier = require('../src/index');
|
||||
|
||||
function node_beautifier_html_tests() {
|
||||
console.log('Testing performance...');
|
||||
var github_css = fs.readFileSync(__dirname + '/../../test/resources/github.css', 'utf8');
|
||||
var options = {
|
||||
wrap_line_length: 80
|
||||
};
|
||||
|
||||
//warm-up
|
||||
beautifier.css(github_css, options);
|
||||
|
||||
var suite = new Benchmark.Suite();
|
||||
|
||||
suite.add("css-beautify (github.css)", function() {
|
||||
beautifier.css(github_css, options);
|
||||
})
|
||||
// add listeners
|
||||
.on('cycle', function(event) {
|
||||
console.log(String(event.target));
|
||||
})
|
||||
.on('error', function(event) {
|
||||
return 1;
|
||||
})
|
||||
.on('complete', function(event) {})
|
||||
.run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (require.main === module) {
|
||||
process.exit(node_beautifier_html_tests());
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
/*jshint node:true */
|
||||
/*jshint unused:false */
|
||||
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs'),
|
||||
SanityTest = require('./sanitytest'),
|
||||
@ -11,6 +12,7 @@ var fs = require('fs'),
|
||||
|
||||
function node_beautifier_html_tests() {
|
||||
console.log('Testing performance...');
|
||||
var github_html = fs.readFileSync(__dirname + '/../../test/resources/github.html', 'utf8');
|
||||
var index_html = fs.readFileSync(__dirname + '/../../index.html', 'utf8');
|
||||
var data_attr = fs.readFileSync(__dirname + '/../../test/resources/html-with-base64image.html', 'utf8');
|
||||
var options = {
|
||||
@ -18,7 +20,7 @@ function node_beautifier_html_tests() {
|
||||
};
|
||||
|
||||
//warm-up
|
||||
beautifier.html(index_html, options);
|
||||
beautifier.html(github_html, options);
|
||||
beautifier.html(data_attr, options);
|
||||
|
||||
var suite = new Benchmark.Suite();
|
||||
@ -29,6 +31,9 @@ function node_beautifier_html_tests() {
|
||||
.add("html-beautify (base64 image)", function() {
|
||||
beautifier.html(data_attr, options);
|
||||
})
|
||||
.add("html-beautify (github.html)", function() {
|
||||
beautifier.html(github_html, options);
|
||||
})
|
||||
// add listeners
|
||||
.on('cycle', function(event) {
|
||||
console.log(String(event.target));
|
||||
|
@ -2,6 +2,8 @@
|
||||
/*jshint node:true */
|
||||
/*jshint unused:false */
|
||||
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs'),
|
||||
SanityTest = require('./sanitytest'),
|
||||
Benchmark = require('benchmark'),
|
||||
@ -12,6 +14,7 @@ function node_beautifier_tests() {
|
||||
console.log('Testing performance...');
|
||||
var data = fs.readFileSync(__dirname + '/../../test/resources/underscore.js', 'utf8');
|
||||
var data_min = fs.readFileSync(__dirname + '/../../test/resources/underscore-min.js', 'utf8');
|
||||
var github_min = fs.readFileSync(__dirname + '/../../test/resources/github-min.js', 'utf8');
|
||||
var options = {
|
||||
wrap_line_length: 80
|
||||
};
|
||||
@ -28,6 +31,9 @@ function node_beautifier_tests() {
|
||||
.add("js-beautify (underscore-min)", function() {
|
||||
beautifier.js(data_min, options);
|
||||
})
|
||||
.add("js-beautify (github-min)", function() {
|
||||
beautifier.js(github_min, options);
|
||||
})
|
||||
// add listeners
|
||||
.on('cycle', function(event) {
|
||||
console.log(String(event.target));
|
||||
|
@ -1,5 +1,7 @@
|
||||
/*jshint node:true */
|
||||
|
||||
'use strict';
|
||||
|
||||
var SanityTest = require('./sanitytest'),
|
||||
Urlencoded = require('../lib/unpackers/urlencode_unpacker'),
|
||||
run_javascript_tests = require('./generated/beautify-javascript-tests').run_javascript_tests,
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
/*jshint node:true */
|
||||
|
||||
'use strict';
|
||||
|
||||
var SanityTest = require('./sanitytest'),
|
||||
Urlencoded = require('../lib/unpackers/urlencode_unpacker'),
|
||||
run_javascript_tests = require('./generated/beautify-javascript-tests').run_javascript_tests,
|
||||
|
@ -1,6 +1,6 @@
|
||||
//
|
||||
// simple testing interface
|
||||
// written by Einar Lielmanis, einar@jsbeautifier.org
|
||||
// written by Einar Lielmanis, einar@beautifier.io
|
||||
//
|
||||
// usage:
|
||||
//
|
||||
@ -10,8 +10,8 @@
|
||||
// output_somewhere(t.results()); // good for <pre>, html safe-ish
|
||||
// alert(t.results_raw()); // html unescaped
|
||||
|
||||
|
||||
function SanityTest(func, name_of_test) {
|
||||
'use strict';
|
||||
|
||||
var test_func = func || function(x) {
|
||||
return x;
|
||||
@ -39,9 +39,11 @@ function SanityTest(func, name_of_test) {
|
||||
// proper array checking is a pain. i'll maybe do it later, compare strings representations instead
|
||||
if ((result === expected_value) || (expected_value instanceof Array && result.join(', ') === expected_value.join(', '))) {
|
||||
n_succeeded += 1;
|
||||
return true;
|
||||
} else {
|
||||
n_failed += 1;
|
||||
failures.push([test_name, parameters, expected_value, result]);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
3503
package-lock.json
generated
3503
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "js-beautify",
|
||||
"version": "1.8.0-rc4",
|
||||
"description": "jsbeautifier.org for node",
|
||||
"version": "1.8.6",
|
||||
"description": "beautifier.io for node",
|
||||
"main": "js/index.js",
|
||||
"bin": {
|
||||
"css-beautify": "./js/bin/css-beautify.js",
|
||||
@ -21,7 +21,7 @@
|
||||
],
|
||||
"scripts": {},
|
||||
"bugs": "https://github.com/beautify-web/js-beautify/issues",
|
||||
"homepage": "http://jsbeautifier.org/",
|
||||
"homepage": "https://beautifier.io/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/beautify-web/js-beautify.git"
|
||||
@ -31,7 +31,7 @@
|
||||
"beautifier",
|
||||
"code-quality"
|
||||
],
|
||||
"author": "Einar Lielmanis <einar@jsbeautifier.org>",
|
||||
"author": "Einar Lielmanis <einar@beautifier.io>",
|
||||
"contributors": [
|
||||
"Vital Batmanov <vital76@gmail.com>",
|
||||
"Chris J. Shull <chrisjshull@gmail.com>",
|
||||
@ -41,24 +41,23 @@
|
||||
"Daniel Stockman <daniel.stockman@gmail.com>",
|
||||
"Harutyun Amirjanyan <amirjanyan@gmail.com>",
|
||||
"Nochum Sossonko <nsossonko@hotmail.com>",
|
||||
"Liam Newman <bitwiseman@gmail.com>"
|
||||
"Liam Newman <bitwiseman@beautifier.io>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"config-chain": "~1.1.5",
|
||||
"editorconfig": "^0.15.0",
|
||||
"mkdirp": "~0.5.0",
|
||||
"nopt": "~4.0.1",
|
||||
"npm": "^6.2.0"
|
||||
"nopt": "~4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"benchmark": "^2.1.4",
|
||||
"jshint": "~2.9.1",
|
||||
"jshint": "^2.9.6",
|
||||
"mocha": "^5.2.0",
|
||||
"mustache": "~2.3.0",
|
||||
"mustache": "^2.3.2",
|
||||
"node-static": "^0.7.10",
|
||||
"requirejs": "^2.3.3",
|
||||
"webpack": "^4.16.2",
|
||||
"requirejs": "^2.3.6",
|
||||
"webpack": "^4.17.1",
|
||||
"webpack-command": "^0.4.1"
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ def beautify_file(file_name, opts=default_options()):
|
||||
raise Exception()
|
||||
|
||||
stream = sys.stdin
|
||||
except Exception as ex:
|
||||
except Exception:
|
||||
print("Must pipe input or define input file.\n", file=sys.stderr)
|
||||
usage(sys.stderr)
|
||||
raise Exception()
|
||||
@ -68,7 +68,7 @@ def usage(stream=sys.stdout):
|
||||
|
||||
print("cssbeautifier.py@" + __version__ + """
|
||||
|
||||
CSS beautifier (http://jsbeautifier.org/)
|
||||
CSS beautifier (https://beautifier.io/)
|
||||
|
||||
Usage: cssbeautifier.py [options] <infile>
|
||||
|
||||
|
@ -3,11 +3,15 @@ import sys
|
||||
import re
|
||||
import copy
|
||||
from .options import BeautifierOptions
|
||||
from jsbeautifier.core.options import mergeOpts
|
||||
from jsbeautifier.core.output import Output
|
||||
from jsbeautifier.core.inputscanner import InputScanner
|
||||
from jsbeautifier.__version__ import __version__
|
||||
|
||||
# This is not pretty, but given how we did the version import
|
||||
# it is the only way to do this without having setup.py fail on a missing
|
||||
# six dependency.
|
||||
six = __import__("six")
|
||||
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
|
||||
@ -34,6 +38,7 @@ from jsbeautifier.__version__ import __version__
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
|
||||
whitespaceChar = re.compile(r"\s")
|
||||
whitespacePattern = re.compile(r"(?:\s|\n)+")
|
||||
|
||||
@ -63,7 +68,7 @@ def usage(stream=sys.stdout):
|
||||
|
||||
print("cssbeautifier.py@" + __version__ + """
|
||||
|
||||
CSS beautifier (http://jsbeautifier.org/)
|
||||
CSS beautifier (https://beautifier.io/)
|
||||
|
||||
""", file=stream)
|
||||
if stream == sys.stderr:
|
||||
@ -72,101 +77,58 @@ CSS beautifier (http://jsbeautifier.org/)
|
||||
return 0
|
||||
|
||||
|
||||
class Printer:
|
||||
|
||||
def __init__(self, indent_char, indent_size, default_indent=""):
|
||||
self.singleIndent = (indent_size) * indent_char
|
||||
self.indentLevel = 0
|
||||
self.nestedLevel = 0
|
||||
|
||||
self.baseIndentString = default_indent
|
||||
self.output = Output(self.singleIndent, self.baseIndentString)
|
||||
|
||||
def indent(self):
|
||||
self.indentLevel += 1
|
||||
|
||||
def outdent(self):
|
||||
if self.indentLevel > 0:
|
||||
self.indentLevel -= 1
|
||||
|
||||
def preserveSingleSpace(self, isAfterSpace):
|
||||
if isAfterSpace:
|
||||
self.output.space_before_token = True
|
||||
|
||||
def print_string(self, output_string):
|
||||
if self.output.just_added_newline():
|
||||
self.output.set_indent(self.indentLevel)
|
||||
|
||||
self.output.add_token(output_string)
|
||||
|
||||
|
||||
class Beautifier:
|
||||
|
||||
def __init__(self, source_text, opts=default_options()):
|
||||
import jsbeautifier.core.acorn as acorn
|
||||
self.lineBreak = acorn.lineBreak
|
||||
self.allLineBreaks = acorn.allLineBreaks
|
||||
# in javascript, these two differ
|
||||
# in python they are the same, different methods are called on them
|
||||
# IMPORTANT: This string must be run through six to handle \u chars
|
||||
self.lineBreak = re.compile(six.u(r"\r\n|[\n\r]"))
|
||||
self.allLineBreaks = self.lineBreak
|
||||
|
||||
self.comment_pattern = re.compile(
|
||||
acorn.six.u(r"\/\/(?:[^\n\r\u2028\u2029]*)"))
|
||||
six.u(r"\/\/(?:[^\n\r\u2028\u2029]*)"))
|
||||
self.block_comment_pattern = re.compile(
|
||||
r"\/\*(?:[\s\S]*?)((?:\*\/)|$)")
|
||||
|
||||
if not source_text:
|
||||
source_text = ''
|
||||
|
||||
opts = mergeOpts(opts, 'css')
|
||||
self.__source_text = source_text
|
||||
|
||||
# Continue to accept deprecated option
|
||||
opts.space_around_combinator = opts.space_around_combinator or opts.space_around_selector_separator
|
||||
self._options = BeautifierOptions(opts)
|
||||
self._input = None
|
||||
self._ch = None
|
||||
|
||||
self.opts = opts
|
||||
self.indentSize = opts.indent_size
|
||||
self.indentChar = opts.indent_char
|
||||
self.input = None
|
||||
self.ch = None
|
||||
|
||||
if self.opts.indent_with_tabs:
|
||||
self.indentChar = "\t"
|
||||
self.indentSize = 1
|
||||
|
||||
if self.opts.eol == 'auto':
|
||||
self.opts.eol = '\n'
|
||||
if self.lineBreak.search(source_text or ''):
|
||||
self.opts.eol = self.lineBreak.search(source_text).group()
|
||||
|
||||
self.opts.eol = self.opts.eol.replace('\\r', '\r').replace('\\n', '\n')
|
||||
|
||||
# HACK: newline parsing inconsistent. This brute force normalizes the
|
||||
# input newlines.
|
||||
self.source_text = re.sub(self.allLineBreaks, '\n', source_text)
|
||||
self._indentLevel = 0
|
||||
self._nestedLevel = 0
|
||||
self._output = None
|
||||
|
||||
# https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
|
||||
# also in CONDITIONAL_GROUP_RULE below
|
||||
self.NESTED_AT_RULE = [
|
||||
self.NESTED_AT_RULE = {
|
||||
"@page",
|
||||
"@font-face",
|
||||
"@keyframes",
|
||||
"@media",
|
||||
"@supports",
|
||||
"@document"]
|
||||
self.CONDITIONAL_GROUP_RULE = [
|
||||
"@document"}
|
||||
self.CONDITIONAL_GROUP_RULE = {
|
||||
"@media",
|
||||
"@supports",
|
||||
"@document"]
|
||||
|
||||
m = re.search("^[\t ]*", self.source_text)
|
||||
self.baseIndentString = m.group(0)
|
||||
"@document"}
|
||||
|
||||
def eatString(self, endChars):
|
||||
result = ''
|
||||
self.ch = self.input.next()
|
||||
while self.ch:
|
||||
result += self.ch
|
||||
if self.ch == "\\":
|
||||
result += self.input.next()
|
||||
elif self.ch in endChars or self.ch == "\n":
|
||||
self._ch = self._input.next()
|
||||
while self._ch:
|
||||
result += self._ch
|
||||
if self._ch == "\\":
|
||||
result += self._input.next()
|
||||
elif self._ch in endChars or self._ch == "\n":
|
||||
break
|
||||
self.ch = self.input.next()
|
||||
self._ch = self._input.next()
|
||||
return result
|
||||
|
||||
# Skips any white space in the source text from the current position.
|
||||
@ -174,15 +136,15 @@ class Beautifier:
|
||||
# newline character found; if the user has preserve_newlines off, only
|
||||
# the first newline will be output
|
||||
def eatWhitespace(self, allowAtLeastOneNewLine=False):
|
||||
result = whitespaceChar.search(self.input.peek() or '') is not None
|
||||
result = whitespaceChar.search(self._input.peek() or '') is not None
|
||||
isFirstNewLine = True
|
||||
|
||||
while whitespaceChar.search(self.input.peek() or '') is not None:
|
||||
self.ch = self.input.next()
|
||||
if allowAtLeastOneNewLine and self.ch == "\n":
|
||||
if self.opts.preserve_newlines or isFirstNewLine:
|
||||
while whitespaceChar.search(self._input.peek() or '') is not None:
|
||||
self._ch = self._input.next()
|
||||
if allowAtLeastOneNewLine and self._ch == "\n":
|
||||
if self._options.preserve_newlines or isFirstNewLine:
|
||||
isFirstNewLine = False
|
||||
self.output.add_new_line(True)
|
||||
self._output.add_new_line(True)
|
||||
return result
|
||||
|
||||
# Nested pseudo-class if we are insideRule
|
||||
@ -191,7 +153,7 @@ class Beautifier:
|
||||
def foundNestedPseudoClass(self):
|
||||
openParen = 0
|
||||
i = 1
|
||||
ch = self.input.peek(i)
|
||||
ch = self._input.peek(i)
|
||||
while ch:
|
||||
if ch == "{":
|
||||
return True
|
||||
@ -205,46 +167,82 @@ class Beautifier:
|
||||
elif ch == ";" or ch == "}":
|
||||
return False
|
||||
i += 1
|
||||
ch = self.input.peek(i)
|
||||
ch = self._input.peek(i)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def indent(self):
|
||||
self._indentLevel += 1
|
||||
|
||||
def outdent(self):
|
||||
if self._indentLevel > 0:
|
||||
self._indentLevel -= 1
|
||||
|
||||
def preserveSingleSpace(self, isAfterSpace):
|
||||
if isAfterSpace:
|
||||
self._output.space_before_token = True
|
||||
|
||||
def print_string(self, output_string):
|
||||
if self._output.just_added_newline():
|
||||
self._output.set_indent(self._indentLevel)
|
||||
|
||||
self._output.add_token(output_string)
|
||||
|
||||
|
||||
def beautify(self):
|
||||
printer = Printer(
|
||||
self.indentChar,
|
||||
self.indentSize,
|
||||
self.baseIndentString)
|
||||
self.output = printer.output
|
||||
self.input = InputScanner(self.source_text)
|
||||
if self._options.disabled:
|
||||
return self.__source_text
|
||||
|
||||
output = self.output
|
||||
input = self.input
|
||||
source_text = self.__source_text
|
||||
|
||||
self.ch = None
|
||||
if self._options.eol == 'auto':
|
||||
self._options.eol = '\n'
|
||||
if self.lineBreak.search(source_text or ''):
|
||||
self._options.eol = self.lineBreak.search(source_text).group()
|
||||
|
||||
|
||||
# HACK: newline parsing inconsistent. This brute force normalizes the
|
||||
# input newlines.
|
||||
source_text = re.sub(self.allLineBreaks, '\n', source_text)
|
||||
baseIndentString = re.search("^[\t ]*", source_text).group(0)
|
||||
|
||||
self._output = Output(self._options, baseIndentString)
|
||||
|
||||
self._input = InputScanner(source_text)
|
||||
|
||||
self._indentLevel = 0
|
||||
self._nestedLevel = 0
|
||||
|
||||
self._ch = None
|
||||
parenLevel = 0
|
||||
|
||||
insideRule = False
|
||||
insidePropertyValue = False
|
||||
enteringConditionalGroup = False
|
||||
insideAtExtend = False
|
||||
parenLevel = 0
|
||||
insideAtImport = False
|
||||
topCharacter = self._ch
|
||||
|
||||
while True:
|
||||
whitespace = input.read(whitespacePattern)
|
||||
whitespace = self._input.read(whitespacePattern)
|
||||
isAfterSpace = whitespace != ''
|
||||
self.ch = input.next()
|
||||
previous_ch = topCharacter
|
||||
self._ch = self._input.next()
|
||||
topCharacter = self._ch
|
||||
|
||||
if not self.ch:
|
||||
if not self._ch:
|
||||
break
|
||||
elif self.ch == '/' and input.peek() == '*':
|
||||
elif self._ch == '/' and self._input.peek() == '*':
|
||||
# /* css comment */
|
||||
# Always start block comments on a new line.
|
||||
# This handles scenarios where a block comment immediately
|
||||
# follows a property definition on the same line or where
|
||||
# minified code is being beautified.
|
||||
output.add_new_line()
|
||||
input.back()
|
||||
printer.print_string(
|
||||
input.read(
|
||||
self._output.add_new_line()
|
||||
self._input.back()
|
||||
self.print_string(
|
||||
self._input.read(
|
||||
self.block_comment_pattern))
|
||||
|
||||
# Ensures any new lines following the comment are preserved
|
||||
@ -252,27 +250,27 @@ class Beautifier:
|
||||
|
||||
# Block comments are followed by a new line so they don't
|
||||
# share a line with other properties
|
||||
output.add_new_line()
|
||||
elif self.ch == '/' and input.peek() == '/':
|
||||
self._output.add_new_line()
|
||||
elif self._ch == '/' and self._input.peek() == '/':
|
||||
# // single line comment
|
||||
# Preserves the space before a comment
|
||||
# on the same line as a rule
|
||||
output.space_before_token = True
|
||||
input.back()
|
||||
printer.print_string(input.read(self.comment_pattern))
|
||||
self._output.space_before_token = True
|
||||
self._input.back()
|
||||
self.print_string(self._input.read(self.comment_pattern))
|
||||
|
||||
# Ensures any new lines following the comment are preserved
|
||||
self.eatWhitespace(True)
|
||||
elif self.ch == '@':
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
elif self._ch == '@':
|
||||
self.preserveSingleSpace(isAfterSpace)
|
||||
|
||||
# deal with less propery mixins @{...}
|
||||
if input.peek() == '{':
|
||||
printer.print_string(self.ch + self.eatString('}'))
|
||||
if self._input.peek() == '{':
|
||||
self.print_string(self._ch + self.eatString('}'))
|
||||
else:
|
||||
printer.print_string(self.ch)
|
||||
# strip trailing space, if present, for hash property check
|
||||
variableOrRule = input.peekUntilAfter(
|
||||
self.print_string(self._ch)
|
||||
# strip trailing space, for hash property check
|
||||
variableOrRule = self._input.peekUntilAfter(
|
||||
re.compile(r"[: ,;{}()[\]\/='\"]"))
|
||||
|
||||
if variableOrRule[-1] in ": ":
|
||||
@ -281,163 +279,182 @@ class Beautifier:
|
||||
variableOrRule = self.eatString(": ")
|
||||
if variableOrRule[-1].isspace():
|
||||
variableOrRule = variableOrRule[:-1]
|
||||
printer.print_string(variableOrRule)
|
||||
output.space_before_token = True
|
||||
self.print_string(variableOrRule)
|
||||
self._output.space_before_token = True
|
||||
|
||||
if variableOrRule[-1].isspace():
|
||||
variableOrRule = variableOrRule[:-1]
|
||||
|
||||
if variableOrRule == "extend":
|
||||
insideAtExtend = True
|
||||
elif variableOrRule == "import":
|
||||
insideAtImport = True
|
||||
|
||||
# might be a nesting at-rule
|
||||
if variableOrRule in self.NESTED_AT_RULE:
|
||||
printer.nestedLevel += 1
|
||||
self._nestedLevel += 1
|
||||
if variableOrRule in self.CONDITIONAL_GROUP_RULE:
|
||||
enteringConditionalGroup = True
|
||||
elif not insideRule and parenLevel == 0 and variableOrRule[-1] == ":":
|
||||
elif not insideRule and parenLevel == 0 and \
|
||||
variableOrRule[-1] == ":":
|
||||
insidePropertyValue = True
|
||||
elif self.ch == '#' and input.peek() == '{':
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.print_string(self.ch + self.eatString('}'))
|
||||
elif self.ch == '{':
|
||||
if input.match(re.compile("[\t\n ]*}")) is not None:
|
||||
output.space_before_token = True
|
||||
printer.print_string("{}")
|
||||
self.eatWhitespace(True)
|
||||
output.add_new_line()
|
||||
self.indent()
|
||||
elif self._ch == '#' and self._input.peek() == '{':
|
||||
self.preserveSingleSpace(isAfterSpace)
|
||||
self.print_string(self._ch + self.eatString('}'))
|
||||
elif self._ch == '{':
|
||||
if insidePropertyValue:
|
||||
insidePropertyValue = False
|
||||
self.outdent()
|
||||
self.indent()
|
||||
self._output.space_before_token = True
|
||||
self.print_string(self._ch)
|
||||
|
||||
if self.opts.newline_between_rules and printer.indentLevel == 0 and not output.just_added_blankline():
|
||||
output.add_new_line(True)
|
||||
# when entering conditional groups, only rulesets are
|
||||
# allowed
|
||||
if enteringConditionalGroup:
|
||||
enteringConditionalGroup = False
|
||||
insideRule = self._indentLevel > self._nestedLevel
|
||||
else:
|
||||
printer.indent()
|
||||
output.space_before_token = True
|
||||
printer.print_string(self.ch)
|
||||
self.eatWhitespace(True)
|
||||
output.add_new_line()
|
||||
# otherwise, declarations are also allowed
|
||||
insideRule = self._indentLevel >= self._nestedLevel
|
||||
|
||||
# when entering conditional groups, only rulesets are
|
||||
# allowed
|
||||
if enteringConditionalGroup:
|
||||
enteringConditionalGroup = False
|
||||
insideRule = printer.indentLevel > printer.nestedLevel
|
||||
else:
|
||||
# otherwise, declarations are also allowed
|
||||
insideRule = printer.indentLevel >= printer.nestedLevel
|
||||
elif self.ch == '}':
|
||||
printer.outdent()
|
||||
output.add_new_line()
|
||||
printer.print_string(self.ch)
|
||||
if self._options.newline_between_rules and insideRule:
|
||||
if self._output.previous_line and \
|
||||
not self._output.previous_line.is_empty() and \
|
||||
self._output.previous_line.item(-1) != '{':
|
||||
self._output.ensure_empty_line_above('/', ',')
|
||||
self.eatWhitespace(True)
|
||||
self._output.add_new_line()
|
||||
elif self._ch == '}':
|
||||
self.outdent()
|
||||
self._output.add_new_line()
|
||||
if previous_ch == '{':
|
||||
self._output.trim(True)
|
||||
insideAtExtend = False
|
||||
insideAtImport = False
|
||||
if insidePropertyValue:
|
||||
self.outdent()
|
||||
insidePropertyValue = False
|
||||
self.print_string(self._ch)
|
||||
insideRule = False
|
||||
insidePropertyValue = False
|
||||
if printer.nestedLevel:
|
||||
printer.nestedLevel -= 1
|
||||
if self._nestedLevel:
|
||||
self._nestedLevel -= 1
|
||||
|
||||
self.eatWhitespace(True)
|
||||
output.add_new_line()
|
||||
self._output.add_new_line()
|
||||
|
||||
if self.opts.newline_between_rules and printer.indentLevel == 0 and not output.just_added_blankline():
|
||||
output.add_new_line(True)
|
||||
elif self.ch == ":":
|
||||
if self._options.newline_between_rules and \
|
||||
not self._output.just_added_blankline():
|
||||
if self._input.peek() != '}':
|
||||
self._output.add_new_line(True)
|
||||
elif self._ch == ":":
|
||||
if (insideRule or enteringConditionalGroup) and \
|
||||
not (input.lookBack('&') or self.foundNestedPseudoClass()) and \
|
||||
not input.lookBack('(') and not insideAtExtend:
|
||||
not (self._input.lookBack('&') or
|
||||
self.foundNestedPseudoClass()) and \
|
||||
not self._input.lookBack('(') and not insideAtExtend:
|
||||
# 'property: value' delimiter
|
||||
# which could be in a conditional group query
|
||||
printer.print_string(":")
|
||||
self.print_string(":")
|
||||
if not insidePropertyValue:
|
||||
insidePropertyValue = True
|
||||
output.space_before_token = True
|
||||
self._output.space_before_token = True
|
||||
self.eatWhitespace(True)
|
||||
self.indent()
|
||||
|
||||
else:
|
||||
# sass/less parent reference don't use a space
|
||||
# sass nested pseudo-class don't use a space
|
||||
|
||||
# preserve space before pseudoclasses/pseudoelements, as it
|
||||
# means "in any child"
|
||||
if input.lookBack(' '):
|
||||
output.space_before_token = True
|
||||
if input.peek() == ":":
|
||||
# preserve space before pseudoclasses/pseudoelements,
|
||||
# as it means "in any child"
|
||||
if self._input.lookBack(' '):
|
||||
self._output.space_before_token = True
|
||||
if self._input.peek() == ":":
|
||||
# pseudo-element
|
||||
self.ch = input.next()
|
||||
printer.print_string("::")
|
||||
self._ch = self._input.next()
|
||||
self.print_string("::")
|
||||
else:
|
||||
# pseudo-element
|
||||
printer.print_string(":")
|
||||
elif self.ch == '"' or self.ch == '\'':
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.print_string(self.ch + self.eatString(self.ch))
|
||||
elif self.ch == ';':
|
||||
insidePropertyValue = False
|
||||
self.print_string(":")
|
||||
elif self._ch == '"' or self._ch == '\'':
|
||||
self.preserveSingleSpace(isAfterSpace)
|
||||
self.print_string(self._ch + self.eatString(self._ch))
|
||||
self.eatWhitespace(True)
|
||||
elif self._ch == ';':
|
||||
if insidePropertyValue:
|
||||
self.outdent()
|
||||
insidePropertyValue = False
|
||||
insideAtExtend = False
|
||||
printer.print_string(self.ch)
|
||||
insideAtImport = False
|
||||
self.print_string(self._ch)
|
||||
self.eatWhitespace(True)
|
||||
|
||||
# This maintains single line comments on the same
|
||||
# line. Block comments are also affected, but
|
||||
# a new line is always output before one inside
|
||||
# that section
|
||||
if input.peek() is not '/':
|
||||
output.add_new_line()
|
||||
elif self.ch == '(':
|
||||
if self._input.peek() is not '/':
|
||||
self._output.add_new_line()
|
||||
elif self._ch == '(':
|
||||
# may be a url
|
||||
if input.lookBack("url"):
|
||||
printer.print_string(self.ch)
|
||||
if self._input.lookBack("url"):
|
||||
self.print_string(self._ch)
|
||||
self.eatWhitespace()
|
||||
self.ch = input.next()
|
||||
if self.ch:
|
||||
if self.ch is not ')' and self.ch is not '"' \
|
||||
and self.ch is not '\'':
|
||||
printer.print_string(self.ch + self.eatString(')'))
|
||||
else:
|
||||
input.back()
|
||||
parenLevel += 1
|
||||
self._ch = self._input.next()
|
||||
if self._ch in {')', '"', '\''}:
|
||||
self._input.back()
|
||||
parenLevel += 1
|
||||
elif self._ch is not None:
|
||||
self.print_string(self._ch + self.eatString(')'))
|
||||
else:
|
||||
parenLevel += 1
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.print_string(self.ch)
|
||||
self.preserveSingleSpace(isAfterSpace)
|
||||
self.print_string(self._ch)
|
||||
self.eatWhitespace()
|
||||
elif self.ch == ')':
|
||||
printer.print_string(self.ch)
|
||||
elif self._ch == ')':
|
||||
self.print_string(self._ch)
|
||||
parenLevel -= 1
|
||||
elif self.ch == ',':
|
||||
printer.print_string(self.ch)
|
||||
elif self._ch == ',':
|
||||
self.print_string(self._ch)
|
||||
self.eatWhitespace(True)
|
||||
if self.opts.selector_separator_newline and not insidePropertyValue and parenLevel < 1:
|
||||
output.add_new_line()
|
||||
if self._options.selector_separator_newline and \
|
||||
not insidePropertyValue and parenLevel < 1 and \
|
||||
not insideAtImport:
|
||||
self._output.add_new_line()
|
||||
else:
|
||||
output.space_before_token = True
|
||||
elif (self.ch == '>' or self.ch == '+' or self.ch == '~') and \
|
||||
self._output.space_before_token = True
|
||||
elif (self._ch == '>' or self._ch == '+' or self._ch == '~') and \
|
||||
not insidePropertyValue and parenLevel < 1:
|
||||
# handle combinator spacing
|
||||
if self.opts.space_around_combinator:
|
||||
output.space_before_token = True
|
||||
printer.print_string(self.ch)
|
||||
output.space_before_token = True
|
||||
if self._options.space_around_combinator:
|
||||
self._output.space_before_token = True
|
||||
self.print_string(self._ch)
|
||||
self._output.space_before_token = True
|
||||
else:
|
||||
printer.print_string(self.ch)
|
||||
self.print_string(self._ch)
|
||||
self.eatWhitespace()
|
||||
# squash extra whitespace
|
||||
if self.ch and bool(whitespaceChar.search(self.ch)):
|
||||
self.ch = ''
|
||||
elif self.ch == ']':
|
||||
printer.print_string(self.ch)
|
||||
elif self.ch == '[':
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.print_string(self.ch)
|
||||
elif self.ch == '=':
|
||||
if self._ch and bool(whitespaceChar.search(self._ch)):
|
||||
self._ch = ''
|
||||
elif self._ch == ']':
|
||||
self.print_string(self._ch)
|
||||
elif self._ch == '[':
|
||||
self.preserveSingleSpace(isAfterSpace)
|
||||
self.print_string(self._ch)
|
||||
elif self._ch == '=':
|
||||
# no whitespace before or after
|
||||
self.eatWhitespace()
|
||||
printer.print_string('=')
|
||||
if bool(whitespaceChar.search(self.ch)):
|
||||
self.ch = ''
|
||||
elif self.ch == '!': # !important
|
||||
printer.print_string(' ')
|
||||
printer.print_string(self.ch)
|
||||
self.print_string('=')
|
||||
if bool(whitespaceChar.search(self._ch)):
|
||||
self._ch = ''
|
||||
elif self._ch == '!': # !important
|
||||
self.print_string(' ')
|
||||
self.print_string(self._ch)
|
||||
else:
|
||||
printer.preserveSingleSpace(isAfterSpace)
|
||||
printer.print_string(self.ch)
|
||||
self.preserveSingleSpace(isAfterSpace)
|
||||
self.print_string(self._ch)
|
||||
|
||||
sweet_code = output.get_code(self.opts.end_with_newline, self.opts.eol)
|
||||
sweet_code = self._output.get_code(self._options.eol)
|
||||
|
||||
return sweet_code
|
||||
|
@ -23,40 +23,18 @@
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
from jsbeautifier.core.options import Options as BaseOptions
|
||||
|
||||
class BeautifierOptions:
|
||||
def __init__(self):
|
||||
self.indent_size = 4
|
||||
self.indent_char = ' '
|
||||
self.indent_with_tabs = False
|
||||
self.preserve_newlines = False
|
||||
self.selector_separator_newline = True
|
||||
self.end_with_newline = False
|
||||
self.newline_between_rules = True
|
||||
self.space_around_combinator = False
|
||||
self.eol = 'auto'
|
||||
class BeautifierOptions(BaseOptions):
|
||||
def __init__(self, options=None):
|
||||
BaseOptions.__init__(self, options, 'css')
|
||||
|
||||
self.css = None
|
||||
self.js = None
|
||||
self.html = None
|
||||
self.selector_separator_newline = self._get_boolean('selector_separator_newline', True)
|
||||
self.newline_between_rules = self._get_boolean('newline_between_rules', True)
|
||||
|
||||
# deprecated
|
||||
self.space_around_selector_separator = False
|
||||
space_around_selector_separator = self._get_boolean('space_around_selector_separator')
|
||||
|
||||
def __repr__(self):
|
||||
return """indent_size = %d
|
||||
indent_char = [%s]
|
||||
indent_with_tabs = [%s]
|
||||
preserve_newlines = [%s]
|
||||
separate_selectors_newline = [%s]
|
||||
end_with_newline = [%s]
|
||||
newline_between_rules = [%s]
|
||||
space_around_combinator = [%s]
|
||||
""" % (self.indent_size,
|
||||
self.indent_char,
|
||||
self.indent_with_tabs,
|
||||
self.preserve_newlines,
|
||||
self.selector_separator_newline,
|
||||
self.end_with_newline,
|
||||
self.newline_between_rules,
|
||||
self.space_around_combinator)
|
||||
# Continue to accept deprecated option
|
||||
self.space_around_combinator = self._get_boolean('space_around_combinator') or \
|
||||
space_around_selector_separator
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,18 +1,34 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
# To run this: ./js-beautify/tools/python-dev python ./python/js-beautify-profile
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
import pstats
|
||||
from pstats import SortKey
|
||||
|
||||
# Speedup things...
|
||||
try:
|
||||
import cProfile as profile
|
||||
except ImportError:
|
||||
import profile
|
||||
import os
|
||||
import copy
|
||||
import jsbeautifier
|
||||
options = jsbeautifier.default_options()
|
||||
options.wrap_line_length = 80
|
||||
|
||||
def beautifier_test_github_min():
|
||||
jsbeautifier.beautify(github_min, options)
|
||||
|
||||
def run():
|
||||
sys.argv.append('discover')
|
||||
unittest.main()
|
||||
if __name__ == '__main__':
|
||||
dirname = os.path.dirname(os.path.abspath(__file__))
|
||||
github_min_file = os.path.join(
|
||||
dirname, "../", "test/resources/github-min.js")
|
||||
github_min = copy.copy(''.join(open( github_min_file).readlines()))
|
||||
|
||||
profile.run('beautifier_test_github_min()',
|
||||
os.path.join(dirname, "../", 'build/jsbstats'))
|
||||
|
||||
profile.run('run()')
|
||||
p = pstats.Stats(os.path.join(dirname, "../", 'build/jsbstats'))
|
||||
p.strip_dirs().sort_stats(SortKey.CUMULATIVE).print_stats()
|
||||
|
@ -9,7 +9,7 @@ import errno
|
||||
import copy
|
||||
from jsbeautifier.__version__ import __version__
|
||||
from jsbeautifier.javascript.options import BeautifierOptions
|
||||
from jsbeautifier.javascript.beautifier import Beautifier, sanitizeOperatorPosition
|
||||
from jsbeautifier.javascript.beautifier import Beautifier
|
||||
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
@ -37,9 +37,9 @@ from jsbeautifier.javascript.beautifier import Beautifier, sanitizeOperatorPosit
|
||||
# SOFTWARE.
|
||||
#
|
||||
# Originally written by Einar Lielmanis et al.,
|
||||
# Conversion to python by Einar Lielmanis, einar@jsbeautifier.org,
|
||||
# Conversion to python by Einar Lielmanis, einar@beautifier.io,
|
||||
# Parsing improvement for brace-less and semicolon-less statements
|
||||
# by Liam Newman <bitwiseman@gmail.com>
|
||||
# by Liam Newman <bitwiseman@beautifier.io>
|
||||
# Python is not my native language, feel free to push things around.
|
||||
#
|
||||
# Use either from command line (script displays its usage when run
|
||||
@ -62,6 +62,9 @@ from jsbeautifier.javascript.beautifier import Beautifier, sanitizeOperatorPosit
|
||||
# Here are the available options: (read source)
|
||||
|
||||
|
||||
class MissingInputStreamError(Exception):
|
||||
pass
|
||||
|
||||
def default_options():
|
||||
return BeautifierOptions()
|
||||
|
||||
@ -108,22 +111,14 @@ def set_file_editorconfig_opts(filename, js_options):
|
||||
# do not error on bad editor config
|
||||
print("Error loading EditorConfig. Ignoring.", file=sys.stderr)
|
||||
|
||||
|
||||
def beautify_file(file_name, opts=default_options()):
|
||||
input_string = ''
|
||||
if file_name == '-': # stdin
|
||||
try:
|
||||
if sys.stdin.isatty():
|
||||
raise Exception()
|
||||
if sys.stdin.isatty():
|
||||
raise MissingInputStreamError()
|
||||
|
||||
stream = sys.stdin
|
||||
input_string = ''.join(stream.readlines())
|
||||
except Exception:
|
||||
print(
|
||||
"Must pipe input or define at least one file.\n",
|
||||
file=sys.stderr)
|
||||
usage(sys.stderr)
|
||||
raise
|
||||
stream = sys.stdin
|
||||
input_string = ''.join(stream.readlines())
|
||||
else:
|
||||
stream = io.open(file_name, 'rt', newline='')
|
||||
input_string = ''.join(stream.readlines())
|
||||
@ -135,7 +130,7 @@ def usage(stream=sys.stdout):
|
||||
|
||||
print("jsbeautifier.py@" + __version__ + """
|
||||
|
||||
Javascript beautifier (http://jsbeautifier.org/)
|
||||
Javascript beautifier (https://beautifier.io/)
|
||||
|
||||
Usage: jsbeautifier.py [options] <infile>
|
||||
|
||||
@ -157,6 +152,7 @@ Output options:
|
||||
-E, --space-in-empty-paren Add a single space inside empty paren, ie. f( )
|
||||
-j, --jslint-happy More jslint-compatible output
|
||||
-a, --space-after-anon-function Add a space before an anonymous function's parens, ie. function ()
|
||||
--space-after-named-function Add a space before a named function's parens, i.e. function example ()
|
||||
-b, --brace-style=collapse Brace style (collapse, expand, end-expand, none)(,preserve-inline)
|
||||
-k, --keep-array-indentation Keep array indentation.
|
||||
-r, --replace Write output in-place, replacing input
|
||||
@ -222,7 +218,7 @@ def main():
|
||||
'space-in-paren', 'space-in-empty-paren', 'jslint-happy', 'space-after-anon-function',
|
||||
'brace-style=', 'keep-array-indentation', 'indent-level=', 'unescape-strings',
|
||||
'help', 'usage', 'stdin', 'eval-code', 'indent-with-tabs', 'keep-function-indentation', 'version',
|
||||
'e4x', 'end-with-newline', 'comma-first', 'operator-position=', 'wrap-line-length', 'editorconfig'])
|
||||
'e4x', 'end-with-newline', 'comma-first', 'operator-position=', 'wrap-line-length', 'editorconfig', 'space-after-named-function'])
|
||||
except getopt.GetoptError as ex:
|
||||
print(ex, file=sys.stderr)
|
||||
return usage(sys.stderr)
|
||||
@ -262,6 +258,8 @@ def main():
|
||||
js_options.jslint_happy = True
|
||||
elif opt in ('--space_after_anon_function', '-a'):
|
||||
js_options.space_after_anon_function = True
|
||||
elif opt in ('--space_after_named_function'):
|
||||
js_options.space_after_named_function = True
|
||||
elif opt in ('--eval-code'):
|
||||
js_options.eval_code = True
|
||||
elif opt in ('--brace-style', '-b'):
|
||||
@ -275,7 +273,7 @@ def main():
|
||||
elif opt in ('--comma-first', '-C'):
|
||||
js_options.comma_first = True
|
||||
elif opt in ('--operator-position', '-O'):
|
||||
js_options.operator_position = sanitizeOperatorPosition(arg)
|
||||
js_options.operator_position = arg
|
||||
elif opt in ('--wrap-line-length ', '-w'):
|
||||
js_options.wrap_line_length = int(arg)
|
||||
elif opt in ('--stdin', '-i'):
|
||||
@ -336,6 +334,19 @@ def main():
|
||||
six = __import__("six")
|
||||
f.write(six.u(pretty))
|
||||
|
||||
except MissingInputStreamError:
|
||||
print(
|
||||
"Must pipe input or define at least one file.\n",
|
||||
file=sys.stderr)
|
||||
usage(sys.stderr)
|
||||
return 1
|
||||
|
||||
except UnicodeError as ex:
|
||||
print("Error while decoding input or encoding output:",
|
||||
file=sys.stderr)
|
||||
print(ex, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
except Exception as ex:
|
||||
print(ex, file=sys.stderr)
|
||||
return 1
|
||||
|
@ -1 +1 @@
|
||||
__version__ = '1.8.0-rc4'
|
||||
__version__ = '1.8.6'
|
||||
|
@ -23,6 +23,122 @@
|
||||
# SOFTWARE.
|
||||
|
||||
import copy
|
||||
import re
|
||||
from collections import namedtuple
|
||||
|
||||
class Options:
|
||||
def __init__(self, options=None, merge_child_field=None):
|
||||
self.css = None
|
||||
self.js = None
|
||||
self.html = None
|
||||
|
||||
options = _mergeOpts(options, merge_child_field)
|
||||
self.raw_options = _normalizeOpts(options)
|
||||
|
||||
# Support passing the source text back with no change
|
||||
self.disabled = self._get_boolean('disabled')
|
||||
|
||||
self.eol = self._get_characters('eol', 'auto')
|
||||
self.end_with_newline = self._get_boolean('end_with_newline')
|
||||
self.indent_size = self._get_number('indent_size', 4)
|
||||
self.indent_char = self._get_characters('indent_char', ' ')
|
||||
self.indent_level = self._get_number('indent_level')
|
||||
|
||||
self.preserve_newlines = self._get_boolean('preserve_newlines', True)
|
||||
# TODO: fix difference in js and python
|
||||
self.max_preserve_newlines = self.max_preserve_newlines = self._get_number('max_preserve_newlines', 10)
|
||||
if not self.preserve_newlines:
|
||||
self.max_preserve_newlines = 0
|
||||
|
||||
self.indent_with_tabs = self._get_boolean('indent_with_tabs')
|
||||
if self.indent_with_tabs:
|
||||
self.indent_char = '\t'
|
||||
self.indent_size = 1
|
||||
|
||||
# Backwards compat with 1.3.x
|
||||
self.wrap_line_length = self._get_number('wrap_line_length', self._get_number('max_char'))
|
||||
|
||||
def _get_array(self, name, default_value=[]):
|
||||
option_value = getattr(self.raw_options, name, default_value)
|
||||
result = []
|
||||
if isinstance(option_value, list):
|
||||
result = copy.copy(option_value)
|
||||
elif isinstance(option_value, str):
|
||||
result = re.compile(r"[^a-zA-Z0-9_/\-]+").split(option_value)
|
||||
|
||||
return result
|
||||
|
||||
def _get_boolean(self, name, default_value=False):
|
||||
option_value = getattr(self.raw_options, name, default_value)
|
||||
result = False
|
||||
try:
|
||||
result = bool(option_value)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return result
|
||||
|
||||
def _get_characters(self, name, default_value=''):
|
||||
option_value = getattr(self.raw_options, name, default_value)
|
||||
result = ''
|
||||
if isinstance(option_value, str):
|
||||
result = option_value.replace('\\r', '\r').replace('\\n', '\n').replace('\\t', '\t')
|
||||
|
||||
return result
|
||||
|
||||
def _get_number(self, name, default_value=0):
|
||||
option_value = getattr(self.raw_options, name, default_value)
|
||||
result = 0
|
||||
try:
|
||||
result = int(option_value)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return result
|
||||
|
||||
def _get_selection(self, name, selection_list, default_value=None):
|
||||
result = self._get_selection_list(name, selection_list, default_value)
|
||||
if len(result) != 1:
|
||||
raise ValueError(
|
||||
"Invalid Option Value: The option '" + name + "' can only be one of the following values:\n" +
|
||||
str(selection_list) +
|
||||
"\nYou passed in: '" +
|
||||
str(getattr(self.raw_options, name, None)) +
|
||||
"'")
|
||||
|
||||
return result[0]
|
||||
|
||||
|
||||
def _get_selection_list(self, name, selection_list, default_value=None):
|
||||
if not selection_list:
|
||||
raise ValueError("Selection list cannot be empty.")
|
||||
|
||||
default_value = default_value or [selection_list[0]]
|
||||
|
||||
if not self._is_valid_selection(default_value, selection_list):
|
||||
raise ValueError("Invalid Default Value!")
|
||||
|
||||
result = self._get_array(name, default_value)
|
||||
if not self._is_valid_selection(result, selection_list):
|
||||
raise ValueError(
|
||||
"Invalid Option Value: The option '" + name + "' can contain only the following values:\n" +
|
||||
str(selection_list) +
|
||||
"\nYou passed in: '" +
|
||||
str(getattr(self.raw_options, name, None)) +
|
||||
"'")
|
||||
|
||||
return result
|
||||
|
||||
def _is_valid_selection(self, result, selection_list):
|
||||
if len(result) == 0 or len(selection_list) == 0:
|
||||
return False
|
||||
|
||||
for item in result:
|
||||
if item not in selection_list:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# merges child options up with the parent options object
|
||||
# Example: obj = {a: 1, b: {a: 2}}
|
||||
@ -31,7 +147,17 @@ import copy
|
||||
# Returns: {a: 2, b: {a: 2}}
|
||||
|
||||
|
||||
def mergeOpts(options, childFieldName):
|
||||
def _mergeOpts(options, childFieldName):
|
||||
if options is None:
|
||||
options = {}
|
||||
|
||||
if isinstance(options, tuple):
|
||||
options = dict(options)
|
||||
|
||||
if isinstance(options, dict):
|
||||
options = _normalizeOpts(options)
|
||||
options = namedtuple("CustomOptions", options.keys())(*options.values())
|
||||
|
||||
finalOpts = copy.copy(options)
|
||||
|
||||
local = getattr(finalOpts, childFieldName, None)
|
||||
@ -41,3 +167,20 @@ def mergeOpts(options, childFieldName):
|
||||
setattr(finalOpts, key, local[key])
|
||||
|
||||
return finalOpts
|
||||
|
||||
def _normalizeOpts(options):
|
||||
convertedOpts = copy.copy(options)
|
||||
if isinstance(convertedOpts, dict):
|
||||
option_keys = list(convertedOpts.keys())
|
||||
for key in option_keys:
|
||||
if '-' in key:
|
||||
del convertedOpts[key]
|
||||
convertedOpts[key.replace('-', '_')] = options[key]
|
||||
else:
|
||||
option_keys = list(getattr(convertedOpts, '__dict__', {}))
|
||||
for key in option_keys:
|
||||
if '-' in key:
|
||||
delattr(convertedOpts, key)
|
||||
setattr(convertedOpts, key.replace('-', '_'), getattr(options, key, None))
|
||||
|
||||
return convertedOpts
|
||||
|
@ -29,24 +29,31 @@ import re
|
||||
|
||||
__all__ = ["Output"]
|
||||
|
||||
|
||||
class OutputLine:
|
||||
def __init__(self, parent):
|
||||
self.__parent = parent
|
||||
self.__character_count = 0
|
||||
self.__indent_count = -1
|
||||
self.__alignment_count = 0
|
||||
|
||||
self.__items = []
|
||||
|
||||
def item(self, index):
|
||||
return self.__items[index]
|
||||
|
||||
def get_character_count(self):
|
||||
return self.__character_count
|
||||
|
||||
def is_empty(self):
|
||||
return len(self.__items) == 0
|
||||
|
||||
def set_indent(self, level):
|
||||
def set_indent(self, indent=0, alignment=0):
|
||||
self.__indent_count = indent
|
||||
self.__alignment_count = alignment
|
||||
self.__character_count = self.__parent.baseIndentLength + \
|
||||
level * self.__parent.indent_length
|
||||
self.__indent_count = level
|
||||
self.__alignment_count + \
|
||||
self.__indent_count * self.__parent.indent_length
|
||||
|
||||
def last(self):
|
||||
if not self.is_empty():
|
||||
@ -79,50 +86,88 @@ class OutputLine:
|
||||
result = ''
|
||||
if not self.is_empty():
|
||||
if self.__indent_count >= 0:
|
||||
result = self.__parent.indent_cache[self.__indent_count]
|
||||
result = self.__parent.get_indent_string(self.__indent_count)
|
||||
if self.__alignment_count >= 0:
|
||||
result += self.__parent.get_alignment_string(
|
||||
self.__alignment_count)
|
||||
result += ''.join(self.__items)
|
||||
return result
|
||||
|
||||
|
||||
class Output:
|
||||
def __init__(self, indent_string, baseIndentString=''):
|
||||
class IndentCache:
|
||||
def __init__(self, base_string, level_string):
|
||||
self.__cache = [base_string]
|
||||
self.__level_string = level_string
|
||||
|
||||
self.indent_string = indent_string
|
||||
self.baseIndentString = baseIndentString
|
||||
self.indent_cache = [baseIndentString]
|
||||
def __ensure_cache(self, level):
|
||||
while level >= len(self.__cache):
|
||||
self.__cache.append(
|
||||
self.__cache[-1] + self.__level_string)
|
||||
|
||||
def get_level_string(self, level):
|
||||
self.__ensure_cache(level)
|
||||
return self.__cache[level]
|
||||
|
||||
|
||||
class Output:
|
||||
def __init__(self, options, baseIndentString=''):
|
||||
|
||||
indent_string = options.indent_char
|
||||
if options.indent_size > 0:
|
||||
indent_string = options.indent_char * options.indent_size
|
||||
|
||||
# Set to null to continue support for auto detection of base levelself.
|
||||
if options.indent_level > 0:
|
||||
baseIndentString = options.indent_level * indent_string
|
||||
|
||||
self.__indent_cache = IndentCache(baseIndentString, indent_string)
|
||||
self.__alignment_cache = IndentCache('', ' ')
|
||||
self.baseIndentLength = len(baseIndentString)
|
||||
self.indent_length = len(indent_string)
|
||||
self.raw = False
|
||||
self.lines = []
|
||||
self._end_with_newline = options.end_with_newline
|
||||
self.__lines = []
|
||||
self.previous_line = None
|
||||
self.current_line = None
|
||||
self.space_before_token = False
|
||||
self.add_outputline()
|
||||
|
||||
def add_outputline(self):
|
||||
self.__add_outputline()
|
||||
|
||||
def __add_outputline(self):
|
||||
self.previous_line = self.current_line
|
||||
self.current_line = OutputLine(self)
|
||||
self.lines.append(self.current_line)
|
||||
self.__lines.append(self.current_line)
|
||||
|
||||
def get_line_number(self):
|
||||
return len(self.lines)
|
||||
return len(self.__lines)
|
||||
|
||||
def get_indent_string(self, level):
|
||||
return self.__indent_cache.get_level_string(level)
|
||||
|
||||
def get_alignment_string(self, level):
|
||||
return self.__alignment_cache.get_level_string(level)
|
||||
|
||||
def is_empty(self):
|
||||
return self.previous_line is None and self.current_line.is_empty()
|
||||
|
||||
def add_new_line(self, force_newline=False):
|
||||
if len(self.lines) == 1 and self.just_added_newline():
|
||||
# no newline on start of file
|
||||
# never newline at the start of file
|
||||
# otherwise, newline only if we didn't just add one or we're forced
|
||||
if self.is_empty() or \
|
||||
(not force_newline and self.just_added_newline()):
|
||||
return False
|
||||
|
||||
if force_newline or not self.just_added_newline():
|
||||
if not self.raw:
|
||||
self.add_outputline()
|
||||
return True
|
||||
return False
|
||||
# if raw output is enabled, don't print additional newlines,
|
||||
# but still return True as though you had
|
||||
if not self.raw:
|
||||
self.__add_outputline()
|
||||
return True
|
||||
|
||||
def get_code(self, end_with_newline, eol):
|
||||
sweet_code = "\n".join(line.toString() for line in self.lines)
|
||||
def get_code(self, eol):
|
||||
sweet_code = "\n".join(line.toString() for line in self.__lines)
|
||||
sweet_code = re.sub('[\r\n\t ]+$', '', sweet_code)
|
||||
|
||||
if end_with_newline:
|
||||
if self._end_with_newline:
|
||||
sweet_code += '\n'
|
||||
|
||||
if not eol == '\n':
|
||||
@ -130,21 +175,17 @@ class Output:
|
||||
|
||||
return sweet_code
|
||||
|
||||
def set_indent(self, level):
|
||||
def set_indent(self, indent=0, alignment=0):
|
||||
# Never indent your first output indent at the start of the file
|
||||
if len(self.lines) > 1:
|
||||
while level >= len(self.indent_cache):
|
||||
self.indent_cache.append(
|
||||
self.indent_cache[-1] + self.indent_string)
|
||||
|
||||
self.current_line.set_indent(level)
|
||||
if len(self.__lines) > 1:
|
||||
self.current_line.set_indent(indent, alignment)
|
||||
return True
|
||||
self.current_line.set_indent(0)
|
||||
self.current_line.set_indent()
|
||||
return False
|
||||
|
||||
def add_raw_token(self, token):
|
||||
for _ in range(token.newlines):
|
||||
self.add_outputline()
|
||||
self.__add_outputline()
|
||||
|
||||
self.current_line.push(token.whitespace_before)
|
||||
self.current_line.push(token.text)
|
||||
@ -159,17 +200,22 @@ class Output:
|
||||
self.current_line.push(' ')
|
||||
self.space_before_token = False
|
||||
|
||||
def remove_indent(self, index):
|
||||
while index < len(self.__lines):
|
||||
self.__lines[index].remove_indent()
|
||||
index += 1
|
||||
|
||||
def trim(self, eat_newlines=False):
|
||||
self.current_line.trim()
|
||||
|
||||
while eat_newlines and len(
|
||||
self.lines) > 1 and self.current_line.is_empty():
|
||||
self.lines.pop()
|
||||
self.current_line = self.lines[-1]
|
||||
self.__lines) > 1 and self.current_line.is_empty():
|
||||
self.__lines.pop()
|
||||
self.current_line = self.__lines[-1]
|
||||
self.current_line.trim()
|
||||
|
||||
if len(self.lines) > 1:
|
||||
self.previous_line = self.lines[-2]
|
||||
if len(self.__lines) > 1:
|
||||
self.previous_line = self.__lines[-2]
|
||||
else:
|
||||
self.previous_line = None
|
||||
|
||||
@ -177,11 +223,18 @@ class Output:
|
||||
return self.current_line.is_empty()
|
||||
|
||||
def just_added_blankline(self):
|
||||
if self.just_added_newline():
|
||||
if len(self.lines) == 1:
|
||||
return True
|
||||
return self.is_empty() or \
|
||||
(self.current_line.is_empty() and self.previous_line.is_empty())
|
||||
|
||||
line = self.lines[-2]
|
||||
return line.is_empty()
|
||||
|
||||
return False
|
||||
def ensure_empty_line_above(self, starts_with, ends_with):
|
||||
index = len(self.__lines) - 2
|
||||
while index >= 0:
|
||||
potentialEmptyLine = self.__lines[index]
|
||||
if potentialEmptyLine.is_empty():
|
||||
break
|
||||
elif not potentialEmptyLine.item(0).startswith(starts_with) and \
|
||||
potentialEmptyLine.item(-1) != ends_with:
|
||||
self.__lines.insert(index + 1, OutputLine(self))
|
||||
self.previous_line = self.__lines[-2]
|
||||
break
|
||||
index -= 1
|
||||
|
@ -36,5 +36,8 @@ class Token:
|
||||
self.newlines = newlines
|
||||
self.whitespace_before = whitespace_before
|
||||
self.parent = None
|
||||
self.next = None
|
||||
self.previous = None
|
||||
self.opened = None
|
||||
self.closed = None
|
||||
self.directives = None
|
||||
|
@ -42,89 +42,100 @@ TOKEN = TokenTypes()
|
||||
|
||||
class Tokenizer:
|
||||
|
||||
def __init__(self, input_string):
|
||||
import jsbeautifier.core.acorn as acorn
|
||||
self.acorn = acorn
|
||||
|
||||
def __init__(self, input_string, options):
|
||||
self._input = InputScanner(input_string)
|
||||
self._tokens = None
|
||||
self._newline_count = 0
|
||||
self._whitespace_before_token = ''
|
||||
self._options = options
|
||||
self.__tokens = None
|
||||
self.__newline_count = 0
|
||||
self.__whitespace_before_token = ''
|
||||
|
||||
self._whitespace_pattern = re.compile(
|
||||
self.acorn.six.u(r'[\n\r\u2028\u2029\t ]+'))
|
||||
self._newline_pattern = re.compile(
|
||||
self.acorn.six.u(r'([\t ]*)(\r\n|[\n\r\u2028\u2029])?'))
|
||||
self._whitespace_pattern = re.compile(r'[\n\r\t ]+')
|
||||
self._newline_pattern = re.compile(r'([^\n\r]*)(\r\n|[\n\r])?')
|
||||
|
||||
def tokenize(self):
|
||||
self._input.restart()
|
||||
self._tokens = TokenStream()
|
||||
self.__tokens = TokenStream()
|
||||
|
||||
current = None
|
||||
last = Token(TOKEN.START,'')
|
||||
previous = Token(TOKEN.START,'')
|
||||
open_token = None
|
||||
open_stack = []
|
||||
comments = TokenStream()
|
||||
|
||||
while last.type != TOKEN.EOF:
|
||||
current = self.get_next_token(last)
|
||||
while previous.type != TOKEN.EOF:
|
||||
current = self.__get_next_token_with_comments(previous, open_token)
|
||||
|
||||
while self.is_comment(current):
|
||||
if self._is_opening(current):
|
||||
open_stack.append(open_token)
|
||||
open_token = current
|
||||
elif open_token is not None and \
|
||||
self._is_closing(current, open_token):
|
||||
current.opened = open_token
|
||||
open_token.closed = current
|
||||
open_token = open_stack.pop()
|
||||
current.parent = open_token
|
||||
|
||||
self.__tokens.add(current)
|
||||
previous = current
|
||||
return self.__tokens
|
||||
|
||||
def __get_next_token_with_comments(self, previous, open_token):
|
||||
current = self._get_next_token(previous, open_token)
|
||||
|
||||
if self._is_comment(current):
|
||||
comments = TokenStream()
|
||||
while self._is_comment(current):
|
||||
comments.add(current)
|
||||
current = self.get_next_token(last)
|
||||
current = self._get_next_token(previous, open_token)
|
||||
|
||||
if not comments.isEmpty():
|
||||
current.comments_before = comments
|
||||
comments = TokenStream()
|
||||
|
||||
if self.is_opening(current):
|
||||
current.parent = last
|
||||
open_stack.append(open_token)
|
||||
open_token = current
|
||||
elif open_token is not None and self.is_closing(current, open_token):
|
||||
current.parent = open_token.parent
|
||||
current.opened = open_token
|
||||
open_token = open_stack.pop()
|
||||
current.parent = open_token
|
||||
current.previous = previous
|
||||
previous.next = current
|
||||
|
||||
self._tokens.add(current)
|
||||
last = current
|
||||
return self._tokens
|
||||
return current
|
||||
|
||||
def reset(self):
|
||||
def _is_first_token(self):
|
||||
return self.__tokens.isEmpty()
|
||||
|
||||
def _reset(self):
|
||||
pass
|
||||
|
||||
def get_next_token(self, last_token):
|
||||
self.readWhitespace()
|
||||
def _get_next_token(self, previous_token, open_token):
|
||||
self._readWhitespace()
|
||||
resulting_string = self._input.read(re.compile(r'.+'))
|
||||
if resulting_string:
|
||||
return self.create_token(TOKEN.RAW, resulting_string)
|
||||
return self._create_token(TOKEN.RAW, resulting_string)
|
||||
else:
|
||||
return self.create_token(TOKEN.EOF, '')
|
||||
return self._create_token(TOKEN.EOF, '')
|
||||
|
||||
def is_comment(self, current_token):
|
||||
def _is_comment(self, current_token):
|
||||
return False
|
||||
|
||||
def is_opening(self, current_token):
|
||||
def _is_opening(self, current_token):
|
||||
return False
|
||||
|
||||
def is_closing(self, current_token, open_token):
|
||||
def _is_closing(self, current_token, open_token):
|
||||
return False
|
||||
|
||||
def create_token(self, token_type, text):
|
||||
token = Token(token_type, text, self._newline_count, self._whitespace_before_token)
|
||||
self._newline_count = 0
|
||||
self._whitespace_before_token = ''
|
||||
def _create_token(self, token_type, text):
|
||||
token = Token(token_type, text,
|
||||
self.__newline_count, self.__whitespace_before_token)
|
||||
self.__newline_count = 0
|
||||
self.__whitespace_before_token = ''
|
||||
return token
|
||||
|
||||
def readWhitespace(self):
|
||||
def _readWhitespace(self):
|
||||
resulting_string = self._input.read(self._whitespace_pattern)
|
||||
if resulting_string != '':
|
||||
if resulting_string == ' ':
|
||||
self._whitespace_before_token = resulting_string
|
||||
else:
|
||||
for nextMatch in self._newline_pattern.findall(resulting_string):
|
||||
if nextMatch[1] != '':
|
||||
self._newline_count += 1
|
||||
else:
|
||||
self._whitespace_before_token = nextMatch[0]
|
||||
break
|
||||
if resulting_string == ' ':
|
||||
self.__whitespace_before_token = resulting_string
|
||||
elif resulting_string != '':
|
||||
for nextMatch in self._newline_pattern.findall(resulting_string):
|
||||
if nextMatch[1] == '':
|
||||
self.__whitespace_before_token = nextMatch[0]
|
||||
break
|
||||
|
||||
self.__newline_count += 1
|
||||
|
@ -29,42 +29,42 @@ from ..core.token import Token
|
||||
class TokenStream:
|
||||
|
||||
def __init__(self, parent_token=None):
|
||||
self._tokens = []
|
||||
self._tokens_length = len(self._tokens)
|
||||
self._position = 0
|
||||
self._parent_token = parent_token
|
||||
self.__tokens = []
|
||||
self.__tokens_length = len(self.__tokens)
|
||||
self.__position = 0
|
||||
self.__parent_token = parent_token
|
||||
|
||||
def restart(self):
|
||||
self._position = 0
|
||||
self.__position = 0
|
||||
|
||||
def isEmpty(self):
|
||||
return self._tokens_length == 0
|
||||
return self.__tokens_length == 0
|
||||
|
||||
def hasNext(self):
|
||||
return self._position < self._tokens_length
|
||||
return self.__position < self.__tokens_length
|
||||
|
||||
def next(self):
|
||||
if self.hasNext():
|
||||
val = self._tokens[self._position]
|
||||
self._position += 1
|
||||
val = self.__tokens[self.__position]
|
||||
self.__position += 1
|
||||
return val
|
||||
else:
|
||||
raise StopIteration
|
||||
|
||||
def peek(self, index=0):
|
||||
val = None
|
||||
index += self._position
|
||||
if index >= 0 and index < self._tokens_length:
|
||||
val = self._tokens[index]
|
||||
index += self.__position
|
||||
if index >= 0 and index < self.__tokens_length:
|
||||
val = self.__tokens[index]
|
||||
|
||||
return val
|
||||
|
||||
def add(self, token):
|
||||
if self._parent_token:
|
||||
token.parent = self._parent_token
|
||||
if self.__parent_token:
|
||||
token.parent = self.__parent_token
|
||||
|
||||
self._tokens.append(token)
|
||||
self._tokens_length += 1
|
||||
self.__tokens.append(token)
|
||||
self.__tokens_length += 1
|
||||
|
||||
def __iter__(self):
|
||||
self.restart()
|
||||
|
@ -18,42 +18,41 @@ six = __import__("six")
|
||||
|
||||
# ## Character categories
|
||||
|
||||
# acorn used char codes to squeeze the last bit of performance out
|
||||
# Beautifier is okay without that, so we're using regex
|
||||
# permit $ (36) and @ (64). @ is used in ES7 decorators.
|
||||
# 65 through 91 are uppercase letters.
|
||||
# permit _ (95).
|
||||
# 97 through 123 are lowercase letters.
|
||||
_baseASCIIidentifierStartChars = six.u(r"\x24\x40\x41-\x5a\x5f\x61-\x7a")
|
||||
|
||||
# inside an identifier @ is not allowed but 0-9 are.
|
||||
_baseASCIIidentifierChars = six.u(r"\x24\x30-\x39\x41-\x5a\x5f\x61-\x7a")
|
||||
|
||||
# Big ugly regular expressions that match characters in the
|
||||
# whitespace, identifier, and identifier-start categories. These
|
||||
# are only applied when a character is found to actually have a
|
||||
# code point above 128.
|
||||
|
||||
# IMPORTANT: These strings must be run through six to handle \u chars
|
||||
_nonASCIIwhitespace = re.compile(
|
||||
six.u(r"[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]"))
|
||||
_baseASCIIidentifierStartChars = six.u(r"\x24\x40\x41-\x5a\x5f\x61-\x7a")
|
||||
_nonASCIIidentifierStartChars = six.u(r"\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc")
|
||||
_baseASCIIidentifierChars = six.u(r"\x24\x30-\x39\x41-\x5a\x5f\x61-\x7a")
|
||||
_nonASCIIidentifierChars = six.u(r"\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f")
|
||||
#_nonASCIIidentifierStart = re.compile("[" + _nonASCIIidentifierStartChars + "]")
|
||||
#_nonASCIIidentifier = re.compile("[" + _nonASCIIidentifierStartChars + _nonASCIIidentifierChars + "]")
|
||||
|
||||
_identifierStart = re.compile(
|
||||
"[" +
|
||||
_baseASCIIidentifierStartChars +
|
||||
_nonASCIIidentifierStartChars +
|
||||
"]")
|
||||
_identifierChars = re.compile(
|
||||
"[" +
|
||||
_baseASCIIidentifierChars +
|
||||
_nonASCIIidentifierStartChars +
|
||||
_nonASCIIidentifierChars +
|
||||
"]")
|
||||
_identifierStart = six.u("[") + \
|
||||
_baseASCIIidentifierStartChars + \
|
||||
_nonASCIIidentifierStartChars + \
|
||||
six.u("]")
|
||||
_identifierChars = six.u("[") + \
|
||||
_baseASCIIidentifierChars + \
|
||||
_nonASCIIidentifierStartChars + \
|
||||
_nonASCIIidentifierChars + \
|
||||
six.u("]*")
|
||||
|
||||
identifier = re.compile(
|
||||
"[" +
|
||||
_baseASCIIidentifierStartChars +
|
||||
_nonASCIIidentifierStartChars +
|
||||
"][" +
|
||||
_baseASCIIidentifierChars +
|
||||
_nonASCIIidentifierStartChars +
|
||||
_nonASCIIidentifierChars +
|
||||
"]*")
|
||||
identifier = re.compile(_identifierStart + _identifierChars)
|
||||
|
||||
_nonASCIIwhitespace = re.compile(
|
||||
six.u(r"[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]"))
|
||||
|
||||
# Whether a single character denotes a newline.
|
||||
# IMPORTANT: This string must be run through six to handle \u chars
|
||||
@ -66,39 +65,4 @@ newline = re.compile(six.u(r"[\n\r\u2028\u2029]"))
|
||||
# in python they are the same, different methods are called on them
|
||||
# IMPORTANT: This string must be run through six to handle \u chars
|
||||
lineBreak = re.compile(six.u(r"\r\n|[\n\r\u2028\u2029]"))
|
||||
allLineBreaks = lineBreak
|
||||
|
||||
|
||||
# Test whether a given character code starts an identifier.
|
||||
def isIdentifierStart(code):
|
||||
# if code < 65:
|
||||
# return code in [36, 64] # permit $ (36) and @ (64). @ is used in ES7 decorators.
|
||||
# if code < 91:
|
||||
# return True # 65 through 91 are uppercase letters
|
||||
# if code < 97:
|
||||
# return code == 95 # permit _ (95)
|
||||
# if code < 123:
|
||||
# return True # 97 through 123 are lowercase letters
|
||||
# return code >= 0xaa and _nonASCIIidentifierStart.match(six.unichr(code))
|
||||
# != None
|
||||
return bool(_identifierStart.match(six.unichr(code)))
|
||||
|
||||
# Test whether a given character is part of an identifier.
|
||||
|
||||
|
||||
def isIdentifierChar(code):
|
||||
# if code < 48:
|
||||
# return code == 36
|
||||
# if code < 58:
|
||||
# return True
|
||||
# if code < 65:
|
||||
# return False
|
||||
# if code < 91:
|
||||
# return True
|
||||
# if code < 97:
|
||||
# return code == 95
|
||||
# if code < 123:
|
||||
# return True
|
||||
# return code >= 0xaa and _nonASCIIidentifier.match(six.unichr(code)) !=
|
||||
# None
|
||||
return bool(_identifierChars.match(six.unichr(code)))
|
||||
allLineBreaks = lineBreak
|
File diff suppressed because it is too large
Load Diff
@ -23,66 +23,72 @@
|
||||
# SOFTWARE.
|
||||
|
||||
|
||||
class BeautifierOptions:
|
||||
def __init__(self):
|
||||
self.indent_size = 4
|
||||
self.indent_char = ' '
|
||||
self.indent_with_tabs = False
|
||||
self.eol = 'auto'
|
||||
self.preserve_newlines = True
|
||||
self.max_preserve_newlines = 10
|
||||
self.space_in_paren = False
|
||||
self.space_in_empty_paren = False
|
||||
self.e4x = False
|
||||
self.jslint_happy = False
|
||||
self.space_after_anon_function = False
|
||||
self.brace_style = 'collapse'
|
||||
self.keep_array_indentation = False
|
||||
self.space_before_conditional = True
|
||||
self.keep_function_indentation = False
|
||||
self.eval_code = False
|
||||
self.unescape_strings = False
|
||||
self.wrap_line_length = 0
|
||||
self.unindent_chained_methods = False
|
||||
self.break_chained_methods = False
|
||||
self.end_with_newline = False
|
||||
self.comma_first = False
|
||||
self.operator_position = 'before-newline'
|
||||
from ..core.options import Options as BaseOptions
|
||||
|
||||
OPERATOR_POSITION = [
|
||||
'before-newline',
|
||||
'after-newline',
|
||||
'preserve-newline'
|
||||
]
|
||||
|
||||
class BeautifierOptions(BaseOptions):
|
||||
def __init__(self, options=None):
|
||||
BaseOptions.__init__(self, options, 'js')
|
||||
|
||||
self.css = None
|
||||
self.js = None
|
||||
self.html = None
|
||||
|
||||
# For testing of beautify ignore:start directive
|
||||
# compatibility, re
|
||||
|
||||
raw_brace_style = getattr(self.raw_options, 'brace_style', None)
|
||||
if raw_brace_style == "expand-strict": # graceful handling of deprecated option
|
||||
setattr(self.raw_options, 'brace_style', "expand")
|
||||
elif raw_brace_style == "collapse-preserve-inline": # graceful handling of deprecated option
|
||||
setattr(self.raw_options, 'brace_style', "collapse,preserve-inline")
|
||||
# elif bool(self.raw_options.braces_on_own_line): # graceful handling of deprecated option
|
||||
# raw_brace_style = "expand": "collapse"
|
||||
# elif raw_brace_style is None: # Nothing exists to set it
|
||||
# setattr(self.raw_options, 'brace_style', "collapse")
|
||||
|
||||
# preserve-inline in delimited string will trigger brace_preserve_inline, everything
|
||||
# else is considered a brace_style and the last one only will have an effect
|
||||
|
||||
brace_style_split = self._get_selection_list('brace_style', ['collapse', 'expand', 'end-expand', 'none', 'preserve-inline'])
|
||||
|
||||
# preserve-inline in delimited string will trigger brace_preserve_inline
|
||||
# Everything else is considered a brace_style and the last one only will
|
||||
# have an effect
|
||||
# specify defaults in case one half of meta-option is missing
|
||||
self.brace_preserve_inline = False
|
||||
self.brace_style = "collapse"
|
||||
|
||||
for bs in brace_style_split:
|
||||
if bs == "preserve-inline":
|
||||
self.brace_preserve_inline = True
|
||||
else:
|
||||
self.brace_style = bs
|
||||
|
||||
self.unindent_chained_methods = self._get_boolean('unindent_chained_methods')
|
||||
self.break_chained_methods = self._get_boolean('break_chained_methods')
|
||||
self.space_in_paren = self._get_boolean('space_in_paren')
|
||||
self.space_in_empty_paren = self._get_boolean('space_in_empty_paren')
|
||||
self.jslint_happy = self._get_boolean('jslint_happy')
|
||||
self.space_after_anon_function = self._get_boolean('space_after_anon_function')
|
||||
self.space_after_named_function = self._get_boolean('space_after_named_function')
|
||||
self.keep_array_indentation = self._get_boolean('keep_array_indentation')
|
||||
self.space_before_conditional = self._get_boolean('space_before_conditional', True)
|
||||
self.unescape_strings = self._get_boolean('unescape_strings')
|
||||
self.e4x = self._get_boolean('e4x')
|
||||
self.comma_first = self._get_boolean('comma_first')
|
||||
self.operator_position = self._get_selection('operator_position', OPERATOR_POSITION)
|
||||
|
||||
# For testing of beautify preserve:start directive
|
||||
self.test_output_raw = False
|
||||
self.editorconfig = False
|
||||
|
||||
def __repr__(self):
|
||||
return \
|
||||
"""indent_size = %d
|
||||
indent_char = [%s]
|
||||
preserve_newlines = %s
|
||||
max_preserve_newlines = %d
|
||||
space_in_paren = %s
|
||||
jslint_happy = %s
|
||||
space_after_anon_function = %s
|
||||
indent_with_tabs = %s
|
||||
brace_style = %s
|
||||
keep_array_indentation = %s
|
||||
eval_code = %s
|
||||
wrap_line_length = %s
|
||||
unescape_strings = %s
|
||||
""" % (self.indent_size,
|
||||
self.indent_char,
|
||||
self.preserve_newlines,
|
||||
self.max_preserve_newlines,
|
||||
self.space_in_paren,
|
||||
self.jslint_happy,
|
||||
self.space_after_anon_function,
|
||||
self.indent_with_tabs,
|
||||
self.brace_style,
|
||||
self.keep_array_indentation,
|
||||
self.eval_code,
|
||||
self.wrap_line_length,
|
||||
self.unescape_strings,
|
||||
)
|
||||
# force opts.space_after_anon_function to true if opts.jslint_happy
|
||||
if self.jslint_happy:
|
||||
self.space_after_anon_function = True
|
||||
|
||||
self.eval_code = False
|
||||
|
@ -114,54 +114,65 @@ class Tokenizer(BaseTokenizer):
|
||||
positionable_operators = positionable_operators
|
||||
line_starters = line_starters
|
||||
|
||||
def __init__(self, input_string, opts, indent_string):
|
||||
BaseTokenizer.__init__(self, input_string)
|
||||
def __init__(self, input_string, opts):
|
||||
BaseTokenizer.__init__(self, input_string, opts)
|
||||
# This is not pretty, but given how we did the version import
|
||||
# it is the only way to do this without having setup.py fail on a missing
|
||||
# six dependency.
|
||||
self._six = __import__("six")
|
||||
|
||||
import jsbeautifier.javascript.acorn as acorn
|
||||
self.acorn = acorn
|
||||
|
||||
self.opts = opts
|
||||
self.indent_string = indent_string
|
||||
self.in_html_comment = False
|
||||
self.has_char_escapes = False
|
||||
|
||||
# comment ends just before nearest linefeed or end of file
|
||||
# IMPORTANT: This string must be run through six to handle \u chars
|
||||
self._whitespace_pattern = re.compile(
|
||||
self._six.u(r'[\n\r\u2028\u2029\t\u000B\u00A0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff ]+'))
|
||||
self._newline_pattern = re.compile(
|
||||
self._six.u(r'([^\n\r\u2028\u2029]*)(\r\n|[\n\r\u2028\u2029])?'))
|
||||
# // comment ends just before nearest linefeed or end of file
|
||||
|
||||
self.comment_pattern = re.compile(
|
||||
self.acorn.six.u(r'//([^\n\r\u2028\u2029]*)'))
|
||||
self._six.u(r'//([^\n\r\u2028\u2029]*)'))
|
||||
|
||||
|
||||
|
||||
def reset(self):
|
||||
def _reset(self):
|
||||
self.in_html_comment = False
|
||||
|
||||
def is_comment(self, current_token):
|
||||
def _is_comment(self, current_token):
|
||||
return current_token.type == TOKEN.COMMENT or \
|
||||
current_token.type == TOKEN.BLOCK_COMMENT or \
|
||||
current_token.type == TOKEN.UNKNOWN
|
||||
|
||||
|
||||
def is_opening(self, current_token):
|
||||
def _is_opening(self, current_token):
|
||||
return current_token.type == TOKEN.START_BLOCK or current_token.type == TOKEN.START_EXPR
|
||||
|
||||
def is_closing(self, current_token, open_token):
|
||||
def _is_closing(self, current_token, open_token):
|
||||
return (current_token.type == TOKEN.END_BLOCK or current_token.type == TOKEN.END_EXPR) and \
|
||||
(open_token is not None and (
|
||||
(current_token.text == ']' and open_token.text == '[') or
|
||||
(current_token.text == ')' and open_token.text == '(') or
|
||||
(current_token.text == '}' and open_token.text == '{')))
|
||||
|
||||
def get_next_token(self, last_token):
|
||||
self.readWhitespace()
|
||||
def _get_next_token(self, previous_token, open_token):
|
||||
self._readWhitespace()
|
||||
token = None
|
||||
c = self._input.peek()
|
||||
|
||||
token = token or self._read_singles(c)
|
||||
token = token or self._read_word(last_token)
|
||||
token = token or self._read_word(previous_token)
|
||||
token = token or self._read_comment(c)
|
||||
token = token or self._read_string(c)
|
||||
token = token or self._read_regexp(c, last_token)
|
||||
token = token or self._read_xml(c, last_token)
|
||||
token = token or self._read_regexp(c, previous_token)
|
||||
token = token or self._read_xml(c, previous_token)
|
||||
token = token or self._read_non_javascript(c)
|
||||
token = token or self._read_punctuation()
|
||||
token = token or self.create_token(TOKEN.UNKNOWN, self._input.next())
|
||||
token = token or self._create_token(TOKEN.UNKNOWN, self._input.next())
|
||||
|
||||
return token
|
||||
|
||||
@ -169,45 +180,45 @@ class Tokenizer(BaseTokenizer):
|
||||
token = None
|
||||
|
||||
if c is None:
|
||||
token = self.create_token(TOKEN.EOF, '')
|
||||
token = self._create_token(TOKEN.EOF, '')
|
||||
elif c == '(' or c == '[':
|
||||
token = self.create_token(TOKEN.START_EXPR, c)
|
||||
token = self._create_token(TOKEN.START_EXPR, c)
|
||||
elif c == ')' or c == ']':
|
||||
token = self.create_token(TOKEN.END_EXPR, c)
|
||||
token = self._create_token(TOKEN.END_EXPR, c)
|
||||
elif c == '{':
|
||||
token = self.create_token(TOKEN.START_BLOCK, c)
|
||||
token = self._create_token(TOKEN.START_BLOCK, c)
|
||||
elif c == '}':
|
||||
token = self.create_token(TOKEN.END_BLOCK, c)
|
||||
token = self._create_token(TOKEN.END_BLOCK, c)
|
||||
elif c == ';':
|
||||
token = self.create_token(TOKEN.SEMICOLON, c)
|
||||
token = self._create_token(TOKEN.SEMICOLON, c)
|
||||
elif c == '.' and bool(dot_pattern.match(self._input.peek(1))):
|
||||
token = self.create_token(TOKEN.DOT, c)
|
||||
token = self._create_token(TOKEN.DOT, c)
|
||||
elif c == ',':
|
||||
token = self.create_token(TOKEN.COMMA, c)
|
||||
token = self._create_token(TOKEN.COMMA, c)
|
||||
|
||||
if token is not None:
|
||||
self._input.next()
|
||||
|
||||
return token
|
||||
|
||||
def _read_word(self, last_token):
|
||||
def _read_word(self, previous_token):
|
||||
resulting_string = self._input.read(self.acorn.identifier)
|
||||
if resulting_string != '':
|
||||
if not (last_token.type == TOKEN.DOT or (
|
||||
last_token.type == TOKEN.RESERVED and (
|
||||
last_token.text == 'set' or last_token.text == 'get')
|
||||
if not (previous_token.type == TOKEN.DOT or (
|
||||
previous_token.type == TOKEN.RESERVED and (
|
||||
previous_token.text == 'set' or previous_token.text == 'get')
|
||||
)) and reserved_word_pattern.match(resulting_string):
|
||||
if resulting_string == 'in' or resulting_string == 'of':
|
||||
# in and of are operators, need to hack
|
||||
return self.create_token(TOKEN.OPERATOR, resulting_string)
|
||||
return self._create_token(TOKEN.OPERATOR, resulting_string)
|
||||
|
||||
return self.create_token(TOKEN.RESERVED, resulting_string)
|
||||
return self._create_token(TOKEN.RESERVED, resulting_string)
|
||||
|
||||
return self.create_token(TOKEN.WORD, resulting_string)
|
||||
return self._create_token(TOKEN.WORD, resulting_string)
|
||||
|
||||
resulting_string = self._input.read(number_pattern)
|
||||
if resulting_string != '':
|
||||
return self.create_token(TOKEN.WORD, resulting_string)
|
||||
return self._create_token(TOKEN.WORD, resulting_string)
|
||||
|
||||
def _read_comment(self, c):
|
||||
token = None
|
||||
@ -220,12 +231,12 @@ class Tokenizer(BaseTokenizer):
|
||||
if directives and directives.get('ignore') == 'start':
|
||||
comment += directives_core.readIgnored(self._input)
|
||||
comment = re.sub(self.acorn.allLineBreaks, '\n', comment)
|
||||
token = self.create_token(TOKEN.BLOCK_COMMENT, comment)
|
||||
token = self._create_token(TOKEN.BLOCK_COMMENT, comment)
|
||||
token.directives = directives
|
||||
|
||||
elif self._input.peek(1) == '/': # peek // comment
|
||||
comment = self._input.read(self.comment_pattern)
|
||||
token = self.create_token(TOKEN.COMMENT, comment)
|
||||
token = self._create_token(TOKEN.COMMENT, comment)
|
||||
|
||||
return token
|
||||
|
||||
@ -241,7 +252,7 @@ class Tokenizer(BaseTokenizer):
|
||||
else:
|
||||
resulting_string = self.parse_string(resulting_string, c)
|
||||
|
||||
if self.has_char_escapes and self.opts.unescape_strings:
|
||||
if self.has_char_escapes and self._options.unescape_strings:
|
||||
resulting_string = self.unescape_string(resulting_string)
|
||||
|
||||
if self._input.peek() == c :
|
||||
@ -250,13 +261,13 @@ class Tokenizer(BaseTokenizer):
|
||||
resulting_string = re.sub(
|
||||
self.acorn.allLineBreaks, '\n', resulting_string)
|
||||
|
||||
return self.create_token(TOKEN.STRING, resulting_string)
|
||||
return self._create_token(TOKEN.STRING, resulting_string)
|
||||
|
||||
return None
|
||||
|
||||
def _read_regexp(self, c, last_token):
|
||||
def _read_regexp(self, c, previous_token):
|
||||
|
||||
if c == '/' and self.allowRegExOrXML(last_token):
|
||||
if c == '/' and self.allowRegExOrXML(previous_token):
|
||||
# handle regexp
|
||||
resulting_string = self._input.next()
|
||||
esc = False
|
||||
@ -286,14 +297,14 @@ class Tokenizer(BaseTokenizer):
|
||||
resulting_string += self._input.read(
|
||||
self.acorn.identifier)
|
||||
|
||||
return self.create_token(TOKEN.STRING, resulting_string)
|
||||
return self._create_token(TOKEN.STRING, resulting_string)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _read_xml(self, c, last_token):
|
||||
if self.opts.e4x and c == "<" and self._input.test(
|
||||
startXmlRegExp) and self.allowRegExOrXML(last_token):
|
||||
def _read_xml(self, c, previous_token):
|
||||
if self._options.e4x and c == "<" and self._input.test(
|
||||
startXmlRegExp) and self.allowRegExOrXML(previous_token):
|
||||
# handle e4x xml literals
|
||||
xmlStr = ""
|
||||
match = self._input.match(xmlRegExp)
|
||||
@ -325,7 +336,7 @@ class Tokenizer(BaseTokenizer):
|
||||
xmlStr += self._input.match(re.compile(r'[\s\S]*')).group(0)
|
||||
|
||||
xmlStr = re.sub(self.acorn.allLineBreaks, '\n', xmlStr)
|
||||
return self.create_token(TOKEN.STRING, xmlStr)
|
||||
return self._create_token(TOKEN.STRING, xmlStr)
|
||||
|
||||
return None
|
||||
|
||||
@ -335,12 +346,12 @@ class Tokenizer(BaseTokenizer):
|
||||
if c == '#':
|
||||
c = self._input.next()
|
||||
# she-bang
|
||||
if self._tokens.isEmpty() and self._input.peek() == '!':
|
||||
if self._is_first_token() and self._input.peek() == '!':
|
||||
resulting_string = c
|
||||
while self._input.hasNext() and c != '\n':
|
||||
c = self._input.next()
|
||||
resulting_string += c
|
||||
return self.create_token(TOKEN.UNKNOWN, resulting_string.strip() + '\n')
|
||||
return self._create_token(TOKEN.UNKNOWN, resulting_string.strip() + '\n')
|
||||
|
||||
# Spidermonkey-specific sharp variables for circular references
|
||||
# https://developer.mozilla.org/En/Sharp_variables_in_JavaScript
|
||||
@ -364,7 +375,7 @@ class Tokenizer(BaseTokenizer):
|
||||
self._input.next()
|
||||
self._input.next()
|
||||
|
||||
return self.create_token(TOKEN.WORD, sharp)
|
||||
return self._create_token(TOKEN.WORD, sharp)
|
||||
|
||||
self._input.back()
|
||||
|
||||
@ -373,7 +384,7 @@ class Tokenizer(BaseTokenizer):
|
||||
resulting_string = self._input.read(template_pattern)
|
||||
if resulting_string:
|
||||
resulting_string = re.sub(self.acorn.allLineBreaks, '\n', resulting_string)
|
||||
return self.create_token(TOKEN.STRING, resulting_string)
|
||||
return self._create_token(TOKEN.STRING, resulting_string)
|
||||
|
||||
elif self._input.match(re.compile(r'<\!--')):
|
||||
c = '<!--'
|
||||
@ -381,12 +392,12 @@ class Tokenizer(BaseTokenizer):
|
||||
c += self._input.next()
|
||||
|
||||
self.in_html_comment = True
|
||||
return self.create_token(TOKEN.COMMENT, c)
|
||||
return self._create_token(TOKEN.COMMENT, c)
|
||||
|
||||
elif c == '-' and self.in_html_comment and self._input.match(
|
||||
re.compile('-->')):
|
||||
self.in_html_comment = False
|
||||
return self.create_token(TOKEN.COMMENT, '-->')
|
||||
return self._create_token(TOKEN.COMMENT, '-->')
|
||||
|
||||
return None
|
||||
|
||||
@ -395,19 +406,20 @@ class Tokenizer(BaseTokenizer):
|
||||
resulting_string = self._input.read(punct_pattern)
|
||||
if resulting_string != '':
|
||||
if resulting_string == '=':
|
||||
token = self.create_token(TOKEN.EQUALS, resulting_string)
|
||||
token = self._create_token(TOKEN.EQUALS, resulting_string)
|
||||
else:
|
||||
token = self.create_token(TOKEN.OPERATOR, resulting_string)
|
||||
token = self._create_token(TOKEN.OPERATOR, resulting_string)
|
||||
|
||||
return token
|
||||
|
||||
|
||||
def allowRegExOrXML(self, last_token):
|
||||
return (last_token.type == TOKEN.RESERVED and last_token.text in ['return', 'case', 'throw', 'else', 'do', 'typeof', 'yield']) or \
|
||||
(last_token.type == TOKEN.END_EXPR and last_token.text == ')' and
|
||||
last_token.parent and last_token.parent.type == TOKEN.RESERVED and last_token.parent.text in ['if', 'while', 'for']) or \
|
||||
(last_token.type in [TOKEN.COMMENT, TOKEN.START_EXPR, TOKEN.START_BLOCK, TOKEN.START, TOKEN.END_BLOCK, TOKEN.OPERATOR,
|
||||
TOKEN.EQUALS, TOKEN.EOF, TOKEN.SEMICOLON, TOKEN.COMMA])
|
||||
__regexTokens = { TOKEN.COMMENT, TOKEN.START_EXPR, TOKEN.START_BLOCK,
|
||||
TOKEN.START, TOKEN.END_BLOCK, TOKEN.OPERATOR,
|
||||
TOKEN.EQUALS, TOKEN.EOF, TOKEN.SEMICOLON, TOKEN.COMMA }
|
||||
def allowRegExOrXML(self, previous_token):
|
||||
return (previous_token.type == TOKEN.RESERVED and previous_token.text in {'return', 'case', 'throw', 'else', 'do', 'typeof', 'yield'}) or \
|
||||
(previous_token.type == TOKEN.END_EXPR and previous_token.text == ')' and
|
||||
previous_token.opened.previous.type == TOKEN.RESERVED and previous_token.opened.previous.text in {'if', 'while', 'for'}) or \
|
||||
(previous_token.type in self.__regexTokens )
|
||||
|
||||
def parse_string(
|
||||
self,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,14 @@ test_cli_common()
|
||||
exit 1
|
||||
}
|
||||
|
||||
# unicode error - only happens in python
|
||||
# Note: different exceptions are thrown on different platforms.
|
||||
$CLI_SCRIPT ../test/resources/unicode-error.js 2>&1 | grep -q "Error while decoding input or encoding output:" || {
|
||||
$CLI_SCRIPT ../test/resources/unicode-error.js 2>&1
|
||||
echo "[$CLI_SCRIPT_NAME] Output should be unicode error message."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$CLI_SCRIPT 2> /dev/null && {
|
||||
echo "[$CLI_SCRIPT_NAME (with no parameters)] Return code should be error."
|
||||
exit 1
|
||||
|
@ -1,6 +1,6 @@
|
||||
#
|
||||
# Unpacker for eval() based packers, a part of javascript beautifier
|
||||
# by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
# by Einar Lielmanis <einar@beautifier.io>
|
||||
#
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
|
@ -2,7 +2,7 @@
|
||||
# simple unpacker/deobfuscator for scripts messed up with
|
||||
# javascriptobfuscator.com
|
||||
#
|
||||
# written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
# written by Einar Lielmanis <einar@beautifier.io>
|
||||
# rewritten in Python by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
# Will always return valid javascript: if `detect()` is false, `code` is
|
||||
|
@ -1,6 +1,6 @@
|
||||
#
|
||||
# deobfuscator for scripts messed up with myobfuscate.com
|
||||
# by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
# by Einar Lielmanis <einar@beautifier.io>
|
||||
#
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
|
@ -1,6 +1,6 @@
|
||||
#
|
||||
# Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier
|
||||
# by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
# by Einar Lielmanis <einar@beautifier.io>
|
||||
#
|
||||
# written by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
|
@ -1,6 +1,6 @@
|
||||
#
|
||||
# Trivial bookmarklet/escaped script detector for the javascript beautifier
|
||||
# written by Einar Lielmanis <einar@jsbeautifier.org>
|
||||
# written by Einar Lielmanis <einar@beautifier.io>
|
||||
# rewritten in Python by Stefano Sanfilippo <a.little.coder@gmail.com>
|
||||
#
|
||||
# Will always return valid javascript: if `detect()` is false, `code` is
|
||||
|
@ -32,8 +32,8 @@ setup(name='jsbeautifier',
|
||||
long_description=('Beautify, unpack or deobfuscate JavaScript. '
|
||||
'Handles popular online obfuscators.'),
|
||||
author='Liam Newman, Einar Lielmanis, et al.',
|
||||
author_email='team@jsbeautifier.org',
|
||||
url='http://jsbeautifier.org',
|
||||
author_email='team@beautifier.io',
|
||||
url='https://beautifier.io',
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'js-beautify = jsbeautifier:main'
|
||||
|
38
python/test-perf-cssbeautifier.py
Executable file
38
python/test-perf-cssbeautifier.py
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import copy
|
||||
import cssbeautifier
|
||||
options = cssbeautifier.default_options()
|
||||
options.wrap_line_length = 80
|
||||
data = ''
|
||||
|
||||
|
||||
def beautifier_test_github_css():
|
||||
cssbeautifier.beautify(data, options)
|
||||
|
||||
|
||||
def report_perf(fn):
|
||||
import timeit
|
||||
iter = 5
|
||||
time = timeit.timeit(
|
||||
fn +
|
||||
"()",
|
||||
setup="from __main__ import " +
|
||||
fn +
|
||||
"; gc.enable()",
|
||||
number=iter)
|
||||
print(fn + ": " + str(iter / time) + " cycles/sec")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
dirname = os.path.dirname(os.path.abspath(__file__))
|
||||
github_file = os.path.join(
|
||||
dirname, "../", "test/resources/github.css")
|
||||
data = copy.copy(''.join(open(github_file).readlines()))
|
||||
|
||||
# warm up
|
||||
beautifier_test_github_css()
|
||||
|
||||
report_perf("beautifier_test_github_css")
|
@ -17,10 +17,13 @@ def beautifier_test_underscore():
|
||||
def beautifier_test_underscore_min():
|
||||
jsbeautifier.beautify(data_min, options)
|
||||
|
||||
def beautifier_test_github_min():
|
||||
jsbeautifier.beautify(github_min, options)
|
||||
|
||||
|
||||
def report_perf(fn):
|
||||
import timeit
|
||||
iter = 50
|
||||
iter = 5
|
||||
time = timeit.timeit(
|
||||
fn +
|
||||
"()",
|
||||
@ -37,12 +40,17 @@ if __name__ == '__main__':
|
||||
dirname, "../", "test/resources/underscore.js")
|
||||
underscore_min_file = os.path.join(
|
||||
dirname, "../", "test/resources/underscore-min.js")
|
||||
github_min_file = os.path.join(
|
||||
dirname, "../", "test/resources/github-min.js")
|
||||
data = copy.copy(''.join(open(underscore_file).readlines()))
|
||||
data_min = copy.copy(''.join(open(underscore_min_file).readlines()))
|
||||
github_min = copy.copy(''.join(open( github_min_file).readlines()))
|
||||
|
||||
# warm up
|
||||
beautifier_test_underscore()
|
||||
beautifier_test_underscore_min()
|
||||
beautifier_test_github_min()
|
||||
|
||||
report_perf("beautifier_test_underscore")
|
||||
report_perf("beautifier_test_underscore_min")
|
||||
report_perf("beautifier_test_github_min")
|
||||
|
@ -26,6 +26,7 @@
|
||||
SOFTWARE.
|
||||
*/
|
||||
/*jshint unused:false */
|
||||
/*jshint strict:false */
|
||||
|
||||
function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_beautify)
|
||||
{
|
||||
@ -50,49 +51,70 @@ function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_bea
|
||||
function reset_options()
|
||||
{
|
||||
opts = JSON.parse(JSON.stringify(default_opts));
|
||||
test_name = 'css-beautify';
|
||||
}
|
||||
|
||||
function test_css_beautifier(input)
|
||||
function test_beautifier(input)
|
||||
{
|
||||
return css_beautify(input, opts);
|
||||
}
|
||||
|
||||
var sanitytest;
|
||||
var test_name = '';
|
||||
|
||||
|
||||
function set_name(name)
|
||||
{
|
||||
name = (name || '').trim();
|
||||
if (name) {
|
||||
test_name = name.replace(/\r/g, '\\r').replace(/\n/g, '\\n');
|
||||
}
|
||||
}
|
||||
|
||||
// test the input on beautifier with the current flag settings
|
||||
// does not check the indentation / surroundings as bt() does
|
||||
function test_fragment(input, expected)
|
||||
{
|
||||
var success = true;
|
||||
sanitytest.test_function(test_beautifier, test_name);
|
||||
expected = expected || expected === '' ? expected : input;
|
||||
sanitytest.expect(input, expected);
|
||||
success = success && sanitytest.expect(input, expected);
|
||||
// if the expected is different from input, run it again
|
||||
// expected output should be unchanged when run twice.
|
||||
if (expected !== input) {
|
||||
sanitytest.expect(expected, expected);
|
||||
if (success && expected !== input) {
|
||||
success = success && sanitytest.expect(expected, expected);
|
||||
}
|
||||
|
||||
// Everywhere we do newlines, they should be replaced with opts.eol
|
||||
sanitytest.test_function(test_beautifier, 'eol ' + test_name);
|
||||
opts.eol = '\r\\n';
|
||||
expected = expected.replace(/[\n]/g, '\r\n');
|
||||
sanitytest.expect(input, expected);
|
||||
if (input && input.indexOf('\n') !== -1) {
|
||||
opts.disabled = true;
|
||||
success = success && sanitytest.expect(input, input || '');
|
||||
success = success && sanitytest.expect('\n\n' + expected, '\n\n' + expected);
|
||||
opts.disabled = false;
|
||||
success = success && sanitytest.expect(input, expected);
|
||||
if (success && input && input.indexOf('\n') !== -1) {
|
||||
input = input.replace(/[\n]/g, '\r\n');
|
||||
sanitytest.expect(input, expected);
|
||||
// Ensure support for auto eol detection
|
||||
opts.eol = 'auto';
|
||||
sanitytest.expect(input, expected);
|
||||
success = success && sanitytest.expect(input, expected);
|
||||
}
|
||||
opts.eol = '\n';
|
||||
return success;
|
||||
}
|
||||
|
||||
// test css
|
||||
function t(input, expectation)
|
||||
{
|
||||
var success = true;
|
||||
var wrapped_input, wrapped_expectation;
|
||||
|
||||
expectation = expectation || expectation === '' ? expectation : input;
|
||||
sanitytest.test_function(test_css_beautifier, 'css_beautify');
|
||||
test_fragment(input, expectation);
|
||||
success = success && test_fragment(input, expectation);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
function unicode_char(value) {
|
||||
@ -112,6 +134,7 @@ function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_bea
|
||||
{{^matrix}}
|
||||
// {{&name}}
|
||||
reset_options();
|
||||
set_name('{{&name}}');
|
||||
{{#options}}
|
||||
opts.{{name}} = {{&value}};
|
||||
{{/options}}
|
||||
@ -123,6 +146,7 @@ function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_bea
|
||||
{{#matrix}}
|
||||
// {{&name}} - ({{#matrix_context_string}}.{{/matrix_context_string}})
|
||||
reset_options();
|
||||
set_name('{{&name}} - ({{#matrix_context_string}}.{{/matrix_context_string}})');
|
||||
{{#options}}
|
||||
opts.{{name}} = {{&value}};
|
||||
{{/options}}
|
||||
@ -142,6 +166,12 @@ function run_css_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_bea
|
||||
//============================================================
|
||||
test_fragment(null, '');
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
// Test user pebkac protection, converts dash names to underscored names
|
||||
opts["end-with-newline"] = true;
|
||||
test_fragment(null, '\n');
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
// test basic css beautifier
|
||||
|
@ -109,6 +109,15 @@ class CSSBeautifierTest(unittest.TestCase):
|
||||
#============================================================
|
||||
t(None, "")
|
||||
|
||||
self.reset_options()
|
||||
#============================================================
|
||||
# Test user pebkac protection, converts dash names to underscored names
|
||||
setattr(self.options, 'end-with-newline', True)
|
||||
t(None, '\n')
|
||||
|
||||
self.reset_options()
|
||||
#============================================================
|
||||
|
||||
t("", "")
|
||||
t("\n", "")
|
||||
t(".tabs{}\n", ".tabs {}")
|
||||
@ -258,6 +267,12 @@ class CSSBeautifierTest(unittest.TestCase):
|
||||
# Everywhere we do newlines, they should be replaced with opts.eol
|
||||
self.options.eol = '\r\\n'
|
||||
expectation = expectation.replace('\n', '\r\n')
|
||||
self.options.disabled = True
|
||||
self.assertMultiLineEqual(
|
||||
cssbeautifier.beautify(input, self.options), input or '')
|
||||
self.assertMultiLineEqual(
|
||||
cssbeautifier.beautify('\n\n' + expectation, self.options), '\n\n' + expectation)
|
||||
self.options.disabled = False;
|
||||
self.assertMultiLineEqual(
|
||||
cssbeautifier.beautify(input, self.options), expectation)
|
||||
if input and input.find('\n') != -1:
|
||||
|
@ -56,6 +56,99 @@ exports.test_data = {
|
||||
{ fragment: true, input: ' \n\n.tabs{}\n\n\n\n', output: ' .tabs {}{{eof}}' },
|
||||
{ fragment: true, input: '\n', output: '{{eof}}' }
|
||||
]
|
||||
}, {
|
||||
name: "Support Indent Level Options and Base Indent Autodetection",
|
||||
description: "If user specifies indent level, use it. If not, autodetect indent level from starting whitespace.",
|
||||
matrix: [{
|
||||
options: [
|
||||
{ name: "indent_size", value: "4" },
|
||||
{ name: "indent_char", value: "' '" },
|
||||
{ name: "indent_with_tabs", value: "false" }
|
||||
],
|
||||
input_start_indent: ' ',
|
||||
output_start_of_base: ' ',
|
||||
i: ' '
|
||||
}, {
|
||||
options: [
|
||||
{ name: "indent_size", value: "4" },
|
||||
{ name: "indent_char", value: "' '" },
|
||||
{ name: "indent_with_tabs", value: "false" },
|
||||
{ name: "indent_level", value: "0" }
|
||||
],
|
||||
input_start_indent: ' ',
|
||||
output_start_of_base: ' ',
|
||||
i: ' '
|
||||
}, {
|
||||
options: [
|
||||
{ name: "indent_size", value: "4" },
|
||||
{ name: "indent_char", value: "' '" },
|
||||
{ name: "indent_with_tabs", value: "false" },
|
||||
{ name: "indent_level", value: "1" }
|
||||
],
|
||||
input_start_indent: ' ',
|
||||
output_start_of_base: ' ',
|
||||
i: ' '
|
||||
}, {
|
||||
options: [
|
||||
{ name: "indent_size", value: "4" },
|
||||
{ name: "indent_char", value: "' '" },
|
||||
{ name: "indent_with_tabs", value: "false" },
|
||||
{ name: "indent_level", value: "2" }
|
||||
],
|
||||
input_start_indent: '',
|
||||
output_start_of_base: ' ',
|
||||
i: ' '
|
||||
}, {
|
||||
options: [
|
||||
{ name: "indent_size", value: "4" },
|
||||
{ name: "indent_char", value: "' '" },
|
||||
{ name: "indent_with_tabs", value: "true" },
|
||||
{ name: "indent_level", value: "2" }
|
||||
],
|
||||
input_start_indent: '',
|
||||
output_start_of_base: '\t\t',
|
||||
i: '\t'
|
||||
}, {
|
||||
options: [
|
||||
{ name: "indent_size", value: "4" },
|
||||
{ name: "indent_char", value: "' '" },
|
||||
{ name: "indent_with_tabs", value: "false" },
|
||||
{ name: "indent_level", value: "0" }
|
||||
],
|
||||
input_start_indent: '\t ',
|
||||
output_start_of_base: '\t ',
|
||||
i: ' '
|
||||
}],
|
||||
tests: [
|
||||
{ fragment: true, input: '{{input_start_indent}}a', output: '{{output_start_of_base}}a' },
|
||||
{
|
||||
fragment: true,
|
||||
input: [
|
||||
'{{input_start_indent}}.a {',
|
||||
' text-align: right;',
|
||||
'}'
|
||||
],
|
||||
output: [
|
||||
'{{output_start_of_base}}.a {',
|
||||
'{{output_start_of_base}}{{i}}text-align: right;',
|
||||
'{{output_start_of_base}}}'
|
||||
]
|
||||
}, {
|
||||
fragment: true,
|
||||
input: [
|
||||
'{{input_start_indent}}// This is a random comment',
|
||||
'.a {',
|
||||
' text-align: right;',
|
||||
'}'
|
||||
],
|
||||
output: [
|
||||
'{{output_start_of_base}}// This is a random comment',
|
||||
'{{output_start_of_base}}.a {',
|
||||
'{{output_start_of_base}}{{i}}text-align: right;',
|
||||
'{{output_start_of_base}}}'
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
name: "Empty braces",
|
||||
description: "",
|
||||
@ -72,6 +165,18 @@ exports.test_data = {
|
||||
tests: [{
|
||||
input: '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity = 90);\n}',
|
||||
output: '#cboxOverlay {\n\tbackground: url(images/overlay.png) repeat 0 0;\n\topacity: 0.9;\n\tfilter: alpha(opacity=90);\n}'
|
||||
}, {
|
||||
comment: 'simple data uri base64 test',
|
||||
input: 'a { background: url(data:image/gif;base64,R0lGODlhCwALAJEAAAAAAP///xUVFf///yH5BAEAAAMALAAAAAALAAsAAAIPnI+py+0/hJzz0IruwjsVADs=); }',
|
||||
output: 'a {\n\tbackground: url(data:image/gif;base64,R0lGODlhCwALAJEAAAAAAP///xUVFf///yH5BAEAAAMALAAAAAALAAsAAAIPnI+py+0/hJzz0IruwjsVADs=);\n}'
|
||||
}, {
|
||||
comment: 'non-base64 data',
|
||||
input: 'a { background: url(data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E); }',
|
||||
output: 'a {\n\tbackground: url(data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E);\n}'
|
||||
}, {
|
||||
comment: 'Beautifier does not fix or mitigate bad data uri',
|
||||
input: 'a { background: url(data: image/gif base64,R0lGODlhCwALAJEAAAAAAP///xUVFf///yH5BAEAAAMALAAAAAALAAsAAAIPnI+py+0/hJzz0IruwjsVADs=); }',
|
||||
output: 'a {\n\tbackground: url(data: image/gif base64,R0lGODlhCwALAJEAAAAAAP///xUVFf///yH5BAEAAAMALAAAAAALAAsAAAIPnI+py+0/hJzz0IruwjsVADs=);\n}'
|
||||
}]
|
||||
}, {
|
||||
name: "Support simple language specific option inheritance/overriding",
|
||||
@ -167,46 +272,95 @@ exports.test_data = {
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
name: "Issue 1373 -- Correct spacing around [attribute~=value]",
|
||||
description: "",
|
||||
tests: [{
|
||||
unchanged: 'header>div[class~="div-all"]'
|
||||
}]
|
||||
}, {
|
||||
name: 'Selector Separator',
|
||||
description: '',
|
||||
matrix: [{
|
||||
options: [
|
||||
{ name: 'selector_separator_newline', value: 'false' },
|
||||
{ name: 'selector_separator', value: '" "' }
|
||||
{ name: 'selector_separator', value: '" "' },
|
||||
{ name: "newline_between_rules", value: "true" }
|
||||
],
|
||||
separator: ' ',
|
||||
separator1: ' '
|
||||
separator1: ' ',
|
||||
new_rule: '\n',
|
||||
first_nested_rule: ''
|
||||
}, {
|
||||
options: [
|
||||
{ name: 'selector_separator_newline', value: 'false' },
|
||||
{ name: 'selector_separator', value: '" "' }
|
||||
{ name: 'selector_separator', value: '" "' },
|
||||
{ name: "newline_between_rules", value: "false" }
|
||||
],
|
||||
separator: ' ',
|
||||
separator1: ' ',
|
||||
new_rule: '',
|
||||
first_nested_rule: ''
|
||||
}, {
|
||||
options: [
|
||||
{ name: 'selector_separator_newline', value: 'false' },
|
||||
{ name: 'selector_separator', value: '" "' },
|
||||
{ name: "newline_between_rules", value: "false" }
|
||||
],
|
||||
// BUG: #713
|
||||
separator: ' ',
|
||||
separator1: ' '
|
||||
separator1: ' ',
|
||||
new_rule: '',
|
||||
first_nested_rule: ''
|
||||
}, {
|
||||
options: [
|
||||
{ name: 'selector_separator_newline', value: 'true' },
|
||||
{ name: 'selector_separator', value: '" "' }
|
||||
{ name: 'selector_separator', value: '" "' },
|
||||
{ name: "newline_between_rules", value: "true" }
|
||||
],
|
||||
separator: '\\n',
|
||||
separator1: '\\n\\t'
|
||||
separator1: '\\n\\t',
|
||||
new_rule: '\n',
|
||||
first_nested_rule: '\n' // bug #1489
|
||||
}, {
|
||||
options: [
|
||||
{ name: 'selector_separator_newline', value: 'true' },
|
||||
{ name: 'selector_separator', value: '" "' }
|
||||
{ name: 'selector_separator', value: '" "' },
|
||||
{ name: "newline_between_rules", value: "false" }
|
||||
],
|
||||
separator: '\\n',
|
||||
separator1: '\\n\\t'
|
||||
separator1: '\\n\\t',
|
||||
new_rule: '',
|
||||
first_nested_rule: ''
|
||||
}, {
|
||||
options: [
|
||||
{ name: 'selector_separator_newline', value: 'true' },
|
||||
{ name: 'selector_separator', value: '" "' },
|
||||
{ name: "newline_between_rules", value: "false" }
|
||||
],
|
||||
separator: '\\n',
|
||||
separator1: '\\n\\t',
|
||||
new_rule: '',
|
||||
new_rule_bug: ''
|
||||
}],
|
||||
tests: [
|
||||
{ input: '#bla, #foo{color:green}', output: '#bla,{{separator}}#foo {\n\tcolor: green\n}' },
|
||||
{ input: '#bla, #foo{color:green}\n#bla, #foo{color:green}', output: '#bla,{{separator}}#foo {\n\tcolor: green\n}{{new_rule}}\n#bla,{{separator}}#foo {\n\tcolor: green\n}' },
|
||||
{ input: '@media print {.tab{}}', output: '@media print {\n\t.tab {}\n}' },
|
||||
{ input: '@media print {.tab,.bat{}}', output: '@media print {\n\t.tab,{{separator1}}.bat {}\n}' },
|
||||
|
||||
{
|
||||
comment: 'This is bug #1489',
|
||||
input: '@media print {.tab,.bat{}}',
|
||||
output: '@media print {\n{{first_nested_rule}}\t.tab,{{separator1}}.bat {}\n}'
|
||||
},
|
||||
{
|
||||
comment: 'This is bug #1489',
|
||||
input: '@media print {// comment\n//comment 2\n.bat{}}',
|
||||
output: '@media print {\n{{new_rule}}\t// comment\n\t//comment 2\n\t.bat {}\n}'
|
||||
},
|
||||
{ input: '#bla, #foo{color:black}', output: '#bla,{{separator}}#foo {\n\tcolor: black\n}' }, {
|
||||
input: 'a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}',
|
||||
output: 'a:first-child,{{separator}}a:first-child {\n\tcolor: red;\n\tdiv:first-child,{{separator1}}div:hover {\n\t\tcolor: black;\n\t}\n}'
|
||||
input: 'a:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}\na:first-child,a:first-child{color:red;div:first-child,div:hover{color:black;}}',
|
||||
output: 'a:first-child,{{separator}}a:first-child {\n\tcolor: red;{{new_rule}}\n\tdiv:first-child,{{separator1}}div:hover {\n\t\tcolor: black;\n\t}\n}\n{{new_rule}}a:first-child,{{separator}}a:first-child {\n\tcolor: red;{{new_rule}}\n\tdiv:first-child,{{separator1}}div:hover {\n\t\tcolor: black;\n\t}\n}'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
@ -257,6 +411,13 @@ exports.test_data = {
|
||||
input: '.tool-tip {\n\tposition: relative;\n\n\t\t\n\t.tool-tip-content {\n\t\t&>* {\n\t\t\tmargin-top: 0;\n\t\t}\n\t\t\n\n\t\t.mixin-box-shadow(.2rem .2rem .5rem rgba(0, 0, 0, .15));\n\t\tpadding: 1rem;\n\t\tposition: absolute;\n\t\tz-index: 10;\n\t}\n}',
|
||||
output: '.tool-tip {\n\tposition: relative;\n\n\n\t.tool-tip-content {\n\t\t&>* {\n\t\t\tmargin-top: 0;\n\t\t}\n\\n\\n\t\t.mixin-box-shadow(.2rem .2rem .5rem rgba(0, 0, 0, .15));\n\t\tpadding: 1rem;\n\t\tposition: absolute;\n\t\tz-index: 10;\n\t}\n}'
|
||||
}]
|
||||
}, {
|
||||
name: "Issue #1338 -- Preserve Newlines within CSS rules",
|
||||
options: [{ name: "preserve_newlines", value: "true" }],
|
||||
description: "",
|
||||
tests: [{
|
||||
unchanged: 'body {\n\tgrid-template-areas:\n\t\t"header header"\n\t\t"main sidebar"\n\t\t"footer footer";\n}'
|
||||
}]
|
||||
}, {
|
||||
name: "Newline Between Rules",
|
||||
description: "",
|
||||
@ -264,28 +425,238 @@ exports.test_data = {
|
||||
options: [
|
||||
{ name: "newline_between_rules", value: "true" }
|
||||
],
|
||||
new_rule: '\n\n'
|
||||
new_rule: '\n'
|
||||
}, {
|
||||
options: [
|
||||
{ name: "newline_between_rules", value: "false" }
|
||||
],
|
||||
new_rule: '\n'
|
||||
new_rule: ''
|
||||
}],
|
||||
tests: [
|
||||
{ input: '.div {}\n.span {}', output: '.div {}{{new_rule}}.span {}' },
|
||||
{ input: '.div{}\n \n.span{}', output: '.div {}{{new_rule}}.span {}' },
|
||||
{ input: '.div {} \n \n.span { } \n', output: '.div {}{{new_rule}}.span {}' },
|
||||
{ input: '.div {\n \n} \n .span {\n } ', output: '.div {}{{new_rule}}.span {}' },
|
||||
{ input: '.div {}\n.span {}', output: '.div {}\n{{new_rule}}.span {}' },
|
||||
{ input: '.div{}\n \n.span{}', output: '.div {}\n{{new_rule}}.span {}' },
|
||||
{ input: '.div {} \n \n.span { } \n', output: '.div {}\n{{new_rule}}.span {}' },
|
||||
{ input: '.div {\n \n} \n .span {\n } ', output: '.div {}\n{{new_rule}}.span {}' },
|
||||
{
|
||||
input: '.selector1 {\n\tmargin: 0; /* This is a comment including an url http://domain.com/path/to/file.ext */\n}\n.div{height:15px;}',
|
||||
output: '.selector1 {\n\tmargin: 0;\n\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n}{{new_rule}}.div {\n\theight: 15px;\n}'
|
||||
output: '.selector1 {\n\tmargin: 0;\n\t/* This is a comment including an url http://domain.com/path/to/file.ext */\n}\n{{new_rule}}.div {\n\theight: 15px;\n}'
|
||||
},
|
||||
{ input: '.tabs{width:10px;//end of line comment\nheight:10px;//another\n}\n.div{height:15px;}', output: '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px; //another\n}{{new_rule}}.div {\n\theight: 15px;\n}' },
|
||||
{ input: '#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', output: '#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}{{new_rule}}.div {\n\theight: 15px;\n}' },
|
||||
{ input: '@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', output: '@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}{{new_rule}}.div {\n\theight: 15px;\n}' },
|
||||
{ input: '@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}', output: '@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}{{new_rule}}@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}' },
|
||||
{ input: 'a:first-child{color:red;div:first-child{color:black;}}\n.div{height:15px;}', output: 'a:first-child {\n\tcolor: red;\n\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}{{new_rule}}.div {\n\theight: 15px;\n}' },
|
||||
{ input: 'a:first-child{color:red;div:not(.peq){color:black;}}\n.div{height:15px;}', output: 'a:first-child {\n\tcolor: red;\n\tdiv:not(.peq) {\n\t\tcolor: black;\n\t}\n}{{new_rule}}.div {\n\theight: 15px;\n}' }
|
||||
{ input: '.tabs{width:10px;//end of line comment\nheight:10px;//another\n}\n.div{height:15px;}', output: '.tabs {\n\twidth: 10px; //end of line comment\n\theight: 10px; //another\n}\n{{new_rule}}.div {\n\theight: 15px;\n}' },
|
||||
{ input: '#foo {\n\tbackground-image: url(foo@2x.png);\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', output: '#foo {\n\tbackground-image: url(foo@2x.png);\n{{new_rule}}\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n{{new_rule}}.div {\n\theight: 15px;\n}' },
|
||||
{ input: '@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n.div{height:15px;}', output: '@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo@2x.png);\n\t}\n{{new_rule}}\t@font-face {\n\t\tfont-family: "Bitstream Vera Serif Bold";\n\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n\t}\n}\n{{new_rule}}.div {\n\theight: 15px;\n}' },
|
||||
{ input: '@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}\n@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}', output: '@font-face {\n\tfont-family: "Bitstream Vera Serif Bold";\n\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");\n}\n{{new_rule}}@media screen {\n\t#foo:hover {\n\t\tbackground-image: url(foo.png);\n\t}\n{{new_rule}}\t@media screen and (min-device-pixel-ratio: 2) {\n\t\t@font-face {\n\t\t\tfont-family: "Helvetica Neue"\n\t\t}\n{{new_rule}}\t\t#foo:hover {\n\t\t\tbackground-image: url(foo@2x.png);\n\t\t}\n\t}\n}' },
|
||||
{ input: 'a:first-child{color:red;div:first-child{color:black;}}\n.div{height:15px;}', output: 'a:first-child {\n\tcolor: red;\n{{new_rule}}\tdiv:first-child {\n\t\tcolor: black;\n\t}\n}\n{{new_rule}}.div {\n\theight: 15px;\n}' },
|
||||
{ input: 'a:first-child{color:red;div:not(.peq){color:black;}}\n.div{height:15px;}', output: 'a:first-child {\n\tcolor: red;\n{{new_rule}}\tdiv:not(.peq) {\n\t\tcolor: black;\n\t}\n}\n{{new_rule}}.div {\n\theight: 15px;\n}' },
|
||||
{
|
||||
input_: [
|
||||
'.list-group {',
|
||||
'\t.list-group-item {',
|
||||
'\t}',
|
||||
'',
|
||||
'\t.list-group-icon {',
|
||||
'\t}',
|
||||
'}',
|
||||
'',
|
||||
'.list-group-condensed {',
|
||||
'}'
|
||||
],
|
||||
output: [
|
||||
'.list-group {',
|
||||
'\t.list-group-item {}',
|
||||
'{{new_rule}}\t.list-group-icon {}',
|
||||
'}',
|
||||
'{{new_rule}}.list-group-condensed {}'
|
||||
]
|
||||
},
|
||||
{
|
||||
input_: [
|
||||
'.list-group {',
|
||||
'\t.list-group-item {',
|
||||
'\t\ta:1',
|
||||
'\t}',
|
||||
'\t.list-group-item {',
|
||||
'\t\ta:1',
|
||||
'\t}',
|
||||
'\t.list-group-icon {',
|
||||
'\t}',
|
||||
'\t.list-group-icon {',
|
||||
'\t}',
|
||||
'}',
|
||||
'.list-group-condensed {',
|
||||
'}'
|
||||
],
|
||||
output: [
|
||||
'.list-group {',
|
||||
'\t.list-group-item {',
|
||||
'\t\ta: 1',
|
||||
'\t}',
|
||||
'{{new_rule}}\t.list-group-item {',
|
||||
'\t\ta: 1',
|
||||
'\t}',
|
||||
'{{new_rule}}\t.list-group-icon {}',
|
||||
'{{new_rule}}\t.list-group-icon {}',
|
||||
'}',
|
||||
'{{new_rule}}.list-group-condensed {}'
|
||||
]
|
||||
},
|
||||
{
|
||||
input_: [
|
||||
'.list-group {',
|
||||
'\t.list-group-item {',
|
||||
'\t\ta:1',
|
||||
'\t}',
|
||||
'\t//this is my pre-comment',
|
||||
'\t.list-group-item {',
|
||||
'\t\ta:1',
|
||||
'\t}',
|
||||
'\t//this is a comment',
|
||||
'\t.list-group-icon {',
|
||||
'\t}',
|
||||
'\t//this is also a comment',
|
||||
'\t.list-group-icon {',
|
||||
'\t}',
|
||||
'}',
|
||||
'.list-group-condensed {',
|
||||
'}'
|
||||
],
|
||||
output: [
|
||||
'.list-group {',
|
||||
'\t.list-group-item {',
|
||||
'\t\ta: 1',
|
||||
'\t}',
|
||||
'{{new_rule}}\t//this is my pre-comment',
|
||||
'\t.list-group-item {',
|
||||
'\t\ta: 1',
|
||||
'\t}',
|
||||
'{{new_rule}}\t//this is a comment',
|
||||
'\t.list-group-icon {}',
|
||||
'{{new_rule}}\t//this is also a comment',
|
||||
'\t.list-group-icon {}',
|
||||
'}',
|
||||
'{{new_rule}}.list-group-condensed {}'
|
||||
]
|
||||
},
|
||||
{
|
||||
input_: [
|
||||
'.list-group {',
|
||||
'\tcolor: #38a0e5;',
|
||||
'\t.list-group-item {',
|
||||
'\t\ta:1',
|
||||
'\t}',
|
||||
'\tcolor: #38a0e5;',
|
||||
'\t.list-group-item {',
|
||||
'\t\ta:1',
|
||||
'\t}',
|
||||
'color: #38a0e5;',
|
||||
'\t.list-group-icon {',
|
||||
'\t}',
|
||||
'\tcolor: #38a0e5;',
|
||||
'\t.list-group-icon {',
|
||||
'\t}',
|
||||
'}',
|
||||
'color: #38a0e5;',
|
||||
'.list-group-condensed {',
|
||||
'}'
|
||||
],
|
||||
output: [
|
||||
'.list-group {',
|
||||
'\tcolor: #38a0e5;',
|
||||
'{{new_rule}}\t.list-group-item {',
|
||||
'\t\ta: 1',
|
||||
'\t}',
|
||||
'{{new_rule}}\tcolor: #38a0e5;',
|
||||
'{{new_rule}}\t.list-group-item {',
|
||||
'\t\ta: 1',
|
||||
'\t}',
|
||||
'{{new_rule}}\tcolor: #38a0e5;',
|
||||
'{{new_rule}}\t.list-group-icon {}',
|
||||
'{{new_rule}}\tcolor: #38a0e5;',
|
||||
'{{new_rule}}\t.list-group-icon {}',
|
||||
'}',
|
||||
'{{new_rule}}color: #38a0e5;',
|
||||
'{{new_rule}}.list-group-condensed {}'
|
||||
]
|
||||
},
|
||||
{
|
||||
input_: [
|
||||
'@media only screen and (max-width: 40em) {',
|
||||
'header {',
|
||||
' margin: 0 auto;',
|
||||
' padding: 10px;',
|
||||
' background: red;',
|
||||
' }',
|
||||
'main {',
|
||||
' margin: 20px auto;',
|
||||
' padding: 4px;',
|
||||
' background: blue;',
|
||||
' }',
|
||||
'}'
|
||||
],
|
||||
output: [
|
||||
'@media only screen and (max-width: 40em) {',
|
||||
'\theader {',
|
||||
'\t\tmargin: 0 auto;',
|
||||
'\t\tpadding: 10px;',
|
||||
'\t\tbackground: red;',
|
||||
'\t}',
|
||||
'{{new_rule}}\tmain {',
|
||||
'\t\tmargin: 20px auto;',
|
||||
'\t\tpadding: 4px;',
|
||||
'\t\tbackground: blue;',
|
||||
'\t}',
|
||||
'}'
|
||||
]
|
||||
},
|
||||
{
|
||||
input_: [
|
||||
'.preloader {',
|
||||
'\theight: 20px;',
|
||||
'\t.line {',
|
||||
'\t\twidth: 1px;',
|
||||
'\t\theight: 12px;',
|
||||
'\t\tbackground: #38a0e5;',
|
||||
'\t\tmargin: 0 1px;',
|
||||
'\t\tdisplay: inline-block;',
|
||||
'\t\t&.line-1 {',
|
||||
'\t\t\tanimation-delay: 800ms;',
|
||||
'\t\t}',
|
||||
'\t\t&.line-2 {',
|
||||
'\t\t\tanimation-delay: 600ms;',
|
||||
'\t\t}',
|
||||
'\t}',
|
||||
'\tdiv {',
|
||||
'\t\tcolor: #38a0e5;',
|
||||
'\t\tfont-family: "Arial", sans-serif;',
|
||||
'\t\tfont-size: 10px;',
|
||||
'\t\tmargin: 5px 0;',
|
||||
'\t}',
|
||||
'}'
|
||||
],
|
||||
output: [
|
||||
'.preloader {',
|
||||
'\theight: 20px;',
|
||||
'{{new_rule}}\t.line {',
|
||||
'\t\twidth: 1px;',
|
||||
'\t\theight: 12px;',
|
||||
'\t\tbackground: #38a0e5;',
|
||||
'\t\tmargin: 0 1px;',
|
||||
'\t\tdisplay: inline-block;',
|
||||
'{{new_rule}}\t\t&.line-1 {',
|
||||
'\t\t\tanimation-delay: 800ms;',
|
||||
'\t\t}',
|
||||
'{{new_rule}}\t\t&.line-2 {',
|
||||
'\t\t\tanimation-delay: 600ms;',
|
||||
'\t\t}',
|
||||
'\t}',
|
||||
'{{new_rule}}\tdiv {',
|
||||
'\t\tcolor: #38a0e5;',
|
||||
'\t\tfont-family: "Arial", sans-serif;',
|
||||
'\t\tfont-size: 10px;',
|
||||
'\t\tmargin: 5px 0;',
|
||||
'\t}',
|
||||
'}'
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
name: "Functions braces",
|
||||
@ -434,6 +805,14 @@ exports.test_data = {
|
||||
}],
|
||||
tests: [
|
||||
{ unchanged: '/* header comment newlines on */' },
|
||||
{
|
||||
input: [
|
||||
'@import "custom.css";<i>.rule{}'
|
||||
],
|
||||
output: [
|
||||
'@import "custom.css";<new_rule>.rule {}'
|
||||
]
|
||||
},
|
||||
{ input: '.tabs{<i>/* test */<i>}', output: '.tabs {<o>\t/* test */<o>}' },
|
||||
{
|
||||
comment: '#1185',
|
||||
@ -525,23 +904,23 @@ exports.test_data = {
|
||||
},
|
||||
{
|
||||
input: '#foo {<i>background-image: url(foo@2x.png);<i>\t@font-face {<i>\t\tfont-family: "Bitstream Vera Serif Bold";<i>\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");<i>\t}<i>}<i>.div{<i>height:15px;<i>}',
|
||||
output: '#foo {<o>\tbackground-image: url(foo@2x.png);<o>\t@font-face {<o>\t\tfont-family: "Bitstream Vera Serif Bold";<o>\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");<o>\t}<o>}<new_rule>.div {<o>\theight: 15px;<o>}'
|
||||
output: '#foo {<o>\tbackground-image: url(foo@2x.png);<new_rule>\t@font-face {<o>\t\tfont-family: "Bitstream Vera Serif Bold";<o>\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");<o>\t}<o>}<new_rule>.div {<o>\theight: 15px;<o>}'
|
||||
},
|
||||
{
|
||||
input: '@media screen {<i>\t#foo:hover {<i>\t\tbackground-image: url(foo@2x.png);<i>\t}<i>\t@font-face {<i>\t\tfont-family: "Bitstream Vera Serif Bold";<i>\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");<i>\t}<i>}<i>.div{<i>height:15px;<i>}',
|
||||
output: '@media screen {<o>\t#foo:hover {<o>\t\tbackground-image: url(foo@2x.png);<o>\t}<o>\t@font-face {<o>\t\tfont-family: "Bitstream Vera Serif Bold";<o>\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");<o>\t}<o>}<new_rule>.div {<o>\theight: 15px;<o>}'
|
||||
output: '@media screen {<o>\t#foo:hover {<o>\t\tbackground-image: url(foo@2x.png);<o>\t}<new_rule>\t@font-face {<o>\t\tfont-family: "Bitstream Vera Serif Bold";<o>\t\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");<o>\t}<o>}<new_rule>.div {<o>\theight: 15px;<o>}'
|
||||
},
|
||||
{
|
||||
input: '@font-face {<i>\tfont-family: "Bitstream Vera Serif Bold";<i>\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");<i>}<i1>@media screen {<i>\t#foo:hover {<i>\t\tbackground-image: url(foo.png);<i>\t}<i>\t@media screen and (min-device-pixel-ratio: 2) {<i>\t\t@font-face {<i>\t\t\tfont-family: "Helvetica Neue";<i>\t\t}<i>\t\t#foo:hover {<i>\t\t\tbackground-image: url(foo@2x.png);<i>\t\t}<i>\t}<i>}',
|
||||
output: '@font-face {<o>\tfont-family: "Bitstream Vera Serif Bold";<o>\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");<o>}<new_rule>@media screen {<o>\t#foo:hover {<o>\t\tbackground-image: url(foo.png);<o>\t}<o>\t@media screen and (min-device-pixel-ratio: 2) {<o>\t\t@font-face {<o>\t\t\tfont-family: "Helvetica Neue";<o>\t\t}<o>\t\t#foo:hover {<o>\t\t\tbackground-image: url(foo@2x.png);<o>\t\t}<o>\t}<o>}'
|
||||
output: '@font-face {<o>\tfont-family: "Bitstream Vera Serif Bold";<o>\tsrc: url("http://developer.mozilla.org/@api/deki/files/2934/=VeraSeBd.ttf");<o>}<new_rule>@media screen {<o>\t#foo:hover {<o>\t\tbackground-image: url(foo.png);<o>\t}<new_rule>\t@media screen and (min-device-pixel-ratio: 2) {<o>\t\t@font-face {<o>\t\t\tfont-family: "Helvetica Neue";<o>\t\t}<new_rule>\t\t#foo:hover {<o>\t\t\tbackground-image: url(foo@2x.png);<o>\t\t}<o>\t}<o>}'
|
||||
},
|
||||
{
|
||||
input: 'a:first-child{<i>color:red;<i>div:first-child{<i>color:black;<i>}<i>}<i>.div{<i>height:15px;<i>}',
|
||||
output: 'a:first-child {<o>\tcolor: red;<o>\tdiv:first-child {<o>\t\tcolor: black;<o>\t}<o>}<new_rule>.div {<o>\theight: 15px;<o>}'
|
||||
output: 'a:first-child {<o>\tcolor: red;<new_rule>\tdiv:first-child {<o>\t\tcolor: black;<o>\t}<o>}<new_rule>.div {<o>\theight: 15px;<o>}'
|
||||
},
|
||||
{
|
||||
input: 'a:first-child{<i>color:red;<i>div:not(.peq){<i>color:black;<i>}<i>}<i>.div{<i>height:15px;<i>}',
|
||||
output: 'a:first-child {<o>\tcolor: red;<o>\tdiv:not(.peq) {<o>\t\tcolor: black;<o>\t}<o>}<new_rule>.div {<o>\theight: 15px;<o>}'
|
||||
output: 'a:first-child {<o>\tcolor: red;<new_rule>\tdiv:not(.peq) {<o>\t\tcolor: black;<o>\t}<o>}<new_rule>.div {<o>\theight: 15px;<o>}'
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -689,6 +1068,36 @@ exports.test_data = {
|
||||
'}'
|
||||
]
|
||||
}]
|
||||
}, {
|
||||
name: "Issue #645",
|
||||
description: "",
|
||||
options: [
|
||||
{ name: "selector_separator_newline", value: "true" },
|
||||
{ name: "preserve_newlines", value: "true" },
|
||||
{ name: "newline_between_rules", value: "true" }
|
||||
|
||||
],
|
||||
tests: [{
|
||||
unchanged: [
|
||||
'/* Comment above first rule */',
|
||||
'',
|
||||
'body {',
|
||||
'\tdisplay: none;',
|
||||
'}',
|
||||
'',
|
||||
'/* Comment between rules */',
|
||||
'',
|
||||
'ul,',
|
||||
'',
|
||||
'/* Comment between selectors */',
|
||||
'',
|
||||
'li {',
|
||||
'\tdisplay: none;',
|
||||
'}',
|
||||
'',
|
||||
'/* Comment after last rule */'
|
||||
]
|
||||
}]
|
||||
}, {
|
||||
name: "Extend Tests",
|
||||
description: "Test for '@extend'",
|
||||
@ -714,6 +1123,33 @@ exports.test_data = {
|
||||
'}'
|
||||
]
|
||||
}]
|
||||
}, {
|
||||
name: "Import Tests",
|
||||
description: "Test for '@import'",
|
||||
options: [],
|
||||
tests: [{
|
||||
input: [
|
||||
'@import "custom.css";.rule{}',
|
||||
'a, p {}'
|
||||
],
|
||||
output: [
|
||||
'@import "custom.css";',
|
||||
'.rule {}',
|
||||
'a,',
|
||||
'p {}'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'@import url("bluish.css") projection,tv;.rule{}',
|
||||
'a, p {}'
|
||||
],
|
||||
output: [
|
||||
'@import url("bluish.css") projection, tv;',
|
||||
'.rule {}',
|
||||
'a,',
|
||||
'p {}'
|
||||
]
|
||||
}]
|
||||
}, {
|
||||
name: "Important ",
|
||||
description: "Spacing of !important",
|
||||
|
@ -26,6 +26,7 @@
|
||||
SOFTWARE.
|
||||
*/
|
||||
/*jshint unused:false */
|
||||
/*jshint strict:false */
|
||||
|
||||
function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_beautify)
|
||||
{
|
||||
@ -50,55 +51,75 @@ function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_be
|
||||
function reset_options()
|
||||
{
|
||||
opts = JSON.parse(JSON.stringify(default_opts));
|
||||
test_name = 'html-beautify';
|
||||
}
|
||||
|
||||
function test_html_beautifier(input)
|
||||
function test_beautifier(input)
|
||||
{
|
||||
return html_beautify(input, opts);
|
||||
}
|
||||
|
||||
var sanitytest;
|
||||
var test_name = '';
|
||||
|
||||
function set_name(name)
|
||||
{
|
||||
name = (name || '').trim();
|
||||
if (name) {
|
||||
test_name = name.replace(/\r/g, '\\r').replace(/\n/g, '\\n');
|
||||
}
|
||||
}
|
||||
|
||||
// test the input on beautifier with the current flag settings
|
||||
// does not check the indentation / surroundings as bt() does
|
||||
function test_fragment(input, expected)
|
||||
{
|
||||
var success = true;
|
||||
sanitytest.test_function(test_beautifier, test_name);
|
||||
expected = expected || expected === '' ? expected : input;
|
||||
sanitytest.expect(input, expected);
|
||||
success = success && sanitytest.expect(input, expected);
|
||||
// if the expected is different from input, run it again
|
||||
// expected output should be unchanged when run twice.
|
||||
if (expected !== input) {
|
||||
sanitytest.expect(expected, expected);
|
||||
if (success && expected !== input) {
|
||||
success = success && sanitytest.expect(expected, expected);
|
||||
}
|
||||
|
||||
// Everywhere we do newlines, they should be replaced with opts.eol
|
||||
opts.eol = '\r\n';
|
||||
sanitytest.test_function(test_beautifier, 'eol ' + test_name);
|
||||
opts.eol = '\r\\n';
|
||||
expected = expected.replace(/[\n]/g, '\r\n');
|
||||
sanitytest.expect(input, expected);
|
||||
if (input && input.indexOf('\n') !== -1) {
|
||||
opts.disabled = true;
|
||||
success = success && sanitytest.expect(input, input || '');
|
||||
success = success && sanitytest.expect('\n\n' + expected, '\n\n' + expected);
|
||||
opts.disabled = false;
|
||||
success = success && sanitytest.expect(input, expected);
|
||||
if (success && input && input.indexOf('\n') !== -1) {
|
||||
input = input.replace(/[\n]/g, '\r\n');
|
||||
sanitytest.expect(input, expected);
|
||||
// Ensure support for auto eol detection
|
||||
opts.eol = 'auto';
|
||||
sanitytest.expect(input, expected);
|
||||
success = success && sanitytest.expect(input, expected);
|
||||
}
|
||||
opts.eol = '\n';
|
||||
return success;
|
||||
}
|
||||
|
||||
// test html
|
||||
function bth(input, expectation)
|
||||
{
|
||||
var success = true;
|
||||
|
||||
var wrapped_input, wrapped_expectation, field_input, field_expectation;
|
||||
|
||||
expectation = expectation || expectation === '' ? expectation : input;
|
||||
sanitytest.test_function(test_html_beautifier, 'html_beautify');
|
||||
test_fragment(input, expectation);
|
||||
success = success && test_fragment(input, expectation);
|
||||
|
||||
if (opts.indent_size === 4 && input) {
|
||||
wrapped_input = '<div>\n' + input.replace(/^(.+)$/mg, ' $1') + '\n <span>inline</span>\n</div>';
|
||||
wrapped_expectation = '<div>\n' + expectation.replace(/^(.+)$/mg, ' $1') + '\n <span>inline</span>\n</div>';
|
||||
test_fragment(wrapped_input, wrapped_expectation);
|
||||
success = success && test_fragment(wrapped_input, wrapped_expectation);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
function unicode_char(value) {
|
||||
@ -118,6 +139,7 @@ function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_be
|
||||
{{^matrix}}
|
||||
// {{&name}}
|
||||
reset_options();
|
||||
set_name('{{&name}}');
|
||||
{{#options}}
|
||||
opts.{{name}} = {{&value}};
|
||||
{{/options}}
|
||||
@ -129,6 +151,7 @@ function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_be
|
||||
{{#matrix}}
|
||||
// {{&name}} - ({{#matrix_context_string}}.{{/matrix_context_string}})
|
||||
reset_options();
|
||||
set_name('{{&name}} - ({{#matrix_context_string}}.{{/matrix_context_string}})');
|
||||
{{#options}}
|
||||
opts.{{name}} = {{&value}};
|
||||
{{/options}}
|
||||
@ -150,7 +173,15 @@ function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_be
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
// Test user pebkac protection, converts dash names to underscored names
|
||||
opts["end-with-newline"] = true;
|
||||
test_fragment(null, '\n');
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
set_name('end_with_newline = true');
|
||||
opts.end_with_newline = true;
|
||||
|
||||
test_fragment('', '\n');
|
||||
test_fragment('<div></div>\n');
|
||||
test_fragment('<div></div>\n\n\n', '<div></div>\n');
|
||||
@ -162,11 +193,17 @@ function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_be
|
||||
'</head>\n');
|
||||
|
||||
|
||||
opts.end_with_newline = false;
|
||||
reset_options();
|
||||
//============================================================
|
||||
set_name('Error cases');
|
||||
// error cases need love too
|
||||
bth('<img title="Bad food!" src="foo.jpg" alt="Evil" ">');
|
||||
bth("<!-- don't blow up if a comment is not complete"); // -->
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
set_name('Basic beautify');
|
||||
|
||||
test_fragment(
|
||||
'<head>\n' +
|
||||
' <script>\n' +
|
||||
@ -262,6 +299,9 @@ function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_be
|
||||
'<div> content <img> content </div>');
|
||||
bth('Text <a href="#">Link</a> Text');
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
set_name('content_unformatted = ["script", "style"]');
|
||||
var content_unformatted = opts.content_unformatted;
|
||||
opts.content_unformatted = ['script', 'style'];
|
||||
bth('<script id="javascriptTemplate" type="text/x-kendo-template">\n' +
|
||||
@ -275,7 +315,10 @@ function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_be
|
||||
' body {background-color:lightgrey}\n' +
|
||||
' h1 {color:blue}\n' +
|
||||
'</style>');
|
||||
opts.content_unformatted = content_unformatted;
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
set_name('inline = ["custom-element"]');
|
||||
|
||||
inline_tags = opts.inline;
|
||||
opts.inline = ['custom-element'];
|
||||
@ -285,6 +328,11 @@ function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_be
|
||||
' insert newlines</div>');
|
||||
opts.inline = inline_tags;
|
||||
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
set_name('line wrap tests');
|
||||
|
||||
bth('<div><span>content</span></div>');
|
||||
|
||||
// Handlebars tests
|
||||
@ -324,52 +372,49 @@ function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_be
|
||||
//...1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
bth('<div>Some test text that should wrap_inside_this section here.</div>',
|
||||
/* expected */
|
||||
'<div>Some test text that should wrap_inside_this\n' +
|
||||
' section here.</div>');
|
||||
'<div>Some test text that should\n' +
|
||||
' wrap_inside_this section here.</div>');
|
||||
|
||||
// Support passing string of number
|
||||
opts.wrap_line_length = "40";
|
||||
//...---------1---------2---------3---------4---------5---------6---------7
|
||||
//...1234567890123456789012345678901234567890123456789012345678901234567890
|
||||
bth('<div>Some test text that should wrap_inside_this section here.</div>',
|
||||
/* expected */
|
||||
'<div>Some test text that should wrap_inside_this\n' +
|
||||
' section here.</div>');
|
||||
'<div>Some test text that should\n' +
|
||||
' wrap_inside_this section here.</div>');
|
||||
|
||||
opts.indent_size = 1;
|
||||
opts.indent_char = '\t';
|
||||
opts.preserve_newlines = false;
|
||||
bth('<div>\n\tfoo\n</div>', '<div> foo </div>');
|
||||
opts.wrap_line_length = 80;
|
||||
// BUGBUG #1238 This is still wrong but is also a good regression test
|
||||
//...---------1---------2---------3---------4---------5---------6---------7---------8---------9--------10--------11--------12--------13--------14--------15--------16--------17--------18--------19--------20--------21--------22--------23--------24--------25--------26--------27--------28--------29
|
||||
bth('<span uib-tooltip="[[firstName]] [[lastName]]" tooltip-enable="showToolTip">\n' +
|
||||
' <ng-letter-avatar charCount="2" data="[[data]]"\n' +
|
||||
' shape="round" fontsize="[[font]]" height="[[height]]" width="[[width]]"\n' +
|
||||
' avatarcustombgcolor="[[bgColor]]" dynamic="true"></ng-letter-avatar>\n' +
|
||||
' </span>',
|
||||
/* expected */
|
||||
'<span uib-tooltip="[[firstName]] [[lastName]]" tooltip-enable="showToolTip">\n' +
|
||||
' <ng-letter-avatar charCount="2" data="[[data]]" shape="round" fontsize="[[font]]"\n' +
|
||||
' height="[[height]]" width="[[width]]" avatarcustombgcolor="[[bgColor]]"\n' +
|
||||
' dynamic="true"></ng-letter-avatar>\n' +
|
||||
'</span>');
|
||||
|
||||
opts.preserve_newlines = true;
|
||||
bth('<div>\n\tfoo\n</div>');
|
||||
// ISSUE #607 - preserve-newlines makes this look a bit odd now, but it much better
|
||||
test_fragment(
|
||||
'<p>В РАБОЧЕМ РЕЖИМЕ, после ввода параметров опыта (номер, шаг отсчетов и глубина зондирования), текущие\n' +
|
||||
' отсчеты сохраняются в контроллере при нажатии кнопки «ПУСК». Одновременно, они распечатываются\n' +
|
||||
' на минипринтере. Управлять контроллером для записи данных зондирования можно при помощи <link_row to="РК.05.01.01">Радиокнопки РК-11</link_row>.</p>',
|
||||
/* expected */
|
||||
'<p>В РАБОЧЕМ РЕЖИМЕ, после ввода параметров опыта (номер, шаг отсчетов и\n' +
|
||||
' глубина зондирования), текущие\n' +
|
||||
' отсчеты сохраняются в контроллере при нажатии кнопки «ПУСК». Одновременно,\n' +
|
||||
' они распечатываются\n' +
|
||||
' на минипринтере. Управлять контроллером для записи данных зондирования\n' +
|
||||
' можно при помощи <link_row to="РК.05.01.01">Радиокнопки РК-11</link_row>.</p>');
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
|
||||
|
||||
// test preserve_newlines and max_preserve_newlines
|
||||
opts.preserve_newlines = false;
|
||||
bth('<div>Should not</div>\n\n\n' +
|
||||
'<div>preserve newlines</div>',
|
||||
'<div>Should not</div>\n' +
|
||||
'<div>preserve newlines</div>');
|
||||
|
||||
opts.preserve_newlines = true;
|
||||
opts.max_preserve_newlines = 0;
|
||||
bth('<div>Should</div>\n\n\n' +
|
||||
'<div>preserve zero newlines</div>',
|
||||
'<div>Should</div>\n' +
|
||||
'<div>preserve zero newlines</div>');
|
||||
|
||||
opts.max_preserve_newlines = 1;
|
||||
bth('<div>Should</div>\n\n\n' +
|
||||
'<div>preserve one newline</div>',
|
||||
'<div>Should</div>\n\n' +
|
||||
'<div>preserve one newline</div>');
|
||||
|
||||
opts.max_preserve_newlines = null;
|
||||
bth('<div>Should</div>\n\n\n' +
|
||||
'<div>preserve one newline</div>',
|
||||
'<div>Should</div>\n\n\n' +
|
||||
'<div>preserve one newline</div>');
|
||||
}
|
||||
|
||||
beautifier_tests();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,7 @@
|
||||
SOFTWARE.
|
||||
*/
|
||||
/*jshint unused:false */
|
||||
/*jshint strict:false */
|
||||
|
||||
function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_beautify)
|
||||
{
|
||||
@ -35,8 +36,6 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
|
||||
indent_char: ' ',
|
||||
preserve_newlines: true,
|
||||
jslint_happy: false,
|
||||
keep_array_indentation: false,
|
||||
brace_style: 'collapse',
|
||||
space_before_conditional: true,
|
||||
break_chained_methods: false,
|
||||
selector_separator: '\n',
|
||||
@ -50,57 +49,75 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
|
||||
function reset_options()
|
||||
{
|
||||
opts = JSON.parse(JSON.stringify(default_opts));
|
||||
test_name = 'js-beautify';
|
||||
}
|
||||
|
||||
function test_js_beautifier(input)
|
||||
function test_beautifier(input)
|
||||
{
|
||||
return js_beautify(input, opts);
|
||||
}
|
||||
|
||||
var sanitytest;
|
||||
var test_name = '';
|
||||
|
||||
function set_name(name)
|
||||
{
|
||||
name = (name || '').trim();
|
||||
if (name) {
|
||||
test_name = name.replace(/\r/g, '\\r').replace(/\n/g, '\\n');
|
||||
}
|
||||
}
|
||||
|
||||
// test the input on beautifier with the current flag settings
|
||||
// does not check the indentation / surroundings as bt() does
|
||||
function test_fragment(input, expected)
|
||||
{
|
||||
var success = true;
|
||||
sanitytest.test_function(test_beautifier, test_name);
|
||||
expected = expected || expected === '' ? expected : input;
|
||||
sanitytest.expect(input, expected);
|
||||
success = success && sanitytest.expect(input, expected);
|
||||
// if the expected is different from input, run it again
|
||||
// expected output should be unchanged when run twice.
|
||||
if (expected !== input) {
|
||||
sanitytest.expect(expected, expected);
|
||||
if (success && expected !== input) {
|
||||
success = success && sanitytest.expect(expected, expected);
|
||||
}
|
||||
|
||||
// Everywhere we do newlines, they should be replaced with opts.eol
|
||||
sanitytest.test_function(test_beautifier, 'eol ' + test_name);
|
||||
opts.eol = '\r\\n';
|
||||
expected = expected.replace(/[\n]/g, '\r\n');
|
||||
sanitytest.expect(input, expected);
|
||||
if (input && input.indexOf('\n') !== -1) {
|
||||
opts.disabled = true;
|
||||
success = success && sanitytest.expect(input, input || '');
|
||||
success = success && sanitytest.expect('\n\n' + expected, '\n\n' + expected);
|
||||
opts.disabled = false;
|
||||
success = success && sanitytest.expect(input, expected);
|
||||
if (success && input && input.indexOf('\n') !== -1) {
|
||||
input = input.replace(/[\n]/g, '\r\n');
|
||||
sanitytest.expect(input, expected);
|
||||
// Ensure support for auto eol detection
|
||||
opts.eol = 'auto';
|
||||
sanitytest.expect(input, expected);
|
||||
success = success && sanitytest.expect(input, expected);
|
||||
}
|
||||
opts.eol = '\n';
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// test the input on beautifier with the current flag settings
|
||||
// test both the input as well as { input } wrapping
|
||||
function bt(input, expectation)
|
||||
{
|
||||
var success = true;
|
||||
|
||||
var wrapped_input, wrapped_expectation;
|
||||
|
||||
expectation = expectation || expectation === '' ? expectation : input;
|
||||
sanitytest.test_function(test_js_beautifier, 'js_beautify');
|
||||
test_fragment(input, expectation);
|
||||
success = success && test_fragment(input, expectation);
|
||||
|
||||
// If we set raw, input should be unchanged
|
||||
opts.test_output_raw = true;
|
||||
if (!opts.end_with_newline) {
|
||||
test_fragment(input, input);
|
||||
success = success && test_fragment(input, input);
|
||||
}
|
||||
opts.test_output_raw = false;
|
||||
|
||||
@ -117,16 +134,16 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
|
||||
if (current_indent_size === 4 && input) {
|
||||
wrapped_input = '{\n' + input.replace(/^(.+)$/mg, ' $1') + '\n foo = bar;\n}';
|
||||
wrapped_expectation = '{\n' + expectation.replace(/^(.+)$/mg, ' $1') + '\n foo = bar;\n}';
|
||||
test_fragment(wrapped_input, wrapped_expectation);
|
||||
success = success && test_fragment(wrapped_input, wrapped_expectation);
|
||||
|
||||
// If we set raw, input should be unchanged
|
||||
opts.test_output_raw = true;
|
||||
if (!opts.end_with_newline) {
|
||||
test_fragment(wrapped_input, wrapped_input);
|
||||
success = success && test_fragment(wrapped_input, wrapped_input);
|
||||
}
|
||||
opts.test_output_raw = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// run all tests for the given brace style ("collapse", "expand", "end-expand", or "none").
|
||||
@ -289,6 +306,7 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
|
||||
{{^matrix}}
|
||||
// {{&name}}
|
||||
reset_options();
|
||||
set_name('{{&name}}');
|
||||
{{#options}}
|
||||
opts.{{name}} = {{&value}};
|
||||
{{/options}}
|
||||
@ -300,6 +318,7 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
|
||||
{{#matrix}}
|
||||
// {{&name}} - ({{#matrix_context_string}}.{{/matrix_context_string}})
|
||||
reset_options();
|
||||
set_name('{{&name}} - ({{#matrix_context_string}}.{{/matrix_context_string}})');
|
||||
{{#options}}
|
||||
opts.{{name}} = {{&value}};
|
||||
{{/options}}
|
||||
@ -319,6 +338,12 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
|
||||
//============================================================
|
||||
test_fragment(null, '');
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
// Test user pebkac protection, converts dash names to underscored names
|
||||
opts["end-with-newline"] = true;
|
||||
test_fragment(null, '\n');
|
||||
|
||||
reset_options();
|
||||
//============================================================
|
||||
opts.indent_size = 1;
|
||||
|
@ -52,8 +52,6 @@ class TestJSBeautifier(unittest.TestCase):
|
||||
default_options.indent_char = ' '
|
||||
default_options.preserve_newlines = true
|
||||
default_options.jslint_happy = false
|
||||
default_options.keep_array_indentation = true
|
||||
default_options.brace_style = 'collapse'
|
||||
default_options.indent_level = 0
|
||||
default_options.break_chained_methods = false
|
||||
default_options.eol = '\n'
|
||||
@ -146,6 +144,27 @@ class TestJSBeautifier(unittest.TestCase):
|
||||
#============================================================
|
||||
bt(None, "")
|
||||
|
||||
self.reset_options()
|
||||
#============================================================
|
||||
# Test user pebkac protection, converts dash names to underscored names
|
||||
setattr(self.options, 'end-with-newline', True)
|
||||
test_fragment(None, '\n')
|
||||
|
||||
self.reset_options()
|
||||
#============================================================
|
||||
# Test passing dictionary or tuple
|
||||
self.options = {'end_with_newline': True, 'eol': '\r\n' }
|
||||
test_fragment(None, '\r\n')
|
||||
|
||||
self.options = {'end-with-newline': True}
|
||||
test_fragment(None, '\n')
|
||||
|
||||
self.options = {'end-with-newline': False}
|
||||
test_fragment(None, '')
|
||||
|
||||
self.options = ( ('end-with-newline', True), ('eol', '\r') )
|
||||
test_fragment(None, '\r')
|
||||
|
||||
self.reset_options()
|
||||
#============================================================
|
||||
self.options.indent_size = 1
|
||||
@ -1274,20 +1293,27 @@ class TestJSBeautifier(unittest.TestCase):
|
||||
self.assertMultiLineEqual(
|
||||
jsbeautifier.beautify(expectation, self.options), expectation)
|
||||
|
||||
# Everywhere we do newlines, they should be replaced with opts.eol
|
||||
self.options.eol = '\r\\n'
|
||||
expectation = expectation.replace('\n', '\r\n')
|
||||
self.assertMultiLineEqual(
|
||||
jsbeautifier.beautify(input, self.options), expectation)
|
||||
if input and input.find('\n') != -1:
|
||||
input = input.replace('\n', '\r\n')
|
||||
if self.options is None or not isinstance(self.options, (dict, tuple)):
|
||||
# Everywhere we do newlines, they should be replaced with opts.eol
|
||||
self.options.eol = '\r\\n'
|
||||
expectation = expectation.replace('\n', '\r\n')
|
||||
self.options.disabled = True
|
||||
self.assertMultiLineEqual(
|
||||
jsbeautifier.beautify(input, self.options), input or '')
|
||||
self.assertMultiLineEqual(
|
||||
jsbeautifier.beautify('\n\n' + expectation, self.options), '\n\n' + expectation)
|
||||
self.options.disabled = False;
|
||||
self.assertMultiLineEqual(
|
||||
jsbeautifier.beautify(input, self.options), expectation)
|
||||
# Ensure support for auto eol detection
|
||||
self.options.eol = 'auto'
|
||||
self.assertMultiLineEqual(
|
||||
jsbeautifier.beautify(input, self.options), expectation)
|
||||
self.options.eol = '\n'
|
||||
if input and input.find('\n') != -1:
|
||||
input = input.replace('\n', '\r\n')
|
||||
self.assertMultiLineEqual(
|
||||
jsbeautifier.beautify(input, self.options), expectation)
|
||||
# Ensure support for auto eol detection
|
||||
self.options.eol = 'auto'
|
||||
self.assertMultiLineEqual(
|
||||
jsbeautifier.beautify(input, self.options), expectation)
|
||||
self.options.eol = '\n'
|
||||
|
||||
def wrap(self, text):
|
||||
return self.wrapregex.sub(' \\1', text)
|
||||
|
@ -31,10 +31,7 @@ exports.test_data = {
|
||||
{ name: "indent_size", value: "4" },
|
||||
{ name: "indent_char", value: "' '" },
|
||||
{ name: "preserve_newlines", value: "true" },
|
||||
{ name: "jslint_happy", value: "false" },
|
||||
{ name: "keep_array_indentation", value: "false" },
|
||||
{ name: "brace_style", value: "'collapse'" },
|
||||
{ name: "operator_position", value: "'before-newline'" }
|
||||
{ name: "jslint_happy", value: "false" }
|
||||
],
|
||||
groups: [{
|
||||
name: "Unicode Support",
|
||||
@ -47,6 +44,9 @@ exports.test_data = {
|
||||
" ' + unicode_char(228) + 'rgerlich: true",
|
||||
"};"
|
||||
]
|
||||
}, {
|
||||
input_: "var' + unicode_char(160) + unicode_char(3232) + '_' + unicode_char(3232) + ' = \"hi\";",
|
||||
output: "var ' + unicode_char(3232) + '_' + unicode_char(3232) + ' = \"hi\";"
|
||||
}]
|
||||
}, {
|
||||
name: "Test template and continuation strings",
|
||||
@ -187,6 +187,81 @@ exports.test_data = {
|
||||
{ fragment: true, input: ' \n\nreturn .5\n\n\n\n', output: ' return .5{{eof}}' },
|
||||
{ fragment: true, input: '\n', output: '{{eof}}' }
|
||||
]
|
||||
}, {
|
||||
name: "Support Indent Level Options and Base Indent Autodetection",
|
||||
description: "If user specifies indent level, use it. If not, autodetect indent level from starting whitespace.",
|
||||
matrix: [{
|
||||
options: [],
|
||||
input_start_indent: ' ',
|
||||
output_start_of_base: ' ',
|
||||
i: ' '
|
||||
}, {
|
||||
options: [
|
||||
{ name: "indent_level", value: "0" }
|
||||
],
|
||||
input_start_indent: ' ',
|
||||
output_start_of_base: ' ',
|
||||
i: ' '
|
||||
}, {
|
||||
options: [
|
||||
{ name: "indent_level", value: "1" }
|
||||
],
|
||||
input_start_indent: ' ',
|
||||
output_start_of_base: ' ',
|
||||
i: ' '
|
||||
}, {
|
||||
options: [
|
||||
{ name: "indent_level", value: "2" }
|
||||
],
|
||||
input_start_indent: '',
|
||||
output_start_of_base: ' ',
|
||||
i: ' '
|
||||
}, {
|
||||
options: [
|
||||
{ name: "indent_with_tabs", value: "true" },
|
||||
{ name: "indent_level", value: "2" }
|
||||
],
|
||||
input_start_indent: '',
|
||||
output_start_of_base: '\t\t',
|
||||
i: '\t'
|
||||
}, {
|
||||
options: [
|
||||
{ name: "indent_level", value: "0" }
|
||||
],
|
||||
input_start_indent: '\t ',
|
||||
output_start_of_base: '\t ',
|
||||
i: ' '
|
||||
}],
|
||||
tests: [
|
||||
{ fragment: true, input: '{{input_start_indent}}a', output: '{{output_start_of_base}}a' },
|
||||
{
|
||||
fragment: true,
|
||||
input: [
|
||||
'{{input_start_indent}}function test(){',
|
||||
' console.log("this is a test");',
|
||||
'}'
|
||||
],
|
||||
output: [
|
||||
'{{output_start_of_base}}function test() {',
|
||||
'{{output_start_of_base}}{{i}}console.log("this is a test");',
|
||||
'{{output_start_of_base}}}'
|
||||
]
|
||||
}, {
|
||||
fragment: true,
|
||||
input: [
|
||||
'{{input_start_indent}}// This is a random comment',
|
||||
'function test(){',
|
||||
' console.log("this is a test");',
|
||||
'}'
|
||||
],
|
||||
output: [
|
||||
'{{output_start_of_base}}// This is a random comment',
|
||||
'{{output_start_of_base}}function test() {',
|
||||
'{{output_start_of_base}}{{i}}console.log("this is a test");',
|
||||
'{{output_start_of_base}}}'
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
name: "Support simple language specific option inheritance/overriding",
|
||||
description: "Support simple language specific option inheritance/overriding",
|
||||
@ -254,6 +329,17 @@ exports.test_data = {
|
||||
},
|
||||
|
||||
// brace_style collapse - Shouldn't preserve if no newlines (uses collapse styling)
|
||||
{
|
||||
options: [],
|
||||
ibo: '',
|
||||
iao: '',
|
||||
ibc: '',
|
||||
iac: '',
|
||||
obo: ' ',
|
||||
oao: '\n ',
|
||||
obc: '\n',
|
||||
oac: ' '
|
||||
},
|
||||
{
|
||||
options: [
|
||||
{ name: "brace_style", value: "'collapse'" }
|
||||
@ -298,16 +384,10 @@ exports.test_data = {
|
||||
output: 'if (1)<obo>{<oao>2<obc>}<oac>else<obo>{<oao>3<obc>}'
|
||||
},
|
||||
{
|
||||
input: 'try<ibo>{<iao>a();<ibc>}<iac>' +
|
||||
'catch(b)<ibo>{<iao>c();<ibc>}<iac>' +
|
||||
'catch(d)<ibo>{}<iac>' +
|
||||
'finally<ibo>{<iao>e();<ibc>}',
|
||||
input: 'try<ibo>{<iao>a();<ibc>}<iac>' + 'catch(b)<ibo>{<iao>c();<ibc>}<iac>' + 'catch(d)<ibo>{}<iac>' + 'finally<ibo>{<iao>e();<ibc>}',
|
||||
output:
|
||||
// expected
|
||||
'try<obo>{<oao>a();<obc>}<oac>' +
|
||||
'catch (b)<obo>{<oao>c();<obc>}<oac>' +
|
||||
'catch (d)<obo>{}<oac>' +
|
||||
'finally<obo>{<oao>e();<obc>}'
|
||||
'try<obo>{<oao>a();<obc>}<oac>' + 'catch (b)<obo>{<oao>c();<obc>}<oac>' + 'catch (d)<obo>{}<oac>' + 'finally<obo>{<oao>e();<obc>}'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
@ -477,8 +557,24 @@ exports.test_data = {
|
||||
' .f();',
|
||||
'});'
|
||||
]
|
||||
},
|
||||
{
|
||||
comment: 'regression test for fix #1533',
|
||||
unchanged: [
|
||||
'angular.module("test").controller("testCtrl", function($scope) {',
|
||||
' $scope.tnew;',
|
||||
' $scope.toggle_tnew = function() {',
|
||||
' $scope.mode = 0;',
|
||||
' if (!$scope.tnew) {',
|
||||
' $scope.tnew = {};',
|
||||
' } else $scope.tnew = null;',
|
||||
' }',
|
||||
' $scope.fn = function() {',
|
||||
' return null;',
|
||||
' }',
|
||||
'});'
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}, {
|
||||
name: "Space in parens tests",
|
||||
@ -570,6 +666,12 @@ exports.test_data = {
|
||||
}, {
|
||||
name: "operator_position option - ensure no neswlines if preserve_newlines is false",
|
||||
matrix: [{
|
||||
options: [
|
||||
// test for default
|
||||
// { name: "operator_position", value: "'before-newline'" },
|
||||
{ name: "preserve_newlines", value: "false" }
|
||||
]
|
||||
}, {
|
||||
options: [
|
||||
{ name: "operator_position", value: "'before-newline'" },
|
||||
{ name: "preserve_newlines", value: "false" }
|
||||
@ -592,7 +694,17 @@ exports.test_data = {
|
||||
output: inputlib.operator_position.sanity
|
||||
}]
|
||||
}, {
|
||||
name: "operator_position option - set to 'before-newline' (default value)",
|
||||
name: 'operator_position option - set to "before-newline" (default value)',
|
||||
matrix: [{
|
||||
options: [
|
||||
// test for default
|
||||
// { name: "operator_position", value: "'before-newline'" }
|
||||
]
|
||||
}, {
|
||||
options: [
|
||||
{ name: "operator_position", value: "'before-newline'" }
|
||||
]
|
||||
}],
|
||||
tests: [{
|
||||
comment: 'comprehensive, various newlines',
|
||||
input: inputlib.operator_position.comprehensive,
|
||||
@ -660,7 +772,7 @@ exports.test_data = {
|
||||
]
|
||||
}]
|
||||
}, {
|
||||
name: "operator_position option - set to 'after_newline'",
|
||||
name: 'operator_position option - set to "after_newline"',
|
||||
options: [{
|
||||
name: "operator_position",
|
||||
value: "'after-newline'"
|
||||
@ -731,7 +843,7 @@ exports.test_data = {
|
||||
]
|
||||
}]
|
||||
}, {
|
||||
name: "operator_position option - set to 'preserve-newline'",
|
||||
name: 'operator_position option - set to "preserve-newline"',
|
||||
options: [{
|
||||
name: "operator_position",
|
||||
value: "'preserve-newline'"
|
||||
@ -858,6 +970,27 @@ exports.test_data = {
|
||||
},
|
||||
{
|
||||
unchanged: "async x => x * 2;"
|
||||
},
|
||||
{
|
||||
unchanged: [
|
||||
'async function() {',
|
||||
' const obj = {',
|
||||
' a: 1,',
|
||||
' b: await fn(),',
|
||||
' c: 2',
|
||||
' };',
|
||||
'}'
|
||||
]
|
||||
},
|
||||
{
|
||||
unchanged: [
|
||||
'const a = 1,',
|
||||
' b = a ? await foo() : b,',
|
||||
' c = await foo(),',
|
||||
' d = 3,',
|
||||
' e = (await foo()),',
|
||||
' f = 4;'
|
||||
]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
@ -1456,12 +1589,16 @@ exports.test_data = {
|
||||
comment: 'Directive: ignore',
|
||||
unchanged: "/* beautify ignore:start */\n/* beautify ignore:end */"
|
||||
},
|
||||
{ unchanged: "/* beautify ignore:start */\n var a,,,{ 1;\n/* beautify ignore:end */" },
|
||||
{ unchanged: "/* beautify ignore:start */\n var a,,,{ 1;\n /* beautify ignore:end */" },
|
||||
{ unchanged: "var a = 1;\n/* beautify ignore:start */\n var a = 1;\n/* beautify ignore:end */" },
|
||||
{ unchanged: "/* beautify ignore:start */ {asdklgh;y;+++;dd2d}/* beautify ignore:end */" },
|
||||
{
|
||||
input_: "var a = 1;\n/* beautify ignore:start */\n var a,,,{ 1;\n/* beautify ignore:end */",
|
||||
output: "var a = 1;\n/* beautify ignore:start */\n var a,,,{ 1;\n/* beautify ignore:end */"
|
||||
comment: 'ignore starts _after_ the start comment, ends after the end comment',
|
||||
unchanged: "/* beautify ignore:start */ {asdklgh;y;+++;dd2d}/* beautify ignore:end */"
|
||||
},
|
||||
{ unchanged: "/* beautify ignore:start */ {asdklgh;y;+++;dd2d} /* beautify ignore:end */" },
|
||||
{
|
||||
input_: "var a = 1;\n/* beautify ignore:start */\n var a,,,{ 1;\n/*beautify ignore:end*/",
|
||||
output: "var a = 1;\n/* beautify ignore:start */\n var a,,,{ 1;\n/*beautify ignore:end*/"
|
||||
},
|
||||
{
|
||||
input_: "var a = 1;\n /* beautify ignore:start */\n var a,,,{ 1;\n/* beautify ignore:end */",
|
||||
@ -1773,28 +1910,39 @@ exports.test_data = {
|
||||
{ name: "space_after_anon_function", value: "true" }
|
||||
],
|
||||
f: ' ',
|
||||
c: ''
|
||||
c: '',
|
||||
nf: ''
|
||||
}, {
|
||||
options: [
|
||||
{ name: "jslint_happy", value: "true" },
|
||||
{ name: "space_after_anon_function", value: "false" }
|
||||
],
|
||||
f: ' ',
|
||||
c: ''
|
||||
c: '',
|
||||
nf: ''
|
||||
}, {
|
||||
options: [
|
||||
{ name: "jslint_happy", value: "false" },
|
||||
{ name: "space_after_anon_function", value: "true" }
|
||||
],
|
||||
f: ' ',
|
||||
c: ' '
|
||||
c: ' ',
|
||||
nf: ''
|
||||
}, {
|
||||
options: [
|
||||
{ name: "jslint_happy", value: "false" },
|
||||
{ name: "space_after_anon_function", value: "false" }
|
||||
],
|
||||
f: '',
|
||||
c: ' '
|
||||
c: ' ',
|
||||
nf: ''
|
||||
}, {
|
||||
options: [
|
||||
{ name: "space_after_named_function", value: "true" }
|
||||
],
|
||||
f: '',
|
||||
c: ' ',
|
||||
nf: ' '
|
||||
}
|
||||
|
||||
|
||||
@ -1807,10 +1955,18 @@ exports.test_data = {
|
||||
input_: 'x();\n\nfunction(){}',
|
||||
output: 'x();\n\nfunction{{f}}() {}'
|
||||
},
|
||||
{
|
||||
input_: 'x();\n\nfunction y(){}',
|
||||
output: 'x();\n\nfunction y{{nf}}() {}'
|
||||
},
|
||||
{
|
||||
input_: 'x();\n\nvar x = {\nx: function(){}\n}',
|
||||
output: 'x();\n\nvar x = {\n x: function{{f}}() {}\n}'
|
||||
},
|
||||
{
|
||||
input_: 'x();\n\nvar x = {\nx: function y(){}\n}',
|
||||
output: 'x();\n\nvar x = {\n x: function y{{nf}}() {}\n}'
|
||||
},
|
||||
{
|
||||
input_: 'function () {\n var a, b, c, d, e = [],\n f;\n}',
|
||||
output: 'function{{f}}() {\n var a, b, c, d, e = [],\n f;\n}'
|
||||
@ -1834,6 +1990,10 @@ exports.test_data = {
|
||||
input_: 'var a2, b2, c2, d2 = 0, c = function() {}, d = \\\'\\\';',
|
||||
output: 'var a2, b2, c2, d2 = 0,\n c = function{{f}}() {},\n d = \\\'\\\';'
|
||||
},
|
||||
{
|
||||
input_: 'var a2, b2, c2, d2 = 0, c = function yoohoo() {}, d = \\\'\\\';',
|
||||
output: 'var a2, b2, c2, d2 = 0,\n c = function yoohoo{{nf}}() {},\n d = \\\'\\\';'
|
||||
},
|
||||
{
|
||||
input_: 'var a2, b2, c2, d2 = 0, c = function() {},\nd = \\\'\\\';',
|
||||
output: 'var a2, b2, c2, d2 = 0,\n c = function{{f}}() {},\n d = \\\'\\\';'
|
||||
@ -1842,8 +2002,26 @@ exports.test_data = {
|
||||
input_: 'var o2=$.extend(a);function(){alert(x);}',
|
||||
output: 'var o2 = $.extend(a);\n\nfunction{{f}}() {\n alert(x);\n}'
|
||||
},
|
||||
{ input: 'function*() {\n yield 1;\n}', output: 'function*{{f}}() {\n yield 1;\n}' },
|
||||
{ unchanged: 'function* x() {\n yield 1;\n}' }
|
||||
{
|
||||
input_: 'var o2=$.extend(a);function yoohoo(){alert(x);}',
|
||||
output: 'var o2 = $.extend(a);\n\nfunction yoohoo{{nf}}() {\n alert(x);\n}'
|
||||
},
|
||||
{
|
||||
input: 'function*() {\n yield 1;\n}',
|
||||
output: 'function*{{f}}() {\n yield 1;\n}'
|
||||
},
|
||||
{
|
||||
input: 'function* yoohoo() {\n yield 1;\n}',
|
||||
output: 'function* yoohoo{{nf}}() {\n yield 1;\n}'
|
||||
},
|
||||
{
|
||||
input: 'function* x() {\n yield 1;\n}',
|
||||
output: 'function* x{{nf}}() {\n yield 1;\n}'
|
||||
},
|
||||
{
|
||||
input: 'async x() {\n yield 1;\n}',
|
||||
output: 'async x{{nf}}() {\n yield 1;\n}'
|
||||
}
|
||||
]
|
||||
}, {
|
||||
name: "Regression tests",
|
||||
@ -2150,6 +2328,19 @@ exports.test_data = {
|
||||
'}'
|
||||
]
|
||||
},
|
||||
{
|
||||
comment: "Issue 1544 - Typescript declare formatting (no newline).",
|
||||
unchanged: [
|
||||
'declare const require: any;',
|
||||
'declare function greet(greeting: string): void;',
|
||||
'declare var foo: number;',
|
||||
'declare namespace myLib {',
|
||||
' function makeGreeting(s: string): string;',
|
||||
' let numberOfGreetings: number;',
|
||||
'}',
|
||||
'declare let test: any;'
|
||||
]
|
||||
},
|
||||
{
|
||||
unchanged: [
|
||||
'interface Test {',
|
||||
@ -2742,8 +2933,7 @@ exports.test_data = {
|
||||
' var obj = {<oao>' + //NL in templates
|
||||
'<oaot><oaot>a: function() { console.log("test"); },',
|
||||
' b()<obo><obot><obot>{<oao>' + //NL in templates
|
||||
'<oaot><oaot><oaot>console.log("test2");' +
|
||||
'<obc> }' + //NL in templates
|
||||
'<oaot><oaot><oaot>console.log("test2");' + '<obc> }' + //NL in templates
|
||||
'<obc> };' + //NL in templates
|
||||
'<obc>}'
|
||||
]
|
||||
@ -2787,6 +2977,11 @@ exports.test_data = {
|
||||
'}'
|
||||
]
|
||||
},
|
||||
{
|
||||
comment: "Issue #1197 - dynamic import() arrow syntax",
|
||||
input: 'frontend = Async(() => import("../frontend").then(m => m.default ))',
|
||||
output: 'frontend = Async(() => import("../frontend").then(m => m.default))'
|
||||
},
|
||||
{
|
||||
comment: "Issue 858 - from is a keyword only after import",
|
||||
unchanged: [
|
||||
@ -3004,6 +3199,9 @@ exports.test_data = {
|
||||
{ unchanged: 'a[1]()', comment: 'another magic function call' },
|
||||
{ input: 'if(a){b();}else if(c) foo();', output: "if (a) {\n b();\n} else if (c) foo();" },
|
||||
{ input: 'switch(x) {case 0: case 1: a(); break; default: break}', output: "switch (x) {\n case 0:\n case 1:\n a();\n break;\n default:\n break\n}" },
|
||||
|
||||
{ input: 'switch(x) {default: case 1: a(); break; case 0: break}', output: "switch (x) {\n default:\n case 1:\n a();\n break;\n case 0:\n break\n}" },
|
||||
|
||||
{ input: 'switch(x){case -1:break;case !y:break;}', output: 'switch (x) {\n case -1:\n break;\n case !y:\n break;\n}' },
|
||||
{ unchanged: 'a !== b' },
|
||||
{ input: 'if (a) b(); else c();', output: "if (a) b();\nelse c();" },
|
||||
|
@ -26,6 +26,8 @@
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var mustache = require('mustache');
|
||||
var path = require('path');
|
||||
@ -100,13 +102,11 @@ function set_formatters(data, test_method, comment_mark) {
|
||||
return function(text, render) {
|
||||
var outputs = [];
|
||||
// text is ignored for this
|
||||
for (var name in context) {
|
||||
if (name === 'options') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (context.hasOwnProperty(name)) {
|
||||
outputs.push(name + ' = "' + context[name].replace(/\n/g, '\\n').replace(/\t/g, '\\t') + '"');
|
||||
if (context.options) {
|
||||
var item;
|
||||
for (var x = 0; x < context.options.length; x++) {
|
||||
item = context.options[x];
|
||||
outputs.push(item.name + ' = "' + item.value.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/[']/g, "\"") + '"');
|
||||
}
|
||||
}
|
||||
return render(outputs.join(', '));
|
||||
|
3
test/resources/github-min.js
vendored
Normal file
3
test/resources/github-min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
test/resources/github.css
Normal file
7
test/resources/github.css
Normal file
File diff suppressed because one or more lines are too long
3634
test/resources/github.html
Normal file
3634
test/resources/github.html
Normal file
File diff suppressed because it is too large
Load Diff
1
test/resources/unicode-error.js
Normal file
1
test/resources/unicode-error.js
Normal file
@ -0,0 +1 @@
|
||||
T(e){var C,T,E,x,A,M,P,D,N,z,B=[],H={},j={},R={},L={},q=!1,I=null,F=null,O=null,U=0,X=[],Y=null,V=null,W=null,G=!1,Q=!1,$=10,K=30,J=!0,Z=!1,et=!1,tt=!1,nt=0,it=0,at=!1;function ot(e){e=e.replace(/https?:\/\/(m\.)?vk\.com\/([^#]+#\/)?/,"");for(var r,s,l,c=Q,u=[e,s=t(e,c)||e,l=n(e,c)||e,i(s),a(l)],d={},p=[],f=0,h=u.length;h>f;f++)u[f]&&!d[u[f]]&&(d[u[f]]=!0,r=o(u[f]),r=r.replace(/[å¸]/gi,"[å¸]").replace(/(e|yo)/gi,"(?:e|yo)"),p.push(new RegExp("(^|\\s|\\(|>)("+r+")","gi")));return p}function rt(e,t,n){if(clearTimeout(F),!n)return F=setTimeout(function(){rt(e,t,!0)},10),!1;var i=r(e)||"";if(I==i)return!1;var a,o="_"+i,l=j[o],c=ot(i);if(!l&&i.length>2&&j["_"+i.slice(0,-2)]){var u="_"+i.slice(0,-2);j[u]&&L[u]&&!j[u].length&&(!tt||tt&&!R[u])&&(L[o]=!0,l=j[o]=[],tt&&(R[o]=""))}if(!l){l=[];var d=0;if(!i&&B.length)for(var p=U,f=U+Math.min($,B.length);f>p;p++)l.push([B[p]]),d++;else{for(var h={},_=0,p=0,f=B.length;f>p;p++){var v=B[p];if(H[v]){if(h[v]=!0,(a=lt(c,H[v][0]))&&(l.push([v,a]),++_>=K))
|
@ -21,18 +21,9 @@ build_js()
|
||||
|
||||
# Wrap webkit output into an non-breaking form.
|
||||
# In an upcoming verion these will be replaced with standard webpack umd
|
||||
cat ./tools/template/beautify.begin.js > ./js/lib/beautify.js
|
||||
cat ./dist/legacy_beautify_js.js >> ./js/lib/beautify.js
|
||||
cat ./tools/template/beautify.end.js >> ./js/lib/beautify.js
|
||||
|
||||
cat ./tools/template/beautify-css.begin.js > ./js/lib/beautify-css.js
|
||||
cat ./dist/legacy_beautify_css.js >> ./js/lib/beautify-css.js
|
||||
cat ./tools/template/beautify-css.end.js >> ./js/lib/beautify-css.js
|
||||
|
||||
cat ./tools/template/beautify-html.begin.js > ./js/lib/beautify-html.js
|
||||
cat ./dist/legacy_beautify_html.js >> ./js/lib/beautify-html.js
|
||||
cat ./tools/template/beautify-html.end.js >> ./js/lib/beautify-html.js
|
||||
|
||||
sed '/GENERATED_BUILD_OUTPUT/ r ./build/legacy/legacy_beautify_js.js' <./tools/template/beautify.wrapper.js >./js/lib/beautify.js || exit 1
|
||||
sed '/GENERATED_BUILD_OUTPUT/ r ./build/legacy/legacy_beautify_css.js' <./tools/template/beautify-css.wrapper.js >./js/lib/beautify-css.js || exit 1
|
||||
sed '/GENERATED_BUILD_OUTPUT/ r ./build/legacy/legacy_beautify_html.js' <./tools/template/beautify-html.wrapper.js >./js/lib/beautify-html.js || exit 1
|
||||
}
|
||||
|
||||
build_beautify()
|
||||
@ -62,8 +53,7 @@ build_beautify()
|
||||
|
||||
$PROJECT_DIR/js/bin/css-beautify.js --config $PROJECT_DIR/jsbeautifyrc -r $PROJECT_DIR/web/common-style.css || exit 1
|
||||
|
||||
# html not ready yet
|
||||
# $PROJECT_DIR/js/bin/html-beautify.js --config $PROJECT_DIR/jsbeautifyrc -r index.html
|
||||
$PROJECT_DIR/js/bin/html-beautify.js --config $PROJECT_DIR/jsbeautifyrc -r index.html
|
||||
|
||||
build_js
|
||||
}
|
||||
|
@ -13,45 +13,35 @@ esac
|
||||
release_python()
|
||||
{
|
||||
cd $SCRIPT_DIR/..
|
||||
git checkout -B release origin/release
|
||||
git clean -xfd || exit 1
|
||||
echo "__version__ = '$NEW_VERSION'" > python/jsbeautifier/__version__.py
|
||||
git commit -am "Python $NEW_VERSION"
|
||||
cd python
|
||||
# python setup.py register -r pypi
|
||||
python setup.py sdist || exit 1
|
||||
python -m twine upload dist/* || exit 1
|
||||
git push
|
||||
}
|
||||
|
||||
release_node()
|
||||
{
|
||||
cd $SCRIPT_DIR/..
|
||||
git checkout -B release origin/release
|
||||
git clean -xfd || exit 1
|
||||
make js || exit 1
|
||||
npm version $NEW_VERSION
|
||||
unset NPM_TAG
|
||||
if [[ $NEW_VERSION =~ .*(rc|beta).* ]]; then
|
||||
NPM_TAG='--tag next'
|
||||
fi
|
||||
npm publish . $NPM_TAG || exit 1
|
||||
git push
|
||||
git push --tags
|
||||
}
|
||||
|
||||
release_web()
|
||||
{
|
||||
cd $SCRIPT_DIR/..
|
||||
local ORIGINAL_BRANCH
|
||||
ORIGINAL_BRANCH=$(git branch | grep '[*] .*' | awk '{print $2}')
|
||||
git clean -xfd || exit 1
|
||||
git fetch || exit 1
|
||||
git checkout -B gh-pages origin/gh-pages || exit 1
|
||||
git merge origin/master --no-edit || exit 1
|
||||
make js || exit 1
|
||||
git add -f js/lib/ || exit 1
|
||||
git commit -m "Built files for $NEW_VERSION"
|
||||
git merge origin/release --no-edit || exit 1
|
||||
git push || exit 1
|
||||
git checkout $ORIGINAL_BRANCH
|
||||
git checkout master
|
||||
}
|
||||
|
||||
sedi() {
|
||||
@ -64,17 +54,39 @@ sedi() {
|
||||
fi
|
||||
}
|
||||
|
||||
update_readme_versions()
|
||||
update_versions()
|
||||
{
|
||||
git fetch --all || exit 1
|
||||
git checkout master || exit 1
|
||||
git reset --hard origin/master || exit 1
|
||||
git clean -xfd || exit 1
|
||||
#sedi -E 's@(cdn.rawgit.+beautify/v)[^/]+@\1'$NEW_VERSION'@' README.md
|
||||
npm version --no-git-tag-version $NEW_VERSION
|
||||
|
||||
sedi -E 's@(cdn.rawgit.+beautify/v)[^/]+@\1'$NEW_VERSION'@' README.md
|
||||
sedi -E 's@(cdnjs.cloudflare.+beautify/)[^/]+@\1'$NEW_VERSION'@' README.md
|
||||
sedi -E 's/\((README\.md:.js-beautify@).+\)/(\1'$NEW_VERSION')/' README.md
|
||||
git add README.md
|
||||
git commit -m "Bump version numbers in README.md"
|
||||
|
||||
echo "__version__ = '$NEW_VERSION'" > python/jsbeautifier/__version__.py
|
||||
git add .
|
||||
git commit -am "Bump version numbers for $NEW_VERSION"
|
||||
git push
|
||||
}
|
||||
|
||||
update_release_branch()
|
||||
{
|
||||
git reset --hard
|
||||
git clean -xfd
|
||||
git checkout -B release origin/release || exit 1
|
||||
git merge origin/master --no-edit || exit 1
|
||||
|
||||
make js || exit 1
|
||||
git add -f js/lib/ || exit 1
|
||||
git commit -m "Release: $NEW_VERSION"
|
||||
git tag "v$NEW_VERSION" || exit 1
|
||||
git push || exit 1
|
||||
git push --tags
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
cd $SCRIPT_DIR/..
|
||||
@ -82,11 +94,9 @@ main()
|
||||
local NEW_VERSION=$1
|
||||
NEW_VERSION=$1
|
||||
|
||||
git checkout master
|
||||
git reset --hard
|
||||
git clean -xfd
|
||||
update_versions
|
||||
update_release_branch
|
||||
|
||||
update_readme_versions
|
||||
release_python
|
||||
release_node
|
||||
release_web
|
||||
|
@ -1,23 +0,0 @@
|
||||
|
||||
var css_beautify = legacy_beautify_css;
|
||||
/* Footer */
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define([], function() {
|
||||
return {
|
||||
css_beautify: css_beautify
|
||||
};
|
||||
});
|
||||
} else if (typeof exports !== "undefined") {
|
||||
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
||||
// and you will be able to `var html_beautify = require("beautify").html_beautify`.
|
||||
exports.css_beautify = css_beautify;
|
||||
} else if (typeof window !== "undefined") {
|
||||
// If we're running a web page and don't have either of the above, add our one global
|
||||
window.css_beautify = css_beautify;
|
||||
} else if (typeof global !== "undefined") {
|
||||
// If we don't even have window, try global.
|
||||
global.css_beautify = css_beautify;
|
||||
}
|
||||
|
||||
}());
|
@ -1,4 +1,3 @@
|
||||
/*jshint curly:false, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/* AUTO-GENERATED. DO NOT MODIFY. */
|
||||
/*
|
||||
|
||||
@ -32,8 +31,8 @@
|
||||
|
||||
Written by Harutyun Amirjanyan, (amirjanyan@gmail.com)
|
||||
|
||||
Based on code initially developed by: Einar Lielmanis, <einar@jsbeautifier.org>
|
||||
http://jsbeautifier.org/
|
||||
Based on code initially developed by: Einar Lielmanis, <einar@beautifier.io>
|
||||
https://beautifier.io/
|
||||
|
||||
Usage:
|
||||
css_beautify(source_text);
|
||||
@ -64,3 +63,28 @@
|
||||
// http://www.w3.org/TR/css3-syntax/
|
||||
|
||||
(function() {
|
||||
|
||||
/* GENERATED_BUILD_OUTPUT */
|
||||
|
||||
var css_beautify = legacy_beautify_css;
|
||||
/* Footer */
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define([], function() {
|
||||
return {
|
||||
css_beautify: css_beautify
|
||||
};
|
||||
});
|
||||
} else if (typeof exports !== "undefined") {
|
||||
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
||||
// and you will be able to `var html_beautify = require("beautify").html_beautify`.
|
||||
exports.css_beautify = css_beautify;
|
||||
} else if (typeof window !== "undefined") {
|
||||
// If we're running a web page and don't have either of the above, add our one global
|
||||
window.css_beautify = css_beautify;
|
||||
} else if (typeof global !== "undefined") {
|
||||
// If we don't even have window, try global.
|
||||
global.css_beautify = css_beautify;
|
||||
}
|
||||
|
||||
}());
|
@ -1,37 +0,0 @@
|
||||
|
||||
var style_html = legacy_beautify_html;
|
||||
/* Footer */
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define(["require", "./beautify", "./beautify-css"], function(requireamd) {
|
||||
var js_beautify = requireamd("./beautify");
|
||||
var css_beautify = requireamd("./beautify-css");
|
||||
|
||||
return {
|
||||
html_beautify: function(html_source, options) {
|
||||
return style_html(html_source, options, js_beautify.js_beautify, css_beautify.css_beautify);
|
||||
}
|
||||
};
|
||||
});
|
||||
} else if (typeof exports !== "undefined") {
|
||||
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
||||
// and you will be able to `var html_beautify = require("beautify").html_beautify`.
|
||||
var js_beautify = require('./beautify.js');
|
||||
var css_beautify = require('./beautify-css.js');
|
||||
|
||||
exports.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, js_beautify.js_beautify, css_beautify.css_beautify);
|
||||
};
|
||||
} else if (typeof window !== "undefined") {
|
||||
// If we're running a web page and don't have either of the above, add our one global
|
||||
window.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, window.js_beautify, window.css_beautify);
|
||||
};
|
||||
} else if (typeof global !== "undefined") {
|
||||
// If we don't even have window, try global.
|
||||
global.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, global.js_beautify, global.css_beautify);
|
||||
};
|
||||
}
|
||||
|
||||
}());
|
@ -1,4 +1,3 @@
|
||||
/*jshint curly:false, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/* AUTO-GENERATED. DO NOT MODIFY. */
|
||||
/*
|
||||
|
||||
@ -32,8 +31,8 @@
|
||||
|
||||
Written by Nochum Sossonko, (nsossonko@hotmail.com)
|
||||
|
||||
Based on code initially developed by: Einar Lielmanis, <einar@jsbeautifier.org>
|
||||
http://jsbeautifier.org/
|
||||
Based on code initially developed by: Einar Lielmanis, <einar@beautifier.io>
|
||||
https://beautifier.io/
|
||||
|
||||
Usage:
|
||||
style_html(html_source);
|
||||
@ -74,3 +73,42 @@
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
/* GENERATED_BUILD_OUTPUT */
|
||||
|
||||
var style_html = legacy_beautify_html;
|
||||
/* Footer */
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define(["require", "./beautify", "./beautify-css"], function(requireamd) {
|
||||
var js_beautify = requireamd("./beautify");
|
||||
var css_beautify = requireamd("./beautify-css");
|
||||
|
||||
return {
|
||||
html_beautify: function(html_source, options) {
|
||||
return style_html(html_source, options, js_beautify.js_beautify, css_beautify.css_beautify);
|
||||
}
|
||||
};
|
||||
});
|
||||
} else if (typeof exports !== "undefined") {
|
||||
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
||||
// and you will be able to `var html_beautify = require("beautify").html_beautify`.
|
||||
var js_beautify = require('./beautify.js');
|
||||
var css_beautify = require('./beautify-css.js');
|
||||
|
||||
exports.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, js_beautify.js_beautify, css_beautify.css_beautify);
|
||||
};
|
||||
} else if (typeof window !== "undefined") {
|
||||
// If we're running a web page and don't have either of the above, add our one global
|
||||
window.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, window.js_beautify, window.css_beautify);
|
||||
};
|
||||
} else if (typeof global !== "undefined") {
|
||||
// If we don't even have window, try global.
|
||||
global.html_beautify = function(html_source, options) {
|
||||
return style_html(html_source, options, global.js_beautify, global.css_beautify);
|
||||
};
|
||||
}
|
||||
|
||||
}());
|
@ -1,21 +0,0 @@
|
||||
|
||||
var js_beautify = legacy_beautify_js;
|
||||
/* Footer */
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define([], function() {
|
||||
return { js_beautify: js_beautify };
|
||||
});
|
||||
} else if (typeof exports !== "undefined") {
|
||||
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
||||
// and you will be able to `var js_beautify = require("beautify").js_beautify`.
|
||||
exports.js_beautify = js_beautify;
|
||||
} else if (typeof window !== "undefined") {
|
||||
// If we're running a web page and don't have either of the above, add our one global
|
||||
window.js_beautify = js_beautify;
|
||||
} else if (typeof global !== "undefined") {
|
||||
// If we don't even have window, try global.
|
||||
global.js_beautify = js_beautify;
|
||||
}
|
||||
|
||||
}());
|
@ -1,6 +1,4 @@
|
||||
/*jshint curly:false, eqeqeq:true, laxbreak:true, noempty:false */
|
||||
/* AUTO-GENERATED. DO NOT MODIFY. */
|
||||
/* see js/src/javascript/index.js */
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
@ -31,12 +29,12 @@
|
||||
---------------
|
||||
|
||||
|
||||
Written by Einar Lielmanis, <einar@jsbeautifier.org>
|
||||
http://jsbeautifier.org/
|
||||
Written by Einar Lielmanis, <einar@beautifier.io>
|
||||
https://beautifier.io/
|
||||
|
||||
Originally converted to javascript by Vital, <vital76@gmail.com>
|
||||
"End braces on own line" added by Chris J. Shull, <chrisjshull@gmail.com>
|
||||
Parsing improvements for brace-less statements by Liam Newman <bitwiseman@gmail.com>
|
||||
Parsing improvements for brace-less statements by Liam Newman <bitwiseman@beautifier.io>
|
||||
|
||||
|
||||
Usage:
|
||||
@ -88,3 +86,27 @@
|
||||
*/
|
||||
|
||||
(function() {
|
||||
|
||||
/* GENERATED_BUILD_OUTPUT */
|
||||
|
||||
var js_beautify = legacy_beautify_js;
|
||||
/* Footer */
|
||||
if (typeof define === "function" && define.amd) {
|
||||
// Add support for AMD ( https://github.com/amdjs/amdjs-api/wiki/AMD#defineamd-property- )
|
||||
define([], function() {
|
||||
return { js_beautify: js_beautify };
|
||||
});
|
||||
} else if (typeof exports !== "undefined") {
|
||||
// Add support for CommonJS. Just put this file somewhere on your require.paths
|
||||
// and you will be able to `var js_beautify = require("beautify").js_beautify`.
|
||||
exports.js_beautify = js_beautify;
|
||||
} else if (typeof window !== "undefined") {
|
||||
// If we're running a web page and don't have either of the above, add our one global
|
||||
window.js_beautify = js_beautify;
|
||||
} else if (typeof global !== "undefined") {
|
||||
// If we don't even have window, try global.
|
||||
global.js_beautify = js_beautify;
|
||||
}
|
||||
|
||||
}());
|
||||
|
@ -1,3 +1,4 @@
|
||||
/*jshint strict:false, node:false */
|
||||
/*exported run_tests, read_settings_from_cookie, beautify, submitIssue */
|
||||
var the = {
|
||||
use_codemirror: !window.location.href.match(/without-codemirror/),
|
||||
@ -20,6 +21,7 @@ requirejs(['beautifier'],
|
||||
the.beautifier = beautifier;
|
||||
});
|
||||
|
||||
|
||||
function any(a, b) {
|
||||
return a || b;
|
||||
}
|
||||
@ -95,26 +97,28 @@ function store_settings_to_cookie() {
|
||||
}
|
||||
|
||||
function unpacker_filter(source) {
|
||||
var trailing_comments = '',
|
||||
var leading_comments = '',
|
||||
comment = '',
|
||||
unpacked = '',
|
||||
found = false;
|
||||
|
||||
// cut trailing comments
|
||||
// cuts leading comments
|
||||
do {
|
||||
found = false;
|
||||
if (/^\s*\/\*/.test(source)) {
|
||||
found = true;
|
||||
comment = source.substr(0, source.indexOf('*/') + 2);
|
||||
source = source.substr(comment.length).replace(/^\s+/, '');
|
||||
trailing_comments += comment + "\n";
|
||||
source = source.substr(comment.length);
|
||||
leading_comments += comment;
|
||||
} else if (/^\s*\/\//.test(source)) {
|
||||
found = true;
|
||||
comment = source.match(/^\s*\/\/.*/)[0];
|
||||
source = source.substr(comment.length).replace(/^\s+/, '');
|
||||
trailing_comments += comment + "\n";
|
||||
source = source.substr(comment.length);
|
||||
leading_comments += comment;
|
||||
}
|
||||
} while (found);
|
||||
leading_comments += '\n';
|
||||
source = source.replace(/^\s+/, '');
|
||||
|
||||
var unpackers = [P_A_C_K_E_R, Urlencoded, JavascriptObfuscator /*, MyObfuscate*/ ];
|
||||
for (var i = 0; i < unpackers.length; i++) {
|
||||
@ -126,7 +130,7 @@ function unpacker_filter(source) {
|
||||
}
|
||||
}
|
||||
|
||||
return trailing_comments + source;
|
||||
return leading_comments + source;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
/*jshint node:false, jquery:true, strict:false */
|
||||
$(function() {
|
||||
|
||||
read_settings_from_cookie();
|
||||
|
@ -13,7 +13,7 @@ var legacy = {
|
||||
output: {
|
||||
library: 'legacy_[name]',
|
||||
filename: 'legacy_[name].js',
|
||||
path: path.resolve(__dirname, 'dist')
|
||||
path: path.resolve(__dirname, 'build/legacy')
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user